diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-22 15:25:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-22 15:25:47 -0400 |
commit | d5d96ed2d89ea228bdc27980b8ee4c94422ddef5 (patch) | |
tree | 378860da8a2b7209905fb8856746a7ce95fbca4c /arch | |
parent | bd3e57f9132ac55e2848aa10cf50341de2508e1d (diff) | |
parent | 9751d7627582fc1cc64625d63bde9528c14f1544 (diff) |
Merge branch 'x86-reboot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/reboot changes from Ingo Molnar:
"Now that the revampted x86 real-mode trampoline code is upstream and
seems to be working well, we can extend the 64-bit reboot code to be
as capable as the 32-bit one."
* 'x86-reboot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86-64, reboot: Be more paranoid in 64-bit reboot=bios
x86, reboot: Drop redundant write of reboot_mode
x86-64, reboot: Allow reboot=bios and reboot-cpu override on x86-64
Diffstat (limited to 'arch')
-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 | 60 | ||||
-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) | 30 |
7 files changed, 59 insertions, 46 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 d0f81d3d388f..52190a938b4a 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -22,14 +22,12 @@ | |||
22 | #include <asm/virtext.h> | 22 | #include <asm/virtext.h> |
23 | #include <asm/cpu.h> | 23 | #include <asm/cpu.h> |
24 | #include <asm/nmi.h> | 24 | #include <asm/nmi.h> |
25 | #include <asm/smp.h> | ||
25 | 26 | ||
26 | #ifdef CONFIG_X86_32 | 27 | #include <linux/ctype.h> |
27 | # include <linux/ctype.h> | 28 | #include <linux/mc146818rtc.h> |
28 | # include <linux/mc146818rtc.h> | 29 | #include <asm/realmode.h> |
29 | # include <asm/realmode.h> | 30 | #include <asm/x86_init.h> |
30 | #else | ||
31 | # include <asm/x86_init.h> | ||
32 | #endif | ||
33 | 31 | ||
34 | /* | 32 | /* |
35 | * Power off function, if any | 33 | * Power off function, if any |
@@ -51,7 +49,7 @@ int reboot_force; | |||
51 | */ | 49 | */ |
52 | static int reboot_default = 1; | 50 | static int reboot_default = 1; |
53 | 51 | ||
54 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) | 52 | #ifdef CONFIG_SMP |
55 | static int reboot_cpu = -1; | 53 | static int reboot_cpu = -1; |
56 | #endif | 54 | #endif |
57 | 55 | ||
@@ -69,8 +67,8 @@ bool port_cf9_safe = false; | |||
69 | * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] | 67 | * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci] |
70 | * warm Don't set the cold reboot flag | 68 | * warm Don't set the cold reboot flag |
71 | * cold Set the cold reboot flag | 69 | * cold Set the cold reboot flag |
72 | * bios Reboot by jumping through the BIOS (only for X86_32) | 70 | * bios Reboot by jumping through the BIOS |
73 | * smp Reboot by executing reset on BSP or other CPU (only for X86_32) | 71 | * smp Reboot by executing reset on BSP or other CPU |
74 | * triple Force a triple fault (init) | 72 | * triple Force a triple fault (init) |
75 | * kbd Use the keyboard controller. cold reset (default) | 73 | * kbd Use the keyboard controller. cold reset (default) |
76 | * acpi Use the RESET_REG in the FADT | 74 | * acpi Use the RESET_REG in the FADT |
@@ -97,7 +95,6 @@ static int __init reboot_setup(char *str) | |||
97 | reboot_mode = 0; | 95 | reboot_mode = 0; |
98 | break; | 96 | break; |
99 | 97 | ||
100 | #ifdef CONFIG_X86_32 | ||
101 | #ifdef CONFIG_SMP | 98 | #ifdef CONFIG_SMP |
102 | case 's': | 99 | case 's': |
103 | if (isdigit(*(str+1))) { | 100 | if (isdigit(*(str+1))) { |
@@ -114,7 +111,6 @@ static int __init reboot_setup(char *str) | |||
114 | #endif /* CONFIG_SMP */ | 111 | #endif /* CONFIG_SMP */ |
115 | 112 | ||
116 | case 'b': | 113 | case 'b': |
117 | #endif | ||
118 | case 'a': | 114 | case 'a': |
119 | case 'k': | 115 | case 'k': |
120 | case 't': | 116 | case 't': |
@@ -140,7 +136,6 @@ static int __init reboot_setup(char *str) | |||
140 | __setup("reboot=", reboot_setup); | 136 | __setup("reboot=", reboot_setup); |
141 | 137 | ||
142 | 138 | ||
143 | #ifdef CONFIG_X86_32 | ||
144 | /* | 139 | /* |
145 | * Reboot options and system auto-detection code provided by | 140 | * Reboot options and system auto-detection code provided by |
146 | * Dell Inc. so their systems "just work". :-) | 141 | * Dell Inc. so their systems "just work". :-) |
@@ -160,11 +155,8 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) | |||
160 | return 0; | 155 | return 0; |
161 | } | 156 | } |
162 | 157 | ||
163 | void machine_real_restart(unsigned int type) | 158 | void __noreturn machine_real_restart(unsigned int type) |
164 | { | 159 | { |
165 | void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) | ||
166 | real_mode_header->machine_real_restart_asm; | ||
167 | |||
168 | local_irq_disable(); | 160 | local_irq_disable(); |
169 | 161 | ||
170 | /* | 162 | /* |
@@ -184,25 +176,28 @@ void machine_real_restart(unsigned int type) | |||
184 | /* | 176 | /* |
185 | * Switch back to the initial page table. | 177 | * Switch back to the initial page table. |
186 | */ | 178 | */ |
179 | #ifdef CONFIG_X86_32 | ||
187 | load_cr3(initial_page_table); | 180 | load_cr3(initial_page_table); |
188 | 181 | #else | |
189 | /* | 182 | write_cr3(real_mode_header->trampoline_pgd); |
190 | * Write 0x1234 to absolute memory location 0x472. The BIOS reads | 183 | #endif |
191 | * this on booting to tell it to "Bypass memory test (also warm | ||
192 | * boot)". This seems like a fairly standard thing that gets set by | ||
193 | * REBOOT.COM programs, and the previous reset routine did this | ||
194 | * too. */ | ||
195 | *((unsigned short *)0x472) = reboot_mode; | ||
196 | 184 | ||
197 | /* Jump to the identity-mapped low memory code */ | 185 | /* Jump to the identity-mapped low memory code */ |
198 | restart_lowmem(type); | 186 | #ifdef CONFIG_X86_32 |
187 | asm volatile("jmpl *%0" : : | ||
188 | "rm" (real_mode_header->machine_real_restart_asm), | ||
189 | "a" (type)); | ||
190 | #else | ||
191 | asm volatile("ljmpl *%0" : : | ||
192 | "m" (real_mode_header->machine_real_restart_asm), | ||
193 | "D" (type)); | ||
194 | #endif | ||
195 | unreachable(); | ||
199 | } | 196 | } |
200 | #ifdef CONFIG_APM_MODULE | 197 | #ifdef CONFIG_APM_MODULE |
201 | EXPORT_SYMBOL(machine_real_restart); | 198 | EXPORT_SYMBOL(machine_real_restart); |
202 | #endif | 199 | #endif |
203 | 200 | ||
204 | #endif /* CONFIG_X86_32 */ | ||
205 | |||
206 | /* | 201 | /* |
207 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot | 202 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot |
208 | */ | 203 | */ |
@@ -227,11 +222,9 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d) | |||
227 | } | 222 | } |
228 | 223 | ||
229 | /* | 224 | /* |
230 | * This is a single dmi_table handling all reboot quirks. Note that | 225 | * This is a single dmi_table handling all reboot quirks. |
231 | * REBOOT_BIOS is only available for 32bit | ||
232 | */ | 226 | */ |
233 | static struct dmi_system_id __initdata reboot_dmi_table[] = { | 227 | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
234 | #ifdef CONFIG_X86_32 | ||
235 | { /* Handle problems with rebooting on Dell E520's */ | 228 | { /* Handle problems with rebooting on Dell E520's */ |
236 | .callback = set_bios_reboot, | 229 | .callback = set_bios_reboot, |
237 | .ident = "Dell E520", | 230 | .ident = "Dell E520", |
@@ -381,7 +374,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
381 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), | 374 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
382 | }, | 375 | }, |
383 | }, | 376 | }, |
384 | #endif /* CONFIG_X86_32 */ | ||
385 | 377 | ||
386 | { /* Handle reboot issue on Acer Aspire one */ | 378 | { /* Handle reboot issue on Acer Aspire one */ |
387 | .callback = set_kbd_reboot, | 379 | .callback = set_kbd_reboot, |
@@ -588,13 +580,11 @@ static void native_machine_emergency_restart(void) | |||
588 | reboot_type = BOOT_KBD; | 580 | reboot_type = BOOT_KBD; |
589 | break; | 581 | break; |
590 | 582 | ||
591 | #ifdef CONFIG_X86_32 | ||
592 | case BOOT_BIOS: | 583 | case BOOT_BIOS: |
593 | machine_real_restart(MRR_BIOS); | 584 | machine_real_restart(MRR_BIOS); |
594 | 585 | ||
595 | reboot_type = BOOT_KBD; | 586 | reboot_type = BOOT_KBD; |
596 | break; | 587 | break; |
597 | #endif | ||
598 | 588 | ||
599 | case BOOT_ACPI: | 589 | case BOOT_ACPI: |
600 | acpi_reboot(); | 590 | acpi_reboot(); |
@@ -636,12 +626,10 @@ void native_machine_shutdown(void) | |||
636 | /* The boot cpu is always logical cpu 0 */ | 626 | /* The boot cpu is always logical cpu 0 */ |
637 | int reboot_cpu_id = 0; | 627 | int reboot_cpu_id = 0; |
638 | 628 | ||
639 | #ifdef CONFIG_X86_32 | ||
640 | /* See if there has been given a command line override */ | 629 | /* See if there has been given a command line override */ |
641 | if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && | 630 | if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) && |
642 | cpu_online(reboot_cpu)) | 631 | cpu_online(reboot_cpu)) |
643 | reboot_cpu_id = reboot_cpu; | 632 | reboot_cpu_id = reboot_cpu; |
644 | #endif | ||
645 | 633 | ||
646 | /* Make certain the cpu I'm about to reboot on is online */ | 634 | /* Make certain the cpu I'm about to reboot on is online */ |
647 | if (!cpu_online(reboot_cpu_id)) | 635 | 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..f932ea61d1c8 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,35 @@ | |||
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 | /* Switch to trampoline GDT as it is guaranteed < 4 GiB */ | ||
26 | movl $__KERNEL_DS, %eax | ||
27 | movl %eax, %ds | ||
28 | lgdtl pa_tr_gdt | ||
29 | |||
30 | /* Disable paging to drop us out of long mode */ | ||
31 | movl %cr0, %eax | ||
32 | andl $~X86_CR0_PG, %eax | ||
33 | movl %eax, %cr0 | ||
34 | ljmpl $__KERNEL32_CS, $pa_machine_real_restart_paging_off | ||
35 | |||
36 | GLOBAL(machine_real_restart_paging_off) | ||
37 | xorl %eax, %eax | ||
38 | xorl %edx, %edx | ||
39 | movl $MSR_EFER, %ecx | ||
40 | wrmsr | ||
41 | |||
42 | movl %edi, %eax | ||
43 | |||
44 | #endif /* CONFIG_X86_64 */ | ||
45 | |||
22 | /* Set up the IDT for real mode. */ | 46 | /* Set up the IDT for real mode. */ |
23 | lidtl pa_machine_real_restart_idt | 47 | lidtl pa_machine_real_restart_idt |
24 | 48 | ||