diff options
-rw-r--r-- | arch/x86/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/kernel/reboot.c (renamed from arch/x86/kernel/reboot_32.c) | 280 | ||||
-rw-r--r-- | arch/x86/kernel/reboot_64.c | 191 | ||||
-rw-r--r-- | include/asm-x86/emergency-restart.h | 3 |
4 files changed, 163 insertions, 315 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 0903bbf0ca4d..b40bed4baa77 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -30,8 +30,8 @@ obj-y += step.o | |||
30 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 30 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
31 | obj-y += cpu/ | 31 | obj-y += cpu/ |
32 | obj-y += acpi/ | 32 | obj-y += acpi/ |
33 | obj-$(CONFIG_X86_BIOS_REBOOT) += reboot_32.o | 33 | obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o |
34 | obj-$(CONFIG_X86_64) += reboot_64.o | 34 | obj-$(CONFIG_X86_64) += reboot.o |
35 | obj-$(CONFIG_MCA) += mca_32.o | 35 | obj-$(CONFIG_MCA) += mca_32.o |
36 | obj-$(CONFIG_X86_MSR) += msr.o | 36 | obj-$(CONFIG_X86_MSR) += msr.o |
37 | obj-$(CONFIG_X86_CPUID) += cpuid.o | 37 | obj-$(CONFIG_X86_CPUID) += cpuid.o |
diff --git a/arch/x86/kernel/reboot_32.c b/arch/x86/kernel/reboot.c index c3376fae639d..5b32f0b4d133 100644 --- a/arch/x86/kernel/reboot_32.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -1,64 +1,94 @@ | |||
1 | #include <linux/mm.h> | ||
2 | #include <linux/module.h> | 1 | #include <linux/module.h> |
3 | #include <linux/delay.h> | ||
4 | #include <linux/init.h> | 2 | #include <linux/init.h> |
5 | #include <linux/interrupt.h> | ||
6 | #include <linux/mc146818rtc.h> | ||
7 | #include <linux/efi.h> | ||
8 | #include <linux/dmi.h> | ||
9 | #include <linux/ctype.h> | ||
10 | #include <linux/pm.h> | ||
11 | #include <linux/reboot.h> | 3 | #include <linux/reboot.h> |
12 | #include <asm/uaccess.h> | 4 | #include <linux/init.h> |
5 | #include <linux/pm.h> | ||
6 | #include <linux/efi.h> | ||
7 | #include <acpi/reboot.h> | ||
8 | #include <asm/io.h> | ||
13 | #include <asm/apic.h> | 9 | #include <asm/apic.h> |
14 | #include <asm/hpet.h> | ||
15 | #include <asm/desc.h> | 10 | #include <asm/desc.h> |
16 | #include "mach_reboot.h" | 11 | #include <asm/hpet.h> |
17 | #include <asm/reboot_fixups.h> | 12 | #include <asm/reboot_fixups.h> |
18 | #include <asm/reboot.h> | 13 | #include <asm/reboot.h> |
19 | 14 | ||
15 | #ifdef CONFIG_X86_32 | ||
16 | # include <linux/dmi.h> | ||
17 | # include <linux/ctype.h> | ||
18 | # include <linux/mc146818rtc.h> | ||
19 | # include <asm/pgtable.h> | ||
20 | #else | ||
21 | # include <asm/iommu.h> | ||
22 | #endif | ||
23 | |||
20 | /* | 24 | /* |
21 | * Power off function, if any | 25 | * Power off function, if any |
22 | */ | 26 | */ |
23 | void (*pm_power_off)(void); | 27 | void (*pm_power_off)(void); |
24 | EXPORT_SYMBOL(pm_power_off); | 28 | EXPORT_SYMBOL(pm_power_off); |
25 | 29 | ||
30 | static long no_idt[3]; | ||
26 | static int reboot_mode; | 31 | static int reboot_mode; |
27 | static int reboot_thru_bios; | 32 | enum reboot_type reboot_type = BOOT_KBD; |
33 | int reboot_force; | ||
28 | 34 | ||
29 | #ifdef CONFIG_SMP | 35 | #if defined(CONFIG_X86_32) && defined(CONFIG_SMP) |
30 | static int reboot_cpu = -1; | 36 | static int reboot_cpu = -1; |
31 | #endif | 37 | #endif |
38 | |||
39 | /* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | ||
40 | warm Don't set the cold reboot flag | ||
41 | cold Set the cold reboot flag | ||
42 | bios Reboot by jumping through the BIOS (only for X86_32) | ||
43 | smp Reboot by executing reset on BSP or other CPU (only for X86_32) | ||
44 | triple Force a triple fault (init) | ||
45 | kbd Use the keyboard controller. cold reset (default) | ||
46 | acpi Use the RESET_REG in the FADT | ||
47 | efi Use efi reset_system runtime service | ||
48 | force Avoid anything that could hang. | ||
49 | */ | ||
32 | static int __init reboot_setup(char *str) | 50 | static int __init reboot_setup(char *str) |
33 | { | 51 | { |
34 | while(1) { | 52 | for (;;) { |
35 | switch (*str) { | 53 | switch (*str) { |
36 | case 'w': /* "warm" reboot (no memory testing etc) */ | 54 | case 'w': |
37 | reboot_mode = 0x1234; | 55 | reboot_mode = 0x1234; |
38 | break; | 56 | break; |
39 | case 'c': /* "cold" reboot (with memory testing etc) */ | 57 | |
40 | reboot_mode = 0x0; | 58 | case 'c': |
41 | break; | 59 | reboot_mode = 0; |
42 | case 'b': /* "bios" reboot by jumping through the BIOS */ | ||
43 | reboot_thru_bios = 1; | ||
44 | break; | ||
45 | case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ | ||
46 | reboot_thru_bios = 0; | ||
47 | break; | 60 | break; |
61 | |||
62 | #ifdef CONFIG_X86_32 | ||
48 | #ifdef CONFIG_SMP | 63 | #ifdef CONFIG_SMP |
49 | case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ | 64 | case 's': |
50 | if (isdigit(*(str+1))) { | 65 | if (isdigit(*(str+1))) { |
51 | reboot_cpu = (int) (*(str+1) - '0'); | 66 | reboot_cpu = (int) (*(str+1) - '0'); |
52 | if (isdigit(*(str+2))) | 67 | if (isdigit(*(str+2))) |
53 | reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); | 68 | reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); |
54 | } | 69 | } |
55 | /* we will leave sorting out the final value | 70 | /* we will leave sorting out the final value |
56 | when we are ready to reboot, since we might not | 71 | when we are ready to reboot, since we might not |
57 | have set up boot_cpu_id or smp_num_cpu */ | 72 | have set up boot_cpu_id or smp_num_cpu */ |
58 | break; | 73 | break; |
74 | #endif /* CONFIG_SMP */ | ||
75 | |||
76 | case 'b': | ||
59 | #endif | 77 | #endif |
78 | case 'a': | ||
79 | case 'k': | ||
80 | case 't': | ||
81 | case 'e': | ||
82 | reboot_type = *str; | ||
83 | break; | ||
84 | |||
85 | case 'f': | ||
86 | reboot_force = 1; | ||
87 | break; | ||
60 | } | 88 | } |
61 | if((str = strchr(str,',')) != NULL) | 89 | |
90 | str = strchr(str, ','); | ||
91 | if (str) | ||
62 | str++; | 92 | str++; |
63 | else | 93 | else |
64 | break; | 94 | break; |
@@ -68,18 +98,21 @@ static int __init reboot_setup(char *str) | |||
68 | 98 | ||
69 | __setup("reboot=", reboot_setup); | 99 | __setup("reboot=", reboot_setup); |
70 | 100 | ||
101 | |||
102 | #ifdef CONFIG_X86_32 | ||
71 | /* | 103 | /* |
72 | * Reboot options and system auto-detection code provided by | 104 | * Reboot options and system auto-detection code provided by |
73 | * Dell Inc. so their systems "just work". :-) | 105 | * Dell Inc. so their systems "just work". :-) |
74 | */ | 106 | */ |
75 | 107 | ||
76 | /* | 108 | /* |
77 | * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. | 109 | * Some machines require the "reboot=b" commandline option, |
110 | * this quirk makes that automatic. | ||
78 | */ | 111 | */ |
79 | static int __init set_bios_reboot(const struct dmi_system_id *d) | 112 | static int __init set_bios_reboot(const struct dmi_system_id *d) |
80 | { | 113 | { |
81 | if (!reboot_thru_bios) { | 114 | if (reboot_type != BOOT_BIOS) { |
82 | reboot_thru_bios = 1; | 115 | reboot_type = BOOT_BIOS; |
83 | printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); | 116 | printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); |
84 | } | 117 | } |
85 | return 0; | 118 | return 0; |
@@ -143,7 +176,6 @@ static int __init reboot_init(void) | |||
143 | dmi_check_system(reboot_dmi_table); | 176 | dmi_check_system(reboot_dmi_table); |
144 | return 0; | 177 | return 0; |
145 | } | 178 | } |
146 | |||
147 | core_initcall(reboot_init); | 179 | core_initcall(reboot_init); |
148 | 180 | ||
149 | /* The following code and data reboots the machine by switching to real | 181 | /* The following code and data reboots the machine by switching to real |
@@ -152,7 +184,6 @@ core_initcall(reboot_init); | |||
152 | controller to pulse the CPU reset line, which is more thorough, but | 184 | controller to pulse the CPU reset line, which is more thorough, but |
153 | doesn't work with at least one type of 486 motherboard. It is easy | 185 | doesn't work with at least one type of 486 motherboard. It is easy |
154 | to stop this code working; hence the copious comments. */ | 186 | to stop this code working; hence the copious comments. */ |
155 | |||
156 | static unsigned long long | 187 | static unsigned long long |
157 | real_mode_gdt_entries [3] = | 188 | real_mode_gdt_entries [3] = |
158 | { | 189 | { |
@@ -163,9 +194,7 @@ real_mode_gdt_entries [3] = | |||
163 | 194 | ||
164 | static struct desc_ptr | 195 | static struct desc_ptr |
165 | real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, | 196 | real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries }, |
166 | real_mode_idt = { 0x3ff, 0 }, | 197 | real_mode_idt = { 0x3ff, 0 }; |
167 | no_idt = { 0, 0 }; | ||
168 | |||
169 | 198 | ||
170 | /* This is 16-bit protected mode code to disable paging and the cache, | 199 | /* This is 16-bit protected mode code to disable paging and the cache, |
171 | switch to real mode and jump to the BIOS reset code. | 200 | switch to real mode and jump to the BIOS reset code. |
@@ -185,7 +214,6 @@ no_idt = { 0, 0 }; | |||
185 | 214 | ||
186 | More could be done here to set up the registers as if a CPU reset had | 215 | More could be done here to set up the registers as if a CPU reset had |
187 | occurred; hopefully real BIOSs don't assume much. */ | 216 | occurred; hopefully real BIOSs don't assume much. */ |
188 | |||
189 | static unsigned char real_mode_switch [] = | 217 | static unsigned char real_mode_switch [] = |
190 | { | 218 | { |
191 | 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ | 219 | 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ |
@@ -223,7 +251,6 @@ void machine_real_restart(unsigned char *code, int length) | |||
223 | `outb_p' is needed instead of just `outb'. Use it to be on the | 251 | `outb_p' is needed instead of just `outb'. Use it to be on the |
224 | safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) | 252 | safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) |
225 | */ | 253 | */ |
226 | |||
227 | spin_lock(&rtc_lock); | 254 | spin_lock(&rtc_lock); |
228 | CMOS_WRITE(0x00, 0x8f); | 255 | CMOS_WRITE(0x00, 0x8f); |
229 | spin_unlock(&rtc_lock); | 256 | spin_unlock(&rtc_lock); |
@@ -231,9 +258,8 @@ void machine_real_restart(unsigned char *code, int length) | |||
231 | /* Remap the kernel at virtual address zero, as well as offset zero | 258 | /* Remap the kernel at virtual address zero, as well as offset zero |
232 | from the kernel segment. This assumes the kernel segment starts at | 259 | from the kernel segment. This assumes the kernel segment starts at |
233 | virtual address PAGE_OFFSET. */ | 260 | virtual address PAGE_OFFSET. */ |
234 | 261 | memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, | |
235 | memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, | 262 | sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); |
236 | sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); | ||
237 | 263 | ||
238 | /* | 264 | /* |
239 | * Use `swapper_pg_dir' as our page directory. | 265 | * Use `swapper_pg_dir' as our page directory. |
@@ -245,7 +271,6 @@ void machine_real_restart(unsigned char *code, int length) | |||
245 | boot)". This seems like a fairly standard thing that gets set by | 271 | boot)". This seems like a fairly standard thing that gets set by |
246 | REBOOT.COM programs, and the previous reset routine did this | 272 | REBOOT.COM programs, and the previous reset routine did this |
247 | too. */ | 273 | too. */ |
248 | |||
249 | *((unsigned short *)0x472) = reboot_mode; | 274 | *((unsigned short *)0x472) = reboot_mode; |
250 | 275 | ||
251 | /* For the switch to real mode, copy some code to low memory. It has | 276 | /* For the switch to real mode, copy some code to low memory. It has |
@@ -253,19 +278,16 @@ void machine_real_restart(unsigned char *code, int length) | |||
253 | has to have the same physical and virtual address, because it turns | 278 | has to have the same physical and virtual address, because it turns |
254 | off paging. Copy it near the end of the first page, out of the way | 279 | off paging. Copy it near the end of the first page, out of the way |
255 | of BIOS variables. */ | 280 | of BIOS variables. */ |
256 | 281 | memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100), | |
257 | memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), | ||
258 | real_mode_switch, sizeof (real_mode_switch)); | 282 | real_mode_switch, sizeof (real_mode_switch)); |
259 | memcpy ((void *) (0x1000 - 100), code, length); | 283 | memcpy((void *)(0x1000 - 100), code, length); |
260 | 284 | ||
261 | /* Set up the IDT for real mode. */ | 285 | /* Set up the IDT for real mode. */ |
262 | |||
263 | load_idt(&real_mode_idt); | 286 | load_idt(&real_mode_idt); |
264 | 287 | ||
265 | /* Set up a GDT from which we can load segment descriptors for real | 288 | /* Set up a GDT from which we can load segment descriptors for real |
266 | mode. The GDT is not used in real mode; it is just needed here to | 289 | mode. The GDT is not used in real mode; it is just needed here to |
267 | prepare the descriptors. */ | 290 | prepare the descriptors. */ |
268 | |||
269 | load_gdt(&real_mode_gdt); | 291 | load_gdt(&real_mode_gdt); |
270 | 292 | ||
271 | /* Load the data segment registers, and thus the descriptors ready for | 293 | /* Load the data segment registers, and thus the descriptors ready for |
@@ -273,7 +295,6 @@ void machine_real_restart(unsigned char *code, int length) | |||
273 | selector value being loaded here. This is so that the segment | 295 | selector value being loaded here. This is so that the segment |
274 | registers don't have to be reloaded after switching to real mode: | 296 | registers don't have to be reloaded after switching to real mode: |
275 | the values are consistent for real mode operation already. */ | 297 | the values are consistent for real mode operation already. */ |
276 | |||
277 | __asm__ __volatile__ ("movl $0x0010,%%eax\n" | 298 | __asm__ __volatile__ ("movl $0x0010,%%eax\n" |
278 | "\tmovl %%eax,%%ds\n" | 299 | "\tmovl %%eax,%%ds\n" |
279 | "\tmovl %%eax,%%es\n" | 300 | "\tmovl %%eax,%%es\n" |
@@ -284,130 +305,145 @@ void machine_real_restart(unsigned char *code, int length) | |||
284 | /* Jump to the 16-bit code that we copied earlier. It disables paging | 305 | /* Jump to the 16-bit code that we copied earlier. It disables paging |
285 | and the cache, switches to real mode, and jumps to the BIOS reset | 306 | and the cache, switches to real mode, and jumps to the BIOS reset |
286 | entry point. */ | 307 | entry point. */ |
287 | |||
288 | __asm__ __volatile__ ("ljmp $0x0008,%0" | 308 | __asm__ __volatile__ ("ljmp $0x0008,%0" |
289 | : | 309 | : |
290 | : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); | 310 | : "i" ((void *)(0x1000 - sizeof (real_mode_switch) - 100))); |
291 | } | 311 | } |
292 | #ifdef CONFIG_APM_MODULE | 312 | #ifdef CONFIG_APM_MODULE |
293 | EXPORT_SYMBOL(machine_real_restart); | 313 | EXPORT_SYMBOL(machine_real_restart); |
294 | #endif | 314 | #endif |
295 | 315 | ||
296 | static void native_machine_shutdown(void) | 316 | #endif /* CONFIG_X86_32 */ |
317 | |||
318 | static inline void kb_wait(void) | ||
319 | { | ||
320 | int i; | ||
321 | |||
322 | for (i = 0; i < 0x10000; i++) | ||
323 | if ((inb_p(0x64) & 0x02) == 0) | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | void machine_emergency_restart(void) | ||
297 | { | 328 | { |
329 | int i; | ||
330 | |||
331 | /* Tell the BIOS if we want cold or warm reboot */ | ||
332 | *((unsigned short *)__va(0x472)) = reboot_mode; | ||
333 | |||
334 | for (;;) { | ||
335 | /* Could also try the reset bit in the Hammer NB */ | ||
336 | switch (reboot_type) { | ||
337 | case BOOT_KBD: | ||
338 | for (i = 0; i < 10; i++) { | ||
339 | kb_wait(); | ||
340 | udelay(50); | ||
341 | outb(0xfe, 0x64); /* pulse reset low */ | ||
342 | udelay(50); | ||
343 | } | ||
344 | |||
345 | case BOOT_TRIPLE: | ||
346 | load_idt((const struct desc_ptr *)&no_idt); | ||
347 | __asm__ __volatile__("int3"); | ||
348 | |||
349 | reboot_type = BOOT_KBD; | ||
350 | break; | ||
351 | |||
352 | #ifdef CONFIG_X86_32 | ||
353 | case BOOT_BIOS: | ||
354 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); | ||
355 | |||
356 | reboot_type = BOOT_KBD; | ||
357 | break; | ||
358 | #endif | ||
359 | |||
360 | case BOOT_ACPI: | ||
361 | acpi_reboot(); | ||
362 | reboot_type = BOOT_KBD; | ||
363 | break; | ||
364 | |||
365 | |||
366 | case BOOT_EFI: | ||
367 | if (efi_enabled) | ||
368 | efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, | ||
369 | EFI_SUCCESS, 0, NULL); | ||
370 | |||
371 | reboot_type = BOOT_KBD; | ||
372 | break; | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | void machine_shutdown(void) | ||
378 | { | ||
379 | /* Stop the cpus and apics */ | ||
298 | #ifdef CONFIG_SMP | 380 | #ifdef CONFIG_SMP |
299 | int reboot_cpu_id; | 381 | int reboot_cpu_id; |
300 | 382 | ||
301 | /* The boot cpu is always logical cpu 0 */ | 383 | /* The boot cpu is always logical cpu 0 */ |
302 | reboot_cpu_id = 0; | 384 | reboot_cpu_id = 0; |
303 | 385 | ||
386 | #ifdef CONFIG_X86_32 | ||
304 | /* See if there has been given a command line override */ | 387 | /* See if there has been given a command line override */ |
305 | if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && | 388 | if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) && |
306 | cpu_isset(reboot_cpu, cpu_online_map)) { | 389 | cpu_isset(reboot_cpu, cpu_online_map)) |
307 | reboot_cpu_id = reboot_cpu; | 390 | reboot_cpu_id = reboot_cpu; |
308 | } | 391 | #endif |
309 | 392 | ||
310 | /* Make certain the cpu I'm rebooting on is online */ | 393 | /* Make certain the cpu I'm about to reboot on is online */ |
311 | if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { | 394 | if (!cpu_isset(reboot_cpu_id, cpu_online_map)) |
312 | reboot_cpu_id = smp_processor_id(); | 395 | reboot_cpu_id = smp_processor_id(); |
313 | } | ||
314 | 396 | ||
315 | /* Make certain I only run on the appropriate processor */ | 397 | /* Make certain I only run on the appropriate processor */ |
316 | set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); | 398 | set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); |
317 | 399 | ||
318 | /* O.K. Now that I'm on the appropriate processor, stop | 400 | /* O.K Now that I'm on the appropriate processor, |
319 | * all of the others, and disable their local APICs. | 401 | * stop all of the others. |
320 | */ | 402 | */ |
321 | |||
322 | smp_send_stop(); | 403 | smp_send_stop(); |
323 | #endif /* CONFIG_SMP */ | 404 | #endif |
324 | 405 | ||
325 | lapic_shutdown(); | 406 | lapic_shutdown(); |
326 | 407 | ||
327 | #ifdef CONFIG_X86_IO_APIC | 408 | #ifdef CONFIG_X86_IO_APIC |
328 | disable_IO_APIC(); | 409 | disable_IO_APIC(); |
329 | #endif | 410 | #endif |
411 | |||
330 | #ifdef CONFIG_HPET_TIMER | 412 | #ifdef CONFIG_HPET_TIMER |
331 | hpet_disable(); | 413 | hpet_disable(); |
332 | #endif | 414 | #endif |
333 | } | ||
334 | 415 | ||
335 | void __attribute__((weak)) mach_reboot_fixups(void) | 416 | #ifdef CONFIG_X86_64 |
336 | { | 417 | pci_iommu_shutdown(); |
418 | #endif | ||
337 | } | 419 | } |
338 | 420 | ||
339 | static void native_machine_emergency_restart(void) | 421 | void machine_restart(char *__unused) |
340 | { | 422 | { |
341 | if (!reboot_thru_bios) { | 423 | printk("machine restart\n"); |
342 | if (efi_enabled) { | ||
343 | efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL); | ||
344 | load_idt(&no_idt); | ||
345 | __asm__ __volatile__("int3"); | ||
346 | } | ||
347 | /* rebooting needs to touch the page at absolute addr 0 */ | ||
348 | *((unsigned short *)__va(0x472)) = reboot_mode; | ||
349 | for (;;) { | ||
350 | mach_reboot_fixups(); /* for board specific fixups */ | ||
351 | mach_reboot(); | ||
352 | /* That didn't work - force a triple fault.. */ | ||
353 | load_idt(&no_idt); | ||
354 | __asm__ __volatile__("int3"); | ||
355 | } | ||
356 | } | ||
357 | if (efi_enabled) | ||
358 | efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL); | ||
359 | |||
360 | machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); | ||
361 | } | ||
362 | 424 | ||
363 | static void native_machine_restart(char * __unused) | 425 | if (!reboot_force) |
364 | { | 426 | machine_shutdown(); |
365 | machine_shutdown(); | ||
366 | machine_emergency_restart(); | 427 | machine_emergency_restart(); |
367 | } | 428 | } |
368 | 429 | ||
369 | static void native_machine_halt(void) | 430 | void machine_halt(void) |
370 | { | 431 | { |
371 | } | 432 | } |
372 | 433 | ||
373 | static void native_machine_power_off(void) | 434 | void machine_power_off(void) |
374 | { | 435 | { |
375 | if (pm_power_off) { | 436 | if (pm_power_off) { |
376 | machine_shutdown(); | 437 | if (!reboot_force) |
438 | machine_shutdown(); | ||
377 | pm_power_off(); | 439 | pm_power_off(); |
378 | } | 440 | } |
379 | } | 441 | } |
380 | 442 | ||
381 | |||
382 | struct machine_ops machine_ops = { | 443 | struct machine_ops machine_ops = { |
383 | .power_off = native_machine_power_off, | 444 | .power_off = machine_power_off, |
384 | .shutdown = native_machine_shutdown, | 445 | .shutdown = machine_shutdown, |
385 | .emergency_restart = native_machine_emergency_restart, | 446 | .emergency_restart = machine_emergency_restart, |
386 | .restart = native_machine_restart, | 447 | .restart = machine_restart, |
387 | .halt = native_machine_halt, | 448 | .halt = machine_halt |
388 | }; | 449 | }; |
389 | |||
390 | void machine_power_off(void) | ||
391 | { | ||
392 | machine_ops.power_off(); | ||
393 | } | ||
394 | |||
395 | void machine_shutdown(void) | ||
396 | { | ||
397 | machine_ops.shutdown(); | ||
398 | } | ||
399 | |||
400 | void machine_emergency_restart(void) | ||
401 | { | ||
402 | machine_ops.emergency_restart(); | ||
403 | } | ||
404 | |||
405 | void machine_restart(char *cmd) | ||
406 | { | ||
407 | machine_ops.restart(cmd); | ||
408 | } | ||
409 | |||
410 | void machine_halt(void) | ||
411 | { | ||
412 | machine_ops.halt(); | ||
413 | } | ||
diff --git a/arch/x86/kernel/reboot_64.c b/arch/x86/kernel/reboot_64.c deleted file mode 100644 index d6bdf93ffca9..000000000000 --- a/arch/x86/kernel/reboot_64.c +++ /dev/null | |||
@@ -1,191 +0,0 @@ | |||
1 | /* Various gunk just to reboot the machine. */ | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/reboot.h> | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/smp.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/ctype.h> | ||
8 | #include <linux/string.h> | ||
9 | #include <linux/pm.h> | ||
10 | #include <linux/kdebug.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/efi.h> | ||
13 | #include <acpi/reboot.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/delay.h> | ||
16 | #include <asm/desc.h> | ||
17 | #include <asm/hw_irq.h> | ||
18 | #include <asm/system.h> | ||
19 | #include <asm/pgtable.h> | ||
20 | #include <asm/tlbflush.h> | ||
21 | #include <asm/apic.h> | ||
22 | #include <asm/hpet.h> | ||
23 | #include <asm/gart.h> | ||
24 | |||
25 | /* | ||
26 | * Power off function, if any | ||
27 | */ | ||
28 | void (*pm_power_off)(void); | ||
29 | EXPORT_SYMBOL(pm_power_off); | ||
30 | |||
31 | static long no_idt[3]; | ||
32 | enum reboot_type reboot_type = BOOT_KBD; | ||
33 | static int reboot_mode = 0; | ||
34 | int reboot_force; | ||
35 | |||
36 | /* reboot=t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | ||
37 | warm Don't set the cold reboot flag | ||
38 | cold Set the cold reboot flag | ||
39 | triple Force a triple fault (init) | ||
40 | kbd Use the keyboard controller. cold reset (default) | ||
41 | acpi Use the RESET_REG in the FADT | ||
42 | efi Use efi reset_system runtime service | ||
43 | force Avoid anything that could hang. | ||
44 | */ | ||
45 | static int __init reboot_setup(char *str) | ||
46 | { | ||
47 | for (;;) { | ||
48 | switch (*str) { | ||
49 | case 'w': | ||
50 | reboot_mode = 0x1234; | ||
51 | break; | ||
52 | |||
53 | case 'c': | ||
54 | reboot_mode = 0; | ||
55 | break; | ||
56 | |||
57 | case 't': | ||
58 | case 'a': | ||
59 | case 'b': | ||
60 | case 'k': | ||
61 | case 'e': | ||
62 | reboot_type = *str; | ||
63 | break; | ||
64 | case 'f': | ||
65 | reboot_force = 1; | ||
66 | break; | ||
67 | } | ||
68 | if((str = strchr(str,',')) != NULL) | ||
69 | str++; | ||
70 | else | ||
71 | break; | ||
72 | } | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | __setup("reboot=", reboot_setup); | ||
77 | |||
78 | static inline void kb_wait(void) | ||
79 | { | ||
80 | int i; | ||
81 | |||
82 | for (i=0; i<0x10000; i++) | ||
83 | if ((inb_p(0x64) & 0x02) == 0) | ||
84 | break; | ||
85 | } | ||
86 | |||
87 | void machine_shutdown(void) | ||
88 | { | ||
89 | unsigned long flags; | ||
90 | |||
91 | /* Stop the cpus and apics */ | ||
92 | #ifdef CONFIG_SMP | ||
93 | int reboot_cpu_id; | ||
94 | |||
95 | /* The boot cpu is always logical cpu 0 */ | ||
96 | reboot_cpu_id = 0; | ||
97 | |||
98 | /* Make certain the cpu I'm about to reboot on is online */ | ||
99 | if (!cpu_isset(reboot_cpu_id, cpu_online_map)) { | ||
100 | reboot_cpu_id = smp_processor_id(); | ||
101 | } | ||
102 | |||
103 | /* Make certain I only run on the appropriate processor */ | ||
104 | set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id)); | ||
105 | |||
106 | /* O.K Now that I'm on the appropriate processor, | ||
107 | * stop all of the others. | ||
108 | */ | ||
109 | smp_send_stop(); | ||
110 | #endif | ||
111 | |||
112 | local_irq_save(flags); | ||
113 | |||
114 | #ifndef CONFIG_SMP | ||
115 | disable_local_APIC(); | ||
116 | #endif | ||
117 | |||
118 | disable_IO_APIC(); | ||
119 | |||
120 | #ifdef CONFIG_HPET_TIMER | ||
121 | hpet_disable(); | ||
122 | #endif | ||
123 | local_irq_restore(flags); | ||
124 | |||
125 | pci_iommu_shutdown(); | ||
126 | } | ||
127 | |||
128 | void machine_emergency_restart(void) | ||
129 | { | ||
130 | int i; | ||
131 | |||
132 | /* Tell the BIOS if we want cold or warm reboot */ | ||
133 | *((unsigned short *)__va(0x472)) = reboot_mode; | ||
134 | |||
135 | for (;;) { | ||
136 | /* Could also try the reset bit in the Hammer NB */ | ||
137 | switch (reboot_type) { | ||
138 | case BOOT_KBD: | ||
139 | for (i=0; i<10; i++) { | ||
140 | kb_wait(); | ||
141 | udelay(50); | ||
142 | outb(0xfe,0x64); /* pulse reset low */ | ||
143 | udelay(50); | ||
144 | } | ||
145 | |||
146 | case BOOT_TRIPLE: | ||
147 | load_idt((const struct desc_ptr *)&no_idt); | ||
148 | __asm__ __volatile__("int3"); | ||
149 | |||
150 | reboot_type = BOOT_KBD; | ||
151 | break; | ||
152 | |||
153 | case BOOT_ACPI: | ||
154 | acpi_reboot(); | ||
155 | reboot_type = BOOT_KBD; | ||
156 | break; | ||
157 | |||
158 | case BOOT_EFI: | ||
159 | if (efi_enabled) | ||
160 | efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, | ||
161 | EFI_SUCCESS, 0, NULL); | ||
162 | reboot_type = BOOT_KBD; | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void machine_restart(char * __unused) | ||
169 | { | ||
170 | printk("machine restart\n"); | ||
171 | |||
172 | if (!reboot_force) { | ||
173 | machine_shutdown(); | ||
174 | } | ||
175 | machine_emergency_restart(); | ||
176 | } | ||
177 | |||
178 | void machine_halt(void) | ||
179 | { | ||
180 | } | ||
181 | |||
182 | void machine_power_off(void) | ||
183 | { | ||
184 | if (pm_power_off) { | ||
185 | if (!reboot_force) { | ||
186 | machine_shutdown(); | ||
187 | } | ||
188 | pm_power_off(); | ||
189 | } | ||
190 | } | ||
191 | |||
diff --git a/include/asm-x86/emergency-restart.h b/include/asm-x86/emergency-restart.h index 54189084462a..8e6aef19f8f0 100644 --- a/include/asm-x86/emergency-restart.h +++ b/include/asm-x86/emergency-restart.h | |||
@@ -4,6 +4,9 @@ | |||
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', | ||
9 | #endif | ||
7 | BOOT_ACPI = 'a', | 10 | BOOT_ACPI = 'a', |
8 | BOOT_EFI = 'e' | 11 | BOOT_EFI = 'e' |
9 | }; | 12 | }; |