1#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2
3#include <linux/module.h>
4#include <linux/reboot.h>
5#include <linux/init.h>
6#include <linux/pm.h>
7#include <linux/efi.h>
8#include <linux/dmi.h>
9#include <linux/sched.h>
10#include <linux/tboot.h>
11#include <linux/delay.h>
12#include <acpi/reboot.h>
13#include <asm/io.h>
14#include <asm/apic.h>
15#include <asm/desc.h>
16#include <asm/hpet.h>
17#include <asm/pgtable.h>
18#include <asm/proto.h>
19#include <asm/reboot_fixups.h>
20#include <asm/reboot.h>
21#include <asm/pci_x86.h>
22#include <asm/virtext.h>
23#include <asm/cpu.h>
24#include <asm/nmi.h>
25#include <asm/smp.h>
26
27#include <linux/ctype.h>
28#include <linux/mc146818rtc.h>
29#include <asm/realmode.h>
30#include <asm/x86_init.h>
31
32
33
34
35void (*pm_power_off)(void);
36EXPORT_SYMBOL(pm_power_off);
37
38static const struct desc_ptr no_idt = {};
39static int reboot_mode;
40enum reboot_type reboot_type = BOOT_ACPI;
41int reboot_force;
42
43
44
45
46
47
48
49
50static int reboot_default = 1;
51
52#ifdef CONFIG_SMP
53static int reboot_cpu = -1;
54#endif
55
56
57
58
59
60
61static int reboot_emergency;
62
63
64bool port_cf9_safe = false;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79static int __init reboot_setup(char *str)
80{
81 for (;;) {
82
83
84
85
86
87 reboot_default = 0;
88
89 switch (*str) {
90 case 'w':
91 reboot_mode = 0x1234;
92 break;
93
94 case 'c':
95 reboot_mode = 0;
96 break;
97
98#ifdef CONFIG_SMP
99 case 's':
100 if (isdigit(*(str+1))) {
101 reboot_cpu = (int) (*(str+1) - '0');
102 if (isdigit(*(str+2)))
103 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
104 }
105
106
107
108
109
110 break;
111#endif
112
113 case 'b':
114 case 'a':
115 case 'k':
116 case 't':
117 case 'e':
118 case 'p':
119 reboot_type = *str;
120 break;
121
122 case 'f':
123 reboot_force = 1;
124 break;
125 }
126
127 str = strchr(str, ',');
128 if (str)
129 str++;
130 else
131 break;
132 }
133 return 1;
134}
135
136__setup("reboot=", reboot_setup);
137
138
139
140
141
142
143
144
145
146
147
148static int __init set_bios_reboot(const struct dmi_system_id *d)
149{
150 if (reboot_type != BOOT_BIOS) {
151 reboot_type = BOOT_BIOS;
152 pr_info("%s series board detected. Selecting %s-method for reboots.\n",
153 "BIOS", d->ident);
154 }
155 return 0;
156}
157
158void __noreturn machine_real_restart(unsigned int type)
159{
160 local_irq_disable();
161
162
163
164
165
166
167
168
169
170
171
172 spin_lock(&rtc_lock);
173 CMOS_WRITE(0x00, 0x8f);
174 spin_unlock(&rtc_lock);
175
176
177
178
179#ifdef CONFIG_X86_32
180 load_cr3(initial_page_table);
181#else
182 write_cr3(real_mode_header->trampoline_pgd);
183
184
185 if (static_cpu_has(X86_FEATURE_PCID))
186 clear_in_cr4(X86_CR4_PCIDE);
187#endif
188
189
190#ifdef CONFIG_X86_32
191 asm volatile("jmpl *%0" : :
192 "rm" (real_mode_header->machine_real_restart_asm),
193 "a" (type));
194#else
195 asm volatile("ljmpl *%0" : :
196 "m" (real_mode_header->machine_real_restart_asm),
197 "D" (type));
198#endif
199 unreachable();
200}
201#ifdef CONFIG_APM_MODULE
202EXPORT_SYMBOL(machine_real_restart);
203#endif
204
205
206
207
208static int __init set_pci_reboot(const struct dmi_system_id *d)
209{
210 if (reboot_type != BOOT_CF9) {
211 reboot_type = BOOT_CF9;
212 pr_info("%s series board detected. Selecting %s-method for reboots.\n",
213 "PCI", d->ident);
214 }
215 return 0;
216}
217
218static int __init set_kbd_reboot(const struct dmi_system_id *d)
219{
220 if (reboot_type != BOOT_KBD) {
221 reboot_type = BOOT_KBD;
222 pr_info("%s series board detected. Selecting %s-method for reboot.\n",
223 "KBD", d->ident);
224 }
225 return 0;
226}
227
228
229
230
231static struct dmi_system_id __initdata reboot_dmi_table[] = {
232 {
233 .callback = set_bios_reboot,
234 .ident = "Dell E520",
235 .matches = {
236 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
237 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
238 },
239 },
240 {
241 .callback = set_bios_reboot,
242 .ident = "Dell PowerEdge 1300",
243 .matches = {
244 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
245 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
246 },
247 },
248 {
249 .callback = set_bios_reboot,
250 .ident = "Dell PowerEdge 300",
251 .matches = {
252 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
253 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
254 },
255 },
256 {
257 .callback = set_bios_reboot,
258 .ident = "Dell OptiPlex 745",
259 .matches = {
260 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
261 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
262 },
263 },
264 {
265 .callback = set_bios_reboot,
266 .ident = "Dell OptiPlex 745",
267 .matches = {
268 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
269 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
270 DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
271 },
272 },
273 {
274 .callback = set_bios_reboot,
275 .ident = "Dell OptiPlex 745",
276 .matches = {
277 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
278 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
279 DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
280 },
281 },
282 {
283 .callback = set_bios_reboot,
284 .ident = "Dell OptiPlex 330",
285 .matches = {
286 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
287 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
288 DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
289 },
290 },
291 {
292 .callback = set_bios_reboot,
293 .ident = "Dell OptiPlex 360",
294 .matches = {
295 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
296 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
297 DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
298 },
299 },
300 {
301 .callback = set_bios_reboot,
302 .ident = "Dell OptiPlex 760",
303 .matches = {
304 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
305 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
306 DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
307 },
308 },
309 {
310 .callback = set_bios_reboot,
311 .ident = "Dell PowerEdge 2400",
312 .matches = {
313 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
314 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
315 },
316 },
317 {
318 .callback = set_bios_reboot,
319 .ident = "Dell Precision T5400",
320 .matches = {
321 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
322 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
323 },
324 },
325 {
326 .callback = set_bios_reboot,
327 .ident = "Dell Precision T7400",
328 .matches = {
329 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
330 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
331 },
332 },
333 {
334 .callback = set_bios_reboot,
335 .ident = "HP Compaq Laptop",
336 .matches = {
337 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
338 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
339 },
340 },
341 {
342 .callback = set_bios_reboot,
343 .ident = "Dell XPS710",
344 .matches = {
345 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
346 DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
347 },
348 },
349 {
350 .callback = set_bios_reboot,
351 .ident = "Dell DXP061",
352 .matches = {
353 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
354 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
355 },
356 },
357 {
358 .callback = set_bios_reboot,
359 .ident = "Sony VGN-Z540N",
360 .matches = {
361 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
362 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
363 },
364 },
365 {
366 .callback = set_bios_reboot,
367 .ident = "ASUS P4S800",
368 .matches = {
369 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
370 DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
371 },
372 },
373
374 {
375 .callback = set_kbd_reboot,
376 .ident = "Acer Aspire One A110",
377 .matches = {
378 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
379 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
380 },
381 },
382 {
383 .callback = set_pci_reboot,
384 .ident = "Apple MacBook5",
385 .matches = {
386 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
387 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
388 },
389 },
390 {
391 .callback = set_pci_reboot,
392 .ident = "Apple MacBookPro5",
393 .matches = {
394 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
395 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
396 },
397 },
398 {
399 .callback = set_pci_reboot,
400 .ident = "Apple Macmini3,1",
401 .matches = {
402 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
403 DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
404 },
405 },
406 {
407 .callback = set_pci_reboot,
408 .ident = "Apple iMac9,1",
409 .matches = {
410 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
411 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
412 },
413 },
414 {
415 .callback = set_pci_reboot,
416 .ident = "Dell Latitude E6320",
417 .matches = {
418 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
419 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
420 },
421 },
422 {
423 .callback = set_pci_reboot,
424 .ident = "Dell Latitude E5420",
425 .matches = {
426 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
427 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
428 },
429 },
430 {
431 .callback = set_pci_reboot,
432 .ident = "Dell Latitude E6420",
433 .matches = {
434 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
435 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
436 },
437 },
438 {
439 .callback = set_pci_reboot,
440 .ident = "Dell OptiPlex 990",
441 .matches = {
442 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
443 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
444 },
445 },
446 {
447 .callback = set_pci_reboot,
448 .ident = "Dell OptiPlex 990",
449 .matches = {
450 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
451 DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"),
452 },
453 },
454 {
455 .callback = set_pci_reboot,
456 .ident = "Dell PowerEdge C6100",
457 .matches = {
458 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
459 DMI_MATCH(DMI_PRODUCT_NAME, "C6100"),
460 },
461 },
462 {
463 .callback = set_pci_reboot,
464 .ident = "Dell PowerEdge C6100",
465 .matches = {
466 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
467 DMI_MATCH(DMI_PRODUCT_NAME, "C6100"),
468 },
469 },
470
471 {
472 .callback = set_pci_reboot,
473 .ident = "ASRock Q1900DC-ITX",
474 .matches = {
475 DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"),
476 DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"),
477 },
478 },
479 { }
480};
481
482static int __init reboot_init(void)
483{
484
485
486
487
488 if (reboot_default)
489 dmi_check_system(reboot_dmi_table);
490 return 0;
491}
492core_initcall(reboot_init);
493
494static inline void kb_wait(void)
495{
496 int i;
497
498 for (i = 0; i < 0x10000; i++) {
499 if ((inb(0x64) & 0x02) == 0)
500 break;
501 udelay(2);
502 }
503}
504
505static void vmxoff_nmi(int cpu, struct pt_regs *regs)
506{
507 cpu_emergency_vmxoff();
508}
509
510
511static void emergency_vmx_disable_all(void)
512{
513
514 local_irq_disable();
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535 if (cpu_has_vmx() && cpu_vmx_enabled()) {
536
537 cpu_vmxoff();
538
539
540 nmi_shootdown_cpus(vmxoff_nmi);
541
542 }
543}
544
545
546void __attribute__((weak)) mach_reboot_fixups(void)
547{
548}
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563static void native_machine_emergency_restart(void)
564{
565 int i;
566 int attempt = 0;
567 int orig_reboot_type = reboot_type;
568
569 if (reboot_emergency)
570 emergency_vmx_disable_all();
571
572 tboot_shutdown(TB_SHUTDOWN_REBOOT);
573
574
575 *((unsigned short *)__va(0x472)) = reboot_mode;
576
577 for (;;) {
578
579 switch (reboot_type) {
580 case BOOT_KBD:
581 mach_reboot_fixups();
582
583 for (i = 0; i < 10; i++) {
584 kb_wait();
585 udelay(50);
586 outb(0xfe, 0x64);
587 udelay(50);
588 }
589 if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
590 attempt = 1;
591 reboot_type = BOOT_ACPI;
592 } else {
593 reboot_type = BOOT_TRIPLE;
594 }
595 break;
596
597 case BOOT_TRIPLE:
598 load_idt(&no_idt);
599 __asm__ __volatile__("int3");
600
601 reboot_type = BOOT_KBD;
602 break;
603
604 case BOOT_BIOS:
605 machine_real_restart(MRR_BIOS);
606
607 reboot_type = BOOT_KBD;
608 break;
609
610 case BOOT_ACPI:
611 acpi_reboot();
612 reboot_type = BOOT_KBD;
613 break;
614
615 case BOOT_EFI:
616 if (efi_enabled(EFI_RUNTIME_SERVICES))
617 efi.reset_system(reboot_mode ?
618 EFI_RESET_WARM :
619 EFI_RESET_COLD,
620 EFI_SUCCESS, 0, NULL);
621 reboot_type = BOOT_KBD;
622 break;
623
624 case BOOT_CF9:
625 port_cf9_safe = true;
626
627
628 case BOOT_CF9_COND:
629 if (port_cf9_safe) {
630 u8 cf9 = inb(0xcf9) & ~6;
631 outb(cf9|2, 0xcf9);
632 udelay(50);
633 outb(cf9|6, 0xcf9);
634 udelay(50);
635 }
636 reboot_type = BOOT_KBD;
637 break;
638 }
639 }
640}
641
642void native_machine_shutdown(void)
643{
644#ifdef CONFIG_SMP
645
646 int reboot_cpu_id = 0;
647#endif
648
649
650#ifdef CONFIG_X86_IO_APIC
651
652
653
654
655
656
657
658
659
660
661
662 disable_IO_APIC();
663#endif
664
665#ifdef CONFIG_SMP
666
667 if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
668 cpu_online(reboot_cpu))
669 reboot_cpu_id = reboot_cpu;
670
671
672 if (!cpu_online(reboot_cpu_id))
673 reboot_cpu_id = smp_processor_id();
674
675
676 set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
677
678
679
680
681
682
683 local_irq_disable();
684 stop_other_cpus();
685#endif
686
687 lapic_shutdown();
688
689#ifdef CONFIG_HPET_TIMER
690 hpet_disable();
691#endif
692
693#ifdef CONFIG_X86_64
694 x86_platform.iommu_shutdown();
695#endif
696}
697
698static void __machine_emergency_restart(int emergency)
699{
700 reboot_emergency = emergency;
701 machine_ops.emergency_restart();
702}
703
704static void native_machine_restart(char *__unused)
705{
706 pr_notice("machine restart\n");
707
708 if (!reboot_force)
709 machine_shutdown();
710 __machine_emergency_restart(0);
711}
712
713static void native_machine_halt(void)
714{
715
716 machine_shutdown();
717
718 tboot_shutdown(TB_SHUTDOWN_HALT);
719
720 stop_this_cpu(NULL);
721}
722
723static void native_machine_power_off(void)
724{
725 if (pm_power_off) {
726 if (!reboot_force)
727 machine_shutdown();
728 pm_power_off();
729 }
730
731 tboot_shutdown(TB_SHUTDOWN_HALT);
732}
733
734struct machine_ops machine_ops = {
735 .power_off = native_machine_power_off,
736 .shutdown = native_machine_shutdown,
737 .emergency_restart = native_machine_emergency_restart,
738 .restart = native_machine_restart,
739 .halt = native_machine_halt,
740#ifdef CONFIG_KEXEC_CORE
741 .crash_shutdown = native_machine_crash_shutdown,
742#endif
743};
744
745void machine_power_off(void)
746{
747 machine_ops.power_off();
748}
749
750void machine_shutdown(void)
751{
752 machine_ops.shutdown();
753}
754
755void machine_emergency_restart(void)
756{
757 __machine_emergency_restart(1);
758}
759
760void machine_restart(char *cmd)
761{
762 machine_ops.restart(cmd);
763}
764
765void machine_halt(void)
766{
767 machine_ops.halt();
768}
769
770#ifdef CONFIG_KEXEC_CORE
771void machine_crash_shutdown(struct pt_regs *regs)
772{
773 machine_ops.crash_shutdown(regs);
774}
775#endif
776
777
778
779int crashing_cpu = -1;
780
781#if defined(CONFIG_SMP)
782
783static nmi_shootdown_cb shootdown_callback;
784
785static atomic_t waiting_for_crash_ipi;
786static int crash_ipi_issued;
787
788static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
789{
790 int cpu;
791
792 cpu = raw_smp_processor_id();
793
794
795
796
797
798
799 if (cpu == crashing_cpu)
800 return NMI_HANDLED;
801 local_irq_disable();
802
803 shootdown_callback(cpu, regs);
804
805 atomic_dec(&waiting_for_crash_ipi);
806
807 halt();
808 for (;;)
809 cpu_relax();
810
811 return NMI_HANDLED;
812}
813
814static void smp_send_nmi_allbutself(void)
815{
816 apic->send_IPI_allbutself(NMI_VECTOR);
817}
818
819
820
821
822
823
824
825
826void nmi_shootdown_cpus(nmi_shootdown_cb callback)
827{
828 unsigned long msecs;
829 local_irq_disable();
830
831
832 crashing_cpu = safe_smp_processor_id();
833
834 shootdown_callback = callback;
835
836 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
837
838 if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
839 NMI_FLAG_FIRST, "crash"))
840 return;
841
842
843
844
845 wmb();
846
847 smp_send_nmi_allbutself();
848
849
850 WRITE_ONCE(crash_ipi_issued, 1);
851
852 msecs = 1000;
853 while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
854 mdelay(1);
855 msecs--;
856 }
857
858
859}
860
861
862
863
864
865
866void run_crash_ipi_callback(struct pt_regs *regs)
867{
868 if (crash_ipi_issued)
869 crash_nmi_callback(0, regs);
870}
871
872
873void nmi_panic_self_stop(struct pt_regs *regs)
874{
875 while (1) {
876
877 run_crash_ipi_callback(regs);
878 cpu_relax();
879 }
880}
881
882#else
883void nmi_shootdown_cpus(nmi_shootdown_cb callback)
884{
885
886}
887
888void run_crash_ipi_callback(struct pt_regs *regs)
889{
890}
891#endif
892