From a1659aa1276dea990f44f7f4a0c9eb9b584fae65 Mon Sep 17 00:00:00 2001 From: apio Date: Tue, 6 Sep 2022 11:47:55 +0200 Subject: [PATCH] Add a reboot() function This reboot function first tries to reboot using ACPI, then pulsing the CPU's RESET line through the keyboard, then triple-faulting. If we're still there, it halts. --- kernel/include/power/reboot.h | 3 ++ kernel/src/power/reboot.cpp | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 kernel/include/power/reboot.h create mode 100644 kernel/src/power/reboot.cpp diff --git a/kernel/include/power/reboot.h b/kernel/include/power/reboot.h new file mode 100644 index 00000000..e7de0de8 --- /dev/null +++ b/kernel/include/power/reboot.h @@ -0,0 +1,3 @@ +#pragma once + +[[noreturn]] void reboot(); \ No newline at end of file diff --git a/kernel/src/power/reboot.cpp b/kernel/src/power/reboot.cpp new file mode 100644 index 00000000..4ce87851 --- /dev/null +++ b/kernel/src/power/reboot.cpp @@ -0,0 +1,65 @@ +#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(); +end: + goto end; +} \ No newline at end of file