1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
3 | |
4 | #include <linux/export.h> |
5 | #include <linux/reboot.h> |
6 | #include <linux/init.h> |
7 | #include <linux/pm.h> |
8 | #include <linux/efi.h> |
9 | #include <linux/dmi.h> |
10 | #include <linux/sched.h> |
11 | #include <linux/tboot.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/objtool.h> |
14 | #include <linux/pgtable.h> |
15 | #include <linux/kexec.h> |
16 | #include <acpi/reboot.h> |
17 | #include <asm/io.h> |
18 | #include <asm/apic.h> |
19 | #include <asm/io_apic.h> |
20 | #include <asm/desc.h> |
21 | #include <asm/hpet.h> |
22 | #include <asm/proto.h> |
23 | #include <asm/reboot_fixups.h> |
24 | #include <asm/reboot.h> |
25 | #include <asm/pci_x86.h> |
26 | #include <asm/cpu.h> |
27 | #include <asm/nmi.h> |
28 | #include <asm/smp.h> |
29 | |
30 | #include <linux/ctype.h> |
31 | #include <linux/mc146818rtc.h> |
32 | #include <asm/realmode.h> |
33 | #include <asm/x86_init.h> |
34 | #include <asm/efi.h> |
35 | |
36 | /* |
37 | * Power off function, if any |
38 | */ |
39 | void (*pm_power_off)(void); |
40 | EXPORT_SYMBOL(pm_power_off); |
41 | |
42 | /* |
43 | * This is set if we need to go through the 'emergency' path. |
44 | * When machine_emergency_restart() is called, we may be on |
45 | * an inconsistent state and won't be able to do a clean cleanup |
46 | */ |
47 | static int reboot_emergency; |
48 | |
49 | /* This is set by the PCI code if either type 1 or type 2 PCI is detected */ |
50 | bool port_cf9_safe = false; |
51 | |
52 | /* |
53 | * Reboot options and system auto-detection code provided by |
54 | * Dell Inc. so their systems "just work". :-) |
55 | */ |
56 | |
57 | /* |
58 | * Some machines require the "reboot=a" commandline options |
59 | */ |
60 | static int __init set_acpi_reboot(const struct dmi_system_id *d) |
61 | { |
62 | if (reboot_type != BOOT_ACPI) { |
63 | reboot_type = BOOT_ACPI; |
64 | pr_info("%s series board detected. Selecting %s-method for reboots.\n", |
65 | d->ident, "ACPI"); |
66 | } |
67 | return 0; |
68 | } |
69 | |
70 | /* |
71 | * Some machines require the "reboot=b" or "reboot=k" commandline options, |
72 | * this quirk makes that automatic. |
73 | */ |
74 | static int __init set_bios_reboot(const struct dmi_system_id *d) |
75 | { |
76 | if (reboot_type != BOOT_BIOS) { |
77 | reboot_type = BOOT_BIOS; |
78 | pr_info("%s series board detected. Selecting %s-method for reboots.\n", |
79 | d->ident, "BIOS"); |
80 | } |
81 | return 0; |
82 | } |
83 | |
84 | /* |
85 | * Some machines don't handle the default ACPI reboot method and |
86 | * require the EFI reboot method: |
87 | */ |
88 | static int __init set_efi_reboot(const struct dmi_system_id *d) |
89 | { |
90 | if (reboot_type != BOOT_EFI && !efi_runtime_disabled()) { |
91 | reboot_type = BOOT_EFI; |
92 | pr_info("%s series board detected. Selecting EFI-method for reboot.\n", d->ident); |
93 | } |
94 | return 0; |
95 | } |
96 | |
97 | void __noreturn machine_real_restart(unsigned int type) |
98 | { |
99 | local_irq_disable(); |
100 | |
101 | /* |
102 | * Write zero to CMOS register number 0x0f, which the BIOS POST |
103 | * routine will recognize as telling it to do a proper reboot. (Well |
104 | * that's what this book in front of me says -- it may only apply to |
105 | * the Phoenix BIOS though, it's not clear). At the same time, |
106 | * disable NMIs by setting the top bit in the CMOS address register, |
107 | * as we're about to do peculiar things to the CPU. I'm not sure if |
108 | * `outb_p' is needed instead of just `outb'. Use it to be on the |
109 | * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) |
110 | */ |
111 | spin_lock(lock: &rtc_lock); |
112 | CMOS_WRITE(0x00, 0x8f); |
113 | spin_unlock(lock: &rtc_lock); |
114 | |
115 | /* |
116 | * Switch to the trampoline page table. |
117 | */ |
118 | load_trampoline_pgtable(); |
119 | |
120 | /* Jump to the identity-mapped low memory code */ |
121 | #ifdef CONFIG_X86_32 |
122 | asm volatile("jmpl *%0": : |
123 | "rm"(real_mode_header->machine_real_restart_asm), |
124 | "a"(type)); |
125 | #else |
126 | asm volatile("ljmpl *%0": : |
127 | "m"(real_mode_header->machine_real_restart_asm), |
128 | "D"(type)); |
129 | #endif |
130 | unreachable(); |
131 | } |
132 | #ifdef CONFIG_APM_MODULE |
133 | EXPORT_SYMBOL(machine_real_restart); |
134 | #endif |
135 | STACK_FRAME_NON_STANDARD(machine_real_restart); |
136 | |
137 | /* |
138 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot |
139 | */ |
140 | static int __init set_pci_reboot(const struct dmi_system_id *d) |
141 | { |
142 | if (reboot_type != BOOT_CF9_FORCE) { |
143 | reboot_type = BOOT_CF9_FORCE; |
144 | pr_info("%s series board detected. Selecting %s-method for reboots.\n", |
145 | d->ident, "PCI"); |
146 | } |
147 | return 0; |
148 | } |
149 | |
150 | static int __init set_kbd_reboot(const struct dmi_system_id *d) |
151 | { |
152 | if (reboot_type != BOOT_KBD) { |
153 | reboot_type = BOOT_KBD; |
154 | pr_info("%s series board detected. Selecting %s-method for reboot.\n", |
155 | d->ident, "KBD"); |
156 | } |
157 | return 0; |
158 | } |
159 | |
160 | /* |
161 | * This is a single dmi_table handling all reboot quirks. |
162 | */ |
163 | static const struct dmi_system_id reboot_dmi_table[] __initconst = { |
164 | |
165 | /* Acer */ |
166 | { /* Handle reboot issue on Acer Aspire one */ |
167 | .callback = set_kbd_reboot, |
168 | .ident = "Acer Aspire One A110", |
169 | .matches = { |
170 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
171 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), |
172 | }, |
173 | }, |
174 | { /* Handle reboot issue on Acer TravelMate X514-51T */ |
175 | .callback = set_efi_reboot, |
176 | .ident = "Acer TravelMate X514-51T", |
177 | .matches = { |
178 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
179 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate X514-51T"), |
180 | }, |
181 | }, |
182 | |
183 | /* Apple */ |
184 | { /* Handle problems with rebooting on Apple MacBook5 */ |
185 | .callback = set_pci_reboot, |
186 | .ident = "Apple MacBook5", |
187 | .matches = { |
188 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
189 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), |
190 | }, |
191 | }, |
192 | { /* Handle problems with rebooting on Apple MacBook6,1 */ |
193 | .callback = set_pci_reboot, |
194 | .ident = "Apple MacBook6,1", |
195 | .matches = { |
196 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
197 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"), |
198 | }, |
199 | }, |
200 | { /* Handle problems with rebooting on Apple MacBookPro5 */ |
201 | .callback = set_pci_reboot, |
202 | .ident = "Apple MacBookPro5", |
203 | .matches = { |
204 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
205 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), |
206 | }, |
207 | }, |
208 | { /* Handle problems with rebooting on Apple Macmini3,1 */ |
209 | .callback = set_pci_reboot, |
210 | .ident = "Apple Macmini3,1", |
211 | .matches = { |
212 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
213 | DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"), |
214 | }, |
215 | }, |
216 | { /* Handle problems with rebooting on the iMac9,1. */ |
217 | .callback = set_pci_reboot, |
218 | .ident = "Apple iMac9,1", |
219 | .matches = { |
220 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
221 | DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"), |
222 | }, |
223 | }, |
224 | { /* Handle problems with rebooting on the iMac10,1. */ |
225 | .callback = set_pci_reboot, |
226 | .ident = "Apple iMac10,1", |
227 | .matches = { |
228 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
229 | DMI_MATCH(DMI_PRODUCT_NAME, "iMac10,1"), |
230 | }, |
231 | }, |
232 | |
233 | /* ASRock */ |
234 | { /* Handle problems with rebooting on ASRock Q1900DC-ITX */ |
235 | .callback = set_pci_reboot, |
236 | .ident = "ASRock Q1900DC-ITX", |
237 | .matches = { |
238 | DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"), |
239 | DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"), |
240 | }, |
241 | }, |
242 | |
243 | /* ASUS */ |
244 | { /* Handle problems with rebooting on ASUS P4S800 */ |
245 | .callback = set_bios_reboot, |
246 | .ident = "ASUS P4S800", |
247 | .matches = { |
248 | DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), |
249 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
250 | }, |
251 | }, |
252 | { /* Handle problems with rebooting on ASUS EeeBook X205TA */ |
253 | .callback = set_acpi_reboot, |
254 | .ident = "ASUS EeeBook X205TA", |
255 | .matches = { |
256 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
257 | DMI_MATCH(DMI_PRODUCT_NAME, "X205TA"), |
258 | }, |
259 | }, |
260 | { /* Handle problems with rebooting on ASUS EeeBook X205TAW */ |
261 | .callback = set_acpi_reboot, |
262 | .ident = "ASUS EeeBook X205TAW", |
263 | .matches = { |
264 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
265 | DMI_MATCH(DMI_PRODUCT_NAME, "X205TAW"), |
266 | }, |
267 | }, |
268 | |
269 | /* Certec */ |
270 | { /* Handle problems with rebooting on Certec BPC600 */ |
271 | .callback = set_pci_reboot, |
272 | .ident = "Certec BPC600", |
273 | .matches = { |
274 | DMI_MATCH(DMI_SYS_VENDOR, "Certec"), |
275 | DMI_MATCH(DMI_PRODUCT_NAME, "BPC600"), |
276 | }, |
277 | }, |
278 | |
279 | /* Dell */ |
280 | { /* Handle problems with rebooting on Dell DXP061 */ |
281 | .callback = set_bios_reboot, |
282 | .ident = "Dell DXP061", |
283 | .matches = { |
284 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
285 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), |
286 | }, |
287 | }, |
288 | { /* Handle problems with rebooting on Dell E520's */ |
289 | .callback = set_bios_reboot, |
290 | .ident = "Dell E520", |
291 | .matches = { |
292 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
293 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), |
294 | }, |
295 | }, |
296 | { /* Handle problems with rebooting on the Latitude E5410. */ |
297 | .callback = set_pci_reboot, |
298 | .ident = "Dell Latitude E5410", |
299 | .matches = { |
300 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
301 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5410"), |
302 | }, |
303 | }, |
304 | { /* Handle problems with rebooting on the Latitude E5420. */ |
305 | .callback = set_pci_reboot, |
306 | .ident = "Dell Latitude E5420", |
307 | .matches = { |
308 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
309 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"), |
310 | }, |
311 | }, |
312 | { /* Handle problems with rebooting on the Latitude E6320. */ |
313 | .callback = set_pci_reboot, |
314 | .ident = "Dell Latitude E6320", |
315 | .matches = { |
316 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
317 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"), |
318 | }, |
319 | }, |
320 | { /* Handle problems with rebooting on the Latitude E6420. */ |
321 | .callback = set_pci_reboot, |
322 | .ident = "Dell Latitude E6420", |
323 | .matches = { |
324 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
325 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"), |
326 | }, |
327 | }, |
328 | { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */ |
329 | .callback = set_bios_reboot, |
330 | .ident = "Dell OptiPlex 330", |
331 | .matches = { |
332 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
333 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"), |
334 | DMI_MATCH(DMI_BOARD_NAME, "0KP561"), |
335 | }, |
336 | }, |
337 | { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */ |
338 | .callback = set_bios_reboot, |
339 | .ident = "Dell OptiPlex 360", |
340 | .matches = { |
341 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
342 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"), |
343 | DMI_MATCH(DMI_BOARD_NAME, "0T656F"), |
344 | }, |
345 | }, |
346 | { /* Handle problems with rebooting on Dell Optiplex 745's SFF */ |
347 | .callback = set_bios_reboot, |
348 | .ident = "Dell OptiPlex 745", |
349 | .matches = { |
350 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
351 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
352 | }, |
353 | }, |
354 | { /* Handle problems with rebooting on Dell Optiplex 745's DFF */ |
355 | .callback = set_bios_reboot, |
356 | .ident = "Dell OptiPlex 745", |
357 | .matches = { |
358 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
359 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
360 | DMI_MATCH(DMI_BOARD_NAME, "0MM599"), |
361 | }, |
362 | }, |
363 | { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */ |
364 | .callback = set_bios_reboot, |
365 | .ident = "Dell OptiPlex 745", |
366 | .matches = { |
367 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
368 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"), |
369 | DMI_MATCH(DMI_BOARD_NAME, "0KW626"), |
370 | }, |
371 | }, |
372 | { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */ |
373 | .callback = set_bios_reboot, |
374 | .ident = "Dell OptiPlex 760", |
375 | .matches = { |
376 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
377 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"), |
378 | DMI_MATCH(DMI_BOARD_NAME, "0G919G"), |
379 | }, |
380 | }, |
381 | { /* Handle problems with rebooting on the OptiPlex 990. */ |
382 | .callback = set_pci_reboot, |
383 | .ident = "Dell OptiPlex 990 BIOS A0x", |
384 | .matches = { |
385 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
386 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"), |
387 | DMI_MATCH(DMI_BIOS_VERSION, "A0"), |
388 | }, |
389 | }, |
390 | { /* Handle problems with rebooting on Dell 300's */ |
391 | .callback = set_bios_reboot, |
392 | .ident = "Dell PowerEdge 300", |
393 | .matches = { |
394 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
395 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), |
396 | }, |
397 | }, |
398 | { /* Handle problems with rebooting on Dell 1300's */ |
399 | .callback = set_bios_reboot, |
400 | .ident = "Dell PowerEdge 1300", |
401 | .matches = { |
402 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
403 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"), |
404 | }, |
405 | }, |
406 | { /* Handle problems with rebooting on Dell 2400's */ |
407 | .callback = set_bios_reboot, |
408 | .ident = "Dell PowerEdge 2400", |
409 | .matches = { |
410 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), |
411 | DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"), |
412 | }, |
413 | }, |
414 | { /* Handle problems with rebooting on the Dell PowerEdge C6100. */ |
415 | .callback = set_pci_reboot, |
416 | .ident = "Dell PowerEdge C6100", |
417 | .matches = { |
418 | DMI_MATCH(DMI_SYS_VENDOR, "Dell"), |
419 | DMI_MATCH(DMI_PRODUCT_NAME, "C6100"), |
420 | }, |
421 | }, |
422 | { /* Handle problems with rebooting on the Precision M6600. */ |
423 | .callback = set_pci_reboot, |
424 | .ident = "Dell Precision M6600", |
425 | .matches = { |
426 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
427 | DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"), |
428 | }, |
429 | }, |
430 | { /* Handle problems with rebooting on Dell T5400's */ |
431 | .callback = set_bios_reboot, |
432 | .ident = "Dell Precision T5400", |
433 | .matches = { |
434 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
435 | DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"), |
436 | }, |
437 | }, |
438 | { /* Handle problems with rebooting on Dell T7400's */ |
439 | .callback = set_bios_reboot, |
440 | .ident = "Dell Precision T7400", |
441 | .matches = { |
442 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
443 | DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"), |
444 | }, |
445 | }, |
446 | { /* Handle problems with rebooting on Dell XPS710 */ |
447 | .callback = set_bios_reboot, |
448 | .ident = "Dell XPS710", |
449 | .matches = { |
450 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
451 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"), |
452 | }, |
453 | }, |
454 | { /* Handle problems with rebooting on Dell Optiplex 7450 AIO */ |
455 | .callback = set_acpi_reboot, |
456 | .ident = "Dell OptiPlex 7450 AIO", |
457 | .matches = { |
458 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
459 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 7450 AIO"), |
460 | }, |
461 | }, |
462 | |
463 | /* Hewlett-Packard */ |
464 | { /* Handle problems with rebooting on HP laptops */ |
465 | .callback = set_bios_reboot, |
466 | .ident = "HP Compaq Laptop", |
467 | .matches = { |
468 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), |
469 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), |
470 | }, |
471 | }, |
472 | |
473 | { /* PCIe Wifi card isn't detected after reboot otherwise */ |
474 | .callback = set_pci_reboot, |
475 | .ident = "Zotac ZBOX CI327 nano", |
476 | .matches = { |
477 | DMI_MATCH(DMI_SYS_VENDOR, "NA"), |
478 | DMI_MATCH(DMI_PRODUCT_NAME, "ZBOX-CI327NANO-GS-01"), |
479 | }, |
480 | }, |
481 | |
482 | /* Sony */ |
483 | { /* Handle problems with rebooting on Sony VGN-Z540N */ |
484 | .callback = set_bios_reboot, |
485 | .ident = "Sony VGN-Z540N", |
486 | .matches = { |
487 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), |
488 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), |
489 | }, |
490 | }, |
491 | |
492 | { } |
493 | }; |
494 | |
495 | static int __init reboot_init(void) |
496 | { |
497 | int rv; |
498 | |
499 | /* |
500 | * Only do the DMI check if reboot_type hasn't been overridden |
501 | * on the command line |
502 | */ |
503 | if (!reboot_default) |
504 | return 0; |
505 | |
506 | /* |
507 | * The DMI quirks table takes precedence. If no quirks entry |
508 | * matches and the ACPI Hardware Reduced bit is set and EFI |
509 | * runtime services are enabled, force EFI reboot. |
510 | */ |
511 | rv = dmi_check_system(list: reboot_dmi_table); |
512 | |
513 | if (!rv && efi_reboot_required() && !efi_runtime_disabled()) |
514 | reboot_type = BOOT_EFI; |
515 | |
516 | return 0; |
517 | } |
518 | core_initcall(reboot_init); |
519 | |
520 | static inline void kb_wait(void) |
521 | { |
522 | int i; |
523 | |
524 | for (i = 0; i < 0x10000; i++) { |
525 | if ((inb(port: 0x64) & 0x02) == 0) |
526 | break; |
527 | udelay(usec: 2); |
528 | } |
529 | } |
530 | |
531 | static inline void nmi_shootdown_cpus_on_restart(void); |
532 | |
533 | #if IS_ENABLED(CONFIG_KVM_X86) |
534 | /* RCU-protected callback to disable virtualization prior to reboot. */ |
535 | static cpu_emergency_virt_cb __rcu *cpu_emergency_virt_callback; |
536 | |
537 | void cpu_emergency_register_virt_callback(cpu_emergency_virt_cb *callback) |
538 | { |
539 | if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback))) |
540 | return; |
541 | |
542 | rcu_assign_pointer(cpu_emergency_virt_callback, callback); |
543 | } |
544 | EXPORT_SYMBOL_GPL(cpu_emergency_register_virt_callback); |
545 | |
546 | void cpu_emergency_unregister_virt_callback(cpu_emergency_virt_cb *callback) |
547 | { |
548 | if (WARN_ON_ONCE(rcu_access_pointer(cpu_emergency_virt_callback) != callback)) |
549 | return; |
550 | |
551 | rcu_assign_pointer(cpu_emergency_virt_callback, NULL); |
552 | synchronize_rcu(); |
553 | } |
554 | EXPORT_SYMBOL_GPL(cpu_emergency_unregister_virt_callback); |
555 | |
556 | /* |
557 | * Disable virtualization, i.e. VMX or SVM, to ensure INIT is recognized during |
558 | * reboot. VMX blocks INIT if the CPU is post-VMXON, and SVM blocks INIT if |
559 | * GIF=0, i.e. if the crash occurred between CLGI and STGI. |
560 | */ |
561 | void cpu_emergency_disable_virtualization(void) |
562 | { |
563 | cpu_emergency_virt_cb *callback; |
564 | |
565 | /* |
566 | * IRQs must be disabled as KVM enables virtualization in hardware via |
567 | * function call IPIs, i.e. IRQs need to be disabled to guarantee |
568 | * virtualization stays disabled. |
569 | */ |
570 | lockdep_assert_irqs_disabled(); |
571 | |
572 | rcu_read_lock(); |
573 | callback = rcu_dereference(cpu_emergency_virt_callback); |
574 | if (callback) |
575 | callback(); |
576 | rcu_read_unlock(); |
577 | } |
578 | |
579 | static void emergency_reboot_disable_virtualization(void) |
580 | { |
581 | local_irq_disable(); |
582 | |
583 | /* |
584 | * Disable virtualization on all CPUs before rebooting to avoid hanging |
585 | * the system, as VMX and SVM block INIT when running in the host. |
586 | * |
587 | * We can't take any locks and we may be on an inconsistent state, so |
588 | * use NMIs as IPIs to tell the other CPUs to disable VMX/SVM and halt. |
589 | * |
590 | * Do the NMI shootdown even if virtualization is off on _this_ CPU, as |
591 | * other CPUs may have virtualization enabled. |
592 | */ |
593 | if (rcu_access_pointer(cpu_emergency_virt_callback)) { |
594 | /* Safely force _this_ CPU out of VMX/SVM operation. */ |
595 | cpu_emergency_disable_virtualization(); |
596 | |
597 | /* Disable VMX/SVM and halt on other CPUs. */ |
598 | nmi_shootdown_cpus_on_restart(); |
599 | } |
600 | } |
601 | #else |
602 | static void emergency_reboot_disable_virtualization(void) { } |
603 | #endif /* CONFIG_KVM_X86 */ |
604 | |
605 | void __attribute__((weak)) mach_reboot_fixups(void) |
606 | { |
607 | } |
608 | |
609 | /* |
610 | * To the best of our knowledge Windows compatible x86 hardware expects |
611 | * the following on reboot: |
612 | * |
613 | * 1) If the FADT has the ACPI reboot register flag set, try it |
614 | * 2) If still alive, write to the keyboard controller |
615 | * 3) If still alive, write to the ACPI reboot register again |
616 | * 4) If still alive, write to the keyboard controller again |
617 | * 5) If still alive, call the EFI runtime service to reboot |
618 | * 6) If no EFI runtime service, call the BIOS to do a reboot |
619 | * |
620 | * We default to following the same pattern. We also have |
621 | * two other reboot methods: 'triple fault' and 'PCI', which |
622 | * can be triggered via the reboot= kernel boot option or |
623 | * via quirks. |
624 | * |
625 | * This means that this function can never return, it can misbehave |
626 | * by not rebooting properly and hanging. |
627 | */ |
628 | static void native_machine_emergency_restart(void) |
629 | { |
630 | int i; |
631 | int attempt = 0; |
632 | int orig_reboot_type = reboot_type; |
633 | unsigned short mode; |
634 | |
635 | if (reboot_emergency) |
636 | emergency_reboot_disable_virtualization(); |
637 | |
638 | tboot_shutdown(shutdown_type: TB_SHUTDOWN_REBOOT); |
639 | |
640 | /* Tell the BIOS if we want cold or warm reboot */ |
641 | mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0; |
642 | *((unsigned short *)__va(0x472)) = mode; |
643 | |
644 | /* |
645 | * If an EFI capsule has been registered with the firmware then |
646 | * override the reboot= parameter. |
647 | */ |
648 | if (efi_capsule_pending(NULL)) { |
649 | pr_info("EFI capsule is pending, forcing EFI reboot.\n"); |
650 | reboot_type = BOOT_EFI; |
651 | } |
652 | |
653 | for (;;) { |
654 | /* Could also try the reset bit in the Hammer NB */ |
655 | switch (reboot_type) { |
656 | case BOOT_ACPI: |
657 | acpi_reboot(); |
658 | reboot_type = BOOT_KBD; |
659 | break; |
660 | |
661 | case BOOT_KBD: |
662 | mach_reboot_fixups(); /* For board specific fixups */ |
663 | |
664 | for (i = 0; i < 10; i++) { |
665 | kb_wait(); |
666 | udelay(usec: 50); |
667 | outb(value: 0xfe, port: 0x64); /* Pulse reset low */ |
668 | udelay(usec: 50); |
669 | } |
670 | if (attempt == 0 && orig_reboot_type == BOOT_ACPI) { |
671 | attempt = 1; |
672 | reboot_type = BOOT_ACPI; |
673 | } else { |
674 | reboot_type = BOOT_EFI; |
675 | } |
676 | break; |
677 | |
678 | case BOOT_EFI: |
679 | efi_reboot(reboot_mode, NULL); |
680 | reboot_type = BOOT_BIOS; |
681 | break; |
682 | |
683 | case BOOT_BIOS: |
684 | machine_real_restart(MRR_BIOS); |
685 | |
686 | /* We're probably dead after this, but... */ |
687 | reboot_type = BOOT_CF9_SAFE; |
688 | break; |
689 | |
690 | case BOOT_CF9_FORCE: |
691 | port_cf9_safe = true; |
692 | fallthrough; |
693 | |
694 | case BOOT_CF9_SAFE: |
695 | if (port_cf9_safe) { |
696 | u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E; |
697 | u8 cf9 = inb(port: 0xcf9) & ~reboot_code; |
698 | outb(value: cf9|2, port: 0xcf9); /* Request hard reset */ |
699 | udelay(usec: 50); |
700 | /* Actually do the reset */ |
701 | outb(value: cf9|reboot_code, port: 0xcf9); |
702 | udelay(usec: 50); |
703 | } |
704 | reboot_type = BOOT_TRIPLE; |
705 | break; |
706 | |
707 | case BOOT_TRIPLE: |
708 | idt_invalidate(); |
709 | __asm__ __volatile__("int3"); |
710 | |
711 | /* We're probably dead after this, but... */ |
712 | reboot_type = BOOT_KBD; |
713 | break; |
714 | } |
715 | } |
716 | } |
717 | |
718 | void native_machine_shutdown(void) |
719 | { |
720 | /* |
721 | * Call enc_kexec_begin() while all CPUs are still active and |
722 | * interrupts are enabled. This will allow all in-flight memory |
723 | * conversions to finish cleanly. |
724 | */ |
725 | if (kexec_in_progress) |
726 | x86_platform.guest.enc_kexec_begin(); |
727 | |
728 | /* Stop the cpus and apics */ |
729 | #ifdef CONFIG_X86_IO_APIC |
730 | /* |
731 | * Disabling IO APIC before local APIC is a workaround for |
732 | * erratum AVR31 in "Intel Atom Processor C2000 Product Family |
733 | * Specification Update". In this situation, interrupts that target |
734 | * a Logical Processor whose Local APIC is either in the process of |
735 | * being hardware disabled or software disabled are neither delivered |
736 | * nor discarded. When this erratum occurs, the processor may hang. |
737 | * |
738 | * Even without the erratum, it still makes sense to quiet IO APIC |
739 | * before disabling Local APIC. |
740 | */ |
741 | clear_IO_APIC(); |
742 | #endif |
743 | |
744 | #ifdef CONFIG_SMP |
745 | /* |
746 | * Stop all of the others. Also disable the local irq to |
747 | * not receive the per-cpu timer interrupt which may trigger |
748 | * scheduler's load balance. |
749 | */ |
750 | local_irq_disable(); |
751 | stop_other_cpus(); |
752 | #endif |
753 | |
754 | lapic_shutdown(); |
755 | restore_boot_irq_mode(); |
756 | |
757 | #ifdef CONFIG_HPET_TIMER |
758 | hpet_disable(); |
759 | #endif |
760 | |
761 | #ifdef CONFIG_X86_64 |
762 | x86_platform.iommu_shutdown(); |
763 | #endif |
764 | |
765 | if (kexec_in_progress) |
766 | x86_platform.guest.enc_kexec_finish(); |
767 | } |
768 | |
769 | static void __machine_emergency_restart(int emergency) |
770 | { |
771 | reboot_emergency = emergency; |
772 | machine_ops.emergency_restart(); |
773 | } |
774 | |
775 | static void native_machine_restart(char *__unused) |
776 | { |
777 | pr_notice("machine restart\n"); |
778 | |
779 | if (!reboot_force) |
780 | machine_shutdown(); |
781 | __machine_emergency_restart(emergency: 0); |
782 | } |
783 | |
784 | static void native_machine_halt(void) |
785 | { |
786 | /* Stop other cpus and apics */ |
787 | machine_shutdown(); |
788 | |
789 | tboot_shutdown(shutdown_type: TB_SHUTDOWN_HALT); |
790 | |
791 | stop_this_cpu(NULL); |
792 | } |
793 | |
794 | static void native_machine_power_off(void) |
795 | { |
796 | if (kernel_can_power_off()) { |
797 | if (!reboot_force) |
798 | machine_shutdown(); |
799 | do_kernel_power_off(); |
800 | } |
801 | /* A fallback in case there is no PM info available */ |
802 | tboot_shutdown(shutdown_type: TB_SHUTDOWN_HALT); |
803 | } |
804 | |
805 | struct machine_ops machine_ops __ro_after_init = { |
806 | .power_off = native_machine_power_off, |
807 | .shutdown = native_machine_shutdown, |
808 | .emergency_restart = native_machine_emergency_restart, |
809 | .restart = native_machine_restart, |
810 | .halt = native_machine_halt, |
811 | #ifdef CONFIG_CRASH_DUMP |
812 | .crash_shutdown = native_machine_crash_shutdown, |
813 | #endif |
814 | }; |
815 | |
816 | void machine_power_off(void) |
817 | { |
818 | machine_ops.power_off(); |
819 | } |
820 | |
821 | void machine_shutdown(void) |
822 | { |
823 | machine_ops.shutdown(); |
824 | } |
825 | |
826 | void machine_emergency_restart(void) |
827 | { |
828 | __machine_emergency_restart(emergency: 1); |
829 | } |
830 | |
831 | void machine_restart(char *cmd) |
832 | { |
833 | machine_ops.restart(cmd); |
834 | } |
835 | |
836 | void machine_halt(void) |
837 | { |
838 | machine_ops.halt(); |
839 | } |
840 | |
841 | #ifdef CONFIG_CRASH_DUMP |
842 | void machine_crash_shutdown(struct pt_regs *regs) |
843 | { |
844 | machine_ops.crash_shutdown(regs); |
845 | } |
846 | #endif |
847 | |
848 | /* This is the CPU performing the emergency shutdown work. */ |
849 | int crashing_cpu = -1; |
850 | |
851 | #if defined(CONFIG_SMP) |
852 | |
853 | static nmi_shootdown_cb shootdown_callback; |
854 | |
855 | static atomic_t waiting_for_crash_ipi; |
856 | static int crash_ipi_issued; |
857 | |
858 | static int crash_nmi_callback(unsigned int val, struct pt_regs *regs) |
859 | { |
860 | int cpu; |
861 | |
862 | cpu = raw_smp_processor_id(); |
863 | |
864 | /* |
865 | * Don't do anything if this handler is invoked on crashing cpu. |
866 | * Otherwise, system will completely hang. Crashing cpu can get |
867 | * an NMI if system was initially booted with nmi_watchdog parameter. |
868 | */ |
869 | if (cpu == crashing_cpu) |
870 | return NMI_HANDLED; |
871 | local_irq_disable(); |
872 | |
873 | if (shootdown_callback) |
874 | shootdown_callback(cpu, regs); |
875 | |
876 | /* |
877 | * Prepare the CPU for reboot _after_ invoking the callback so that the |
878 | * callback can safely use virtualization instructions, e.g. VMCLEAR. |
879 | */ |
880 | cpu_emergency_disable_virtualization(); |
881 | |
882 | atomic_dec(v: &waiting_for_crash_ipi); |
883 | |
884 | if (smp_ops.stop_this_cpu) { |
885 | smp_ops.stop_this_cpu(); |
886 | BUG(); |
887 | } |
888 | |
889 | /* Assume hlt works */ |
890 | halt(); |
891 | for (;;) |
892 | cpu_relax(); |
893 | |
894 | return NMI_HANDLED; |
895 | } |
896 | |
897 | /** |
898 | * nmi_shootdown_cpus - Stop other CPUs via NMI |
899 | * @callback: Optional callback to be invoked from the NMI handler |
900 | * |
901 | * The NMI handler on the remote CPUs invokes @callback, if not |
902 | * NULL, first and then disables virtualization to ensure that |
903 | * INIT is recognized during reboot. |
904 | * |
905 | * nmi_shootdown_cpus() can only be invoked once. After the first |
906 | * invocation all other CPUs are stuck in crash_nmi_callback() and |
907 | * cannot respond to a second NMI. |
908 | */ |
909 | void nmi_shootdown_cpus(nmi_shootdown_cb callback) |
910 | { |
911 | unsigned long msecs; |
912 | |
913 | local_irq_disable(); |
914 | |
915 | /* |
916 | * Avoid certain doom if a shootdown already occurred; re-registering |
917 | * the NMI handler will cause list corruption, modifying the callback |
918 | * will do who knows what, etc... |
919 | */ |
920 | if (WARN_ON_ONCE(crash_ipi_issued)) |
921 | return; |
922 | |
923 | /* Make a note of crashing cpu. Will be used in NMI callback. */ |
924 | crashing_cpu = smp_processor_id(); |
925 | |
926 | shootdown_callback = callback; |
927 | |
928 | atomic_set(v: &waiting_for_crash_ipi, i: num_online_cpus() - 1); |
929 | |
930 | /* |
931 | * Set emergency handler to preempt other handlers. |
932 | */ |
933 | set_emergency_nmi_handler(type: NMI_LOCAL, handler: crash_nmi_callback); |
934 | |
935 | apic_send_IPI_allbutself(NMI_VECTOR); |
936 | |
937 | /* Kick CPUs looping in NMI context. */ |
938 | WRITE_ONCE(crash_ipi_issued, 1); |
939 | |
940 | msecs = 1000; /* Wait at most a second for the other cpus to stop */ |
941 | while ((atomic_read(v: &waiting_for_crash_ipi) > 0) && msecs) { |
942 | mdelay(1); |
943 | msecs--; |
944 | } |
945 | |
946 | /* |
947 | * Leave the nmi callback set, shootdown is a one-time thing. Clearing |
948 | * the callback could result in a NULL pointer dereference if a CPU |
949 | * (finally) responds after the timeout expires. |
950 | */ |
951 | } |
952 | |
953 | static inline void nmi_shootdown_cpus_on_restart(void) |
954 | { |
955 | if (!crash_ipi_issued) |
956 | nmi_shootdown_cpus(NULL); |
957 | } |
958 | |
959 | /* |
960 | * Check if the crash dumping IPI got issued and if so, call its callback |
961 | * directly. This function is used when we have already been in NMI handler. |
962 | * It doesn't return. |
963 | */ |
964 | void run_crash_ipi_callback(struct pt_regs *regs) |
965 | { |
966 | if (crash_ipi_issued) |
967 | crash_nmi_callback(val: 0, regs); |
968 | } |
969 | |
970 | /* Override the weak function in kernel/panic.c */ |
971 | void __noreturn nmi_panic_self_stop(struct pt_regs *regs) |
972 | { |
973 | while (1) { |
974 | /* If no CPU is preparing crash dump, we simply loop here. */ |
975 | run_crash_ipi_callback(regs); |
976 | cpu_relax(); |
977 | } |
978 | } |
979 | |
980 | #else /* !CONFIG_SMP */ |
981 | void nmi_shootdown_cpus(nmi_shootdown_cb callback) |
982 | { |
983 | /* No other CPUs to shoot down */ |
984 | } |
985 | |
986 | static inline void nmi_shootdown_cpus_on_restart(void) { } |
987 | |
988 | void run_crash_ipi_callback(struct pt_regs *regs) |
989 | { |
990 | } |
991 | #endif |
992 |
Definitions
- pm_power_off
- reboot_emergency
- port_cf9_safe
- set_acpi_reboot
- set_bios_reboot
- set_efi_reboot
- machine_real_restart
- set_pci_reboot
- set_kbd_reboot
- reboot_dmi_table
- reboot_init
- kb_wait
- cpu_emergency_virt_callback
- cpu_emergency_register_virt_callback
- cpu_emergency_unregister_virt_callback
- cpu_emergency_disable_virtualization
- emergency_reboot_disable_virtualization
- mach_reboot_fixups
- native_machine_emergency_restart
- native_machine_shutdown
- __machine_emergency_restart
- native_machine_restart
- native_machine_halt
- native_machine_power_off
- machine_ops
- machine_power_off
- machine_shutdown
- machine_emergency_restart
- machine_restart
- machine_halt
- machine_crash_shutdown
- crashing_cpu
- shootdown_callback
- waiting_for_crash_ipi
- crash_ipi_issued
- crash_nmi_callback
- nmi_shootdown_cpus
- nmi_shootdown_cpus_on_restart
- run_crash_ipi_callback
Improve your Profiling and Debugging skills
Find out more