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 cc70c1c78ca..75ce3f47d20 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 fce3f4ae5bd..fe1ec5bcd84 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 92f297069e8..a82c4f1b4d8 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 25b48edb847..6ddb9cd0ced 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 5b84a2d3088..b2d534cab25 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 fadf48378ad..a28221d94e6 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 114044876b3..6bf8feac555 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 | ||