/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include "../crashhandler.hpp" #include "chfcts.hpp" #include #include #include #include #include #include #include #include #include #include #include #if defined(a64) #include "../../arch/amd64/cpu/gdt.hpp" #include "../arch/amd64/cpu/apic.hpp" #elif defined(a32) #include "../../arch/i386/cpu/gdt.hpp" #include "../arch/i386/cpu/apic.hpp" #elif defined(aa64) #endif #include "../../kernel.h" NewLock(UserInputLock); namespace CrashHandler { uintptr_t PageFaultAddress = 0; void *EHIntFrames[INT_FRAMES_MAX]; static bool ExceptionOccurred = false; int SBIdx = 255; CrashKeyboardDriver *kbd; SafeFunction void printfWrapper(char c, void *unused) { Display->Print(c, SBIdx, true); UNUSED(unused); } SafeFunction void EHPrint(const char *Format, ...) { va_list args; va_start(args, Format); vfctprintf(printfWrapper, NULL, Format, args); va_end(args); } SafeFunction void EHDumpData(void *Address, unsigned long Length) { EHPrint("-------------------------------------------------------------------------\n"); Display->SetBuffer(SBIdx); unsigned char *AddressChar = (unsigned char *)Address; unsigned char Buffer[17]; unsigned long Iterate; for (Iterate = 0; Iterate < Length; Iterate++) { if ((Iterate % 16) == 0) { if (Iterate != 0) EHPrint(" \e8A78FF%s\eAABBCC\n", Buffer); EHPrint(" \e9E9E9E%04x\eAABBCC ", Iterate); Display->SetBuffer(SBIdx); } EHPrint(" \e4287f5%02x\eAABBCC", AddressChar[Iterate]); if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e)) Buffer[Iterate % 16] = '.'; else Buffer[Iterate % 16] = AddressChar[Iterate]; Buffer[(Iterate % 16) + 1] = '\0'; } while ((Iterate % 16) != 0) { EHPrint(" "); Display->SetBuffer(SBIdx); Iterate++; } EHPrint(" \e8A78FF%s\eAABBCC\n", Buffer); EHPrint("-------------------------------------------------------------------------\n\n."); Display->SetBuffer(SBIdx); } SafeFunction char *TrimWhiteSpace(char *str) { char *end; while (*str == ' ') str++; if (*str == 0) return str; end = str + strlen(str) - 1; while (end > str && *end == ' ') end--; *(end + 1) = 0; return str; } CRData crashdata{}; SafeFunction void DisplayTopOverlay() { Video::ScreenBuffer *sb = Display->GetBuffer(SBIdx); Video::Font *f = Display->GetCurrentFont(); Video::FontInfo fi = f->GetInfo(); for (uint32_t i = 0; i < sb->Width; i++) for (uint32_t j = 0; j < fi.Height + 8; j++) Display->SetPixel(i, j, 0x282828, SBIdx); Display->SetBufferCursor(SBIdx, 8, (fi.Height + 8) / 6); switch (SBIdx) { case 255: { EHPrint("\eAAAAAAMAIN \e606060DETAILS \e606060FRAMES \e606060TASKS \e606060CONSOLE"); break; } case 254: { EHPrint("\e606060MAIN \eAAAAAADETAILS \e606060FRAMES \e606060TASKS \e606060CONSOLE"); break; } case 253: { EHPrint("\e606060MAIN \e606060DETAILS \eAAAAAAFRAMES \e606060TASKS \e606060CONSOLE"); break; } case 252: { EHPrint("\e606060MAIN \e606060DETAILS \e606060FRAMES \eAAAAAATASKS \e606060CONSOLE"); break; } case 251: { EHPrint("\e606060MAIN \e606060DETAILS \e606060FRAMES \e606060TASKS \eAAAAAACONSOLE"); break; } default: { EHPrint("\e606060MAIN \e606060DETAILS \e606060FRAMES \e606060TASKS \e606060CONSOLE"); break; } } EHPrint(" \e00AAFF%ld MiB / %ld MiB (%ld MiB Reserved)", TO_MiB(KernelAllocator.GetUsedMemory()), TO_MiB(KernelAllocator.GetTotalMemory()), TO_MiB(KernelAllocator.GetReservedMemory())); EHPrint(" \eAA0F0F%s", CPU::Hypervisor()); EHPrint(" \eAAF00F%s", CPU::Vendor()); EHPrint(" \eAA00FF%s", CPU::Name()); Display->SetBufferCursor(SBIdx, 0, fi.Height + 10); /* https://imgflip.com/i/77slbl */ if ((Random::rand32() % 100) >= 98) { debug("Easter egg activated!"); int BaseXOffset = sb->Width - 14; int BaseYOffset = 8; Display->SetPixel(BaseXOffset + 3, BaseYOffset + 0, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 0, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 0, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 7, BaseYOffset + 0, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 2, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 3, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 5, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 7, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 8, BaseYOffset + 1, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 1, BaseYOffset + 2, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 2, BaseYOffset + 2, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 3, BaseYOffset + 2, 0xFFFFFF, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 2, 0x000000, SBIdx); Display->SetPixel(BaseXOffset + 5, BaseYOffset + 2, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 2, 0xFFFFFF, SBIdx); Display->SetPixel(BaseXOffset + 7, BaseYOffset + 2, 0x000000, SBIdx); Display->SetPixel(BaseXOffset + 8, BaseYOffset + 2, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 1, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 2, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 3, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 5, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 7, BaseYOffset + 3, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 0, BaseYOffset + 4, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 1, BaseYOffset + 4, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 2, BaseYOffset + 4, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 3, BaseYOffset + 4, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 4, 0xA84832, SBIdx); Display->SetPixel(BaseXOffset + 5, BaseYOffset + 4, 0xA84832, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 4, 0xA84832, SBIdx); Display->SetPixel(BaseXOffset + 7, BaseYOffset + 4, 0xA84832, SBIdx); Display->SetPixel(BaseXOffset + 0, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 1, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 2, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 3, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 5, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 5, 0x21852E, SBIdx); Display->SetPixel(BaseXOffset + 0, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetPixel(BaseXOffset + 1, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetPixel(BaseXOffset + 2, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetPixel(BaseXOffset + 3, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetPixel(BaseXOffset + 4, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetPixel(BaseXOffset + 5, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetPixel(BaseXOffset + 6, BaseYOffset + 6, 0x1216FF, SBIdx); Display->SetBuffer(SBIdx); } } SafeFunction void DisplayBottomOverlay() { Video::ScreenBuffer *sb = Display->GetBuffer(SBIdx); Video::Font *f = Display->GetCurrentFont(); Video::FontInfo fi = f->GetInfo(); for (uint32_t i = 0; i < sb->Width; i++) for (uint32_t j = sb->Height - fi.Height - 8; j < sb->Height; j++) Display->SetPixel(i, j, 0x282828, SBIdx); Display->SetBufferCursor(SBIdx, 8, sb->Height - fi.Height - 4); EHPrint("\eAAAAAA> \eFAFAFA"); } SafeFunction void ArrowInput(uint8_t key) { switch (key) { case KEY_D_UP: if (SBIdx < 255) SBIdx++; else return; break; case KEY_D_LEFT: if (SBIdx < 255) SBIdx++; else return; break; case KEY_D_RIGHT: if (SBIdx > 251) SBIdx--; else return; break; case KEY_D_DOWN: if (SBIdx > 251) SBIdx--; else return; break; default: break; } Display->ClearBuffer(SBIdx); DisplayTopOverlay(); EHPrint("\eFAFAFA"); switch (SBIdx) { case 255: { DisplayMainScreen(crashdata); break; } case 254: { DisplayDetailsScreen(crashdata); break; } case 253: { DisplayStackFrameScreen(crashdata); break; } case 252: { DisplayTasksScreen(crashdata); break; } case 251: { DisplayConsoleScreen(crashdata); break; } default: { break; } } DisplayBottomOverlay(); Display->SetBuffer(SBIdx); } SafeFunction void UserInput(char *Input) { SmartCriticalSection(UserInputLock); Display->ClearBuffer(SBIdx); DisplayTopOverlay(); EHPrint("\eFAFAFA"); if (strcmp(Input, "help") == 0) { EHPrint("Available commands are:\n"); EHPrint("exit - Shutdown the OS.\n"); EHPrint("reboot - Reboot the OS.\n"); EHPrint("help - Display this help message.\n"); EHPrint("showbuf,sb - Display the contents of a screen buffer.\n"); EHPrint(" - A sleep timer will be enabled. This will cause the OS to sleep for an unknown amount of time.\n"); EHPrint("ifr - Show interrupt frames.\n"); EHPrint("tlb
- Print the page table entries\n"); EHPrint("bitmap - Print the memory bitmap\n"); EHPrint("mem - Print the memory allocation\n"); EHPrint("cr - Print the CPU control register\n"); EHPrint("tss - Print the CPU task state segment\n"); EHPrint("dump
- Dump memory\n"); EHPrint("uartmemdmp - Dump the memory of a UART.\n"); EHPrint("main - Show the main screen.\n"); EHPrint("details - Show the details screen.\n"); EHPrint("frames - Show the stack frame screen.\n"); EHPrint("tasks - Show the tasks screen.\n"); EHPrint("console - Show the console screen.\n"); EHPrint("Also, you can use the arrow keys to navigate between the screens.\n"); EHPrint("=========================================================================\n"); EHPrint("Kernel Compiled at: %s %s with C++ Standard: %d\n", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD); EHPrint("C++ Language Version (__cplusplus): %ld\n", __cplusplus); } else if (strcmp(Input, "exit") == 0) { PowerManager->Shutdown(); EHPrint("\eFFFFFFNow it's safe to turn off your computer."); Display->SetBuffer(SBIdx); CPU::Stop(); } else if (strcmp(Input, "reboot") == 0) { PowerManager->Reboot(); EHPrint("\eFFFFFFNow it's safe to reboot your computer."); Display->SetBuffer(SBIdx); CPU::Stop(); } else if (strncmp(Input, "showbuf", 7) == 0 || strncmp(Input, "sb", 2) == 0) { char *arg = TrimWhiteSpace(Input + 7); int tmpidx = SBIdx; SBIdx = atoi(arg); Display->SetBuffer(SBIdx); #if defined(a86) for (int i = 0; i < 5000000; i++) inb(0x80); #endif // a64 || a32 SBIdx = tmpidx; Display->SetBuffer(SBIdx); } else if (strncmp(Input, "ifr", 3) == 0) { char *arg = TrimWhiteSpace(Input + 3); int CountI = atoi(arg); int TotalCount = sizeof(EHIntFrames) / sizeof(EHIntFrames[0]); debug("Printing %ld interrupt frames.", CountI); if (CountI > TotalCount) { EHPrint("\eFF4400Count too big! Maximum allowed is %ld\eFAFAFA\n", TotalCount); Display->SetBuffer(SBIdx); } else { for (int i = 0; i < CountI; i++) { if (EHIntFrames[i]) { if (!Memory::Virtual().Check(EHIntFrames[i])) continue; EHPrint("\n\e2565CC%p", EHIntFrames[i]); EHPrint("\e7925CC-"); #if defined(a64) if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end) #elif defined(a32) if ((uintptr_t)EHIntFrames[i] >= 0xC0000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end) #elif defined(aa64) if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end) #endif EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbol((uintptr_t)EHIntFrames[i])); else EHPrint("\eFF4CA9Outside Kernel"); #if defined(a86) for (int i = 0; i < 20000; i++) inb(0x80); #endif // a64 || a32 Display->SetBuffer(SBIdx); } } } } else if (strncmp(Input, "tlb", 3) == 0) { char *arg = TrimWhiteSpace(Input + 3); uintptr_t Address = NULL; Address = strtol(arg, NULL, 16); debug("Converted %s to %#lx", arg, Address); Memory::PageTable *BasePageTable = (Memory::PageTable *)Address; if (Memory::Virtual().Check(BasePageTable)) { for (int PMLIndex = 0; PMLIndex < 512; PMLIndex++) { #if defined(a64) Memory::PageMapLevel4 PML4 = BasePageTable->Entries[PMLIndex]; EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n", PMLIndex, 0, 0, 0, PML4.Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PML4.GetAddress() << 12); Display->SetBuffer(SBIdx); if (PML4.Present) { Memory::PageDirectoryPointerTableEntryPtr *PDPTE = (Memory::PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12); if (PDPTE) { for (int PDPTEIndex = 0; PDPTEIndex < 512; PDPTEIndex++) { EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n", PMLIndex, PDPTEIndex, 0, 0, PDPTE->Entries[PDPTEIndex].Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDPTE->Entries[PDPTEIndex].GetAddress() << 12); Display->SetBuffer(SBIdx); if ((PDPTE->Entries[PDPTEIndex].Present)) { Memory::PageDirectoryEntryPtr *PDE = (Memory::PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[PDPTEIndex].GetAddress() << 12); if (PDE) { for (int PDEIndex = 0; PDEIndex < 512; PDEIndex++) { EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n", PMLIndex, PDPTEIndex, PDEIndex, 0, PDE->Entries[PDEIndex].Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PDE->Entries[PDEIndex].GetAddress() << 12); Display->SetBuffer(SBIdx); if ((PDE->Entries[PDEIndex].Present)) { Memory::PageTableEntryPtr *PTE = (Memory::PageTableEntryPtr *)((uintptr_t)PDE->Entries[PDEIndex].GetAddress() << 12); if (PTE) { for (int PTEIndex = 0; PTEIndex < 512; PTEIndex++) { EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s D:%s PAT:%s G:%s PK:%d NX:%s Address:\e888888%#lx\n", PMLIndex, PDPTEIndex, PDEIndex, PTEIndex, PTE->Entries[PTEIndex].Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].Dirty ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].PageAttributeTable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].Global ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].ProtectionKey, PTE->Entries[PTEIndex].ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5", PTE->Entries[PTEIndex].GetAddress() << 12); Display->SetBuffer(SBIdx); } } } } } } } } } #endif } } } else if (strncmp(Input, "bitmap", 6) == 0) { Bitmap bm = KernelAllocator.GetPageBitmap(); EHPrint("\n\eFAFAFA[0%%] %08ld: ", 0); for (size_t i = 0; i < bm.Size; i++) { if (bm.Get(i)) EHPrint("\eFF00001"); else EHPrint("\e00FF000"); if (i % 128 == 127) { short Percentage = s_cst(short, (i * 100) / bm.Size); EHPrint("\n\eFAFAFA[%03ld%%] %08ld: ", Percentage, i); Display->SetBuffer(SBIdx); } } EHPrint("\n\e22AA44--- END OF BITMAP ---\nBitmap size: %ld\n\n.", bm.Size); Display->SetBuffer(SBIdx); } else if (strcmp(Input, "mem") == 0) { uint64_t Total = KernelAllocator.GetTotalMemory(); uint64_t Used = KernelAllocator.GetUsedMemory(); uint64_t Free = KernelAllocator.GetFreeMemory(); uint64_t Reserved = KernelAllocator.GetReservedMemory(); EHPrint("\e22AA44Total: %ld bytes\n\eFF0000Used: %ld bytes\n\e00FF00Free: %ld bytes\n\eFF00FFReserved: %ld bytes\n", Total, Used, Free, Reserved); int Progress = s_cst(int, (Used * 100) / Total); int ReservedProgress = s_cst(int, (Reserved * 100) / Total); EHPrint("\e22AA44%3d%% \eCCCCCC[", Progress); for (int i = 0; i < Progress; i++) EHPrint("\eFF0000|"); for (int i = 0; i < 100 - Progress; i++) EHPrint("\e00FF00|"); for (int i = 0; i < ReservedProgress; i++) EHPrint("\eFF00FF|"); EHPrint("\eCCCCCC]\n"); Display->SetBuffer(SBIdx); } else if (strncmp(Input, "cr", 2) == 0) { char *cr = TrimWhiteSpace(Input + 2); switch (cr[0]) { case '0': { #if defined(a64) EHPrint("\e44AA000: %#lx\n", CPU::x64::readcr0()); #elif defined(a32) EHPrint("\e44AA000: %#lx\n", CPU::x32::readcr0()); #endif break; } case '2': { #if defined(a64) EHPrint("\e44AA002: %#lx\n", PageFaultAddress); #elif defined(a32) EHPrint("\e44AA002: %#lx\n", CPU::x32::readcr2()); #endif break; } case '3': { #if defined(a64) EHPrint("\e44AA003: %#lx\n", CPU::x64::readcr3()); #elif defined(a32) EHPrint("\e44AA003: %#lx\n", CPU::x32::readcr3()); #endif break; } case '4': { #if defined(a64) EHPrint("\e44AA004: %#lx\n", CPU::x64::readcr4()); #elif defined(a32) EHPrint("\e44AA004: %#lx\n", CPU::x32::readcr4()); #endif break; } case '8': { #if defined(a64) EHPrint("\e44AA008: %#lx\n", CPU::x64::readcr8()); #elif defined(a32) EHPrint("\e44AA008: %#lx\n", CPU::x32::readcr8()); #endif break; } default: EHPrint("\eFF0000Invalid CR\n"); break; } } else if (strncmp(Input, "tss", 3) == 0) { char *arg = TrimWhiteSpace(Input + 3); int TSSIndex = atoi(arg); if (TSSIndex > SMP::CPUCores) { EHPrint("\eFF0000Invalid TSS index\n"); } else { #if defined(a86) GlobalDescriptorTable::TaskStateSegment tss = GlobalDescriptorTable::tss[TSSIndex]; EHPrint("\eFAFAFAStack Pointer 0: \eAABB22%#lx\n", tss.StackPointer[0]); EHPrint("\eFAFAFAStack Pointer 1: \eAABB22%#lx\n", tss.StackPointer[1]); EHPrint("\eFAFAFAStack Pointer 2: \eAABB22%#lx\n", tss.StackPointer[2]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[0]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[1]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[2]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[3]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[4]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[5]); EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[6]); EHPrint("\eFAFAFAI/O Map Base Address Offset: \eAABB22%#lx\n", tss.IOMapBaseAddressOffset); EHPrint("\eFAFAFAReserved 0: \eAABB22%#lx\n", tss.Reserved0); EHPrint("\eFAFAFAReserved 1: \eAABB22%#lx\n", tss.Reserved1); EHPrint("\eFAFAFAReserved 2: \eAABB22%#lx\n", tss.Reserved2); #elif defined(aa64) EHPrint("\eFF0000AArch64 does not have TSS\n"); #endif } } else if (strncmp(Input, "dump", 4) == 0) { char *arg = TrimWhiteSpace(Input + 4); char *addr = strtok(arg, " "); char *len = strtok(NULL, " "); if (addr == NULL || len == NULL) { EHPrint("\eFF0000Invalid arguments\n"); } else { uintptr_t Address = strtoul(addr, NULL, 16); size_t Length = strtoul(len, NULL, 10); size_t ActualLength = Length; uintptr_t AlignedAddress = ROUND_DOWN(Address, PAGE_SIZE); { Memory::Virtual vmm; for (uintptr_t adr = AlignedAddress; adr < Address + Length; adr += PAGE_SIZE) { if (!vmm.Check((void *)adr)) { EHPrint("\eFFA500Address %#lx is not mapped\n", adr); Display->SetBuffer(SBIdx); ActualLength -= PAGE_SIZE; } } } debug("Dumping %ld bytes from %#lx\n", ActualLength, AlignedAddress); EHDumpData((void *)AlignedAddress, (unsigned long)ActualLength); } } else if (strncmp(Input, "uartmemdmp", 10) == 0) { char *arg = TrimWhiteSpace(Input + 10); char *cPort = strtok(arg, " "); char *cBoolSkip = strtok(NULL, " "); UniversalAsynchronousReceiverTransmitter::SerialPorts port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM1; switch (cPort[0]) { case '1': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM1; break; case '2': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM2; break; case '3': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM3; break; case '4': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM4; break; case '5': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM5; break; case '6': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM6; break; case '7': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM7; break; case '8': port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM8; break; default: EHPrint("\eFF0000Invalid port! Defaulting to 1.\n"); break; } EHPrint("\eF8F8F8Dumping memory to UART port %c (%#lx) and %s inaccessible pages.\n", cPort[0], port, cBoolSkip[0] == '1' ? "skipping" : "zeroing"); Display->SetBuffer(SBIdx); uint64_t TotalMemLength = KernelAllocator.GetTotalMemory(); uint64_t ProgressLength = TotalMemLength; UniversalAsynchronousReceiverTransmitter::UART uart(port); Memory::Virtual vmm; uint8_t *Address = 0x0; int Progress = 0; for (size_t i = 0; i < TotalMemLength; i++) { if (vmm.Check(Address)) uart.Write(*Address); else if (cBoolSkip[0] == '0') uart.Write((uint8_t)0); else ProgressLength--; Address++; if (unlikely(i % 0x1000 == 0)) { int NewProgress = (int)((i * 100) / ProgressLength); if (unlikely(NewProgress != Progress)) { Progress = NewProgress; EHPrint("\n%d%%\n", Progress); Display->SetBuffer(SBIdx); } Display->Print('.', SBIdx); if (unlikely(i % 0x500 == 0)) Display->SetBuffer(SBIdx); } } EHPrint("\nDone.\n"); } else if (strcmp(Input, "main") == 0) { SBIdx = 255; DisplayTopOverlay(); DisplayMainScreen(crashdata); Display->SetBuffer(SBIdx); } else if (strcmp(Input, "details") == 0) { SBIdx = 254; DisplayTopOverlay(); DisplayDetailsScreen(crashdata); Display->SetBuffer(SBIdx); } else if (strcmp(Input, "frames") == 0) { SBIdx = 253; DisplayTopOverlay(); DisplayStackFrameScreen(crashdata); Display->SetBuffer(SBIdx); } else if (strcmp(Input, "tasks") == 0) { SBIdx = 252; DisplayTopOverlay(); DisplayTasksScreen(crashdata); Display->SetBuffer(SBIdx); } else if (strcmp(Input, "console") == 0) { SBIdx = 251; DisplayTopOverlay(); DisplayConsoleScreen(crashdata); Display->SetBuffer(SBIdx); } else if (strlen(Input) > 0) EHPrint("Unknown command: %s", Input); DisplayBottomOverlay(); Display->SetBuffer(SBIdx); } SafeFunction void StopAllCores() { #if defined(a86) /* FIXME: Can't send IPIs to other cores * because it causes another exception on * the other cores. * * Also it makes every core to stay at 100% usage for some reason. */ return; if (SMP::CPUCores > 1) { APIC::InterruptCommandRegister icr{}; bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC; if (likely(x2APIC)) { icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ31); icr.x2.MT = APIC::Fixed; icr.x2.L = APIC::Assert; for (int i = 1; i < SMP::CPUCores; i++) { icr.x2.DES = uint8_t(i); ((APIC::APIC *)Interrupts::apic[i])->ICR(icr); } } else { icr.VEC = s_cst(uint8_t, CPU::x86::IRQ31); icr.MT = APIC::Fixed; icr.L = APIC::Assert; for (int i = 1; i < SMP::CPUCores; i++) { icr.DES = uint8_t(i); ((APIC::APIC *)Interrupts::apic[i])->ICR(icr); } } CPU::Interrupts(CPU::Disable); } #elif defined(aa64) #endif } SafeFunction inline bool Handle_x86_64(CHArchTrapFrame *Frame) { #ifdef a64 trace("Exception at %s", KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip) : "No symbol"); for (size_t i = 0; i < INT_FRAMES_MAX; i++) EHIntFrames[i] = Interrupts::InterruptFrames[i]; PageFaultAddress = CPU::x64::readcr2().PFLA; if (unlikely(Frame->cs != GDT_USER_CODE && Frame->cs != GDT_USER_DATA)) { if (PageFaultAddress) { debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))", Frame->rip, PageFaultAddress, KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } else { debug("Exception in kernel mode (ip: %#lx (%s))", Frame->rip, KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } CPUData *data = GetCurrentCPU(); if (data) { if (data->CurrentThread) { if (!data->CurrentThread->Security.IsCritical) { fixme("Exception in non-critical thread (kernel mode)"); } } } if (TaskManager) TaskManager->Panic(); ForceUnlock = true; Display->CreateBuffer(0, 0, SBIdx); StopAllCores(); } else { CPUData *data = GetCurrentCPU(); if (PageFaultAddress) { debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))", Frame->rip, PageFaultAddress, data->CurrentProcess->ELFSymbolTable ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } else { debug("Exception in user mode (ip: %#lx (%s))", Frame->rip, data->CurrentProcess->ELFSymbolTable ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } if (UserModeExceptionHandler(Frame)) return true; else if (DebuggerIsAttached) asmv("int $0x8"); if (unlikely(data->CurrentThread->Security.IsCritical)) { error("Critical thread \"%s\"(%d) died", data->CurrentThread->Name, data->CurrentThread->ID); if (TaskManager) TaskManager->Panic(); ForceUnlock = true; Display->CreateBuffer(0, 0, SBIdx); StopAllCores(); return false; } Tasking::TCB *tcb = data->CurrentThread; CPU::Interrupts(CPU::Enable); while (true) { tcb->GetContext()->Yield(); CPU::Halt(TaskManager->IsPanic()); } } #endif return false; } SafeFunction inline bool Handle_x86_32(CHArchTrapFrame *Frame) { #ifdef a32 trace("Exception at %s", KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip) : "No symbol"); for (size_t i = 0; i < INT_FRAMES_MAX; i++) EHIntFrames[i] = Interrupts::InterruptFrames[i]; PageFaultAddress = CPU::x32::readcr2().PFLA; if (Frame->cs != GDT_USER_CODE && Frame->cs != GDT_USER_DATA) { CPUData *data = GetCurrentCPU(); if (PageFaultAddress) { debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))", Frame->eip, PageFaultAddress, data->CurrentProcess->ELFSymbolTable ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } else { debug("Exception in kernel mode (ip: %#lx (%s))", Frame->eip, data->CurrentProcess->ELFSymbolTable ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } if (UserModeExceptionHandler(Frame)) return true; else if (DebuggerIsAttached) asmv("int $0x8"); if (data->CurrentThread) { if (!data->CurrentThread->Security.IsCritical) { fixme("Exception in non-critical thread (kernel mode)"); } } if (TaskManager) TaskManager->Panic(); ForceUnlock = true; Display->CreateBuffer(0, 0, SBIdx); StopAllCores(); } else { CPUData *data = GetCurrentCPU(); if (PageFaultAddress) { debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))", Frame->eip, PageFaultAddress, KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } else { debug("Exception in user mode (ip: %#lx (%s))", Frame->eip, KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } if (UserModeExceptionHandler(Frame)) return true; else if (DebuggerIsAttached) asmv("int $0x8"); if (unlikely(data->CurrentThread->Security.IsCritical)) { error("Critical thread \"%s\"(%d) died", data->CurrentThread->Name, data->CurrentThread->ID); if (TaskManager) TaskManager->Panic(); ForceUnlock = true; Display->CreateBuffer(0, 0, SBIdx); StopAllCores(); return false; } Tasking::TCB *tcb = data->CurrentThread; CPU::Interrupts(CPU::Enable); while (true) { tcb->GetContext()->Yield(); CPU::Halt(TaskManager->IsPanic()); } } #endif return false; } SafeFunction inline void Print_x86_64(CHArchTrapFrame *Frame) { #ifdef a64 CPU::x64::CR0 cr0 = CPU::x64::readcr0(); CPU::x64::CR2 cr2 = CPU::x64::CR2{.PFLA = PageFaultAddress}; CPU::x64::CR3 cr3 = CPU::x64::readcr3(); CPU::x64::CR4 cr4 = CPU::x64::readcr4(); CPU::x64::CR8 cr8 = CPU::x64::readcr8(); CPU::x64::EFER efer; efer.raw = CPU::x64::rdmsr(CPU::x64::MSR_EFER); uintptr_t ds; asmv("mov %%ds, %0" : "=r"(ds)); EHPrint("\eFF2525FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx\n", CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE), Frame->ss, Frame->cs, ds); EHPrint("R8=%#lx R9=%#lx R10=%#lx R11=%#lx\n", Frame->r8, Frame->r9, Frame->r10, Frame->r11); EHPrint("R12=%#lx R13=%#lx R14=%#lx R15=%#lx\n", Frame->r12, Frame->r13, Frame->r14, Frame->r15); EHPrint("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx\n", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx); EHPrint("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx\n", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp); EHPrint("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx EFER=%#lx\n", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw); EHPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw); EHPrint("CR0: PE:%s MP:%s EM:%s TS:%s\n ET:%s NE:%s WP:%s AM:%s\n NW:%s CD:%s PG:%s\n R0:%#x R1:%#x R2:%#x\n", cr0.PE ? "True " : "False", cr0.MP ? "True " : "False", cr0.EM ? "True " : "False", cr0.TS ? "True " : "False", cr0.ET ? "True " : "False", cr0.NE ? "True " : "False", cr0.WP ? "True " : "False", cr0.AM ? "True " : "False", cr0.NW ? "True " : "False", cr0.CD ? "True " : "False", cr0.PG ? "True " : "False", cr0.Reserved0, cr0.Reserved1, cr0.Reserved2); EHPrint("CR2: PFLA: %#lx\n", cr2.PFLA); EHPrint("CR3: PWT:%s PCD:%s PDBR:%#lx\n", cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR); EHPrint("CR4: VME:%s PVI:%s TSD:%s DE:%s\n PSE:%s PAE:%s MCE:%s PGE:%s\n PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s\n LA57:%s VMXE:%s SMXE:%s PCIDE:%s\n OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s\n R0:%#x R1:%#x R2:%#x\n", cr4.VME ? "True " : "False", cr4.PVI ? "True " : "False", cr4.TSD ? "True " : "False", cr4.DE ? "True " : "False", cr4.PSE ? "True " : "False", cr4.PAE ? "True " : "False", cr4.MCE ? "True " : "False", cr4.PGE ? "True " : "False", cr4.PCE ? "True " : "False", cr4.UMIP ? "True " : "False", cr4.OSFXSR ? "True " : "False", cr4.OSXMMEXCPT ? "True " : "False", cr4.LA57 ? "True " : "False", cr4.VMXE ? "True " : "False", cr4.SMXE ? "True " : "False", cr4.PCIDE ? "True " : "False", cr4.OSXSAVE ? "True " : "False", cr4.SMEP ? "True " : "False", cr4.SMAP ? "True " : "False", cr4.PKE ? "True " : "False", cr4.Reserved0, cr4.Reserved1, cr4.Reserved2); EHPrint("CR8: TPL:%d\n", cr8.TPL); EHPrint("RFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x R3:%#x\n", Frame->rflags.CF ? "True " : "False", Frame->rflags.PF ? "True " : "False", Frame->rflags.AF ? "True " : "False", Frame->rflags.ZF ? "True " : "False", Frame->rflags.SF ? "True " : "False", Frame->rflags.TF ? "True " : "False", Frame->rflags.IF ? "True " : "False", Frame->rflags.DF ? "True " : "False", Frame->rflags.OF ? "True " : "False", Frame->rflags.IOPL ? "True " : "False", Frame->rflags.NT ? "True " : "False", Frame->rflags.RF ? "True " : "False", Frame->rflags.VM ? "True " : "False", Frame->rflags.AC ? "True " : "False", Frame->rflags.VIF ? "True " : "False", Frame->rflags.VIP ? "True " : "False", Frame->rflags.ID ? "True " : "False", Frame->rflags.AlwaysOne, Frame->rflags.Reserved0, Frame->rflags.Reserved1, Frame->rflags.Reserved2, Frame->rflags.Reserved3); EHPrint("EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n R0:%#x R1:%#x R2:%#x\n", efer.SCE ? "True " : "False", efer.LME ? "True " : "False", efer.LMA ? "True " : "False", efer.NXE ? "True " : "False", efer.SVME ? "True " : "False", efer.LMSLE ? "True " : "False", efer.FFXSR ? "True " : "False", efer.TCE ? "True " : "False", efer.Reserved0, efer.Reserved1, efer.Reserved2); #endif } SafeFunction inline void Print_x86_32(CHArchTrapFrame *Frame) { #ifdef a32 CPU::x32::CR0 cr0 = CPU::x32::readcr0(); CPU::x32::CR2 cr2 = CPU::x32::CR2{.PFLA = PageFaultAddress}; CPU::x32::CR3 cr3 = CPU::x32::readcr3(); CPU::x32::CR4 cr4 = CPU::x32::readcr4(); CPU::x32::CR8 cr8 = CPU::x32::readcr8(); uintptr_t ds; asmv("mov %%ds, %0" : "=r"(ds)); EHPrint("\eFF2525FS=%#x GS=%#x CS=%#x DS=%#x\n", CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE), Frame->cs, ds); EHPrint("EAX=%#x EBX=%#x ECX=%#x EDX=%#x\n", Frame->eax, Frame->ebx, Frame->ecx, Frame->edx); EHPrint("ESI=%#x EDI=%#x EBP=%#x ESP=%#x\n", Frame->esi, Frame->edi, Frame->ebp, Frame->esp); EHPrint("EIP=%#x EFL=%#x INT=%#x ERR=%#x\n", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode); EHPrint("CR0=%#x CR2=%#x CR3=%#x CR4=%#x CR8=%#x\n", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw); EHPrint("CR0: PE:%s MP:%s EM:%s TS:%s\n ET:%s NE:%s WP:%s AM:%s\n NW:%s CD:%s PG:%s\n R0:%#x R1:%#x R2:%#x\n", cr0.PE ? "True " : "False", cr0.MP ? "True " : "False", cr0.EM ? "True " : "False", cr0.TS ? "True " : "False", cr0.ET ? "True " : "False", cr0.NE ? "True " : "False", cr0.WP ? "True " : "False", cr0.AM ? "True " : "False", cr0.NW ? "True " : "False", cr0.CD ? "True " : "False", cr0.PG ? "True " : "False", cr0.Reserved0, cr0.Reserved1, cr0.Reserved2); EHPrint("CR2: PFLA: %#x\n", cr2.PFLA); EHPrint("CR3: PWT:%s PCD:%s PDBR:%#x\n", cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR); EHPrint("CR4: VME:%s PVI:%s TSD:%s DE:%s\n PSE:%s PAE:%s MCE:%s PGE:%s\n PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s\n LA57:%s VMXE:%s SMXE:%s PCIDE:%s\n OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s\n R0:%#x R1:%#x\n", cr4.VME ? "True " : "False", cr4.PVI ? "True " : "False", cr4.TSD ? "True " : "False", cr4.DE ? "True " : "False", cr4.PSE ? "True " : "False", cr4.PAE ? "True " : "False", cr4.MCE ? "True " : "False", cr4.PGE ? "True " : "False", cr4.PCE ? "True " : "False", cr4.UMIP ? "True " : "False", cr4.OSFXSR ? "True " : "False", cr4.OSXMMEXCPT ? "True " : "False", cr4.LA57 ? "True " : "False", cr4.VMXE ? "True " : "False", cr4.SMXE ? "True " : "False", cr4.PCIDE ? "True " : "False", cr4.OSXSAVE ? "True " : "False", cr4.SMEP ? "True " : "False", cr4.SMAP ? "True " : "False", cr4.PKE ? "True " : "False", cr4.Reserved0, cr4.Reserved1); EHPrint("CR8: TPL:%d\n", cr8.TPL); EHPrint("RFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x\n", Frame->eflags.CF ? "True " : "False", Frame->eflags.PF ? "True " : "False", Frame->eflags.AF ? "True " : "False", Frame->eflags.ZF ? "True " : "False", Frame->eflags.SF ? "True " : "False", Frame->eflags.TF ? "True " : "False", Frame->eflags.IF ? "True " : "False", Frame->eflags.DF ? "True " : "False", Frame->eflags.OF ? "True " : "False", Frame->eflags.IOPL ? "True " : "False", Frame->eflags.NT ? "True " : "False", Frame->eflags.RF ? "True " : "False", Frame->eflags.VM ? "True " : "False", Frame->eflags.AC ? "True " : "False", Frame->eflags.VIF ? "True " : "False", Frame->eflags.VIP ? "True " : "False", Frame->eflags.ID ? "True " : "False", Frame->eflags.AlwaysOne, Frame->eflags.Reserved0, Frame->eflags.Reserved1, Frame->eflags.Reserved2); #endif } SafeFunction void Handle(void *Data) { // TODO: SUPPORT SMP CPU::Interrupts(CPU::Disable); CHArchTrapFrame *Frame = (CHArchTrapFrame *)Data; SBIdx = 255; debug("-----------------------------------------------------------------------------------"); debug("%ld MiB / %ld MiB (%ld MiB Reserved)", TO_MiB(KernelAllocator.GetUsedMemory()), TO_MiB(KernelAllocator.GetTotalMemory()), TO_MiB(KernelAllocator.GetReservedMemory())); error("Exception: %#x", Frame->InterruptNumber); #if defined(a64) if (Handle_x86_64(Frame)) #elif defined(a32) if (Handle_x86_32(Frame)) #endif return; if (ExceptionOccurred) { SBIdx = 255; Display->ClearBuffer(SBIdx); Display->SetBufferCursor(SBIdx, 0, 0); #if defined(a64) Print_x86_64(Frame); #elif defined(a32) Print_x86_32(Frame); #endif EHPrint("\nException occurred while handling exception! HALTED!"); Display->SetBuffer(SBIdx); Interrupts::RemoveAll(); CPU::Stop(); } ExceptionOccurred = true; if (DriverManager) DriverManager->Panic(); debug("Reading control registers..."); crashdata.Frame = Frame; #if defined(a64) crashdata.cr0 = CPU::x64::readcr0(); crashdata.cr2 = CPU::x64::CR2{.PFLA = PageFaultAddress}; crashdata.cr3 = CPU::x64::readcr3(); crashdata.cr4 = CPU::x64::readcr4(); crashdata.cr8 = CPU::x64::readcr8(); crashdata.efer.raw = CPU::x64::rdmsr(CPU::x64::MSR_EFER); #elif defined(a32) crashdata.cr0 = CPU::x32::readcr0(); crashdata.cr2 = CPU::x32::CR2{.PFLA = PageFaultAddress}; crashdata.cr3 = CPU::x32::readcr3(); crashdata.cr4 = CPU::x32::readcr4(); crashdata.cr8 = CPU::x32::readcr8(); #endif uintptr_t ds; asmv("mov %%ds, %0" : "=r"(ds)); // Get debug registers #ifdef a64 asmv("movq %%dr0, %0" : "=r"(crashdata.dr0)); asmv("movq %%dr1, %0" : "=r"(crashdata.dr1)); asmv("movq %%dr2, %0" : "=r"(crashdata.dr2)); asmv("movq %%dr3, %0" : "=r"(crashdata.dr3)); asmv("movq %%dr6, %0" : "=r"(crashdata.dr6.raw)); asmv("movq %%dr7, %0" : "=r"(crashdata.dr7.raw)); #endif CPUData *cpudata = GetCurrentCPU(); if (cpudata == nullptr) { EHPrint("\eFFA500Invalid CPU data!\n"); for (long i = 0; i < MAX_CPU; i++) { cpudata = GetCPU(i); if (cpudata != nullptr) break; if (i == MAX_CPU - 1) { EHPrint("\eFF0000No CPU data found!\n"); cpudata = nullptr; } } debug("CPU ptr %#lx", cpudata); } if (cpudata != nullptr) { crashdata.ID = cpudata->ID; crashdata.CPUData = cpudata; error("Technical Informations on CPU %d:", cpudata->ID); } if (TaskManager && cpudata != nullptr) { crashdata.Process = cpudata->CurrentProcess.load(); crashdata.Thread = cpudata->CurrentThread.load(); error("Current Process: %s(%ld)", cpudata->CurrentProcess->Name, cpudata->CurrentProcess->ID); error("Current Thread: %s(%ld)", cpudata->CurrentThread->Name, cpudata->CurrentThread->ID); } { #if defined(a64) error("FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx", CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE), Frame->ss, Frame->cs, ds); error("R8=%#llx R9=%#llx R10=%#llx R11=%#llx", Frame->r8, Frame->r9, Frame->r10, Frame->r11); error("R12=%#llx R13=%#llx R14=%#llx R15=%#llx", Frame->r12, Frame->r13, Frame->r14, Frame->r15); error("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx); error("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp); error("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, crashdata.efer.raw); error("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx", crashdata.cr0.raw, crashdata.cr2.raw, crashdata.cr3.raw, crashdata.cr4.raw, crashdata.cr8.raw); error("DR0=%#llx DR1=%#llx DR2=%#llx DR3=%#llx DR6=%#llx DR7=%#llx", crashdata.dr0, crashdata.dr1, crashdata.dr2, crashdata.dr3, crashdata.dr6.raw, crashdata.dr7.raw); error("CR0: PE:%s MP:%s EM:%s TS:%s ET:%s NE:%s WP:%s AM:%s NW:%s CD:%s PG:%s R0:%#x R1:%#x R2:%#x", crashdata.cr0.PE ? "True " : "False", crashdata.cr0.MP ? "True " : "False", crashdata.cr0.EM ? "True " : "False", crashdata.cr0.TS ? "True " : "False", crashdata.cr0.ET ? "True " : "False", crashdata.cr0.NE ? "True " : "False", crashdata.cr0.WP ? "True " : "False", crashdata.cr0.AM ? "True " : "False", crashdata.cr0.NW ? "True " : "False", crashdata.cr0.CD ? "True " : "False", crashdata.cr0.PG ? "True " : "False", crashdata.cr0.Reserved0, crashdata.cr0.Reserved1, crashdata.cr0.Reserved2); error("CR2: PFLA: %#llx", crashdata.cr2.PFLA); error("CR3: PWT:%s PCD:%s PDBR:%#llx", crashdata.cr3.PWT ? "True " : "False", crashdata.cr3.PCD ? "True " : "False", crashdata.cr3.PDBR); error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x R2:%#x", crashdata.cr4.VME ? "True " : "False", crashdata.cr4.PVI ? "True " : "False", crashdata.cr4.TSD ? "True " : "False", crashdata.cr4.DE ? "True " : "False", crashdata.cr4.PSE ? "True " : "False", crashdata.cr4.PAE ? "True " : "False", crashdata.cr4.MCE ? "True " : "False", crashdata.cr4.PGE ? "True " : "False", crashdata.cr4.PCE ? "True " : "False", crashdata.cr4.UMIP ? "True " : "False", crashdata.cr4.OSFXSR ? "True " : "False", crashdata.cr4.OSXMMEXCPT ? "True " : "False", crashdata.cr4.LA57 ? "True " : "False", crashdata.cr4.VMXE ? "True " : "False", crashdata.cr4.SMXE ? "True " : "False", crashdata.cr4.PCIDE ? "True " : "False", crashdata.cr4.OSXSAVE ? "True " : "False", crashdata.cr4.SMEP ? "True " : "False", crashdata.cr4.SMAP ? "True " : "False", crashdata.cr4.PKE ? "True " : "False", crashdata.cr4.Reserved0, crashdata.cr4.Reserved1, crashdata.cr4.Reserved2); error("CR8: TPL:%d", crashdata.cr8.TPL); error("RFL: CF:%s PF:%s AF:%s ZF:%s SF:%s TF:%s IF:%s DF:%s OF:%s IOPL:%s NT:%s RF:%s VM:%s AC:%s VIF:%s VIP:%s ID:%s AlwaysOne:%d R0:%#x R1:%#x R2:%#x R3:%#x", Frame->rflags.CF ? "True " : "False", Frame->rflags.PF ? "True " : "False", Frame->rflags.AF ? "True " : "False", Frame->rflags.ZF ? "True " : "False", Frame->rflags.SF ? "True " : "False", Frame->rflags.TF ? "True " : "False", Frame->rflags.IF ? "True " : "False", Frame->rflags.DF ? "True " : "False", Frame->rflags.OF ? "True " : "False", Frame->rflags.IOPL ? "True " : "False", Frame->rflags.NT ? "True " : "False", Frame->rflags.RF ? "True " : "False", Frame->rflags.VM ? "True " : "False", Frame->rflags.AC ? "True " : "False", Frame->rflags.VIF ? "True " : "False", Frame->rflags.VIP ? "True " : "False", Frame->rflags.ID ? "True " : "False", Frame->rflags.AlwaysOne, Frame->rflags.Reserved0, Frame->rflags.Reserved1, Frame->rflags.Reserved2, Frame->rflags.Reserved3); error("DR6: B0:%s B1:%s B2:%s B3:%s BD:%s BS:%s BT:%s", crashdata.dr6.B0 ? "True " : "False", crashdata.dr6.B1 ? "True " : "False", crashdata.dr6.B2 ? "True " : "False", crashdata.dr6.B3 ? "True " : "False", crashdata.dr6.BD ? "True " : "False", crashdata.dr6.BS ? "True " : "False", crashdata.dr6.BT ? "True " : "False"); error("DR7: L0:%s G0:%s L1:%s G1:%s L2:%s G2:%s L3:%s G3:%s LE:%s GE:%s GD:%s R/W0:%s LEN0:%s R/W1:%s LEN1:%s R/W2:%s LEN2:%s R/W3:%s LEN3:%s", crashdata.dr7.L0 ? "True " : "False", crashdata.dr7.G0 ? "True " : "False", crashdata.dr7.L1 ? "True " : "False", crashdata.dr7.G1 ? "True " : "False", crashdata.dr7.L2 ? "True " : "False", crashdata.dr7.G2 ? "True " : "False", crashdata.dr7.L3 ? "True " : "False", crashdata.dr7.G3 ? "True " : "False", crashdata.dr7.LE ? "True " : "False", crashdata.dr7.GE ? "True " : "False", crashdata.dr7.GD ? "True " : "False", crashdata.dr7.RW0 ? "True " : "False", crashdata.dr7.LEN0 ? "True " : "False", crashdata.dr7.RW1 ? "True " : "False", crashdata.dr7.LEN1 ? "True " : "False", crashdata.dr7.RW2 ? "True " : "False", crashdata.dr7.LEN2 ? "True " : "False", crashdata.dr7.RW3 ? "True " : "False", crashdata.dr7.LEN3 ? "True " : "False"); error("EFER: SCE:%s LME:%s LMA:%s NXE:%s SVME:%s LMSLE:%s FFXSR:%s TCE:%s R0:%#x R1:%#x R2:%#x", crashdata.efer.SCE ? "True " : "False", crashdata.efer.LME ? "True " : "False", crashdata.efer.LMA ? "True " : "False", crashdata.efer.NXE ? "True " : "False", crashdata.efer.SVME ? "True " : "False", crashdata.efer.LMSLE ? "True " : "False", crashdata.efer.FFXSR ? "True " : "False", crashdata.efer.TCE ? "True " : "False", crashdata.efer.Reserved0, crashdata.efer.Reserved1, crashdata.efer.Reserved2); #elif defined(a32) error("FS=%#x GS=%#x CS=%#x DS=%#x", CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE), Frame->cs, ds); error("EAX=%#x EBX=%#x ECX=%#x EDX=%#x", Frame->eax, Frame->ebx, Frame->ecx, Frame->edx); error("ESI=%#x EDI=%#x EBP=%#x ESP=%#x", Frame->esi, Frame->edi, Frame->ebp, Frame->esp); error("EIP=%#x EFL=%#x INT=%#x ERR=%#x", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode); error("CR0=%#x CR2=%#x CR3=%#x CR4=%#x CR8=%#x", crashdata.cr0.raw, crashdata.cr2.raw, crashdata.cr3.raw, crashdata.cr4.raw, crashdata.cr8.raw); error("DR0=%#x DR1=%#x DR2=%#x DR3=%#x DR6=%#x DR7=%#x", crashdata.dr0, crashdata.dr1, crashdata.dr2, crashdata.dr3, crashdata.dr6.raw, crashdata.dr7.raw); error("CR0: PE:%s MP:%s EM:%s TS:%s ET:%s NE:%s WP:%s AM:%s NW:%s CD:%s PG:%s R0:%#x R1:%#x R2:%#x", crashdata.cr0.PE ? "True " : "False", crashdata.cr0.MP ? "True " : "False", crashdata.cr0.EM ? "True " : "False", crashdata.cr0.TS ? "True " : "False", crashdata.cr0.ET ? "True " : "False", crashdata.cr0.NE ? "True " : "False", crashdata.cr0.WP ? "True " : "False", crashdata.cr0.AM ? "True " : "False", crashdata.cr0.NW ? "True " : "False", crashdata.cr0.CD ? "True " : "False", crashdata.cr0.PG ? "True " : "False", crashdata.cr0.Reserved0, crashdata.cr0.Reserved1, crashdata.cr0.Reserved2); error("CR2: PFLA: %#x", crashdata.cr2.PFLA); error("CR3: PWT:%s PCD:%s PDBR:%#x", crashdata.cr3.PWT ? "True " : "False", crashdata.cr3.PCD ? "True " : "False", crashdata.cr3.PDBR); error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x", crashdata.cr4.VME ? "True " : "False", crashdata.cr4.PVI ? "True " : "False", crashdata.cr4.TSD ? "True " : "False", crashdata.cr4.DE ? "True " : "False", crashdata.cr4.PSE ? "True " : "False", crashdata.cr4.PAE ? "True " : "False", crashdata.cr4.MCE ? "True " : "False", crashdata.cr4.PGE ? "True " : "False", crashdata.cr4.PCE ? "True " : "False", crashdata.cr4.UMIP ? "True " : "False", crashdata.cr4.OSFXSR ? "True " : "False", crashdata.cr4.OSXMMEXCPT ? "True " : "False", crashdata.cr4.LA57 ? "True " : "False", crashdata.cr4.VMXE ? "True " : "False", crashdata.cr4.SMXE ? "True " : "False", crashdata.cr4.PCIDE ? "True " : "False", crashdata.cr4.OSXSAVE ? "True " : "False", crashdata.cr4.SMEP ? "True " : "False", crashdata.cr4.SMAP ? "True " : "False", crashdata.cr4.PKE ? "True " : "False", crashdata.cr4.Reserved0, crashdata.cr4.Reserved1); error("CR8: TPL:%d", crashdata.cr8.TPL); error("RFL: CF:%s PF:%s AF:%s ZF:%s SF:%s TF:%s IF:%s DF:%s OF:%s IOPL:%s NT:%s RF:%s VM:%s AC:%s VIF:%s VIP:%s ID:%s AlwaysOne:%d R0:%#x R1:%#x R2:%#x", Frame->eflags.CF ? "True " : "False", Frame->eflags.PF ? "True " : "False", Frame->eflags.AF ? "True " : "False", Frame->eflags.ZF ? "True " : "False", Frame->eflags.SF ? "True " : "False", Frame->eflags.TF ? "True " : "False", Frame->eflags.IF ? "True " : "False", Frame->eflags.DF ? "True " : "False", Frame->eflags.OF ? "True " : "False", Frame->eflags.IOPL ? "True " : "False", Frame->eflags.NT ? "True " : "False", Frame->eflags.RF ? "True " : "False", Frame->eflags.VM ? "True " : "False", Frame->eflags.AC ? "True " : "False", Frame->eflags.VIF ? "True " : "False", Frame->eflags.VIP ? "True " : "False", Frame->eflags.ID ? "True " : "False", Frame->eflags.AlwaysOne, Frame->eflags.Reserved0, Frame->eflags.Reserved1, Frame->eflags.Reserved2); error("DR6: B0:%s B1:%s B2:%s B3:%s BD:%s BS:%s BT:%s", crashdata.dr6.B0 ? "True " : "False", crashdata.dr6.B1 ? "True " : "False", crashdata.dr6.B2 ? "True " : "False", crashdata.dr6.B3 ? "True " : "False", crashdata.dr6.BD ? "True " : "False", crashdata.dr6.BS ? "True " : "False", crashdata.dr6.BT ? "True " : "False"); error("DR7: L0:%s G0:%s L1:%s G1:%s L2:%s G2:%s L3:%s G3:%s LE:%s GE:%s GD:%s R/W0:%s LEN0:%s R/W1:%s LEN1:%s R/W2:%s LEN2:%s R/W3:%s LEN3:%s", crashdata.dr7.L0 ? "True " : "False", crashdata.dr7.G0 ? "True " : "False", crashdata.dr7.L1 ? "True " : "False", crashdata.dr7.G1 ? "True " : "False", crashdata.dr7.L2 ? "True " : "False", crashdata.dr7.G2 ? "True " : "False", crashdata.dr7.L3 ? "True " : "False", crashdata.dr7.G3 ? "True " : "False", crashdata.dr7.LE ? "True " : "False", crashdata.dr7.GE ? "True " : "False", crashdata.dr7.GD ? "True " : "False", crashdata.dr7.RW0 ? "True " : "False", crashdata.dr7.LEN0 ? "True " : "False", crashdata.dr7.RW1 ? "True " : "False", crashdata.dr7.LEN1 ? "True " : "False", crashdata.dr7.RW2 ? "True " : "False", crashdata.dr7.LEN2 ? "True " : "False", crashdata.dr7.RW3 ? "True " : "False", crashdata.dr7.LEN3 ? "True " : "False"); #endif } if (Config.InterruptsOnCrash) { // 255 // Main Display->CreateBuffer(0, 0, 254); // Details Display->CreateBuffer(0, 0, 253); // Frames Display->CreateBuffer(0, 0, 252); // Tasks Display->CreateBuffer(0, 0, 251); // Console Display->CreateBuffer(0, 0, 250); // Empty DisplayTopOverlay(); DisplayMainScreen(crashdata); Display->SetBuffer(255); Interrupts::RemoveAll(); kbd = new CrashKeyboardDriver; DisplayBottomOverlay(); Display->SetBuffer(255); } else { /* TODO: Stuff that should be done when IOC is disabled. */ Display->SetBuffer(255); } CPU::Halt(true); } }