xref: /linux/arch/x86/kernel/reboot.c (revision c415b3dce30dfb41234e118662e8720f47343a4f)
14d022e35SMiguel Boton #include <linux/module.h>
24d022e35SMiguel Boton #include <linux/reboot.h>
34d022e35SMiguel Boton #include <linux/init.h>
44d022e35SMiguel Boton #include <linux/pm.h>
54d022e35SMiguel Boton #include <linux/efi.h>
64d022e35SMiguel Boton #include <acpi/reboot.h>
74d022e35SMiguel Boton #include <asm/io.h>
84d022e35SMiguel Boton #include <asm/apic.h>
94d022e35SMiguel Boton #include <asm/desc.h>
104d022e35SMiguel Boton #include <asm/hpet.h>
1168db065cSJeremy Fitzhardinge #include <asm/pgtable.h>
124412620fSDmitri Vorobiev #include <asm/proto.h>
134d022e35SMiguel Boton #include <asm/reboot_fixups.h>
144d022e35SMiguel Boton #include <asm/reboot.h>
154d022e35SMiguel Boton 
164d022e35SMiguel Boton #ifdef CONFIG_X86_32
174d022e35SMiguel Boton # include <linux/dmi.h>
184d022e35SMiguel Boton # include <linux/ctype.h>
194d022e35SMiguel Boton # include <linux/mc146818rtc.h>
204d022e35SMiguel Boton #else
214d022e35SMiguel Boton # include <asm/iommu.h>
224d022e35SMiguel Boton #endif
234d022e35SMiguel Boton 
242ddded21SEduardo Habkost #include <mach_ipi.h>
252ddded21SEduardo Habkost 
262ddded21SEduardo Habkost 
274d022e35SMiguel Boton /*
284d022e35SMiguel Boton  * Power off function, if any
294d022e35SMiguel Boton  */
304d022e35SMiguel Boton void (*pm_power_off)(void);
314d022e35SMiguel Boton EXPORT_SYMBOL(pm_power_off);
324d022e35SMiguel Boton 
33ebdd561aSJan Beulich static const struct desc_ptr no_idt = {};
344d022e35SMiguel Boton static int reboot_mode;
358d00450dSEduardo Habkost enum reboot_type reboot_type = BOOT_KBD;
364d022e35SMiguel Boton int reboot_force;
374d022e35SMiguel Boton 
384d022e35SMiguel Boton #if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
394d022e35SMiguel Boton static int reboot_cpu = -1;
404d022e35SMiguel Boton #endif
414d022e35SMiguel Boton 
424d022e35SMiguel Boton /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]
434d022e35SMiguel Boton    warm   Don't set the cold reboot flag
444d022e35SMiguel Boton    cold   Set the cold reboot flag
454d022e35SMiguel Boton    bios   Reboot by jumping through the BIOS (only for X86_32)
464d022e35SMiguel Boton    smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
474d022e35SMiguel Boton    triple Force a triple fault (init)
484d022e35SMiguel Boton    kbd    Use the keyboard controller. cold reset (default)
494d022e35SMiguel Boton    acpi   Use the RESET_REG in the FADT
504d022e35SMiguel Boton    efi    Use efi reset_system runtime service
514d022e35SMiguel Boton    force  Avoid anything that could hang.
524d022e35SMiguel Boton  */
534d022e35SMiguel Boton static int __init reboot_setup(char *str)
544d022e35SMiguel Boton {
554d022e35SMiguel Boton 	for (;;) {
564d022e35SMiguel Boton 		switch (*str) {
574d022e35SMiguel Boton 		case 'w':
584d022e35SMiguel Boton 			reboot_mode = 0x1234;
594d022e35SMiguel Boton 			break;
604d022e35SMiguel Boton 
614d022e35SMiguel Boton 		case 'c':
624d022e35SMiguel Boton 			reboot_mode = 0;
634d022e35SMiguel Boton 			break;
644d022e35SMiguel Boton 
654d022e35SMiguel Boton #ifdef CONFIG_X86_32
664d022e35SMiguel Boton #ifdef CONFIG_SMP
674d022e35SMiguel Boton 		case 's':
684d022e35SMiguel Boton 			if (isdigit(*(str+1))) {
694d022e35SMiguel Boton 				reboot_cpu = (int) (*(str+1) - '0');
704d022e35SMiguel Boton 				if (isdigit(*(str+2)))
714d022e35SMiguel Boton 					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
724d022e35SMiguel Boton 			}
734d022e35SMiguel Boton 				/* we will leave sorting out the final value
744d022e35SMiguel Boton 				   when we are ready to reboot, since we might not
754d022e35SMiguel Boton 				   have set up boot_cpu_id or smp_num_cpu */
764d022e35SMiguel Boton 			break;
774d022e35SMiguel Boton #endif /* CONFIG_SMP */
784d022e35SMiguel Boton 
794d022e35SMiguel Boton 		case 'b':
804d022e35SMiguel Boton #endif
814d022e35SMiguel Boton 		case 'a':
824d022e35SMiguel Boton 		case 'k':
834d022e35SMiguel Boton 		case 't':
844d022e35SMiguel Boton 		case 'e':
854d022e35SMiguel Boton 			reboot_type = *str;
864d022e35SMiguel Boton 			break;
874d022e35SMiguel Boton 
884d022e35SMiguel Boton 		case 'f':
894d022e35SMiguel Boton 			reboot_force = 1;
904d022e35SMiguel Boton 			break;
914d022e35SMiguel Boton 		}
924d022e35SMiguel Boton 
934d022e35SMiguel Boton 		str = strchr(str, ',');
944d022e35SMiguel Boton 		if (str)
954d022e35SMiguel Boton 			str++;
964d022e35SMiguel Boton 		else
974d022e35SMiguel Boton 			break;
984d022e35SMiguel Boton 	}
994d022e35SMiguel Boton 	return 1;
1004d022e35SMiguel Boton }
1014d022e35SMiguel Boton 
1024d022e35SMiguel Boton __setup("reboot=", reboot_setup);
1034d022e35SMiguel Boton 
1044d022e35SMiguel Boton 
1054d022e35SMiguel Boton #ifdef CONFIG_X86_32
1064d022e35SMiguel Boton /*
1074d022e35SMiguel Boton  * Reboot options and system auto-detection code provided by
1084d022e35SMiguel Boton  * Dell Inc. so their systems "just work". :-)
1094d022e35SMiguel Boton  */
1104d022e35SMiguel Boton 
1114d022e35SMiguel Boton /*
1124d022e35SMiguel Boton  * Some machines require the "reboot=b"  commandline option,
1134d022e35SMiguel Boton  * this quirk makes that automatic.
1144d022e35SMiguel Boton  */
1154d022e35SMiguel Boton static int __init set_bios_reboot(const struct dmi_system_id *d)
1164d022e35SMiguel Boton {
1174d022e35SMiguel Boton 	if (reboot_type != BOOT_BIOS) {
1184d022e35SMiguel Boton 		reboot_type = BOOT_BIOS;
1194d022e35SMiguel Boton 		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
1204d022e35SMiguel Boton 	}
1214d022e35SMiguel Boton 	return 0;
1224d022e35SMiguel Boton }
1234d022e35SMiguel Boton 
1244d022e35SMiguel Boton static struct dmi_system_id __initdata reboot_dmi_table[] = {
1254d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell E520's */
1264d022e35SMiguel Boton 		.callback = set_bios_reboot,
1274d022e35SMiguel Boton 		.ident = "Dell E520",
1284d022e35SMiguel Boton 		.matches = {
1294d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1304d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
1314d022e35SMiguel Boton 		},
1324d022e35SMiguel Boton 	},
1334d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 1300's */
1344d022e35SMiguel Boton 		.callback = set_bios_reboot,
1354d022e35SMiguel Boton 		.ident = "Dell PowerEdge 1300",
1364d022e35SMiguel Boton 		.matches = {
1374d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1384d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
1394d022e35SMiguel Boton 		},
1404d022e35SMiguel Boton 	},
1414d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 300's */
1424d022e35SMiguel Boton 		.callback = set_bios_reboot,
1434d022e35SMiguel Boton 		.ident = "Dell PowerEdge 300",
1444d022e35SMiguel Boton 		.matches = {
1454d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1464d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
1474d022e35SMiguel Boton 		},
1484d022e35SMiguel Boton 	},
1494d022e35SMiguel Boton 	{       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
1504d022e35SMiguel Boton 		.callback = set_bios_reboot,
1514d022e35SMiguel Boton 		.ident = "Dell OptiPlex 745",
1524d022e35SMiguel Boton 		.matches = {
1534d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1544d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
1554d022e35SMiguel Boton 		},
1564d022e35SMiguel Boton 	},
157fc115bf1SColeman Kane 	{       /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
158fc115bf1SColeman Kane 		.callback = set_bios_reboot,
159fc115bf1SColeman Kane 		.ident = "Dell OptiPlex 745",
160fc115bf1SColeman Kane 		.matches = {
161fc115bf1SColeman Kane 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
162fc115bf1SColeman Kane 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
163fc115bf1SColeman Kane 			DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
164fc115bf1SColeman Kane 		},
165fc115bf1SColeman Kane 	},
166fc1c8925SHeinz-Ado Arnolds 	{       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
167fc1c8925SHeinz-Ado Arnolds 		.callback = set_bios_reboot,
168fc1c8925SHeinz-Ado Arnolds 		.ident = "Dell OptiPlex 745",
169fc1c8925SHeinz-Ado Arnolds 		.matches = {
170fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
171fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
172fc1c8925SHeinz-Ado Arnolds 			DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
173fc1c8925SHeinz-Ado Arnolds 		},
174fc1c8925SHeinz-Ado Arnolds 	},
1754d022e35SMiguel Boton 	{	/* Handle problems with rebooting on Dell 2400's */
1764d022e35SMiguel Boton 		.callback = set_bios_reboot,
1774d022e35SMiguel Boton 		.ident = "Dell PowerEdge 2400",
1784d022e35SMiguel Boton 		.matches = {
1794d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
1804d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
1814d022e35SMiguel Boton 		},
1824d022e35SMiguel Boton 	},
183fab3b58dSIngo Molnar 	{	/* Handle problems with rebooting on Dell T5400's */
184fab3b58dSIngo Molnar 		.callback = set_bios_reboot,
185fab3b58dSIngo Molnar 		.ident = "Dell Precision T5400",
186fab3b58dSIngo Molnar 		.matches = {
187fab3b58dSIngo Molnar 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
188fab3b58dSIngo Molnar 			DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
189fab3b58dSIngo Molnar 		},
190fab3b58dSIngo Molnar 	},
1914d022e35SMiguel Boton 	{	/* Handle problems with rebooting on HP laptops */
1924d022e35SMiguel Boton 		.callback = set_bios_reboot,
1934d022e35SMiguel Boton 		.ident = "HP Compaq Laptop",
1944d022e35SMiguel Boton 		.matches = {
1954d022e35SMiguel Boton 			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1964d022e35SMiguel Boton 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
1974d022e35SMiguel Boton 		},
1984d022e35SMiguel Boton 	},
1994d022e35SMiguel Boton 	{ }
2004d022e35SMiguel Boton };
2014d022e35SMiguel Boton 
2024d022e35SMiguel Boton static int __init reboot_init(void)
2034d022e35SMiguel Boton {
2044d022e35SMiguel Boton 	dmi_check_system(reboot_dmi_table);
2054d022e35SMiguel Boton 	return 0;
2064d022e35SMiguel Boton }
2074d022e35SMiguel Boton core_initcall(reboot_init);
2084d022e35SMiguel Boton 
2094d022e35SMiguel Boton /* The following code and data reboots the machine by switching to real
2104d022e35SMiguel Boton    mode and jumping to the BIOS reset entry point, as if the CPU has
2114d022e35SMiguel Boton    really been reset.  The previous version asked the keyboard
2124d022e35SMiguel Boton    controller to pulse the CPU reset line, which is more thorough, but
2134d022e35SMiguel Boton    doesn't work with at least one type of 486 motherboard.  It is easy
2144d022e35SMiguel Boton    to stop this code working; hence the copious comments. */
215ebdd561aSJan Beulich static const unsigned long long
2164d022e35SMiguel Boton real_mode_gdt_entries [3] =
2174d022e35SMiguel Boton {
2184d022e35SMiguel Boton 	0x0000000000000000ULL,	/* Null descriptor */
219ebdd561aSJan Beulich 	0x00009b000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
220ebdd561aSJan Beulich 	0x000093000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
2214d022e35SMiguel Boton };
2224d022e35SMiguel Boton 
223ebdd561aSJan Beulich static const struct desc_ptr
2244d022e35SMiguel Boton real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
2254d022e35SMiguel Boton real_mode_idt = { 0x3ff, 0 };
2264d022e35SMiguel Boton 
2274d022e35SMiguel Boton /* This is 16-bit protected mode code to disable paging and the cache,
2284d022e35SMiguel Boton    switch to real mode and jump to the BIOS reset code.
2294d022e35SMiguel Boton 
2304d022e35SMiguel Boton    The instruction that switches to real mode by writing to CR0 must be
2314d022e35SMiguel Boton    followed immediately by a far jump instruction, which set CS to a
2324d022e35SMiguel Boton    valid value for real mode, and flushes the prefetch queue to avoid
2334d022e35SMiguel Boton    running instructions that have already been decoded in protected
2344d022e35SMiguel Boton    mode.
2354d022e35SMiguel Boton 
2364d022e35SMiguel Boton    Clears all the flags except ET, especially PG (paging), PE
2374d022e35SMiguel Boton    (protected-mode enable) and TS (task switch for coprocessor state
2384d022e35SMiguel Boton    save).  Flushes the TLB after paging has been disabled.  Sets CD and
2394d022e35SMiguel Boton    NW, to disable the cache on a 486, and invalidates the cache.  This
2404d022e35SMiguel Boton    is more like the state of a 486 after reset.  I don't know if
2414d022e35SMiguel Boton    something else should be done for other chips.
2424d022e35SMiguel Boton 
2434d022e35SMiguel Boton    More could be done here to set up the registers as if a CPU reset had
2444d022e35SMiguel Boton    occurred; hopefully real BIOSs don't assume much. */
245ebdd561aSJan Beulich static const unsigned char real_mode_switch [] =
2464d022e35SMiguel Boton {
2474d022e35SMiguel Boton 	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
2484d022e35SMiguel Boton 	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
2494d022e35SMiguel Boton 	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */
2504d022e35SMiguel Boton 	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
2514d022e35SMiguel Boton 	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
2524d022e35SMiguel Boton 	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
2534d022e35SMiguel Boton 	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
2544d022e35SMiguel Boton 	0x74, 0x02,				/*    jz    f                */
2554d022e35SMiguel Boton 	0x0f, 0x09,				/*    wbinvd                 */
2564d022e35SMiguel Boton 	0x24, 0x10,				/* f: andb  $0x10,al         */
2574d022e35SMiguel Boton 	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
2584d022e35SMiguel Boton };
259ebdd561aSJan Beulich static const unsigned char jump_to_bios [] =
2604d022e35SMiguel Boton {
2614d022e35SMiguel Boton 	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */
2624d022e35SMiguel Boton };
2634d022e35SMiguel Boton 
2644d022e35SMiguel Boton /*
2654d022e35SMiguel Boton  * Switch to real mode and then execute the code
2664d022e35SMiguel Boton  * specified by the code and length parameters.
2674d022e35SMiguel Boton  * We assume that length will aways be less that 100!
2684d022e35SMiguel Boton  */
269ebdd561aSJan Beulich void machine_real_restart(const unsigned char *code, int length)
2704d022e35SMiguel Boton {
2714d022e35SMiguel Boton 	local_irq_disable();
2724d022e35SMiguel Boton 
2734d022e35SMiguel Boton 	/* Write zero to CMOS register number 0x0f, which the BIOS POST
2744d022e35SMiguel Boton 	   routine will recognize as telling it to do a proper reboot.  (Well
2754d022e35SMiguel Boton 	   that's what this book in front of me says -- it may only apply to
2764d022e35SMiguel Boton 	   the Phoenix BIOS though, it's not clear).  At the same time,
2774d022e35SMiguel Boton 	   disable NMIs by setting the top bit in the CMOS address register,
2784d022e35SMiguel Boton 	   as we're about to do peculiar things to the CPU.  I'm not sure if
2794d022e35SMiguel Boton 	   `outb_p' is needed instead of just `outb'.  Use it to be on the
2804d022e35SMiguel Boton 	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
2814d022e35SMiguel Boton 	 */
2824d022e35SMiguel Boton 	spin_lock(&rtc_lock);
2834d022e35SMiguel Boton 	CMOS_WRITE(0x00, 0x8f);
2844d022e35SMiguel Boton 	spin_unlock(&rtc_lock);
2854d022e35SMiguel Boton 
2864d022e35SMiguel Boton 	/* Remap the kernel at virtual address zero, as well as offset zero
2874d022e35SMiguel Boton 	   from the kernel segment.  This assumes the kernel segment starts at
2884d022e35SMiguel Boton 	   virtual address PAGE_OFFSET. */
28968db065cSJeremy Fitzhardinge 	memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
2904d022e35SMiguel Boton 		sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
2914d022e35SMiguel Boton 
2924d022e35SMiguel Boton 	/*
2934d022e35SMiguel Boton 	 * Use `swapper_pg_dir' as our page directory.
2944d022e35SMiguel Boton 	 */
2954d022e35SMiguel Boton 	load_cr3(swapper_pg_dir);
2964d022e35SMiguel Boton 
2974d022e35SMiguel Boton 	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
2984d022e35SMiguel Boton 	   this on booting to tell it to "Bypass memory test (also warm
2994d022e35SMiguel Boton 	   boot)".  This seems like a fairly standard thing that gets set by
3004d022e35SMiguel Boton 	   REBOOT.COM programs, and the previous reset routine did this
3014d022e35SMiguel Boton 	   too. */
3024d022e35SMiguel Boton 	*((unsigned short *)0x472) = reboot_mode;
3034d022e35SMiguel Boton 
3044d022e35SMiguel Boton 	/* For the switch to real mode, copy some code to low memory.  It has
3054d022e35SMiguel Boton 	   to be in the first 64k because it is running in 16-bit mode, and it
3064d022e35SMiguel Boton 	   has to have the same physical and virtual address, because it turns
3074d022e35SMiguel Boton 	   off paging.  Copy it near the end of the first page, out of the way
3084d022e35SMiguel Boton 	   of BIOS variables. */
3094d022e35SMiguel Boton 	memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100),
3104d022e35SMiguel Boton 		real_mode_switch, sizeof (real_mode_switch));
3114d022e35SMiguel Boton 	memcpy((void *)(0x1000 - 100), code, length);
3124d022e35SMiguel Boton 
3134d022e35SMiguel Boton 	/* Set up the IDT for real mode. */
3144d022e35SMiguel Boton 	load_idt(&real_mode_idt);
3154d022e35SMiguel Boton 
3164d022e35SMiguel Boton 	/* Set up a GDT from which we can load segment descriptors for real
3174d022e35SMiguel Boton 	   mode.  The GDT is not used in real mode; it is just needed here to
3184d022e35SMiguel Boton 	   prepare the descriptors. */
3194d022e35SMiguel Boton 	load_gdt(&real_mode_gdt);
3204d022e35SMiguel Boton 
3214d022e35SMiguel Boton 	/* Load the data segment registers, and thus the descriptors ready for
3224d022e35SMiguel Boton 	   real mode.  The base address of each segment is 0x100, 16 times the
3234d022e35SMiguel Boton 	   selector value being loaded here.  This is so that the segment
3244d022e35SMiguel Boton 	   registers don't have to be reloaded after switching to real mode:
3254d022e35SMiguel Boton 	   the values are consistent for real mode operation already. */
3264d022e35SMiguel Boton 	__asm__ __volatile__ ("movl $0x0010,%%eax\n"
3274d022e35SMiguel Boton 				"\tmovl %%eax,%%ds\n"
3284d022e35SMiguel Boton 				"\tmovl %%eax,%%es\n"
3294d022e35SMiguel Boton 				"\tmovl %%eax,%%fs\n"
3304d022e35SMiguel Boton 				"\tmovl %%eax,%%gs\n"
3314d022e35SMiguel Boton 				"\tmovl %%eax,%%ss" : : : "eax");
3324d022e35SMiguel Boton 
3334d022e35SMiguel Boton 	/* Jump to the 16-bit code that we copied earlier.  It disables paging
3344d022e35SMiguel Boton 	   and the cache, switches to real mode, and jumps to the BIOS reset
3354d022e35SMiguel Boton 	   entry point. */
3364d022e35SMiguel Boton 	__asm__ __volatile__ ("ljmp $0x0008,%0"
3374d022e35SMiguel Boton 				:
3384d022e35SMiguel Boton 				: "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100)));
3394d022e35SMiguel Boton }
3404d022e35SMiguel Boton #ifdef CONFIG_APM_MODULE
3414d022e35SMiguel Boton EXPORT_SYMBOL(machine_real_restart);
3424d022e35SMiguel Boton #endif
3434d022e35SMiguel Boton 
3444d022e35SMiguel Boton #endif /* CONFIG_X86_32 */
3454d022e35SMiguel Boton 
3464d022e35SMiguel Boton static inline void kb_wait(void)
3474d022e35SMiguel Boton {
3484d022e35SMiguel Boton 	int i;
3494d022e35SMiguel Boton 
350c84d6af8SAlan Cox 	for (i = 0; i < 0x10000; i++) {
351c84d6af8SAlan Cox 		if ((inb(0x64) & 0x02) == 0)
3524d022e35SMiguel Boton 			break;
353c84d6af8SAlan Cox 		udelay(2);
354c84d6af8SAlan Cox 	}
3554d022e35SMiguel Boton }
3564d022e35SMiguel Boton 
3577432d149SIngo Molnar void __attribute__((weak)) mach_reboot_fixups(void)
3587432d149SIngo Molnar {
3597432d149SIngo Molnar }
3607432d149SIngo Molnar 
361416e2d63SJody Belka static void native_machine_emergency_restart(void)
3624d022e35SMiguel Boton {
3634d022e35SMiguel Boton 	int i;
3644d022e35SMiguel Boton 
3654d022e35SMiguel Boton 	/* Tell the BIOS if we want cold or warm reboot */
3664d022e35SMiguel Boton 	*((unsigned short *)__va(0x472)) = reboot_mode;
3674d022e35SMiguel Boton 
3684d022e35SMiguel Boton 	for (;;) {
3694d022e35SMiguel Boton 		/* Could also try the reset bit in the Hammer NB */
3704d022e35SMiguel Boton 		switch (reboot_type) {
3714d022e35SMiguel Boton 		case BOOT_KBD:
3727432d149SIngo Molnar 			mach_reboot_fixups(); /* for board specific fixups */
3737432d149SIngo Molnar 
3744d022e35SMiguel Boton 			for (i = 0; i < 10; i++) {
3754d022e35SMiguel Boton 				kb_wait();
3764d022e35SMiguel Boton 				udelay(50);
3774d022e35SMiguel Boton 				outb(0xfe, 0x64); /* pulse reset low */
3784d022e35SMiguel Boton 				udelay(50);
3794d022e35SMiguel Boton 			}
3804d022e35SMiguel Boton 
3814d022e35SMiguel Boton 		case BOOT_TRIPLE:
382ebdd561aSJan Beulich 			load_idt(&no_idt);
3834d022e35SMiguel Boton 			__asm__ __volatile__("int3");
3844d022e35SMiguel Boton 
3854d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
3864d022e35SMiguel Boton 			break;
3874d022e35SMiguel Boton 
3884d022e35SMiguel Boton #ifdef CONFIG_X86_32
3894d022e35SMiguel Boton 		case BOOT_BIOS:
3904d022e35SMiguel Boton 			machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
3914d022e35SMiguel Boton 
3924d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
3934d022e35SMiguel Boton 			break;
3944d022e35SMiguel Boton #endif
3954d022e35SMiguel Boton 
3964d022e35SMiguel Boton 		case BOOT_ACPI:
3974d022e35SMiguel Boton 			acpi_reboot();
3984d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
3994d022e35SMiguel Boton 			break;
4004d022e35SMiguel Boton 
4014d022e35SMiguel Boton 
4024d022e35SMiguel Boton 		case BOOT_EFI:
4034d022e35SMiguel Boton 			if (efi_enabled)
4044d022e35SMiguel Boton 				efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD,
4054d022e35SMiguel Boton 						 EFI_SUCCESS, 0, NULL);
4064d022e35SMiguel Boton 
4074d022e35SMiguel Boton 			reboot_type = BOOT_KBD;
4084d022e35SMiguel Boton 			break;
4094d022e35SMiguel Boton 		}
4104d022e35SMiguel Boton 	}
4114d022e35SMiguel Boton }
4124d022e35SMiguel Boton 
4133c62c625SGlauber Costa void native_machine_shutdown(void)
4144d022e35SMiguel Boton {
4154d022e35SMiguel Boton 	/* Stop the cpus and apics */
4164d022e35SMiguel Boton #ifdef CONFIG_SMP
4174d022e35SMiguel Boton 
4184d022e35SMiguel Boton 	/* The boot cpu is always logical cpu 0 */
41965c01184SMike Travis 	int reboot_cpu_id = 0;
4204d022e35SMiguel Boton 
4214d022e35SMiguel Boton #ifdef CONFIG_X86_32
4224d022e35SMiguel Boton 	/* See if there has been given a command line override */
4234d022e35SMiguel Boton 	if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
4240bc3cc03SMike Travis 		cpu_online(reboot_cpu))
4254d022e35SMiguel Boton 		reboot_cpu_id = reboot_cpu;
4264d022e35SMiguel Boton #endif
4274d022e35SMiguel Boton 
4284d022e35SMiguel Boton 	/* Make certain the cpu I'm about to reboot on is online */
4290bc3cc03SMike Travis 	if (!cpu_online(reboot_cpu_id))
4304d022e35SMiguel Boton 		reboot_cpu_id = smp_processor_id();
4314d022e35SMiguel Boton 
4324d022e35SMiguel Boton 	/* Make certain I only run on the appropriate processor */
4330bc3cc03SMike Travis 	set_cpus_allowed_ptr(current, &cpumask_of_cpu(reboot_cpu_id));
4344d022e35SMiguel Boton 
4354d022e35SMiguel Boton 	/* O.K Now that I'm on the appropriate processor,
4364d022e35SMiguel Boton 	 * stop all of the others.
4374d022e35SMiguel Boton 	 */
4384d022e35SMiguel Boton 	smp_send_stop();
4394d022e35SMiguel Boton #endif
4404d022e35SMiguel Boton 
4414d022e35SMiguel Boton 	lapic_shutdown();
4424d022e35SMiguel Boton 
4434d022e35SMiguel Boton #ifdef CONFIG_X86_IO_APIC
4444d022e35SMiguel Boton 	disable_IO_APIC();
4454d022e35SMiguel Boton #endif
4464d022e35SMiguel Boton 
4474d022e35SMiguel Boton #ifdef CONFIG_HPET_TIMER
4484d022e35SMiguel Boton 	hpet_disable();
4494d022e35SMiguel Boton #endif
4504d022e35SMiguel Boton 
4514d022e35SMiguel Boton #ifdef CONFIG_X86_64
4524d022e35SMiguel Boton 	pci_iommu_shutdown();
4534d022e35SMiguel Boton #endif
4544d022e35SMiguel Boton }
4554d022e35SMiguel Boton 
456416e2d63SJody Belka static void native_machine_restart(char *__unused)
4574d022e35SMiguel Boton {
4584d022e35SMiguel Boton 	printk("machine restart\n");
4594d022e35SMiguel Boton 
4604d022e35SMiguel Boton 	if (!reboot_force)
4614d022e35SMiguel Boton 		machine_shutdown();
4624d022e35SMiguel Boton 	machine_emergency_restart();
4634d022e35SMiguel Boton }
4644d022e35SMiguel Boton 
465416e2d63SJody Belka static void native_machine_halt(void)
4664d022e35SMiguel Boton {
4674d022e35SMiguel Boton }
4684d022e35SMiguel Boton 
469416e2d63SJody Belka static void native_machine_power_off(void)
4704d022e35SMiguel Boton {
4714d022e35SMiguel Boton 	if (pm_power_off) {
4724d022e35SMiguel Boton 		if (!reboot_force)
4734d022e35SMiguel Boton 			machine_shutdown();
4744d022e35SMiguel Boton 		pm_power_off();
4754d022e35SMiguel Boton 	}
4764d022e35SMiguel Boton }
4774d022e35SMiguel Boton 
4784d022e35SMiguel Boton struct machine_ops machine_ops = {
479416e2d63SJody Belka 	.power_off = native_machine_power_off,
480416e2d63SJody Belka 	.shutdown = native_machine_shutdown,
481416e2d63SJody Belka 	.emergency_restart = native_machine_emergency_restart,
482416e2d63SJody Belka 	.restart = native_machine_restart,
483ed23dc6fSGlauber Costa 	.halt = native_machine_halt,
484ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
485ed23dc6fSGlauber Costa 	.crash_shutdown = native_machine_crash_shutdown,
486ed23dc6fSGlauber Costa #endif
4874d022e35SMiguel Boton };
488416e2d63SJody Belka 
489416e2d63SJody Belka void machine_power_off(void)
490416e2d63SJody Belka {
491416e2d63SJody Belka 	machine_ops.power_off();
492416e2d63SJody Belka }
493416e2d63SJody Belka 
494416e2d63SJody Belka void machine_shutdown(void)
495416e2d63SJody Belka {
496416e2d63SJody Belka 	machine_ops.shutdown();
497416e2d63SJody Belka }
498416e2d63SJody Belka 
499416e2d63SJody Belka void machine_emergency_restart(void)
500416e2d63SJody Belka {
501416e2d63SJody Belka 	machine_ops.emergency_restart();
502416e2d63SJody Belka }
503416e2d63SJody Belka 
504416e2d63SJody Belka void machine_restart(char *cmd)
505416e2d63SJody Belka {
506416e2d63SJody Belka 	machine_ops.restart(cmd);
507416e2d63SJody Belka }
508416e2d63SJody Belka 
509416e2d63SJody Belka void machine_halt(void)
510416e2d63SJody Belka {
511416e2d63SJody Belka 	machine_ops.halt();
512416e2d63SJody Belka }
513416e2d63SJody Belka 
514ed23dc6fSGlauber Costa #ifdef CONFIG_KEXEC
515ed23dc6fSGlauber Costa void machine_crash_shutdown(struct pt_regs *regs)
516ed23dc6fSGlauber Costa {
517ed23dc6fSGlauber Costa 	machine_ops.crash_shutdown(regs);
518ed23dc6fSGlauber Costa }
519ed23dc6fSGlauber Costa #endif
5202ddded21SEduardo Habkost 
5212ddded21SEduardo Habkost 
522bb8dd270SEduardo Habkost #if defined(CONFIG_SMP)
5232ddded21SEduardo Habkost 
5242ddded21SEduardo Habkost /* This keeps a track of which one is crashing cpu. */
5252ddded21SEduardo Habkost static int crashing_cpu;
5262ddded21SEduardo Habkost static nmi_shootdown_cb shootdown_callback;
5272ddded21SEduardo Habkost 
5282ddded21SEduardo Habkost static atomic_t waiting_for_crash_ipi;
5292ddded21SEduardo Habkost 
5302ddded21SEduardo Habkost static int crash_nmi_callback(struct notifier_block *self,
5312ddded21SEduardo Habkost 			unsigned long val, void *data)
5322ddded21SEduardo Habkost {
5332ddded21SEduardo Habkost 	int cpu;
5342ddded21SEduardo Habkost 
5352ddded21SEduardo Habkost 	if (val != DIE_NMI_IPI)
5362ddded21SEduardo Habkost 		return NOTIFY_OK;
5372ddded21SEduardo Habkost 
5382ddded21SEduardo Habkost 	cpu = raw_smp_processor_id();
5392ddded21SEduardo Habkost 
5402ddded21SEduardo Habkost 	/* Don't do anything if this handler is invoked on crashing cpu.
5412ddded21SEduardo Habkost 	 * Otherwise, system will completely hang. Crashing cpu can get
5422ddded21SEduardo Habkost 	 * an NMI if system was initially booted with nmi_watchdog parameter.
5432ddded21SEduardo Habkost 	 */
5442ddded21SEduardo Habkost 	if (cpu == crashing_cpu)
5452ddded21SEduardo Habkost 		return NOTIFY_STOP;
5462ddded21SEduardo Habkost 	local_irq_disable();
5472ddded21SEduardo Habkost 
5482ddded21SEduardo Habkost 	shootdown_callback(cpu, (struct die_args *)data);
5492ddded21SEduardo Habkost 
5502ddded21SEduardo Habkost 	atomic_dec(&waiting_for_crash_ipi);
5512ddded21SEduardo Habkost 	/* Assume hlt works */
5522ddded21SEduardo Habkost 	halt();
5532ddded21SEduardo Habkost 	for (;;)
5542ddded21SEduardo Habkost 		cpu_relax();
5552ddded21SEduardo Habkost 
5562ddded21SEduardo Habkost 	return 1;
5572ddded21SEduardo Habkost }
5582ddded21SEduardo Habkost 
5592ddded21SEduardo Habkost static void smp_send_nmi_allbutself(void)
5602ddded21SEduardo Habkost {
5612ddded21SEduardo Habkost 	cpumask_t mask = cpu_online_map;
5622ddded21SEduardo Habkost 	cpu_clear(safe_smp_processor_id(), mask);
5632ddded21SEduardo Habkost 	if (!cpus_empty(mask))
5642ddded21SEduardo Habkost 		send_IPI_mask(mask, NMI_VECTOR);
5652ddded21SEduardo Habkost }
5662ddded21SEduardo Habkost 
5672ddded21SEduardo Habkost static struct notifier_block crash_nmi_nb = {
5682ddded21SEduardo Habkost 	.notifier_call = crash_nmi_callback,
5692ddded21SEduardo Habkost };
5702ddded21SEduardo Habkost 
571bb8dd270SEduardo Habkost /* Halt all other CPUs, calling the specified function on each of them
572bb8dd270SEduardo Habkost  *
573bb8dd270SEduardo Habkost  * This function can be used to halt all other CPUs on crash
574bb8dd270SEduardo Habkost  * or emergency reboot time. The function passed as parameter
575bb8dd270SEduardo Habkost  * will be called inside a NMI handler on all CPUs.
576bb8dd270SEduardo Habkost  */
5772ddded21SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
5782ddded21SEduardo Habkost {
5792ddded21SEduardo Habkost 	unsigned long msecs;
580*c415b3dcSEduardo Habkost 	local_irq_disable();
5812ddded21SEduardo Habkost 
5822ddded21SEduardo Habkost 	/* Make a note of crashing cpu. Will be used in NMI callback.*/
5832ddded21SEduardo Habkost 	crashing_cpu = safe_smp_processor_id();
5842ddded21SEduardo Habkost 
5852ddded21SEduardo Habkost 	shootdown_callback = callback;
5862ddded21SEduardo Habkost 
5872ddded21SEduardo Habkost 	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
5882ddded21SEduardo Habkost 	/* Would it be better to replace the trap vector here? */
5892ddded21SEduardo Habkost 	if (register_die_notifier(&crash_nmi_nb))
5902ddded21SEduardo Habkost 		return;		/* return what? */
5912ddded21SEduardo Habkost 	/* Ensure the new callback function is set before sending
5922ddded21SEduardo Habkost 	 * out the NMI
5932ddded21SEduardo Habkost 	 */
5942ddded21SEduardo Habkost 	wmb();
5952ddded21SEduardo Habkost 
5962ddded21SEduardo Habkost 	smp_send_nmi_allbutself();
5972ddded21SEduardo Habkost 
5982ddded21SEduardo Habkost 	msecs = 1000; /* Wait at most a second for the other cpus to stop */
5992ddded21SEduardo Habkost 	while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
6002ddded21SEduardo Habkost 		mdelay(1);
6012ddded21SEduardo Habkost 		msecs--;
6022ddded21SEduardo Habkost 	}
6032ddded21SEduardo Habkost 
6042ddded21SEduardo Habkost 	/* Leave the nmi callback set */
6052ddded21SEduardo Habkost }
606bb8dd270SEduardo Habkost #else /* !CONFIG_SMP */
607bb8dd270SEduardo Habkost void nmi_shootdown_cpus(nmi_shootdown_cb callback)
608bb8dd270SEduardo Habkost {
609bb8dd270SEduardo Habkost 	/* No other CPUs to shoot down */
610bb8dd270SEduardo Habkost }
6112ddded21SEduardo Habkost #endif
612