#define MODULE "power" #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() { kinfoln("Fetching pointer to RSDT/XSDT"); ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT(); if (!rootSDT) { kinfoln("The pointer to the RSDT/XSDT is null"); return; } if (!ACPI::ValidateSDTHeader(rootSDT)) { kinfoln("The RSDT/XSDT has an invalid header"); return; } if (strncmp(rootSDT->Signature, "RSDT", 4) != 0 && strncmp(rootSDT->Signature, "XSDT", 4) != 0) { kinfoln("The RSDT/XSDT's signature is not RSDT or XSDT"); return; } kinfoln("Searching for the FADT"); ACPI::FADT* fadt = (ACPI::FADT*)ACPI::FindTable(rootSDT, "FACP"); if (!fadt) { kinfoln("Unable to find the FADT"); return; } if (fadt->header.Revision < 2) { kinfoln("ACPI revision is too low (%d), ACPI Reset is only implemented in ACPI 2.0+", fadt->header.Revision); return; } if (!(fadt->Flags & 1 << 10)) { kinfoln("This system does not support ACPI Reset"); return; } switch (fadt->ResetReg.AddressSpace) { case ACPI::SystemIO: kinfoln("Attempting ACPI Reset via SystemIO: sending byte %d to port %lx", fadt->ResetValue, fadt->ResetReg.Address); IO::outb(fadt->ResetReg.Address, fadt->ResetValue); break; case ACPI::GeneralPurposeIO: kinfoln("Attempting ACPI Reset via GeneralPurposeIO: sending byte %d to port %lx", fadt->ResetValue, fadt->ResetReg.Address); IO::outb(fadt->ResetReg.Address, fadt->ResetValue); break; default: kinfoln("This method of rebooting via ACPI is not yet implemented"); return; } kinfoln("Tried to reboot, but apparently did nothing"); } 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(); }