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.
This commit is contained in:
parent
aa673e1402
commit
a1659aa127
3
kernel/include/power/reboot.h
Normal file
3
kernel/include/power/reboot.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
[[noreturn]] void reboot();
|
65
kernel/src/power/reboot.cpp
Normal file
65
kernel/src/power/reboot.cpp
Normal file
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user