128 lines
4.6 KiB
C++
128 lines
4.6 KiB
C++
/*
|
|
* Panic.cpp
|
|
* Copyright (c) 2025 Daniel Hammer
|
|
*/
|
|
|
|
#include "Panic.hpp"
|
|
#include "../CppLib/BoxUI.hpp"
|
|
#include "../Drivers/Graphics/IntelGPU.hpp"
|
|
|
|
static constexpr int BoxWidth = 72;
|
|
|
|
static void PrintHorizontalEdge(const char* left, const char* right) {
|
|
kerr << left;
|
|
for (int i = 0; i < BoxWidth - 2; ++i) kerr << BOXUI_H;
|
|
kerr << right << "\n";
|
|
}
|
|
|
|
static void PrintPageFaultInfo(System::PanicFrame*& frame) {
|
|
auto* pf = (System::PageFaultPanicFrame*)frame;
|
|
frame = (System::PanicFrame*)&pf->IP;
|
|
|
|
uint64_t cr2;
|
|
asm volatile("mov %%cr2, %0" : "=r"(cr2));
|
|
PrintBoxedHex(kerr, "Faulting Address (CR2)", cr2, BoxWidth);
|
|
|
|
PrintBoxedLine(kerr, "Page Fault Error:", BoxWidth, true);
|
|
PrintBoxedDec(kerr, "Present", pf->PageFaultError.Present, BoxWidth);
|
|
PrintBoxedDec(kerr, "Write", pf->PageFaultError.Write, BoxWidth);
|
|
PrintBoxedDec(kerr, "User", pf->PageFaultError.User, BoxWidth);
|
|
PrintBoxedDec(kerr, "Reserved Write", pf->PageFaultError.ReservedWrite, BoxWidth);
|
|
PrintBoxedDec(kerr, "Instruction Fetch",pf->PageFaultError.InstructionFetch, BoxWidth);
|
|
PrintBoxedDec(kerr, "Protection Key", pf->PageFaultError.ProtectionKey, BoxWidth);
|
|
PrintBoxedDec(kerr, "Shadow Stack", pf->PageFaultError.ShadowStack, BoxWidth);
|
|
PrintBoxedDec(kerr, "SGX", pf->PageFaultError.SGX, BoxWidth);
|
|
}
|
|
|
|
static void PrintGPFInfo(System::PanicFrame*& frame) {
|
|
auto* gpf = (System::GPFPanicFrame*)frame;
|
|
frame = (System::PanicFrame*)&gpf->IP;
|
|
|
|
PrintBoxedLine(kerr, "General Protection Fault:", BoxWidth, true);
|
|
PrintBoxedDec(kerr, "Error Code", gpf->GeneralProtectionFaultError, BoxWidth);
|
|
}
|
|
|
|
// Link-time base of the kernel image (see linker-x86_64.ld).
|
|
static constexpr uint64_t KernelBaseVirt = 0xFFFFFFFF80000000ULL;
|
|
|
|
static void PrintRegisters(System::PanicFrame* frame) {
|
|
PrintBoxedSeparator(kerr, BoxWidth);
|
|
PrintBoxedLine(kerr, "Registers:", BoxWidth, true);
|
|
PrintBoxedHex(kerr, "Instruction Pointer", frame->IP, BoxWidth);
|
|
|
|
// The absolute address means nothing without the link map. Its offset from
|
|
// the kernel's load base is what `nm bin-x86_64/kernel` can be searched
|
|
// for directly, so print that next to it.
|
|
if (frame->IP >= KernelBaseVirt)
|
|
PrintBoxedHex(kerr, " kernel+", frame->IP - KernelBaseVirt, BoxWidth);
|
|
|
|
|
|
PrintBoxedHex(kerr, "Code Segment", frame->CS, BoxWidth);
|
|
PrintBoxedHex(kerr, "Flags", frame->Flags, BoxWidth);
|
|
PrintBoxedHex(kerr, "Stack Pointer", frame->SP, BoxWidth);
|
|
PrintBoxedHex(kerr, "Stack Segment", frame->SS, BoxWidth);
|
|
}
|
|
|
|
[[noreturn]] static void Halt() {
|
|
while (true) {
|
|
#if defined (__x86_64__)
|
|
asm ("cli");
|
|
asm ("hlt");
|
|
#elif defined (__aarch64__) || defined (__riscv)
|
|
asm ("wfi");
|
|
#elif defined (__loongarch64)
|
|
asm ("idle 0");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Panic(const char *meditationString, System::PanicFrame* frame) {
|
|
// Bring scanout back to buffer 0 first: if a page-flipped client was
|
|
// showing the other buffer, the panic box would land on an invisible
|
|
// surface. Safe no-op when the GPU driver is inactive.
|
|
Drivers::Graphics::IntelGPU::PanicRestoreScanout();
|
|
Kt::EnablePanicOutput();
|
|
|
|
// Header
|
|
kerr << BOXUI_ANSI_RED_BG << BOXUI_ANSI_WHITE_FG << BOXUI_ANSI_BOLD << "\n";
|
|
PrintHorizontalEdge(BOXUI_TL, BOXUI_TR);
|
|
PrintBoxedLine(kerr, "!!! KERNEL PANIC !!!", BoxWidth, true);
|
|
PrintBoxedLine(kerr, "", BoxWidth);
|
|
PrintBoxedLine(kerr, "System halted. Please reboot.", BoxWidth, true);
|
|
PrintBoxedLine(kerr, "", BoxWidth);
|
|
|
|
// Meditation string
|
|
PrintBoxedSeparator(kerr, BoxWidth);
|
|
PrintBoxedLine(kerr, meditationString, BoxWidth);
|
|
PrintBoxedLine(kerr, "", BoxWidth);
|
|
|
|
// CPU state (x86_64 only)
|
|
#if defined (__x86_64__)
|
|
if (frame != nullptr) {
|
|
PrintBoxedSeparator(kerr, BoxWidth);
|
|
PrintBoxedLine(kerr, "CPU State:", BoxWidth, true);
|
|
PrintBoxedHex(kerr, "Interrupt Vector", frame->InterruptVector, BoxWidth);
|
|
|
|
if (frame->InterruptVector == 0xE)
|
|
PrintPageFaultInfo(frame);
|
|
else if (frame->InterruptVector == 0xD)
|
|
PrintGPFInfo(frame);
|
|
|
|
PrintRegisters(frame);
|
|
}
|
|
#endif
|
|
|
|
// Footer
|
|
PrintBoxedLine(kerr, "", BoxWidth);
|
|
PrintHorizontalEdge(BOXUI_BL, BOXUI_BR);
|
|
kerr << BOXUI_ANSI_RESET;
|
|
|
|
#if defined (__x86_64__)
|
|
// The framebuffer is write-combining. Drain the final panic text before
|
|
// halting all forward progress so it cannot remain in a CPU write buffer.
|
|
asm volatile("sfence" ::: "memory");
|
|
#endif
|
|
|
|
Halt();
|
|
}
|