aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-06-17 00:47:37 -0400
committerH. Peter Anvin <hpa@zytor.com>2012-06-17 13:51:01 -0400
commit650513979a437c32d7a0a84f0ed952a55bbb5583 (patch)
treeb831bcbfdfce6abb31573e67669272f368626b5b
parentcfaf025112d3856637ff34a767ef785ef5cf2ca9 (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.h2
-rw-r--r--arch/x86/include/asm/realmode.h3
-rw-r--r--arch/x86/include/asm/reboot.h4
-rw-r--r--arch/x86/kernel/reboot.c52
-rw-r--r--arch/x86/realmode/rm/Makefile2
-rw-r--r--arch/x86/realmode/rm/header.S4
-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 @@
4enum reboot_type { 4enum 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
19void native_machine_crash_shutdown(struct pt_regs *regs); 19void native_machine_crash_shutdown(struct pt_regs *regs);
20void native_machine_shutdown(void); 20void native_machine_shutdown(void);
21void machine_real_restart(unsigned int type); 21void __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 */
50static int reboot_default = 1; 48static int reboot_default = 1;
51 49
52#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 50#ifdef CONFIG_SMP
53static int reboot_cpu = -1; 51static 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
160void machine_real_restart(unsigned int type) 155void __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
198EXPORT_SYMBOL(machine_real_restart); 203EXPORT_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 */
229static struct dmi_system_id __initdata reboot_dmi_table[] = { 231static 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
22realmode-y += header.o 22realmode-y += header.o
23realmode-y += trampoline_$(BITS).o 23realmode-y += trampoline_$(BITS).o
24realmode-y += stack.o 24realmode-y += stack.o
25realmode-$(CONFIG_X86_32) += reboot_32.o 25realmode-y += reboot.o
26realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs) 26realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs)
27 27
28targets += $(realmode-y) 28targets += $(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
34END(real_mode_header) 36END(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
21ENTRY(machine_real_restart_asm) 22ENTRY(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
321:
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