#include "power/reboot.h" #include "acpi/FADT.h" #include "acpi/RSDT.h" #include "assert.h" #include "interrupts/IDT.h" #include "interrupts/Interrupts.h" #include "io/IO.h" #include "log/Log.h" #include "panic/hang.h" #include "std/string.h" static void try_acpi_reboot() { ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT(); if (!rootSDT) return; if (!ACPI::ValidateSDTHeader(rootSDT)) return; if (strncmp(rootSDT->Signature, "RSDT", 4) != 0 && strncmp(rootSDT->Signature, "XSDT", 4) != 0) return; ACPI::FADT* fadt = (ACPI::FADT*)ACPI::FindTable(rootSDT, "FACP"); if (!fadt) return; if (!ACPI::ValidateSDTHeader(&fadt->header)) return; if (!(fadt->Flags & 1 << 10)) return; switch (fadt->ResetReg.AddressSpace) { case ACPI::SystemIO: IO::outb(fadt->ResetReg.Address, fadt->ResetValue); break; case ACPI::GeneralPurposeIO: IO::outb(fadt->ResetReg.Address, fadt->ResetValue); break; default: return; } } static void try_kbd_reboot() { Interrupts::disable(); uint8_t temp; do { temp = IO::inb(0x64); if (temp & 0b1) IO::inb(0x60); } while (temp & 0b10); IO::outb(0x64, 0xFE); } static void try_idt_triple_fault() { IDTR idtr; idtr.limit = 0x0000; idtr.offset = 0x0000; asm volatile("lidt %0" : : "m"(idtr)); Interrupts::enable(); asm volatile("int $0x80"); } [[noreturn]] void reboot() { kinfoln("Attempting reboot using ACPI"); try_acpi_reboot(); kinfoln("Attempting reboot using keyboard RESET pulsing"); try_kbd_reboot(); kinfoln("Attempting reboot by triple faulting"); try_idt_triple_fault(); kerrorln("Failed to reboot, halting machine"); hang(); }