aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-22 15:25:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-22 15:25:47 -0400
commitd5d96ed2d89ea228bdc27980b8ee4c94422ddef5 (patch)
tree378860da8a2b7209905fb8856746a7ce95fbca4c /arch
parentbd3e57f9132ac55e2848aa10cf50341de2508e1d (diff)
parent9751d7627582fc1cc64625d63bde9528c14f1544 (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.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.c60
-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)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 @@
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 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
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 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 */
52static int reboot_default = 1; 50static int reboot_default = 1;
53 51
54#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) 52#ifdef CONFIG_SMP
55static int reboot_cpu = -1; 53static 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
163void machine_real_restart(unsigned int type) 158void __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
201EXPORT_SYMBOL(machine_real_restart); 198EXPORT_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 */
233static struct dmi_system_id __initdata reboot_dmi_table[] = { 227static 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
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 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
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 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
21ENTRY(machine_real_restart_asm) 22ENTRY(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
36GLOBAL(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