diff options
Diffstat (limited to 'arch/x86/kernel/reboot.c')
-rw-r--r-- | arch/x86/kernel/reboot.c | 204 |
1 files changed, 97 insertions, 107 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index e3af342fe83a..9242436e9937 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/dmi.h> | 6 | #include <linux/dmi.h> |
7 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
8 | #include <linux/tboot.h> | 8 | #include <linux/tboot.h> |
9 | #include <linux/delay.h> | ||
9 | #include <acpi/reboot.h> | 10 | #include <acpi/reboot.h> |
10 | #include <asm/io.h> | 11 | #include <asm/io.h> |
11 | #include <asm/apic.h> | 12 | #include <asm/apic.h> |
@@ -18,6 +19,7 @@ | |||
18 | #include <asm/pci_x86.h> | 19 | #include <asm/pci_x86.h> |
19 | #include <asm/virtext.h> | 20 | #include <asm/virtext.h> |
20 | #include <asm/cpu.h> | 21 | #include <asm/cpu.h> |
22 | #include <asm/nmi.h> | ||
21 | 23 | ||
22 | #ifdef CONFIG_X86_32 | 24 | #ifdef CONFIG_X86_32 |
23 | # include <linux/ctype.h> | 25 | # include <linux/ctype.h> |
@@ -34,7 +36,7 @@ EXPORT_SYMBOL(pm_power_off); | |||
34 | 36 | ||
35 | static const struct desc_ptr no_idt = {}; | 37 | static const struct desc_ptr no_idt = {}; |
36 | static int reboot_mode; | 38 | static int reboot_mode; |
37 | enum reboot_type reboot_type = BOOT_KBD; | 39 | enum reboot_type reboot_type = BOOT_ACPI; |
38 | int reboot_force; | 40 | int reboot_force; |
39 | 41 | ||
40 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) | 42 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) |
@@ -84,7 +86,7 @@ static int __init reboot_setup(char *str) | |||
84 | } | 86 | } |
85 | /* we will leave sorting out the final value | 87 | /* we will leave sorting out the final value |
86 | when we are ready to reboot, since we might not | 88 | when we are ready to reboot, since we might not |
87 | have set up boot_cpu_id or smp_num_cpu */ | 89 | have detected BSP APIC ID or smp_num_cpu */ |
88 | break; | 90 | break; |
89 | #endif /* CONFIG_SMP */ | 91 | #endif /* CONFIG_SMP */ |
90 | 92 | ||
@@ -284,6 +286,22 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
284 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), | 286 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
285 | }, | 287 | }, |
286 | }, | 288 | }, |
289 | { /* Handle problems with rebooting on VersaLogic Menlow boards */ | ||
290 | .callback = set_bios_reboot, | ||
291 | .ident = "VersaLogic Menlow based board", | ||
292 | .matches = { | ||
293 | DMI_MATCH(DMI_BOARD_VENDOR, "VersaLogic Corporation"), | ||
294 | DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"), | ||
295 | }, | ||
296 | }, | ||
297 | { /* Handle reboot issue on Acer Aspire one */ | ||
298 | .callback = set_bios_reboot, | ||
299 | .ident = "Acer Aspire One A110", | ||
300 | .matches = { | ||
301 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
302 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), | ||
303 | }, | ||
304 | }, | ||
287 | { } | 305 | { } |
288 | }; | 306 | }; |
289 | 307 | ||
@@ -294,68 +312,16 @@ static int __init reboot_init(void) | |||
294 | } | 312 | } |
295 | core_initcall(reboot_init); | 313 | core_initcall(reboot_init); |
296 | 314 | ||
297 | /* The following code and data reboots the machine by switching to real | 315 | extern const unsigned char machine_real_restart_asm[]; |
298 | mode and jumping to the BIOS reset entry point, as if the CPU has | 316 | extern const u64 machine_real_restart_gdt[3]; |
299 | really been reset. The previous version asked the keyboard | ||
300 | controller to pulse the CPU reset line, which is more thorough, but | ||
301 | doesn't work with at least one type of 486 motherboard. It is easy | ||
302 | to stop this code working; hence the copious comments. */ | ||
303 | static const unsigned long long | ||
304 | real_mode_gdt_entries [3] = | ||
305 | { | ||
306 | 0x0000000000000000ULL, /* Null descriptor */ | ||
307 | 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ | ||
308 | 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ | ||
309 | }; | ||
310 | 317 | ||
311 | static const struct desc_ptr | 318 | void machine_real_restart(unsigned int type) |
312 | real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, | ||
313 | real_mode_idt = { 0x3ff, 0 }; | ||
314 | |||
315 | /* This is 16-bit protected mode code to disable paging and the cache, | ||
316 | switch to real mode and jump to the BIOS reset code. | ||
317 | |||
318 | The instruction that switches to real mode by writing to CR0 must be | ||
319 | followed immediately by a far jump instruction, which set CS to a | ||
320 | valid value for real mode, and flushes the prefetch queue to avoid | ||
321 | running instructions that have already been decoded in protected | ||
322 | mode. | ||
323 | |||
324 | Clears all the flags except ET, especially PG (paging), PE | ||
325 | (protected-mode enable) and TS (task switch for coprocessor state | ||
326 | save). Flushes the TLB after paging has been disabled. Sets CD and | ||
327 | NW, to disable the cache on a 486, and invalidates the cache. This | ||
328 | is more like the state of a 486 after reset. I don't know if | ||
329 | something else should be done for other chips. | ||
330 | |||
331 | More could be done here to set up the registers as if a CPU reset had | ||
332 | occurred; hopefully real BIOSs don't assume much. */ | ||
333 | static const unsigned char real_mode_switch [] = | ||
334 | { | 319 | { |
335 | 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ | 320 | void *restart_va; |
336 | 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ | 321 | unsigned long restart_pa; |
337 | 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ | 322 | void (*restart_lowmem)(unsigned int); |
338 | 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ | 323 | u64 *lowmem_gdt; |
339 | 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ | ||
340 | 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ | ||
341 | 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ | ||
342 | 0x74, 0x02, /* jz f */ | ||
343 | 0x0f, 0x09, /* wbinvd */ | ||
344 | 0x24, 0x10, /* f: andb $0x10,al */ | ||
345 | 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ | ||
346 | }; | ||
347 | static const unsigned char jump_to_bios [] = | ||
348 | { | ||
349 | 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ | ||
350 | }; | ||
351 | 324 | ||
352 | /* | ||
353 | * Switch to real mode and then execute the code | ||
354 | * specified by the code and length parameters. | ||
355 | * We assume that length will aways be less that 100! | ||
356 | */ | ||
357 | void machine_real_restart(const unsigned char *code, int length) | ||
358 | { | ||
359 | local_irq_disable(); | 325 | local_irq_disable(); |
360 | 326 | ||
361 | /* Write zero to CMOS register number 0x0f, which the BIOS POST | 327 | /* Write zero to CMOS register number 0x0f, which the BIOS POST |
@@ -371,16 +337,10 @@ void machine_real_restart(const unsigned char *code, int length) | |||
371 | CMOS_WRITE(0x00, 0x8f); | 337 | CMOS_WRITE(0x00, 0x8f); |
372 | spin_unlock(&rtc_lock); | 338 | spin_unlock(&rtc_lock); |
373 | 339 | ||
374 | /* Remap the kernel at virtual address zero, as well as offset zero | ||
375 | from the kernel segment. This assumes the kernel segment starts at | ||
376 | virtual address PAGE_OFFSET. */ | ||
377 | memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, | ||
378 | sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); | ||
379 | |||
380 | /* | 340 | /* |
381 | * Use `swapper_pg_dir' as our page directory. | 341 | * Switch back to the initial page table. |
382 | */ | 342 | */ |
383 | load_cr3(swapper_pg_dir); | 343 | load_cr3(initial_page_table); |
384 | 344 | ||
385 | /* Write 0x1234 to absolute memory location 0x472. The BIOS reads | 345 | /* Write 0x1234 to absolute memory location 0x472. The BIOS reads |
386 | this on booting to tell it to "Bypass memory test (also warm | 346 | this on booting to tell it to "Bypass memory test (also warm |
@@ -389,41 +349,23 @@ void machine_real_restart(const unsigned char *code, int length) | |||
389 | too. */ | 349 | too. */ |
390 | *((unsigned short *)0x472) = reboot_mode; | 350 | *((unsigned short *)0x472) = reboot_mode; |
391 | 351 | ||
392 | /* For the switch to real mode, copy some code to low memory. It has | 352 | /* Patch the GDT in the low memory trampoline */ |
393 | to be in the first 64k because it is running in 16-bit mode, and it | 353 | lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); |
394 | has to have the same physical and virtual address, because it turns | 354 | |
395 | off paging. Copy it near the end of the first page, out of the way | 355 | restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); |
396 | of BIOS variables. */ | 356 | restart_pa = virt_to_phys(restart_va); |
397 | memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100), | 357 | restart_lowmem = (void (*)(unsigned int))restart_pa; |
398 | real_mode_switch, sizeof (real_mode_switch)); | 358 | |
399 | memcpy((void *)(0x1000 - 100), code, length); | 359 | /* GDT[0]: GDT self-pointer */ |
400 | 360 | lowmem_gdt[0] = | |
401 | /* Set up the IDT for real mode. */ | 361 | (u64)(sizeof(machine_real_restart_gdt) - 1) + |
402 | load_idt(&real_mode_idt); | 362 | ((u64)virt_to_phys(lowmem_gdt) << 16); |
403 | 363 | /* GDT[1]: 64K real mode code segment */ | |
404 | /* Set up a GDT from which we can load segment descriptors for real | 364 | lowmem_gdt[1] = |
405 | mode. The GDT is not used in real mode; it is just needed here to | 365 | GDT_ENTRY(0x009b, restart_pa, 0xffff); |
406 | prepare the descriptors. */ | 366 | |
407 | load_gdt(&real_mode_gdt); | 367 | /* Jump to the identity-mapped low memory code */ |
408 | 368 | restart_lowmem(type); | |
409 | /* Load the data segment registers, and thus the descriptors ready for | ||
410 | real mode. The base address of each segment is 0x100, 16 times the | ||
411 | selector value being loaded here. This is so that the segment | ||
412 | registers don't have to be reloaded after switching to real mode: | ||
413 | the values are consistent for real mode operation already. */ | ||
414 | __asm__ __volatile__ ("movl $0x0010,%%eax\n" | ||
415 | "\tmovl %%eax,%%ds\n" | ||
416 | "\tmovl %%eax,%%es\n" | ||
417 | "\tmovl %%eax,%%fs\n" | ||
418 | "\tmovl %%eax,%%gs\n" | ||
419 | "\tmovl %%eax,%%ss" : : : "eax"); | ||
420 | |||
421 | /* Jump to the 16-bit code that we copied earlier. It disables paging | ||
422 | and the cache, switches to real mode, and jumps to the BIOS reset | ||
423 | entry point. */ | ||
424 | __asm__ __volatile__ ("ljmp $0x0008,%0" | ||
425 | : | ||
426 | : "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100))); | ||
427 | } | 369 | } |
428 | #ifdef CONFIG_APM_MODULE | 370 | #ifdef CONFIG_APM_MODULE |
429 | EXPORT_SYMBOL(machine_real_restart); | 371 | EXPORT_SYMBOL(machine_real_restart); |
@@ -477,6 +419,30 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { | |||
477 | DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), | 419 | DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), |
478 | }, | 420 | }, |
479 | }, | 421 | }, |
422 | { /* Handle problems with rebooting on the Latitude E6320. */ | ||
423 | .callback = set_pci_reboot, | ||
424 | .ident = "Dell Latitude E6320", | ||
425 | .matches = { | ||
426 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
427 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), | ||
428 | }, | ||
429 | }, | ||
430 | { /* Handle problems with rebooting on the Latitude E5420. */ | ||
431 | .callback = set_pci_reboot, | ||
432 | .ident = "Dell Latitude E5420", | ||
433 | .matches = { | ||
434 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
435 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), | ||
436 | }, | ||
437 | }, | ||
438 | { /* Handle problems with rebooting on the Latitude E6420. */ | ||
439 | .callback = set_pci_reboot, | ||
440 | .ident = "Dell Latitude E6420", | ||
441 | .matches = { | ||
442 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
443 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), | ||
444 | }, | ||
445 | }, | ||
480 | { } | 446 | { } |
481 | }; | 447 | }; |
482 | 448 | ||
@@ -544,9 +510,24 @@ void __attribute__((weak)) mach_reboot_fixups(void) | |||
544 | { | 510 | { |
545 | } | 511 | } |
546 | 512 | ||
513 | /* | ||
514 | * Windows compatible x86 hardware expects the following on reboot: | ||
515 | * | ||
516 | * 1) If the FADT has the ACPI reboot register flag set, try it | ||
517 | * 2) If still alive, write to the keyboard controller | ||
518 | * 3) If still alive, write to the ACPI reboot register again | ||
519 | * 4) If still alive, write to the keyboard controller again | ||
520 | * | ||
521 | * If the machine is still alive at this stage, it gives up. We default to | ||
522 | * following the same pattern, except that if we're still alive after (4) we'll | ||
523 | * try to force a triple fault and then cycle between hitting the keyboard | ||
524 | * controller and doing that | ||
525 | */ | ||
547 | static void native_machine_emergency_restart(void) | 526 | static void native_machine_emergency_restart(void) |
548 | { | 527 | { |
549 | int i; | 528 | int i; |
529 | int attempt = 0; | ||
530 | int orig_reboot_type = reboot_type; | ||
550 | 531 | ||
551 | if (reboot_emergency) | 532 | if (reboot_emergency) |
552 | emergency_vmx_disable_all(); | 533 | emergency_vmx_disable_all(); |
@@ -568,6 +549,13 @@ static void native_machine_emergency_restart(void) | |||
568 | outb(0xfe, 0x64); /* pulse reset low */ | 549 | outb(0xfe, 0x64); /* pulse reset low */ |
569 | udelay(50); | 550 | udelay(50); |
570 | } | 551 | } |
552 | if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { | ||
553 | attempt = 1; | ||
554 | reboot_type = BOOT_ACPI; | ||
555 | } else { | ||
556 | reboot_type = BOOT_TRIPLE; | ||
557 | } | ||
558 | break; | ||
571 | 559 | ||
572 | case BOOT_TRIPLE: | 560 | case BOOT_TRIPLE: |
573 | load_idt(&no_idt); | 561 | load_idt(&no_idt); |
@@ -578,7 +566,7 @@ static void native_machine_emergency_restart(void) | |||
578 | 566 | ||
579 | #ifdef CONFIG_X86_32 | 567 | #ifdef CONFIG_X86_32 |
580 | case BOOT_BIOS: | 568 | case BOOT_BIOS: |
581 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); | 569 | machine_real_restart(MRR_BIOS); |
582 | 570 | ||
583 | reboot_type = BOOT_KBD; | 571 | reboot_type = BOOT_KBD; |
584 | break; | 572 | break; |
@@ -641,7 +629,7 @@ void native_machine_shutdown(void) | |||
641 | /* O.K Now that I'm on the appropriate processor, | 629 | /* O.K Now that I'm on the appropriate processor, |
642 | * stop all of the others. | 630 | * stop all of the others. |
643 | */ | 631 | */ |
644 | smp_send_stop(); | 632 | stop_other_cpus(); |
645 | #endif | 633 | #endif |
646 | 634 | ||
647 | lapic_shutdown(); | 635 | lapic_shutdown(); |
@@ -753,7 +741,7 @@ static int crash_nmi_callback(struct notifier_block *self, | |||
753 | { | 741 | { |
754 | int cpu; | 742 | int cpu; |
755 | 743 | ||
756 | if (val != DIE_NMI_IPI) | 744 | if (val != DIE_NMI) |
757 | return NOTIFY_OK; | 745 | return NOTIFY_OK; |
758 | 746 | ||
759 | cpu = raw_smp_processor_id(); | 747 | cpu = raw_smp_processor_id(); |
@@ -784,6 +772,8 @@ static void smp_send_nmi_allbutself(void) | |||
784 | 772 | ||
785 | static struct notifier_block crash_nmi_nb = { | 773 | static struct notifier_block crash_nmi_nb = { |
786 | .notifier_call = crash_nmi_callback, | 774 | .notifier_call = crash_nmi_callback, |
775 | /* we want to be the first one called */ | ||
776 | .priority = NMI_LOCAL_HIGH_PRIOR+1, | ||
787 | }; | 777 | }; |
788 | 778 | ||
789 | /* Halt all other CPUs, calling the specified function on each of them | 779 | /* Halt all other CPUs, calling the specified function on each of them |