diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2012-06-17 00:47:37 -0400 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2012-06-17 13:51:01 -0400 |
| commit | 650513979a437c32d7a0a84f0ed952a55bbb5583 (patch) | |
| tree | b831bcbfdfce6abb31573e67669272f368626b5b | |
| parent | cfaf025112d3856637ff34a767ef785ef5cf2ca9 (diff) | |
x86-64, reboot: Allow reboot=bios and reboot-cpu override on x86-64
With the revamped realmode trampoline code, it is trivial to extend
support for reboot=bios to x86-64. Furthermore, while we are at it,
remove the restriction that only we can only override the reboot CPU
on 32 bits.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Link: http://lkml.kernel.org/n/tip-jopx7y6g6dbcx4tpal8q0jlr@git.kernel.org
| -rw-r--r-- | arch/x86/include/asm/emergency-restart.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/realmode.h | 3 | ||||
| -rw-r--r-- | arch/x86/include/asm/reboot.h | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/reboot.c | 52 | ||||
| -rw-r--r-- | arch/x86/realmode/rm/Makefile | 2 | ||||
| -rw-r--r-- | arch/x86/realmode/rm/header.S | 4 | ||||
| -rw-r--r-- | arch/x86/realmode/rm/reboot.S (renamed from arch/x86/realmode/rm/reboot_32.S) | 26 |
7 files changed, 55 insertions, 38 deletions
diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h index cc70c1c78ca4..75ce3f47d204 100644 --- a/arch/x86/include/asm/emergency-restart.h +++ b/arch/x86/include/asm/emergency-restart.h | |||
| @@ -4,9 +4,7 @@ | |||
| 4 | enum reboot_type { | 4 | enum reboot_type { |
| 5 | BOOT_TRIPLE = 't', | 5 | BOOT_TRIPLE = 't', |
| 6 | BOOT_KBD = 'k', | 6 | BOOT_KBD = 'k', |
| 7 | #ifdef CONFIG_X86_32 | ||
| 8 | BOOT_BIOS = 'b', | 7 | BOOT_BIOS = 'b', |
| 9 | #endif | ||
| 10 | BOOT_ACPI = 'a', | 8 | BOOT_ACPI = 'a', |
| 11 | BOOT_EFI = 'e', | 9 | BOOT_EFI = 'e', |
| 12 | BOOT_CF9 = 'p', | 10 | BOOT_CF9 = 'p', |
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index fce3f4ae5bd6..fe1ec5bcd846 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h | |||
| @@ -21,8 +21,9 @@ struct real_mode_header { | |||
| 21 | u32 wakeup_header; | 21 | u32 wakeup_header; |
| 22 | #endif | 22 | #endif |
| 23 | /* APM/BIOS reboot */ | 23 | /* APM/BIOS reboot */ |
| 24 | #ifdef CONFIG_X86_32 | ||
| 25 | u32 machine_real_restart_asm; | 24 | u32 machine_real_restart_asm; |
| 25 | #ifdef CONFIG_X86_64 | ||
| 26 | u32 machine_real_restart_seg; | ||
| 26 | #endif | 27 | #endif |
| 27 | }; | 28 | }; |
| 28 | 29 | ||
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index 92f297069e87..a82c4f1b4d83 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h | |||
| @@ -18,8 +18,8 @@ extern struct machine_ops machine_ops; | |||
| 18 | 18 | ||
| 19 | void native_machine_crash_shutdown(struct pt_regs *regs); | 19 | void native_machine_crash_shutdown(struct pt_regs *regs); |
| 20 | void native_machine_shutdown(void); | 20 | void native_machine_shutdown(void); |
| 21 | void machine_real_restart(unsigned int type); | 21 | void __noreturn machine_real_restart(unsigned int type); |
| 22 | /* These must match dispatch_table in reboot_32.S */ | 22 | /* These must match dispatch in arch/x86/realmore/rm/reboot.S */ |
| 23 | #define MRR_BIOS 0 | 23 | #define MRR_BIOS 0 |
| 24 | #define MRR_APM 1 | 24 | #define MRR_APM 1 |
| 25 | 25 | ||
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 25b48edb847c..6ddb9cd0ced0 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
| @@ -20,14 +20,12 @@ | |||
| 20 | #include <asm/virtext.h> | 20 | #include <asm/virtext.h> |
| 21 | #include <asm/cpu.h> | 21 | #include <asm/cpu.h> |
| 22 | #include <asm/nmi.h> | 22 | #include <asm/nmi.h> |
| 23 | #include <asm/smp.h> | ||
| 23 | 24 | ||
| 24 | #ifdef CONFIG_X86_32 | 25 | #include <linux/ctype.h> |
| 25 | # include <linux/ctype.h> | 26 | #include <linux/mc146818rtc.h> |
| 26 | # include <linux/mc146818rtc.h> | 27 | #include <asm/realmode.h> |
| 27 | # include <asm/realmode.h> | 28 | #include <asm/x86_init.h> |
| 28 | #else | ||
| 29 | # include <asm/x86_init.h> | ||
| 30 | #endif | ||
| 31 | 29 | ||
| 32 | /* | 30 | /* |
| 33 | * Power off function, if any | 31 | * Power off function, if any |
| @@ -49,7 +47,7 @@ int reboot_force; | |||
| 49 | */ | 47 | */ |
| 50 | static int reboot_default = 1; | 48 | static int reboot_default = 1; |
| 51 | 49 | ||
| 52 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) | 50 | #ifdef CONFIG_SMP |
| 53 | static int reboot_cpu = -1; | 51 | static int reboot_cpu = -1; |
| 54 | #endif | 52 | #endif |
| 55 | 53 | ||
| @@ -67,8 +65,8 @@ bool port_cf9_safe = false; | |||
| 67 | * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] | 65 | * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] |
| 68 | * warm Don't set the cold reboot flag | 66 | * warm Don't set the cold reboot flag |
| 69 | * cold Set the cold reboot flag | 67 | * cold Set the cold reboot flag |
| 70 | * bios Reboot by jumping through the BIOS (only for X86_32) | 68 | * bios Reboot by jumping through the BIOS |
| 71 | * smp Reboot by executing reset on BSP or other CPU (only for X86_32) | 69 | * smp Reboot by executing reset on BSP or other CPU |
| 72 | * triple Force a triple fault (init) | 70 | * triple Force a triple fault (init) |
| 73 | * kbd Use the keyboard controller. cold reset (default) | 71 | * kbd Use the keyboard controller. cold reset (default) |
| 74 | * acpi Use the RESET_REG in the FADT | 72 | * acpi Use the RESET_REG in the FADT |
| @@ -95,7 +93,6 @@ static int __init reboot_setup(char *str) | |||
| 95 | reboot_mode = 0; | 93 | reboot_mode = 0; |
| 96 | break; | 94 | break; |
| 97 | 95 | ||
| 98 | #ifdef CONFIG_X86_32 | ||
| 99 | #ifdef CONFIG_SMP | 96 | #ifdef CONFIG_SMP |
| 100 | case 's': | 97 | case 's': |
| 101 | if (isdigit(*(str+1))) { | 98 | if (isdigit(*(str+1))) { |
| @@ -112,7 +109,6 @@ static int __init reboot_setup(char *str) | |||
| 112 | #endif /* CONFIG_SMP */ | 109 | #endif /* CONFIG_SMP */ |
| 113 | 110 | ||
| 114 | case 'b': | 111 | case 'b': |
| 115 | #endif | ||
| 116 | case 'a': | 112 | case 'a': |
| 117 | case 'k': | 113 | case 'k': |
| 118 | case 't': | 114 | case 't': |
| @@ -138,7 +134,6 @@ static int __init reboot_setup(char *str) | |||
| 138 | __setup("reboot=", reboot_setup); | 134 | __setup("reboot=", reboot_setup); |
| 139 | 135 | ||
| 140 | 136 | ||
| 141 | #ifdef CONFIG_X86_32 | ||
| 142 | /* | 137 | /* |
| 143 | * Reboot options and system auto-detection code provided by | 138 | * Reboot options and system auto-detection code provided by |
| 144 | * Dell Inc. so their systems "just work". :-) | 139 | * Dell Inc. so their systems "just work". :-) |
| @@ -157,11 +152,8 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) | |||
| 157 | return 0; | 152 | return 0; |
| 158 | } | 153 | } |
| 159 | 154 | ||
| 160 | void machine_real_restart(unsigned int type) | 155 | void __noreturn machine_real_restart(unsigned int type) |
| 161 | { | 156 | { |
| 162 | void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) | ||
| 163 | real_mode_header->machine_real_restart_asm; | ||
| 164 | |||
| 165 | local_irq_disable(); | 157 | local_irq_disable(); |
| 166 | 158 | ||
| 167 | /* | 159 | /* |
| @@ -181,7 +173,11 @@ void machine_real_restart(unsigned int type) | |||
| 181 | /* | 173 | /* |
| 182 | * Switch back to the initial page table. | 174 | * Switch back to the initial page table. |
| 183 | */ | 175 | */ |
| 176 | #ifdef CONFIG_X86_32 | ||
| 184 | load_cr3(initial_page_table); | 177 | load_cr3(initial_page_table); |
| 178 | #else | ||
| 179 | write_cr3(real_mode_header->trampoline_pgd); | ||
| 180 | #endif | ||
| 185 | 181 | ||
| 186 | /* | 182 | /* |
| 187 | * Write 0x1234 to absolute memory location 0x472. The BIOS reads | 183 | * Write 0x1234 to absolute memory location 0x472. The BIOS reads |
| @@ -192,14 +188,21 @@ void machine_real_restart(unsigned int type) | |||
| 192 | *((unsigned short *)0x472) = reboot_mode; | 188 | *((unsigned short *)0x472) = reboot_mode; |
| 193 | 189 | ||
| 194 | /* Jump to the identity-mapped low memory code */ | 190 | /* Jump to the identity-mapped low memory code */ |
| 195 | restart_lowmem(type); | 191 | #ifdef CONFIG_X86_32 |
| 192 | asm volatile("jmpl *%0" : : | ||
| 193 | "rm" (real_mode_header->machine_real_restart_asm), | ||
| 194 | "a" (type)); | ||
| 195 | #else | ||
| 196 | asm volatile("ljmpl *%0" : : | ||
| 197 | "m" (real_mode_header->machine_real_restart_asm), | ||
| 198 | "D" (type)); | ||
| 199 | #endif | ||
| 200 | unreachable(); | ||
| 196 | } | 201 | } |
| 197 | #ifdef CONFIG_APM_MODULE | 202 | #ifdef CONFIG_APM_MODULE |
| 198 | EXPORT_SYMBOL(machine_real_restart); | 203 | EXPORT_SYMBOL(machine_real_restart); |
| 199 | #endif | 204 | #endif |
| 200 | 205 | ||
| 201 | #endif /* CONFIG_X86_32 */ | ||
| 202 | |||
| 203 | /* | 206 | /* |
| 204 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot | 207 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot |
| 205 | */ | 208 | */ |
| @@ -223,11 +226,9 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d) | |||
| 223 | } | 226 | } |
| 224 | 227 | ||
| 225 | /* | 228 | /* |
| 226 | * This is a single dmi_table handling all reboot quirks. Note that | 229 | * This is a single dmi_table handling all reboot quirks. |
| 227 | * REBOOT_BIOS is only available for 32bit | ||
| 228 | */ | 230 | */ |
| 229 | static struct dmi_system_id __initdata reboot_dmi_table[] = { | 231 | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
| 230 | #ifdef CONFIG_X86_32 | ||
| 231 | { /* Handle problems with rebooting on Dell E520's */ | 232 | { /* Handle problems with rebooting on Dell E520's */ |
| 232 | .callback = set_bios_reboot, | 233 | .callback = set_bios_reboot, |
| 233 | .ident = "Dell E520", | 234 | .ident = "Dell E520", |
| @@ -377,7 +378,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
| 377 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), | 378 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
| 378 | }, | 379 | }, |
| 379 | }, | 380 | }, |
| 380 | #endif /* CONFIG_X86_32 */ | ||
| 381 | 381 | ||
| 382 | { /* Handle reboot issue on Acer Aspire one */ | 382 | { /* Handle reboot issue on Acer Aspire one */ |
| 383 | .callback = set_kbd_reboot, | 383 | .callback = set_kbd_reboot, |
| @@ -576,13 +576,11 @@ static void native_machine_emergency_restart(void) | |||
| 576 | reboot_type = BOOT_KBD; | 576 | reboot_type = BOOT_KBD; |
| 577 | break; | 577 | break; |
| 578 | 578 | ||
| 579 | #ifdef CONFIG_X86_32 | ||
| 580 | case BOOT_BIOS: | 579 | case BOOT_BIOS: |
| 581 | machine_real_restart(MRR_BIOS); | 580 | machine_real_restart(MRR_BIOS); |
| 582 | 581 | ||
| 583 | reboot_type = BOOT_KBD; | 582 | reboot_type = BOOT_KBD; |
| 584 | break; | 583 | break; |
| 585 | #endif | ||
| 586 | 584 | ||
| 587 | case BOOT_ACPI: | 585 | case BOOT_ACPI: |
| 588 | acpi_reboot(); | 586 | acpi_reboot(); |
| @@ -624,12 +622,10 @@ void native_machine_shutdown(void) | |||
| 624 | /* The boot cpu is always logical cpu 0 */ | 622 | /* The boot cpu is always logical cpu 0 */ |
| 625 | int reboot_cpu_id = 0; | 623 | int reboot_cpu_id = 0; |
| 626 | 624 | ||
| 627 | #ifdef CONFIG_X86_32 | ||
| 628 | /* See if there has been given a command line override */ | 625 | /* See if there has been given a command line override */ |
| 629 | if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && | 626 | if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && |
| 630 | cpu_online(reboot_cpu)) | 627 | cpu_online(reboot_cpu)) |
| 631 | reboot_cpu_id = reboot_cpu; | 628 | reboot_cpu_id = reboot_cpu; |
| 632 | #endif | ||
| 633 | 629 | ||
| 634 | /* Make certain the cpu I'm about to reboot on is online */ | 630 | /* Make certain the cpu I'm about to reboot on is online */ |
| 635 | if (!cpu_online(reboot_cpu_id)) | 631 | if (!cpu_online(reboot_cpu_id)) |
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 5b84a2d30888..b2d534cab25f 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile | |||
| @@ -22,7 +22,7 @@ wakeup-objs += video-bios.o | |||
| 22 | realmode-y += header.o | 22 | realmode-y += header.o |
| 23 | realmode-y += trampoline_$(BITS).o | 23 | realmode-y += trampoline_$(BITS).o |
| 24 | realmode-y += stack.o | 24 | realmode-y += stack.o |
| 25 | realmode-$(CONFIG_X86_32) += reboot_32.o | 25 | realmode-y += reboot.o |
| 26 | realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs) | 26 | realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs) |
| 27 | 27 | ||
| 28 | targets += $(realmode-y) | 28 | targets += $(realmode-y) |
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index fadf48378ada..a28221d94e69 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <linux/linkage.h> | 7 | #include <linux/linkage.h> |
| 8 | #include <asm/page_types.h> | 8 | #include <asm/page_types.h> |
| 9 | #include <asm/segment.h> | ||
| 9 | 10 | ||
| 10 | #include "realmode.h" | 11 | #include "realmode.h" |
| 11 | 12 | ||
| @@ -28,8 +29,9 @@ GLOBAL(real_mode_header) | |||
| 28 | .long pa_wakeup_header | 29 | .long pa_wakeup_header |
| 29 | #endif | 30 | #endif |
| 30 | /* APM/BIOS reboot */ | 31 | /* APM/BIOS reboot */ |
| 31 | #ifdef CONFIG_X86_32 | ||
| 32 | .long pa_machine_real_restart_asm | 32 | .long pa_machine_real_restart_asm |
| 33 | #ifdef CONFIG_X86_64 | ||
| 34 | .long __KERNEL32_CS | ||
| 33 | #endif | 35 | #endif |
| 34 | END(real_mode_header) | 36 | END(real_mode_header) |
| 35 | 37 | ||
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot.S index 114044876b3d..6bf8feac5557 100644 --- a/arch/x86/realmode/rm/reboot_32.S +++ b/arch/x86/realmode/rm/reboot.S | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
| 3 | #include <asm/segment.h> | 3 | #include <asm/segment.h> |
| 4 | #include <asm/page_types.h> | 4 | #include <asm/page_types.h> |
| 5 | #include <asm/processor-flags.h> | ||
| 6 | #include <asm/msr-index.h> | ||
| 5 | #include "realmode.h" | 7 | #include "realmode.h" |
| 6 | 8 | ||
| 7 | /* | 9 | /* |
| @@ -12,13 +14,31 @@ | |||
| 12 | * doesn't work with at least one type of 486 motherboard. It is easy | 14 | * doesn't work with at least one type of 486 motherboard. It is easy |
| 13 | * to stop this code working; hence the copious comments. | 15 | * to stop this code working; hence the copious comments. |
| 14 | * | 16 | * |
| 15 | * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. | 17 | * This code is called with the restart type (0 = BIOS, 1 = APM) in |
| 18 | * the primary argument register (%eax for 32 bit, %edi for 64 bit). | ||
| 16 | */ | 19 | */ |
| 17 | .section ".text32", "ax" | 20 | .section ".text32", "ax" |
| 18 | .code32 | 21 | .code32 |
| 19 | |||
| 20 | .balign 16 | ||
| 21 | ENTRY(machine_real_restart_asm) | 22 | ENTRY(machine_real_restart_asm) |
| 23 | |||
| 24 | #ifdef CONFIG_X86_64 | ||
| 25 | |||
| 26 | /* Disable paging to drop us out of long mode */ | ||
| 27 | movl %cr0, %eax | ||
| 28 | andl $~X86_CR0_PG, %eax | ||
| 29 | movl %eax, %cr0 | ||
| 30 | jmp 1f /* "A branch" may be needed here, assume near is OK */ | ||
| 31 | |||
| 32 | 1: | ||
| 33 | xorl %eax, %eax | ||
| 34 | xorl %edx, %edx | ||
| 35 | movl $MSR_EFER, %ecx | ||
| 36 | wrmsr | ||
| 37 | |||
| 38 | movl %edi, %eax | ||
| 39 | |||
| 40 | #endif /* CONFIG_X86_64 */ | ||
| 41 | |||
| 22 | /* Set up the IDT for real mode. */ | 42 | /* Set up the IDT for real mode. */ |
| 23 | lidtl pa_machine_real_restart_idt | 43 | lidtl pa_machine_real_restart_idt |
| 24 | 44 | ||
