diff options
author | Ian Moffett <ian@osmora.org> | 2025-08-20 04:25:32 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-08-20 04:25:32 -0400 |
commit | bf48729c47e3b7c762d97238370fea99748433b7 (patch) | |
tree | 3671a524c8ec6100c9eff15a51242f52102d6a6f /sys | |
parent | d35b0f3da392a125f8ec27f6f4dd07ebc2d4972c (diff) |
kernel/amd64: reboot: Add reboot fallback methods
This commit introduces several fallback methods for system reboots in
case once fails.
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/reboot.c | 47 |
1 files changed, 43 insertions, 4 deletions
diff --git a/sys/arch/amd64/amd64/reboot.c b/sys/arch/amd64/amd64/reboot.c index d47a352..8ebe15e 100644 --- a/sys/arch/amd64/amd64/reboot.c +++ b/sys/arch/amd64/amd64/reboot.c @@ -34,9 +34,49 @@ #include <machine/cpu.h> #include <dev/acpi/acpi.h> +static void +cpu_reset_intel(struct cpu_info *ci) +{ + /* + * Ivy bridge processors and their panther point chipsets + * (family 6) can be reset through special PCH reset control + * registers + */ + if (ci->family == 6) { + outb(0xCF9, 3 << 1); + } +} + +/* + * Attempt to reboot the system, we do this in many + * stages of escalation. If a reset via the i8042 + * controller fails and we are on an Intel processor, + * attempt a chipset specific reset. If that somehow fails + * as well, just smack the cpu with a NULL IDTR as well + * as an INT $0x0 + */ +static void +__cpu_reset(struct cpu_info *ci) +{ + /* Try via the i8042 */ + outb(0x64, 0xFE); + + /* Something went wrong if we are here */ + if (ci == NULL) { + return; + } + + if (ci->vendor == CPU_VENDOR_INTEL) { + cpu_reset_intel(ci); + } +} + void cpu_reboot(int method) { + struct cpu_info *ci = this_cpu(); + uint32_t *__dmmy = NULL; + if (ISSET(method, REBOOT_POWEROFF)) { acpi_sleep(ACPI_SLEEP_S5); } @@ -45,10 +85,9 @@ cpu_reboot(int method) cpu_halt_all(); } - /* Pulse the reset line until the machine goes down */ - for (;;) { - outb(0x64, 0xFE); - } + __cpu_reset(ci); + asm volatile("lgdt %0; int $0x0" :: "m" (__dmmy)); + __builtin_unreachable(); } /* |