Revamped kernel panic functions with significant improvements

This commit is contained in:
EnderIce2 2024-02-28 06:31:02 +02:00
parent ddad5ca38a
commit 5fd8d3b3a5
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
23 changed files with 2057 additions and 3573 deletions

View File

@ -1,348 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../crashhandler.hpp"
#include "chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../kernel.h"
static const char *PageFaultDescriptions[8] = {
"Supervisory process tried to read a non-present page entry\n",
"Supervisory process tried to read a page and caused a protection fault\n",
"Supervisory process tried to write to a non-present page entry\n",
"Supervisory process tried to write a page and caused a protection fault\n",
"User process tried to read a non-present page entry\n",
"User process tried to read a page and caused a protection fault\n",
"User process tried to write to a non-present page entry\n",
"User process tried to write a page and caused a protection fault\n"};
nsa void DivideByZeroExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Divide by zero exception\n");
UNUSED(Frame);
}
nsa void DebugExceptionHandler(CPU::TrapFrame *Frame)
{
CrashHandler::EHPrint("Kernel triggered debug exception.\n");
UNUSED(Frame);
}
nsa void NonMaskableInterruptExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("NMI exception");
UNUSED(Frame);
}
nsa void BreakpointExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Breakpoint exception");
UNUSED(Frame);
}
nsa void OverflowExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Overflow exception");
UNUSED(Frame);
}
nsa void BoundRangeExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Bound range exception");
UNUSED(Frame);
}
nsa void InvalidOpcodeExceptionHandler(CPU::TrapFrame *Frame)
{
CrashHandler::EHPrint("Kernel tried to execute an invalid opcode.\n");
UNUSED(Frame);
}
nsa void DeviceNotAvailableExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Device not available exception");
UNUSED(Frame);
}
nsa void DoubleFaultExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Double fault exception");
UNUSED(Frame);
}
nsa void CoprocessorSegmentOverrunExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Coprocessor segment overrun exception");
UNUSED(Frame);
}
nsa void InvalidTSSExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Invalid TSS exception");
UNUSED(Frame);
}
nsa void SegmentNotPresentExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Segment not present exception");
UNUSED(Frame);
}
nsa void StackFaultExceptionHandler(CPU::TrapFrame *Frame)
{
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
#if defined(a64)
CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->rip);
#elif defined(a32)
CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->eip);
#elif defined(aa64)
#endif
CrashHandler::EHPrint("External: %d\n", SelCode.External);
CrashHandler::EHPrint("Table: %d\n", SelCode.Table);
CrashHandler::EHPrint("Index: %#x\n", SelCode.Idx);
CrashHandler::EHPrint("Error code: %#lx\n", Frame->ErrorCode);
}
nsa void GeneralProtectionExceptionHandler(CPU::TrapFrame *Frame)
{
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
// switch (SelCode.Table)
// {
// case CPU::x64::0b00:
// memcpy(desc_tmp, "GDT", 3);
// break;
// case CPU::x64::0b01:
// memcpy(desc_tmp, "IDT", 3);
// break;
// case CPU::x64::0b10:
// memcpy(desc_tmp, "LDT", 3);
// break;
// case CPU::x64::0b11:
// memcpy(desc_tmp, "IDT", 3);
// break;
// default:
// memcpy(desc_tmp, "Unknown", 7);
// break;
// }
CrashHandler::EHPrint("Kernel performed an illegal operation.\n");
CrashHandler::EHPrint("External: %d\n", SelCode.External);
CrashHandler::EHPrint("Table: %d\n", SelCode.Table);
CrashHandler::EHPrint("Index: %#x\n", SelCode.Idx);
}
nsa void PageFaultExceptionHandler(CPU::TrapFrame *Frame)
{
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
#if defined(a64)
CrashHandler::EHPrint("\eAFAFAFAn exception occurred at %#lx by %#lx\n", CrashHandler::PageFaultAddress, Frame->rip);
#elif defined(a32)
CrashHandler::EHPrint("\eAFAFAFAn exception occurred at %#lx by %#lx\n", CrashHandler::PageFaultAddress, Frame->eip);
#elif defined(aa64)
#endif
CrashHandler::EHPrint("Page: %s\n", params.P ? "Present" : "Not Present");
CrashHandler::EHPrint("Write Operation: %s\n", params.W ? "Read-Only" : "Read-Write");
CrashHandler::EHPrint("Processor Mode: %s\n", params.U ? "User-Mode" : "Kernel-Mode");
CrashHandler::EHPrint("CPU Reserved Bits: %s\n", params.R ? "Reserved" : "Unreserved");
CrashHandler::EHPrint("Caused By An Instruction Fetch: %s\n", params.I ? "Yes" : "No");
CrashHandler::EHPrint("Caused By A Protection-Key Violation: %s\n", params.PK ? "Yes" : "No");
CrashHandler::EHPrint("Caused By A Shadow Stack Access: %s\n", params.SS ? "Yes" : "No");
CrashHandler::EHPrint("Caused By An SGX Violation: %s\n", params.SGX ? "Yes" : "No");
if (Frame->ErrorCode & 0x00000008)
CrashHandler::EHPrint("One or more page directory entries contain reserved bits which are set to 1.\n");
else
CrashHandler::EHPrint(PageFaultDescriptions[Frame->ErrorCode & 0b111]);
#ifdef DEBUG
uintptr_t CheckPageFaultAddress = 0;
CheckPageFaultAddress = CrashHandler::PageFaultAddress;
if (CheckPageFaultAddress == 0)
#ifdef a64
CheckPageFaultAddress = Frame->rip;
#elif defined(a32)
CheckPageFaultAddress = Frame->eip;
#elif defined(aa64)
CheckPageFaultAddress = 0;
#endif
#if defined(a64)
Memory::Virtual vmm(((Memory::PageTable *)CPU::x64::readcr3().raw));
#elif defined(a32)
Memory::Virtual vmm(((Memory::PageTable *)CPU::x32::readcr3().raw));
#elif defined(aa64)
Memory::Virtual vmm();
#warning "TODO: aa64"
#endif
bool PageAvailable = vmm.Check((void *)CheckPageFaultAddress);
debug("Page available (Check(...)): %s. %s",
PageAvailable ? "Yes" : "No",
(params.P && !PageAvailable) ? "CR2 == Present; Check() != Present??????" : "CR2 confirms Check() result.");
if (PageAvailable)
{
bool Present = vmm.Check((void *)CheckPageFaultAddress);
bool ReadWrite = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW);
bool User = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US);
bool WriteThrough = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT);
bool CacheDisabled = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD);
bool Accessed = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A);
bool Dirty = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D);
bool Global = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::G);
/* ... */
debug("Page available: %s", Present ? "Yes" : "No");
debug("Page read/write: %s", ReadWrite ? "Yes" : "No");
debug("Page user/kernel: %s", User ? "User" : "Kernel");
debug("Page write-through: %s", WriteThrough ? "Yes" : "No");
debug("Page cache disabled: %s", CacheDisabled ? "Yes" : "No");
debug("Page accessed: %s", Accessed ? "Yes" : "No");
debug("Page dirty: %s", Dirty ? "Yes" : "No");
debug("Page global: %s", Global ? "Yes" : "No");
if (Present)
{
#if defined(a64)
uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress;
CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000;
debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress);
Memory::Virtual::PageMapIndexer Index = Memory::Virtual::PageMapIndexer((uintptr_t)CheckPageFaultLinearAddress);
debug("Index for %#lx is PML:%d PDPTE:%d PDE:%d PTE:%d",
CheckPageFaultLinearAddress,
Index.PMLIndex,
Index.PDPTEIndex,
Index.PDEIndex,
Index.PTEIndex);
#if defined(a64)
Memory::PageMapLevel4 PML4 = ((Memory::PageTable *)CPU::x64::readcr3().raw)->Entries[Index.PMLIndex];
#elif defined(a32)
Memory::PageMapLevel4 PML4 = ((Memory::PageTable *)CPU::x32::readcr3().raw)->Entries[Index.PMLIndex];
#elif defined(aa64)
Memory::PageMapLevel4 PML4 = {.raw = 0};
#warning "TODO: aa64"
#endif
Memory::PageDirectoryPointerTableEntryPtr *PDPTE = (Memory::PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
Memory::PageDirectoryEntryPtr *PDE = (Memory::PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
Memory::PageTableEntryPtr *PTE = (Memory::PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
Index.PMLIndex, 0, 0, 0,
PML4.Present ? "1" : "0",
PML4.ReadWrite ? "1" : "0",
PML4.UserSupervisor ? "1" : "0",
PML4.WriteThrough ? "1" : "0",
PML4.CacheDisable ? "1" : "0",
PML4.Accessed ? "1" : "0",
PML4.ExecuteDisable ? "1" : "0",
PML4.GetAddress() << 12);
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
Index.PMLIndex, Index.PDPTEIndex, 0, 0,
PDPTE->Entries[Index.PDPTEIndex].Present ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].ReadWrite ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].UserSupervisor ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].WriteThrough ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].CacheDisable ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].Accessed ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].ExecuteDisable ? "1" : "0",
PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, 0,
PDE->Entries[Index.PDEIndex].Present ? "1" : "0",
PDE->Entries[Index.PDEIndex].ReadWrite ? "1" : "0",
PDE->Entries[Index.PDEIndex].UserSupervisor ? "1" : "0",
PDE->Entries[Index.PDEIndex].WriteThrough ? "1" : "0",
PDE->Entries[Index.PDEIndex].CacheDisable ? "1" : "0",
PDE->Entries[Index.PDEIndex].Accessed ? "1" : "0",
PDE->Entries[Index.PDEIndex].ExecuteDisable ? "1" : "0",
PDE->Entries[Index.PDEIndex].GetAddress() << 12);
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s D:%s PAT:%s G:%s PK:%d NX:%s Address:%#lx",
Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, Index.PTEIndex,
PTE->Entries[Index.PTEIndex].Present ? "1" : "0",
PTE->Entries[Index.PTEIndex].ReadWrite ? "1" : "0",
PTE->Entries[Index.PTEIndex].UserSupervisor ? "1" : "0",
PTE->Entries[Index.PTEIndex].WriteThrough ? "1" : "0",
PTE->Entries[Index.PTEIndex].CacheDisable ? "1" : "0",
PTE->Entries[Index.PTEIndex].Accessed ? "1" : "0",
PTE->Entries[Index.PTEIndex].Dirty ? "1" : "0",
PTE->Entries[Index.PTEIndex].PageAttributeTable ? "1" : "0",
PTE->Entries[Index.PTEIndex].Global ? "1" : "0",
PTE->Entries[Index.PTEIndex].ProtectionKey,
PTE->Entries[Index.PTEIndex].ExecuteDisable ? "1" : "0",
PTE->Entries[Index.PTEIndex].GetAddress() << 12);
#endif
}
}
#endif
}
nsa void x87FloatingPointExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("x87 floating point exception");
UNUSED(Frame);
}
nsa void AlignmentCheckExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Alignment check exception");
UNUSED(Frame);
}
nsa void MachineCheckExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Machine check exception");
UNUSED(Frame);
}
nsa void SIMDFloatingPointExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("SIMD floating point exception");
UNUSED(Frame);
}
nsa void VirtualizationExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Virtualization exception");
UNUSED(Frame);
}
nsa void SecurityExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Security exception");
UNUSED(Frame);
}
nsa void UnknownExceptionHandler(CPU::TrapFrame *Frame)
{
fixme("Unknown exception");
UNUSED(Frame);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,291 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../crashhandler.hpp"
#include "chfcts.hpp"
#include <display.hpp>
#include <convert.h>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#include <io.h>
#if defined(a64)
#include "../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../kernel.h"
const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y',
'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g',
'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '};
const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^',
'&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G',
'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '};
static int LowerCase = true;
static inline int GetLetterFromScanCode(uint8_t ScanCode)
{
if (ScanCode & 0x80)
{
switch (ScanCode)
{
case KEY_U_LSHIFT:
LowerCase = true;
return KEY_INVALID;
case KEY_U_RSHIFT:
LowerCase = true;
return KEY_INVALID;
default:
return KEY_INVALID;
}
}
else
{
switch (ScanCode)
{
case KEY_D_RETURN:
return '\n';
case KEY_D_LSHIFT:
LowerCase = false;
return KEY_INVALID;
case KEY_D_RSHIFT:
LowerCase = false;
return KEY_INVALID;
case KEY_D_BACKSPACE:
return ScanCode;
default:
{
if (ScanCode > 0x39)
break;
if (LowerCase)
return sc_ascii_low[ScanCode];
else
return sc_ascii_high[ScanCode];
}
}
}
return KEY_INVALID;
}
namespace CrashHandler
{
void CrashKeyboardDriver::PS2Wait(bool Read)
{
int Timeout = 100000;
uint8_t Status = 0;
while (Timeout--)
{
Status = inb(0x64);
if (Read)
{
if ((Status & 1) == 1)
return;
}
else
{
if ((Status & 2) == 0)
return;
}
}
}
CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */
{
#define WaitRead PS2Wait(true)
#define WaitWrite PS2Wait(false)
CPU::Interrupts(CPU::Disable);
#if defined(a86)
/* Disable Port 1 */
WaitWrite;
outb(0x64, 0xAD);
/* Disable Port 2 */
WaitWrite;
outb(0x64, 0xA7);
/* Flush */
WaitRead;
inb(0x60);
/* Test PS/2 controller */
WaitWrite;
outb(0x64, 0xAA);
WaitRead;
uint8_t test = inb(0x60);
if (test != 0x55)
{
if (test == 0xFA)
warn("PS/2 controller acknowledged? (expected TEST_PASSED = 0x55)");
else
{
error("PS/2 controller self test failed (%#x)", test);
// CPU::Stop();
}
}
/* Enable Port 1 */
WaitWrite;
outb(0x64, 0xAE);
/* Reset Port 1 */
WaitWrite;
outb(0x64, 0xFF); /* This may break some keyboards? */
/* Test Port 1 */
WaitWrite;
outb(0x64, 0xAB);
WaitRead;
test = inb(0x60);
if (test != 0x00)
{
if (test == 0xFA)
warn("PS/2 keyboard acknowledged? (expected TEST_PASSED = 0x00)");
else
{
error("PS/2 keyboard self test failed (%#x)", test);
// CPU::Stop();
}
}
/* Disable Port 1 */
WaitWrite;
outb(0x64, 0xAD);
/* Disable Port 2 */
WaitWrite;
outb(0x64, 0xA7);
/* Flush Port 1 */
WaitRead;
inb(0x60);
/* Read Controller Configuration */
WaitWrite;
outb(0x64, 0x20);
WaitRead;
uint8_t cfg = inb(0x60);
/* Enable Port 1 & Port 1 translation */
cfg |= 0b01000001;
/* Write Controller Configuration */
WaitWrite;
outb(0x64, 0x60);
WaitWrite;
outb(0x60, cfg);
/* Enable Port 1 */
outb(0x64, 0xAE);
/* Set scan code set 1 */
WaitWrite;
outb(0x60, 0xF0);
WaitWrite;
outb(0x60, 0x02);
/* Check if we have scan code set 1 */
WaitWrite;
outb(0x60, 0xF0);
WaitWrite;
outb(0x60, 0x00);
/* Read scan code set */
WaitRead;
uint8_t scs = inb(0x60);
if (scs != 0x41)
{
warn("PS/2 keyboard scan code set 1 not supported (%#x)", scs);
}
#endif // defined(a86)
CPU::Interrupts(CPU::Enable);
}
CrashKeyboardDriver::~CrashKeyboardDriver()
{
error("CrashKeyboardDriver::~CrashKeyboardDriver() called");
}
int BackSpaceLimit = 0;
static char UserInputBuffer[1024];
nsa void CrashKeyboardDriver::OnInterruptReceived(CPU::TrapFrame *Frame)
{
#if defined(a86)
UNUSED(Frame);
uint8_t scanCode = inb(0x60);
if (scanCode == KEY_D_TAB ||
scanCode == KEY_D_LCTRL ||
scanCode == KEY_D_LALT ||
scanCode == KEY_U_LCTRL ||
scanCode == KEY_U_LALT)
return;
switch (scanCode)
{
case KEY_D_UP:
case KEY_D_LEFT:
case KEY_D_RIGHT:
case KEY_D_DOWN:
ArrowInput(scanCode);
break;
default:
break;
}
int key = GetLetterFromScanCode(scanCode);
if (key != KEY_INVALID)
{
if (key == KEY_D_BACKSPACE)
{
if (BackSpaceLimit > 0)
{
Display->Print('\b');
backspace(UserInputBuffer);
BackSpaceLimit--;
}
}
else if (key == '\n')
{
UserInput(UserInputBuffer);
BackSpaceLimit = 0;
UserInputBuffer[0] = '\0';
}
else
{
append(UserInputBuffer, s_cst(char, key));
Display->Print((char)key);
BackSpaceLimit++;
}
Display->UpdateBuffer(); /* Update as we type. */
}
#endif // a64 || a32
}
}

View File

@ -1,42 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../../crashhandler.hpp"
#include "../chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../../kernel.h"
namespace CrashHandler
{
nsa void DisplayConsoleScreen(CRData data)
{
EHPrint("TODO");
UNUSED(data);
}
}

View File

@ -1,265 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../../crashhandler.hpp"
#include "../chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../../kernel.h"
namespace CrashHandler
{
nsa void DisplayDetailsScreen(CRData data)
{
if (data.Process)
EHPrint("\e7981FCCurrent Process: %s(%ld)\n",
data.Process->Name,
data.Process->ID);
if (data.Thread)
EHPrint("\e7981FCCurrent Thread: %s(%ld)\n",
data.Thread->Name,
data.Thread->ID);
EHPrint("\e7981FCTechnical Informations on CPU %lld:\n", data.ID);
uintptr_t ds;
#if defined(a64)
CPUData *cpu = (CPUData *)data.CPUData;
if (cpu)
{
EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu);
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n",
cpu->Stack, cpu->ID, cpu->ErrorCode);
EHPrint("Is Active: %s\n", cpu->IsActive ? "true" : "false");
EHPrint("Current Process: %#lx, Current Thread: %#lx\n",
cpu->CurrentProcess.load(), cpu->CurrentThread.load());
EHPrint("Arch Specific Data: %#lx\n", cpu->Data);
EHPrint("Checksum: 0x%X\n", cpu->Checksum);
}
asmv("mov %%ds, %0"
: "=r"(ds));
#elif defined(a32)
asmv("mov %%ds, %0"
: "=r"(ds));
#elif defined(aa64)
#endif
#if defined(a64)
EHPrint("\e7981FCFS=%#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),
data.Frame->ss, data.Frame->cs, ds);
EHPrint("R8=%#lx R9=%#lx R10=%#lx R11=%#lx\n", data.Frame->r8, data.Frame->r9, data.Frame->r10, data.Frame->r11);
EHPrint("R12=%#lx R13=%#lx R14=%#lx R15=%#lx\n", data.Frame->r12, data.Frame->r13, data.Frame->r14, data.Frame->r15);
EHPrint("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx\n", data.Frame->rax, data.Frame->rbx, data.Frame->rcx, data.Frame->rdx);
EHPrint("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx\n", data.Frame->rsi, data.Frame->rdi, data.Frame->rbp, data.Frame->rsp);
EHPrint("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx EFER=%#lx\n", data.Frame->rip, data.Frame->rflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw);
#elif defined(a32)
EHPrint("\e7981FCFS=%#x GS=%#x CS=%#x DS=%#x\n",
CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE),
data.Frame->cs, ds);
EHPrint("EAX=%#x EBX=%#x ECX=%#x EDX=%#x\n", data.Frame->eax, data.Frame->ebx, data.Frame->ecx, data.Frame->edx);
EHPrint("ESI=%#x EDI=%#x EBP=%#x ESP=%#x\n", data.Frame->esi, data.Frame->edi, data.Frame->ebp, data.Frame->esp);
EHPrint("EIP=%#x EFL=%#x INT=%#x ERR=%#x\n", data.Frame->eip, data.Frame->eflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode);
#elif defined(aa64)
#endif
#if defined(a86)
EHPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n", data.cr0.raw, data.cr2.raw, data.cr3.raw, data.cr4.raw, data.cr8.raw);
EHPrint("DR0=%#lx DR1=%#lx DR2=%#lx DR3=%#lx DR6=%#lx DR7=%#lx\n", data.dr0, data.dr1, data.dr2, data.dr3, data.dr6, data.dr7.raw);
EHPrint("\eFC797BCR0: 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",
data.cr0.PE ? "True " : "False", data.cr0.MP ? "True " : "False", data.cr0.EM ? "True " : "False", data.cr0.TS ? "True " : "False",
data.cr0.ET ? "True " : "False", data.cr0.NE ? "True " : "False", data.cr0.WP ? "True " : "False", data.cr0.AM ? "True " : "False",
data.cr0.NW ? "True " : "False", data.cr0.CD ? "True " : "False", data.cr0.PG ? "True " : "False");
EHPrint("\eFCBD79CR2: PFLA: %#lx\n",
data.cr2.PFLA);
EHPrint("\e79FC84CR3: PWT:%s PCD:%s PDBR:%#lx\n",
data.cr3.PWT ? "True " : "False", data.cr3.PCD ? "True " : "False", data.cr3.PDBR);
EHPrint("\eBD79FCCR4: 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",
data.cr4.VME ? "True " : "False", data.cr4.PVI ? "True " : "False", data.cr4.TSD ? "True " : "False", data.cr4.DE ? "True " : "False",
data.cr4.PSE ? "True " : "False", data.cr4.PAE ? "True " : "False", data.cr4.MCE ? "True " : "False", data.cr4.PGE ? "True " : "False",
data.cr4.PCE ? "True " : "False", data.cr4.UMIP ? "True " : "False", data.cr4.OSFXSR ? "True " : "False", data.cr4.OSXMMEXCPT ? "True " : "False",
data.cr4.LA57 ? "True " : "False", data.cr4.VMXE ? "True " : "False", data.cr4.SMXE ? "True " : "False", data.cr4.PCIDE ? "True " : "False",
data.cr4.OSXSAVE ? "True " : "False", data.cr4.SMEP ? "True " : "False", data.cr4.SMAP ? "True " : "False", data.cr4.PKE ? "True " : "False");
EHPrint("\e79FCF5CR8: TPL:%d\n", data.cr8.TPL);
#endif // a64 || a32
#if defined(a64)
EHPrint("\eFCFC02RFL: 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",
data.Frame->rflags.CF ? "True " : "False", data.Frame->rflags.PF ? "True " : "False", data.Frame->rflags.AF ? "True " : "False", data.Frame->rflags.ZF ? "True " : "False",
data.Frame->rflags.SF ? "True " : "False", data.Frame->rflags.TF ? "True " : "False", data.Frame->rflags.IF ? "True " : "False", data.Frame->rflags.DF ? "True " : "False",
data.Frame->rflags.OF ? "True " : "False", data.Frame->rflags.IOPL ? "True " : "False", data.Frame->rflags.NT ? "True " : "False", data.Frame->rflags.RF ? "True " : "False",
data.Frame->rflags.VM ? "True " : "False", data.Frame->rflags.AC ? "True " : "False", data.Frame->rflags.VIF ? "True " : "False", data.Frame->rflags.VIP ? "True " : "False",
data.Frame->rflags.ID ? "True " : "False", data.Frame->rflags.AlwaysOne);
#elif defined(a32)
EHPrint("\eFCFC02EFL: 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",
data.Frame->eflags.CF ? "True " : "False", data.Frame->eflags.PF ? "True " : "False", data.Frame->eflags.AF ? "True " : "False", data.Frame->eflags.ZF ? "True " : "False",
data.Frame->eflags.SF ? "True " : "False", data.Frame->eflags.TF ? "True " : "False", data.Frame->eflags.IF ? "True " : "False", data.Frame->eflags.DF ? "True " : "False",
data.Frame->eflags.OF ? "True " : "False", data.Frame->eflags.IOPL ? "True " : "False", data.Frame->eflags.NT ? "True " : "False", data.Frame->eflags.RF ? "True " : "False",
data.Frame->eflags.VM ? "True " : "False", data.Frame->eflags.AC ? "True " : "False", data.Frame->eflags.VIF ? "True " : "False", data.Frame->eflags.VIP ? "True " : "False",
data.Frame->eflags.ID ? "True " : "False", data.Frame->eflags.AlwaysOne);
#elif defined(aa64)
#endif
#if defined(a86)
EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s\n BD:%s BS:%s BT:%s\n",
data.dr6.B0 ? "True " : "False", data.dr6.B1 ? "True " : "False", data.dr6.B2 ? "True " : "False", data.dr6.B3 ? "True " : "False",
data.dr6.BD ? "True " : "False", data.dr6.BS ? "True " : "False", data.dr6.BT ? "True " : "False");
EHPrint("\eA0F0F0DR7: L0:%s G0:%s L1:%s G1:%s\n L2:%s G2:%s L3:%s G3:%s\n LE:%s GE:%s GD:%s\n R/W0:%s LEN0:%s R/W1:%s LEN1:%s\n R/W2:%s LEN2:%s R/W3:%s LEN3:%s\n",
data.dr7.L0 ? "True " : "False", data.dr7.G0 ? "True " : "False", data.dr7.L1 ? "True " : "False", data.dr7.G1 ? "True " : "False",
data.dr7.L2 ? "True " : "False", data.dr7.G2 ? "True " : "False", data.dr7.L3 ? "True " : "False", data.dr7.G3 ? "True " : "False",
data.dr7.LE ? "True " : "False", data.dr7.GE ? "True " : "False", data.dr7.GD ? "True " : "False", data.dr7.RW0 ? "True " : "False",
data.dr7.LEN0 ? "True " : "False", data.dr7.RW1 ? "True " : "False", data.dr7.LEN1 ? "True " : "False", data.dr7.RW2 ? "True " : "False",
data.dr7.LEN2 ? "True " : "False", data.dr7.RW3 ? "True " : "False", data.dr7.LEN3 ? "True " : "False");
#ifdef a64
EHPrint("\e009FF0EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n\n",
data.efer.SCE ? "True " : "False", data.efer.LME ? "True " : "False", data.efer.LMA ? "True " : "False", data.efer.NXE ? "True " : "False",
data.efer.SVME ? "True " : "False", data.efer.LMSLE ? "True " : "False", data.efer.FFXSR ? "True " : "False", data.efer.TCE ? "True " : "False");
#endif // a64
#endif
switch (data.Frame->InterruptNumber)
{
case CPU::x86::DivideByZero:
{
DivideByZeroExceptionHandler(data.Frame);
break;
}
case CPU::x86::Debug:
{
DebugExceptionHandler(data.Frame);
break;
}
case CPU::x86::NonMaskableInterrupt:
{
NonMaskableInterruptExceptionHandler(data.Frame);
break;
}
case CPU::x86::Breakpoint:
{
BreakpointExceptionHandler(data.Frame);
break;
}
case CPU::x86::Overflow:
{
OverflowExceptionHandler(data.Frame);
break;
}
case CPU::x86::BoundRange:
{
BoundRangeExceptionHandler(data.Frame);
break;
}
case CPU::x86::InvalidOpcode:
{
InvalidOpcodeExceptionHandler(data.Frame);
break;
}
case CPU::x86::DeviceNotAvailable:
{
DeviceNotAvailableExceptionHandler(data.Frame);
break;
}
case CPU::x86::DoubleFault:
{
DoubleFaultExceptionHandler(data.Frame);
break;
}
case CPU::x86::CoprocessorSegmentOverrun:
{
CoprocessorSegmentOverrunExceptionHandler(data.Frame);
break;
}
case CPU::x86::InvalidTSS:
{
InvalidTSSExceptionHandler(data.Frame);
break;
}
case CPU::x86::SegmentNotPresent:
{
SegmentNotPresentExceptionHandler(data.Frame);
break;
}
case CPU::x86::StackSegmentFault:
{
StackFaultExceptionHandler(data.Frame);
break;
}
case CPU::x86::GeneralProtectionFault:
{
GeneralProtectionExceptionHandler(data.Frame);
break;
}
case CPU::x86::PageFault:
{
PageFaultExceptionHandler(data.Frame);
break;
}
case CPU::x86::x87FloatingPoint:
{
x87FloatingPointExceptionHandler(data.Frame);
break;
}
case CPU::x86::AlignmentCheck:
{
AlignmentCheckExceptionHandler(data.Frame);
break;
}
case CPU::x86::MachineCheck:
{
MachineCheckExceptionHandler(data.Frame);
break;
}
case CPU::x86::SIMDFloatingPoint:
{
SIMDFloatingPointExceptionHandler(data.Frame);
break;
}
case CPU::x86::Virtualization:
{
VirtualizationExceptionHandler(data.Frame);
break;
}
case CPU::x86::Security:
{
SecurityExceptionHandler(data.Frame);
break;
}
default:
{
UnknownExceptionHandler(data.Frame);
break;
}
}
}
}

View File

@ -1,390 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../../crashhandler.hpp"
#include "../chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../../kernel.h"
static const char *PagefaultDescriptions[8] = {
"Supervisory process tried to read a non-present page entry\n",
"Supervisory process tried to read a page and caused a protection fault\n",
"Supervisory process tried to write to a non-present page entry\n",
"Supervisory process tried to write a page and caused a protection fault\n",
"User process tried to read a non-present page entry\n",
"User process tried to read a page and caused a protection fault\n",
"User process tried to write to a non-present page entry\n",
"User process tried to write a page and caused a protection fault\n"};
namespace CrashHandler
{
nsa void DisplayMainScreen(CRData data)
{
CPU::TrapFrame *Frame = data.Frame;
/*
_______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____
| __| | | __|_ _| ___| | | | | __ \ _ | __| | | ___| \
|__ |\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |
|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/
*/
EHPrint("\eFF5500 _______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____ \n");
EHPrint("| __| | | __|_ _| ___| | | | | __ \\ _ | __| | | ___| \\ \n");
EHPrint("|__ |\\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |\n");
EHPrint("|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/ \n\eFAFAFA");
switch (Frame->InterruptNumber)
{
case CPU::x86::DivideByZero:
{
EHPrint("Exception: Divide By Zero\n");
EHPrint("The processor attempted to divide a number by zero.\n");
break;
}
case CPU::x86::Debug:
{
EHPrint("Exception: Debug\n");
EHPrint("A debug exception has occurred.\n");
break;
}
case CPU::x86::NonMaskableInterrupt:
{
EHPrint("Exception: Non-Maskable Interrupt\n");
EHPrint("A non-maskable interrupt was received.\n");
break;
}
case CPU::x86::Breakpoint:
{
EHPrint("Exception: Breakpoint\n");
EHPrint("The processor encountered a breakpoint.\n");
break;
}
case CPU::x86::Overflow:
{
EHPrint("Exception: Overflow\n");
EHPrint("The processor attempted to add a number to a number that was too large.\n");
break;
}
case CPU::x86::BoundRange:
{
EHPrint("Exception: Bound Range\n");
EHPrint("The processor attempted to access an array element that is out of bounds.\n");
break;
}
case CPU::x86::InvalidOpcode:
{
EHPrint("Exception: Invalid Opcode\n");
EHPrint("The processor attempted to execute an invalid opcode.\n");
break;
}
case CPU::x86::DeviceNotAvailable:
{
EHPrint("Exception: Device Not Available\n");
EHPrint("The processor attempted to use a device that is not available.\n");
break;
}
case CPU::x86::DoubleFault:
{
EHPrint("Exception: Double Fault\n");
EHPrint("The processor encountered a double fault.\n");
break;
}
case CPU::x86::CoprocessorSegmentOverrun:
{
EHPrint("Exception: Coprocessor Segment Overrun\n");
EHPrint("The processor attempted to access a segment that is not available.\n");
break;
}
case CPU::x86::InvalidTSS:
{
EHPrint("Exception: Invalid TSS\n");
EHPrint("The processor attempted to access a task state segment that is not available or valid.\n");
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
EHPrint("GDT IDT LDT IDT\n");
switch (SelCode.Table)
{
case 0b00:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b01:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b10:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b11:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
default:
{
EHPrint(" ? \n");
EHPrint(" ? \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
}
break;
}
case CPU::x86::SegmentNotPresent:
{
EHPrint("Exception: Segment Not Present\n");
EHPrint("The processor attempted to access a segment that is not present.\n");
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
EHPrint("GDT IDT LDT IDT\n");
switch (SelCode.Table)
{
case 0b00:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b01:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b10:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b11:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
default:
{
EHPrint(" ? \n");
EHPrint(" ? \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
}
break;
}
case CPU::x86::StackSegmentFault:
{
EHPrint("Exception: Stack Segment Fault\n");
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
EHPrint("GDT IDT LDT IDT\n");
switch (SelCode.Table)
{
case 0b00:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b01:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b10:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b11:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
default:
{
EHPrint(" ? \n");
EHPrint(" ? \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
}
break;
}
case CPU::x86::GeneralProtectionFault:
{
EHPrint("Exception: General Protection Fault\n");
EHPrint("Kernel performed an illegal operation.\n");
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
EHPrint("GDT IDT LDT IDT\n");
switch (SelCode.Table)
{
case 0b00:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b01:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b10:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
case 0b11:
{
EHPrint(" ^ \n");
EHPrint(" | \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
default:
{
EHPrint(" ? \n");
EHPrint(" ? \n");
EHPrint(" %ld\n", SelCode.Idx);
break;
}
}
break;
}
case CPU::x86::PageFault:
{
EHPrint("Exception: Page Fault\n");
EHPrint("The processor attempted to access a page that is not present/accessible.\n");
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
#if defined(a64)
EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->rip);
#elif defined(a32)
EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->eip);
#elif defined(aa64)
#endif
EHPrint("Page: %s\eFAFAFA\n", params.P ? "\e058C19Present" : "\eE85230Not Present");
EHPrint("Write Operation: \e8888FF%s\eFAFAFA\n", params.W ? "Read-Only" : "Read-Write");
EHPrint("Processor Mode: \e8888FF%s\eFAFAFA\n", params.U ? "User-Mode" : "Kernel-Mode");
EHPrint("CPU Reserved Bits: %s\eFAFAFA\n", params.R ? "\eE85230Reserved" : "\e058C19Unreserved");
EHPrint("Caused By An Instruction Fetch: %s\eFAFAFA\n", params.I ? "\eE85230Yes" : "\e058C19No");
EHPrint("Caused By A Protection-Key Violation: %s\eFAFAFA\n", params.PK ? "\eE85230Yes" : "\e058C19No");
EHPrint("Caused By A Shadow Stack Access: %s\eFAFAFA\n", params.SS ? "\eE85230Yes" : "\e058C19No");
EHPrint("Caused By An SGX Violation: %s\eFAFAFA\n", params.SGX ? "\eE85230Yes" : "\e058C19No");
EHPrint("More Info: \e8888FF");
if (Frame->ErrorCode & 0x00000008)
EHPrint("One or more page directory entries contain reserved bits which are set to 1.\n");
else
EHPrint(PagefaultDescriptions[Frame->ErrorCode & 0b111]);
EHPrint("\eFAFAFA");
break;
}
case CPU::x86::x87FloatingPoint:
{
EHPrint("Exception: x87 Floating Point\n");
EHPrint("The x87 FPU generated an error.\n");
break;
}
case CPU::x86::AlignmentCheck:
{
EHPrint("Exception: Alignment Check\n");
EHPrint("The CPU detected an unaligned memory access.\n");
break;
}
case CPU::x86::MachineCheck:
{
EHPrint("Exception: Machine Check\n");
EHPrint("The CPU detected a hardware error.\n");
break;
}
case CPU::x86::SIMDFloatingPoint:
{
EHPrint("Exception: SIMD Floating Point\n");
EHPrint("The CPU detected an error in the SIMD unit.\n");
break;
}
case CPU::x86::Virtualization:
{
EHPrint("Exception: Virtualization\n");
EHPrint("The CPU detected a virtualization error.\n");
break;
}
case CPU::x86::Security:
{
EHPrint("Exception: Security\n");
EHPrint("The CPU detected a security violation.\n");
break;
}
default:
{
EHPrint("Exception: Unknown\n");
EHPrint("The CPU generated an unknown exception.\n");
break;
}
}
#if defined(a64)
EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->rip);
#elif defined(a32)
EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->eip);
#elif defined(aa64)
#endif
}
}

View File

@ -1,78 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../../crashhandler.hpp"
#include "../chfcts.hpp"
#include <ints.hpp>
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../../kernel.h"
namespace CrashHandler
{
nsa void DisplayStackFrameScreen(CRData data)
{
EHPrint("\eFAFAFATracing 10 frames...");
TraceFrames(data, 10, KernelSymbolTable, true);
if (data.Process)
{
EHPrint("\n\eFAFAFATracing 10 process frames...");
SymbolResolver::Symbols *pSt = data.Process->ELFSymbolTable;
debug("pSt = %#lx", pSt);
if (!pSt || !pSt->SymTableExists)
EHPrint("\n\eFF0000< No symbol table available. >\n");
else
TraceFrames(data, 10, pSt, false);
}
EHPrint("\n\eFAFAFATracing interrupt frames...");
for (short i = 0; i < 8; 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");
}
}
}
}

View File

@ -1,99 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../../crashhandler.hpp"
#include "../chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../../kernel.h"
namespace CrashHandler
{
nsa void DisplayTasksScreen(CRData data)
{
const char *StatusColor[] = {
"FF0000", // Unknown
"AAFF00", // Ready
"00AA00", // Running
"FFAA00", // Sleeping
"FFAA00", // Blocked
"FFAA00", // Stopped
"FFAA00", // Waiting
"FF00FF", // Core dump
"FF0088", // Zombie
"FF0000", // Terminated
};
const char *StatusString[] = {
"Unknown", // Unknown
"Ready", // Ready
"Running", // Running
"Sleeping", // Sleeping
"Blocked", // Blocked
"Stopped", // Stopped
"Waiting", // Waiting
"CoreDump", // Core dump
"Zombie", // Zombie
"Terminated", // Terminated
};
if (TaskManager)
{
std::list<Tasking::PCB *> Plist = TaskManager->GetProcessList();
if (data.Thread)
#if defined(a64)
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n",
data.Thread->Name, data.Thread->ID, data.Frame->rip);
#elif defined(a32)
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n",
data.Thread->Name, data.Thread->ID, data.Frame->eip);
#elif defined(aa64)
#endif
EHPrint("\eFAFAFAProcess list (%ld):\n", Plist.size());
foreach (auto Process in Plist)
{
EHPrint("\e%s-> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA PT:\e00AAAA%#lx\n",
StatusColor[Process->State.load()], Process->Name,
Process->ID, StatusString[Process->State.load()],
Process->PageTable);
foreach (auto Thread in Process->Threads)
EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n",
StatusColor[Thread->State.load()], Thread->Name,
Thread->ID, StatusString[Thread->State.load()],
Thread->Stack);
}
}
else
EHPrint("\eFAFAFATaskManager is not initialized!\n");
}
}

View File

@ -1,175 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../crashhandler.hpp"
#include "chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../kernel.h"
#define AddrToStr(addr) SymHandle->GetSymbol(addr)
namespace CrashHandler
{
struct StackFrame
{
struct StackFrame *rbp;
uintptr_t rip;
};
nsa void TraceFrames(CRData data, int Count,
SymbolResolver::Symbols *SymHandle,
bool Kernel)
{
Memory::Virtual vmm;
if (!vmm.Check(data.Frame))
{
EHPrint("Invalid frame pointer: %p\n", data.Frame);
return;
}
if (!vmm.Check(SymHandle))
{
EHPrint("Invalid symbol handle: %p\n", SymHandle);
return;
}
bool TriedRetryBP = false;
struct StackFrame *frames = nullptr;
RetryBP:
#if defined(a64)
if (TriedRetryBP == false)
frames = (struct StackFrame *)data.Frame->rbp;
#elif defined(a32)
if (TriedRetryBP == false)
frames = (struct StackFrame *)data.Frame->ebp;
#elif defined(aa64)
#endif
if (!vmm.Check((void *)frames))
{
if (TriedRetryBP == false)
{
Memory::Virtual vma(data.Process->PageTable);
debug("Invalid frame pointer: %p", frames);
frames = (struct StackFrame *)data.Process->PageTable->Get((void *)frames);
debug("Physical frame pointer: %p", frames);
TriedRetryBP = true;
goto RetryBP;
}
#if defined(a64)
EHPrint("Invalid rbp pointer: %p\n", data.Frame->rbp);
#elif defined(a32)
EHPrint("Invalid ebp pointer: %p\n", data.Frame->ebp);
#elif defined(aa64)
#endif
return;
}
debug("Stack tracing... %p %d %p %d",
data.Frame, Count, frames, Kernel);
EHPrint("\e7981FC\nStack Trace:\n");
if (!frames || !frames->rip || !frames->rbp)
{
#if defined(a64)
EHPrint("\e2565CC%p", (void *)data.Frame->rip);
#elif defined(a32)
EHPrint("\e2565CC%p", (void *)data.Frame->eip);
#elif defined(aa64)
#endif
EHPrint("\e7925CC-");
#if defined(a64)
EHPrint("\eAA25CC%s", AddrToStr(data.Frame->rip));
#elif defined(a32)
EHPrint("\eAA25CC%s", AddrToStr(data.Frame->eip));
#elif defined(aa64)
#endif
EHPrint("\e7981FC <- Exception");
EHPrint("\eFF0000\n< No stack trace available. >\n");
}
else
{
#if defined(a64)
debug("Exception in function %s(%p)",
AddrToStr(data.Frame->rip),
data.Frame->rip);
EHPrint("\e2565CC%p", (void *)data.Frame->rip);
EHPrint("\e7925CC-");
if ((data.Frame->rip >= 0xFFFFFFFF80000000 &&
data.Frame->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
{
EHPrint("\eAA25CC%s", AddrToStr(data.Frame->rip));
}
else
EHPrint("Outside Kernel");
#elif defined(a32)
EHPrint("\e2565CC%p", (void *)data.Frame->eip);
EHPrint("\e7925CC-");
if ((data.Frame->eip >= 0xC0000000 &&
data.Frame->eip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
{
EHPrint("\eAA25CC%s", AddrToStr(data.Frame->eip));
}
else
EHPrint("Outside Kernel");
#elif defined(aa64)
#endif
EHPrint("\e7981FC <- Exception");
for (int frame = 0; frame < Count; ++frame)
{
if (!frames->rip)
break;
EHPrint("\n\e2565CC%p", (void *)frames->rip);
EHPrint("\e7925CC-");
#if defined(a64)
if ((frames->rip >= 0xFFFFFFFF80000000 &&
frames->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
#elif defined(a32)
if ((frames->rip >= 0xC0000000 &&
frames->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
#elif defined(aa64)
if ((frames->rip >= 0xFFFFFFFF80000000 &&
frames->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
#endif
EHPrint("\e25CCC9%s", AddrToStr(frames->rip));
else
EHPrint("\eFF4CA9Outside Kernel");
if (!vmm.Check(frames->rbp))
return;
frames = frames->rbp;
}
}
EHPrint("\n");
}
}

View File

@ -1,225 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "../crashhandler.hpp"
#include "chfcts.hpp"
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../kernel.h"
nsa bool UserModeExceptionHandler(CPU::TrapFrame *Frame)
{
CPUData *CurCPU = GetCurrentCPU();
Tasking::PCB *CurProc = CurCPU->CurrentProcess;
Tasking::TCB *CurThread = CurCPU->CurrentThread;
debug("Current process %s(%d) and thread %s(%d)",
CurProc->Name, CurProc->ID, CurThread->Name, CurThread->ID);
CurThread->SetState(Tasking::Waiting);
#ifdef DEBUG
{
#if defined(a64)
CPU::x64::CR0 cr0 = CPU::x64::readcr0();
CPU::x64::CR2 cr2 = CPU::x64::CR2{.PFLA = CrashHandler::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));
#elif defined(a32)
CPU::x32::CR0 cr0 = CPU::x32::readcr0();
CPU::x32::CR2 cr2 = CPU::x32::CR2{.PFLA = CrashHandler::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));
#elif defined(aa64)
#endif
#if defined(a64)
debug("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
debug("R8=%#lx R9=%#lx R10=%#lx R11=%#lx", Frame->r8, Frame->r9, Frame->r10, Frame->r11);
debug("R12=%#lx R13=%#lx R14=%#lx R15=%#lx", Frame->r12, Frame->r13, Frame->r14, Frame->r15);
debug("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
debug("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
debug("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx EFER=%#lx", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
#elif defined(a32)
debug("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);
debug("EAX=%#x EBX=%#x ECX=%#x EDX=%#x", Frame->eax, Frame->ebx, Frame->ecx, Frame->edx);
debug("ESI=%#x EDI=%#x EBP=%#x ESP=%#x", Frame->esi, Frame->edi, Frame->ebp, Frame->esp);
debug("EIP=%#x EFL=%#x INT=%#x ERR=%#x", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode);
#elif defined(aa64)
#endif
#if defined(a86)
debug("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw);
debug("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",
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);
debug("CR2: PFLA: %#lx",
cr2.PFLA);
debug("CR3: PWT:%s PCD:%s PDBR:%#llx",
cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR);
#endif // defined(a86)
#if defined(a64)
debug("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",
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);
#elif defined(a32)
debug("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",
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);
#endif
#if defined(a86)
debug("CR8: TPL:%d", cr8.TPL);
#endif // defined(a86)
#if defined(a64)
debug("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);
#elif defined(a32)
debug("EFL: 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);
#elif defined(aa64)
#endif
#if defined(a64)
debug("EFER: SCE:%s LME:%s LMA:%s NXE:%s SVME:%s LMSLE:%s FFXSR:%s TCE:%s R0:%#x R1:%#x R2:%#x",
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
}
#endif
switch (Frame->InterruptNumber)
{
case CPU::x86::PageFault:
{
bool Handled = false;
Handled = CurProc->vma->HandleCoW(CrashHandler::PageFaultAddress);
if (!Handled)
Handled = CurThread->Stack->Expand(CrashHandler::PageFaultAddress);
if (Handled)
{
debug("Page fault handled");
CurThread->SetState(Tasking::Ready);
return true;
}
CurProc->Signals->SendSignal(SIGSEGV,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::Debug:
case CPU::x86::Breakpoint:
{
CurProc->Signals->SendSignal(SIGTRAP,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::DivideByZero:
case CPU::x86::Overflow:
case CPU::x86::BoundRange:
case CPU::x86::x87FloatingPoint:
case CPU::x86::SIMDFloatingPoint:
{
CurProc->Signals->SendSignal(SIGFPE,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::InvalidOpcode:
case CPU::x86::GeneralProtectionFault:
{
CurProc->Signals->SendSignal(SIGILL,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::DeviceNotAvailable:
{
CurProc->Signals->SendSignal(SIGBUS,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::NonMaskableInterrupt:
case CPU::x86::DoubleFault:
case CPU::x86::CoprocessorSegmentOverrun:
case CPU::x86::InvalidTSS:
case CPU::x86::SegmentNotPresent:
case CPU::x86::StackSegmentFault:
case CPU::x86::AlignmentCheck:
case CPU::x86::MachineCheck:
case CPU::x86::Virtualization:
case CPU::x86::Security:
default:
{
error("Unhandled exception %d on CPU %d",
Frame->InterruptNumber, CurCPU->ID);
break;
}
}
error("User mode exception handler failed");
return false;
}

View File

@ -1,35 +0,0 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_CRASH_HANDLER_H__
#define __FENNIX_KERNEL_CRASH_HANDLER_H__
#include <types.h>
#include <ints.hpp>
#include <cpu.hpp>
namespace CrashHandler
{
extern uintptr_t PageFaultAddress;
extern void *EHIntFrames[INT_FRAMES_MAX];
void EHPrint(const char *Format, ...);
void Handle(void *Data);
}
#endif // !__FENNIX_KERNEL_CRASH_HANDLER_H__

View File

@ -479,9 +479,8 @@ namespace Driver
{
dbg_api("%d, %s", MajorID, Name);
Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr,
Name, Tasking::System,
nullptr, true, 0, 0);
Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr, Name, Tasking::System,
true, 0, 0);
return pcb->ID;
}

View File

@ -38,6 +38,8 @@
#define ACPI_PCIE_WAKE 0x4000
#define ACPI_WAKE 0x8000
extern std::atomic<bool> ExceptionLock;
namespace ACPI
{
__always_inline inline bool IsCanonical(uint64_t Address)
@ -104,6 +106,12 @@ namespace ACPI
}
else if (Event & ACPI_POWER_BUTTON)
{
if (ExceptionLock.load())
{
this->Shutdown();
CPU::Stop();
}
Tasking::PCB *pcb = thisProcess;
if (pcb && !pcb->GetContext()->IsPanic())
{

View File

@ -34,7 +34,6 @@
#elif defined(aa64)
#endif
#include "crashhandler.hpp"
#include "../kernel.h"
void HandleException(CPU::ExceptionFrame *Frame);
@ -112,7 +111,6 @@ namespace Interrupts
/* APIC::Timer */ void *apicTimer[MAX_CPU] = {nullptr};
#elif defined(aa64)
#endif
void *InterruptFrames[INT_FRAMES_MAX];
void Initialize(int Core)
{
@ -293,17 +291,6 @@ namespace Interrupts
#endif
// debug("IRQ%ld", Frame->InterruptNumber - 32);
memmove(InterruptFrames + 1,
InterruptFrames,
sizeof(InterruptFrames) - sizeof(InterruptFrames[0]));
#if defined(a64)
InterruptFrames[0] = (void *)Frame->rip;
#elif defined(a32)
InterruptFrames[0] = (void *)Frame->eip;
#elif defined(aa64)
InterruptFrames[0] = (void *)Frame->pc;
#endif
CPUData *CoreData = GetCurrentCPU();
int Core = 0;
if (likely(CoreData != nullptr))

145
core/panic/diag.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include <display.hpp>
#include <bitmap.hpp>
#include <convert.h>
#include <printf.h>
#include <lock.hpp>
#include <rand.hpp>
#include <uart.hpp>
#include <time.hpp>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#include <io.h>
#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"
#include "keyboard.hpp"
extern void ExPrint(const char *Format, ...);
extern Video::Font *CrashFont;
extern void DisplayTopOverlay();
extern CPU::ExceptionFrame *ExFrame;
/* TODO: Add more info */
struct DiagnosticFile
{
__packed __aligned(16) struct
{
uint8_t Signature[5] = {'D', 'I', 'A', 'G', '\0'};
uint32_t Version = 1;
char Is64Bit = 0;
uint32_t Length = 0;
} Header;
__packed __aligned(16) struct
{
CPU::ExceptionFrame Frame;
uint32_t KernelMemoryLength;
uint8_t KernelMemory[];
} Data;
};
nsa bool WriteDiagDataToNode(vfs::RefNode *refFile)
{
uintptr_t KStart = (uintptr_t)&_kernel_start;
uintptr_t kEnd = (uintptr_t)&_kernel_end;
size_t kSize = kEnd - KStart;
size_t fileSize = sizeof(DiagnosticFile) + kSize;
uint8_t *buf = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(fileSize));
if (!buf)
{
ExPrint("\eFF0000Failed to allocate memory for diagnostic data\n");
Display->UpdateBuffer();
return false;
}
DiagnosticFile *file = (DiagnosticFile *)buf;
file->Header = {};
file->Header.Length = uint32_t(fileSize);
file->Header.Is64Bit = sizeof(void *) == 8;
file->Data.Frame = *ExFrame;
file->Data.KernelMemoryLength = uint32_t(kSize);
memcpy(file->Data.KernelMemory, (void *)KStart, kSize);
ExPrint("\eFAFAFAWriting to %s\n", refFile->node->FullPath);
size_t w = refFile->write(buf, fileSize);
if (w != fileSize)
{
debug("%d out of %d bytes written", w, fileSize);
ExPrint("\eFF0000Failed to write diagnostic data to file: %s\n",
strerror((int)w));
Display->UpdateBuffer();
return false;
}
return true;
}
nsa void DiagnosticDataCollection()
{
Display->ClearBuffer();
DisplayTopOverlay();
ExPrint("\n\eFAFAFAPlease wait while we collect some diagnostic information...\n");
ExPrint("This may take a while...\n");
vfs::Node *panicDir = fs->CreateIfNotExists("/var/panic", vfs::DIRECTORY);
if (!panicDir)
{
ExPrint("\eFF0000Failed to create /var/panic\n");
Display->UpdateBuffer();
return;
}
Time::Clock clock = Time::ReadClock();
char filename[64];
for (int i = 0; i < INT32_MAX; i++)
{
sprintf(filename, "dump-%d-%d-%d-%d.dmp",
clock.Year, clock.Month, clock.Day, i);
if (fs->PathExists(filename, panicDir))
continue;
fs->Create(filename, vfs::FILE, panicDir);
break;
}
vfs::RefNode *refFile = fs->Open(filename, panicDir);
if (!WriteDiagDataToNode(refFile))
{
delete refFile;
return;
}
ExPrint("You can find the diagnostic file in /var/panic/%s\n", filename);
Display->UpdateBuffer();
delete refFile;
}

336
core/panic/handler.cpp Normal file
View File

@ -0,0 +1,336 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include <display.hpp>
#include <bitmap.hpp>
#include <convert.h>
#include <printf.h>
#include <lock.hpp>
#include <rand.hpp>
#include <uart.hpp>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#include <io.h>
#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"
extern const char *x86ExceptionMnemonics[];
extern void DisplayCrashScreen(CPU::ExceptionFrame *Frame);
extern bool UserModeExceptionHandler(CPU::ExceptionFrame *Frame);
extern void DisplayStackSmashing();
extern void DisplayBufferOverflow();
Video::Font *CrashFont = nullptr;
nsa void __printfWrapper(char c, void *)
{
Display->Print(c, CrashFont, true);
}
nsa void ExPrint(const char *Format, ...)
{
va_list args;
va_start(args, Format);
vfctprintf(__printfWrapper, NULL, Format, args);
va_end(args);
}
nsa void HaltAllCores()
{
if (SMP::CPUCores <= 1)
return;
#if defined(a86)
if (Interrupts::apic[0] == nullptr)
return;
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);
}
}
#elif defined(aa64)
#endif
}
nsa void InitFont()
{
if (CrashFont == nullptr)
{
/* Hope we won't crash here */
CrashFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_start,
&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_end,
Video::FontType::PCScreenFont2);
}
}
std::atomic<bool> UnrecoverableLock = false;
nsa __noreturn void HandleUnrecoverableException(CPU::ExceptionFrame *Frame)
{
static int setOnce = 0;
if (!setOnce++) /* FIXME: SMP */
{
for (uint32_t x = 0; x < Display->GetWidth; x++)
for (uint32_t y = 0; y < Display->GetHeight; y++)
Display->SetPixel(x, y, 0xFF250500);
Display->SetBufferCursor(0, 0);
}
CPUData *core = GetCurrentCPU();
while (UnrecoverableLock.exchange(true, std::memory_order_acquire))
CPU::Pause();
ExPrint("\eFFFFFF-----------------------------------------------\n");
ExPrint("Unrecoverable exception %#lx on CPU %d\n",
Frame->InterruptNumber, core->ID);
#if defined(a86)
ExPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n",
Frame->cr0, Frame->cr2, Frame->cr3, Frame->cr4, Frame->cr8);
ExPrint("DR0=%#lx DR1=%#lx DR2=%#lx DR3=%#lx DR6=%#lx DR7=%#lx\n",
Frame->dr0, Frame->dr1, Frame->dr2, Frame->dr3, Frame->dr6, Frame->dr7);
ExPrint("GS=%#lx FS=%#lx ES=%#lx DS=%#lx SS=%#lx CS=%#lx\n",
Frame->gs, Frame->fs, Frame->es, Frame->ds, Frame->ss, Frame->cs);
#endif
#if defined(a64)
ExPrint("R8=%#lx R9=%#lx R10=%#lx R11=%#lx R12=%#lx R13=%#lx R14=%#lx R15=%#lx\n",
Frame->r8, Frame->r9, Frame->r10, Frame->r11, Frame->r12, Frame->r13,
Frame->r14, Frame->r15);
#endif
#if defined(a86)
ExPrint("AX=%#lx BX=%#lx CX=%#lx DX=%#lx SI=%#lx DI=%#lx BP=%#lx SP=%#lx\n",
#ifdef a64
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx, Frame->rsi, Frame->rdi,
Frame->rbp, Frame->rsp);
#else
Frame->eax, Frame->ebx, Frame->ecx, Frame->edx, Frame->esi, Frame->edi,
Frame->ebp, Frame->esp);
#endif /* a64 */
ExPrint("IP=%#lx FL=%#lx INT=%#lx ERR=%#lx\n",
#ifdef a64
Frame->rip, Frame->rflags.raw,
#else
Frame->eip, Frame->eflags.raw,
#endif /* a64 */
Frame->InterruptNumber, Frame->ErrorCode);
#endif /* a86 */
Display->UpdateBuffer();
error("Unrecoverable Exception: %#lx", Frame->InterruptNumber);
UnrecoverableLock.store(false, std::memory_order_release);
CPU::Stop();
}
nsa __noreturn void HandleExceptionInsideException(CPU::ExceptionFrame *Frame)
{
ExPrint("\eFFFFFF-----------------------------------------------\n");
ExPrint("Exception inside exception: %#lx at %#lx\n",
Frame->InterruptNumber,
#if defined(a64)
Frame->rip);
#elif defined(a32)
Frame->eip);
#elif defined(aa64)
Frame->pc);
#endif
#if defined(a86)
ExPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n",
Frame->cr0, Frame->cr2, Frame->cr3, Frame->cr4, Frame->cr8);
ExPrint("DR0=%#lx DR1=%#lx DR2=%#lx DR3=%#lx DR6=%#lx DR7=%#lx\n",
Frame->dr0, Frame->dr1, Frame->dr2, Frame->dr3, Frame->dr6, Frame->dr7);
ExPrint("GS=%#lx FS=%#lx ES=%#lx DS=%#lx SS=%#lx CS=%#lx\n",
Frame->gs, Frame->fs, Frame->es, Frame->ds, Frame->ss, Frame->cs);
#endif
#if defined(a64)
ExPrint("R8=%#lx R9=%#lx R10=%#lx R11=%#lx R12=%#lx R13=%#lx R14=%#lx R15=%#lx\n",
Frame->r8, Frame->r9, Frame->r10, Frame->r11, Frame->r12, Frame->r13,
Frame->r14, Frame->r15);
#endif
#if defined(a86)
ExPrint("AX=%#lx BX=%#lx CX=%#lx DX=%#lx SI=%#lx DI=%#lx BP=%#lx SP=%#lx\n",
#ifdef a64
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx, Frame->rsi, Frame->rdi,
Frame->rbp, Frame->rsp);
#else
Frame->eax, Frame->ebx, Frame->ecx, Frame->edx, Frame->esi, Frame->edi,
Frame->ebp, Frame->esp);
#endif /* a64 */
ExPrint("IP=%#lx FL=%#lx INT=%#lx ERR=%#lx\n",
#ifdef a64
Frame->rip, Frame->rflags.raw,
#else
Frame->eip, Frame->eflags.raw,
#endif /* a64 */
Frame->InterruptNumber, Frame->ErrorCode);
#endif /* a86 */
Display->UpdateBuffer();
CPU::Stop();
}
std::atomic<bool> ExceptionLock = false;
nsa void HandleException(CPU::ExceptionFrame *Frame)
{
/* We don't need to restore the page table
because the ExceptionHandlerStub will
do it for us if we return. */
CPU::PageTable(KernelPageTable);
InitFont();
/* First check the exception */
if (unlikely(Frame->InterruptNumber == CPU::x86::DoubleFault))
{
ExceptionLock.store(true, std::memory_order_release);
HandleUnrecoverableException(Frame);
}
if (Frame->cs == GDT_USER_CODE && Frame->cs == GDT_USER_DATA)
{
if (UserModeExceptionHandler(Frame))
goto ExceptionExit;
CPUData *core = GetCurrentCPU();
if (likely(core->CurrentThread->Security.IsCritical == false))
TaskManager->Yield();
error("Critical thread \"%s\"(%d) died",
core->CurrentThread->Name,
core->CurrentThread->ID);
}
debug("-----------------------------------------------------------------------------------");
error("Exception: %#x", Frame->InterruptNumber);
debug("%ld MiB / %ld MiB (%ld MiB Reserved)",
TO_MiB(KernelAllocator.GetUsedMemory()),
TO_MiB(KernelAllocator.GetTotalMemory()),
TO_MiB(KernelAllocator.GetReservedMemory()));
if (ExceptionLock.load(std::memory_order_acquire))
HandleExceptionInsideException(Frame);
ExceptionLock.store(true, std::memory_order_release);
{
const char msg[] = "Entering in panic mode...";
size_t msgLen = strlen(msg);
size_t msgPixels = msgLen * CrashFont->GetInfo().Width;
uint32_t x = uint32_t((Display->GetWidth - msgPixels) / 2);
uint32_t y = uint32_t((Display->GetHeight - CrashFont->GetInfo().Height) / 2);
Display->SetBufferCursor(x, y);
Display->PrintString("\eFF2525");
Display->PrintString(msg, CrashFont);
Display->UpdateBuffer();
}
if (DriverManager)
DriverManager->Panic();
if (TaskManager)
TaskManager->Panic();
Interrupts::RemoveAll();
HaltAllCores();
ForceUnlock = true;
DisplayCrashScreen(Frame);
CPU::Stop();
ExceptionExit:
ExceptionLock.store(false, std::memory_order_release);
}
nsa void BaseBufferStackError()
{
/* We don't need to restore the page table
because the ExceptionHandlerStub will
do it for us if we return. */
CPU::PageTable(KernelPageTable);
if (CrashFont == nullptr)
{
/* Hope we won't crash here */
CrashFont = new Video::Font(&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_start,
&_binary_files_tamsyn_font_1_11_Tamsyn8x16b_psf_end,
Video::FontType::PCScreenFont2);
}
ExceptionLock.store(true, std::memory_order_release);
if (DriverManager)
DriverManager->Panic();
if (TaskManager)
TaskManager->Panic();
HaltAllCores();
ForceUnlock = true;
debug("-----------------------------------------------------------------------------------");
error("Buffer overflow detected");
debug("%ld MiB / %ld MiB (%ld MiB Reserved)",
TO_MiB(KernelAllocator.GetUsedMemory()),
TO_MiB(KernelAllocator.GetTotalMemory()),
TO_MiB(KernelAllocator.GetReservedMemory()));
}
nsa __noreturn void HandleStackSmashing()
{
BaseBufferStackError();
DisplayStackSmashing();
CPU::Stop();
}
nsa __noreturn void HandleBufferOverflow()
{
BaseBufferStackError();
DisplayBufferOverflow();
CPU::Stop();
}

388
core/panic/keyboard.cpp Normal file
View File

@ -0,0 +1,388 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include "keyboard.hpp"
#include <display.hpp>
#include <convert.h>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#include <io.h>
#if defined(a64)
#include "../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../kernel.h"
#define ERROR_COLOR "\eFF0000"
#define WARN_COLOR "\eFFAA00"
#define DEFAULT_COLOR "\e00FF00"
extern void ExPrint(const char *Format, ...);
extern void ArrowInput(uint8_t key);
extern void UserInput(char *Input);
const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y',
'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g',
'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '};
const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^',
'&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G',
'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '};
static int LowerCase = true;
nsa static inline int GetLetterFromScanCode(uint8_t ScanCode)
{
if (ScanCode & 0x80)
{
switch (ScanCode)
{
case KEY_U_LSHIFT:
LowerCase = true;
return KEY_INVALID;
case KEY_U_RSHIFT:
LowerCase = true;
return KEY_INVALID;
default:
return KEY_INVALID;
}
}
else
{
switch (ScanCode)
{
case KEY_D_RETURN:
return '\n';
case KEY_D_LSHIFT:
LowerCase = false;
return KEY_INVALID;
case KEY_D_RSHIFT:
LowerCase = false;
return KEY_INVALID;
case KEY_D_BACKSPACE:
return ScanCode;
default:
{
if (ScanCode > 0x39)
break;
if (LowerCase)
return sc_ascii_low[ScanCode];
else
return sc_ascii_high[ScanCode];
}
}
}
return KEY_INVALID;
}
nsa void CrashKeyboardDriver::PS2Wait(bool Read)
{
TimeoutCallNumber++;
#if defined(a86)
int Timeout = 100000;
uint8_t Status = 0;
while (Timeout--)
{
Status = inb(0x64);
if (Read)
{
if ((Status & 1) == 1)
return;
}
else
{
if ((Status & 2) == 0)
return;
}
}
ExPrint(WARN_COLOR "PS/2 controller timeout (%s;%d)\n" DEFAULT_COLOR,
Read ? "read" : "write", TimeoutCallNumber - 1);
#endif // a86
}
/*
This simple driver relies on the PS/2 controller to handle the keyboard.
Maybe is not the most efficient way but most x86 devices out there
still has PS/2 support (emulated or not).
We even have to make sure IRQ1 is enabled in the PIC but on x64 we use
the I/O APIC... "outb(0x21, 0b11111101);" can be used but the EOI is
automatically sent to I/O APIC if enabled/supported which is bad.
FIXME: On some real devices, the PS/2 keyboard doesn't send interrupts.
TODO: Implement a way to handle USB keyboards in the future.
*/
CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */
{
#define WaitRead PS2Wait(true)
#define WaitWrite PS2Wait(false)
#define SetMessageLocation \
Display->SetBufferCursor(8, \
Display->GetHeight - \
Display->GetCurrentFont()->GetInfo().Height - 24)
CPU::Interrupts(CPU::Disable);
/* Dots will be printed at the bottom of the screen as a progress bar. */
Display->SetBufferCursor(8,
Display->GetHeight -
Display->GetCurrentFont()->GetInfo().Height - 8);
#if defined(a86)
/* Disable port 1 & 2 */
{
/* Disable Port 1 */
WaitWrite;
outb(0x64, 0xAD);
/* Disable Port 2 */
WaitWrite;
outb(0x64, 0xA7);
}
Display->Print('.');
/* Flush */
{
int Timeout = 100000;
while ((inb(0x64) & 1) && Timeout-- > 0)
inb(0x60);
if (Timeout <= 0)
{
SetMessageLocation;
ExPrint(ERROR_COLOR
"PS/2 controller timeout (flush;0)\n" DEFAULT_COLOR);
CPU::Stop();
}
}
Display->Print('.');
/* Test controller */
{
/* Save config */
WaitWrite;
outb(0x64, 0x20);
WaitRead;
uint8_t cfg = inb(0x60);
/* Test PS/2 controller */
WaitWrite;
outb(0x64, 0xAA);
WaitRead;
uint8_t test = inb(0x60);
if (test != 0x55)
{
if (test == 0xFA)
{
trace("PS/2 controller sent ACK to test request.");
WaitRead;
test = inb(0x60);
}
if (test != 0x55)
{
SetMessageLocation;
ExPrint(ERROR_COLOR
"PS/2 controller self test failed (%#x)\n" DEFAULT_COLOR,
test);
CPU::Stop();
}
}
/* Restore config */
WaitWrite;
outb(0x64, 0x60);
WaitWrite;
outb(0x60, cfg);
}
Display->Print('.');
/* Disable scanning; Enable port 1; Set default settings */
{
/* Disable scanning */
outb(0x60, 0xF5);
/* Enable Port 1 */
WaitWrite;
outb(0x64, 0xAE);
/* Set default settings */
outb(0x60, 0xF6);
}
Display->Print('.');
/* Test port 1 */
{
WaitWrite;
outb(0x64, 0xAB);
WaitRead;
uint8_t test = inb(0x60);
if (test != 0x00)
{
if (test == 0xFA)
{
trace("PS/2 keyboard sent ACK to test request.");
WaitRead;
test = inb(0x60);
}
if (test != 0x00)
{
SetMessageLocation;
ExPrint(ERROR_COLOR
"PS/2 keyboard self test failed (%#x)\n" DEFAULT_COLOR,
test);
CPU::Stop();
}
}
}
Display->Print('.');
/* Configure the controller */
{
/* Read Controller Configuration */
WaitWrite;
outb(0x64, 0x20);
WaitRead;
uint8_t cfg = inb(0x60);
/* Enable Port 1 & Port 1 translation */
cfg |= 0b01000001;
/* Write Controller Configuration */
WaitWrite;
outb(0x64, 0x60);
WaitWrite;
outb(0x60, cfg);
}
Display->Print('.');
/* Enable port 1; Set scan code; Enable scanning */
{
/* Enable Port 1 */
outb(0x64, 0xAE);
/* Set scan code set 1 */
WaitWrite;
outb(0x60, 0xF0);
WaitWrite;
outb(0x60, 0x02);
/* Check if we have scan code set 1 */
WaitWrite;
outb(0x60, 0xF0);
WaitWrite;
outb(0x60, 0x00);
/* Read scan code set */
WaitRead;
uint8_t scs = inb(0x60);
if (scs == 0xFA || scs == 0xFE)
{
if (scs == 0xFA)
trace("PS/2 keyboard sent ACK to scan code set request.");
if (scs == 0xFE)
trace("PS/2 keyboard sent RESEND to scan code set request.");
WaitRead;
scs = inb(0x60);
}
if (scs != 0x41)
{
SetMessageLocation;
ExPrint(WARN_COLOR
"PS/2 keyboard scan code set 1 not supported (%#x)\n" DEFAULT_COLOR,
scs);
}
/* Enable scanning */
outb(0x60, 0xF4);
}
Display->Print('.');
#endif // defined(a86)
CPU::Interrupts(CPU::Enable);
}
nsa void CrashKeyboardDriver::OnInterruptReceived(CPU::TrapFrame *Frame)
{
#if defined(a86)
UNUSED(Frame);
uint8_t scanCode = inb(0x60);
if (scanCode == KEY_D_TAB ||
scanCode == KEY_D_LCTRL ||
scanCode == KEY_D_LALT ||
scanCode == KEY_U_LCTRL ||
scanCode == KEY_U_LALT)
return;
switch (scanCode)
{
case KEY_D_UP:
case KEY_D_LEFT:
case KEY_D_RIGHT:
case KEY_D_DOWN:
ArrowInput(scanCode);
break;
default:
break;
}
int key = GetLetterFromScanCode(scanCode);
if (key != KEY_INVALID)
{
if (key == KEY_D_BACKSPACE)
{
if (BackSpaceLimit > 0)
{
Display->Print('\b');
backspace(UserInputBuffer);
BackSpaceLimit--;
}
}
else if (key == '\n')
{
UserInput(UserInputBuffer);
BackSpaceLimit = 0;
UserInputBuffer[0] = '\0';
}
else
{
append(UserInputBuffer, s_cst(char, key));
Display->Print((char)key);
BackSpaceLimit++;
}
Display->UpdateBuffer(); /* Update as we type. */
}
#endif // a64 || a32
}

View File

@ -15,69 +15,9 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
#define __FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
#include <types.h>
#include <ints.hpp>
#include <task.hpp>
#include <cpu.hpp>
#if defined(a64)
struct CRData
{
CPU::TrapFrame *Frame;
CPU::x64::CR0 cr0;
CPU::x64::CR2 cr2;
CPU::x64::CR3 cr3;
CPU::x64::CR4 cr4;
CPU::x64::CR8 cr8;
CPU::x64::EFER efer;
uintptr_t dr0, dr1, dr2, dr3;
CPU::x64::DR6 dr6;
CPU::x64::DR7 dr7;
long ID;
void *CPUData;
Tasking::PCB *Process;
Tasking::TCB *Thread;
};
#elif defined(a32)
struct CRData
{
CPU::TrapFrame *Frame;
CPU::x32::CR0 cr0;
CPU::x32::CR2 cr2;
CPU::x32::CR3 cr3;
CPU::x32::CR4 cr4;
CPU::x32::CR8 cr8;
uintptr_t dr0, dr1, dr2, dr3;
CPU::x32::DR6 dr6;
CPU::x32::DR7 dr7;
long ID;
void *CPUData;
Tasking::PCB *Process;
Tasking::TCB *Thread;
};
#elif defined(aa64)
struct CRData
{
CPU::TrapFrame *Frame;
long ID;
void *CPUData;
Tasking::PCB *Process;
Tasking::TCB *Thread;
};
#endif
#pragma once
enum Keys
{
@ -263,56 +203,17 @@ enum Keys
KEY_U_F12 = 0xd8,
};
namespace CrashHandler
class CrashKeyboardDriver : public Interrupts::Handler
{
extern int SBIdx;
private:
void PS2Wait(bool Read);
void OnInterruptReceived(CPU::TrapFrame *Frame);
class CrashKeyboardDriver : public Interrupts::Handler
{
private:
void PS2Wait(bool Read);
void OnInterruptReceived(CPU::TrapFrame *Frame);
int BackSpaceLimit = 0;
char UserInputBuffer[256];
int TimeoutCallNumber = 0;
public:
CrashKeyboardDriver();
~CrashKeyboardDriver();
};
void TraceFrames(CRData data, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel);
void ArrowInput(uint8_t key);
void UserInput(char *Input);
void DisplayMainScreen(CRData data);
void DisplayDetailsScreen(CRData data);
void DisplayStackFrameScreen(CRData data);
void DisplayTasksScreen(CRData data);
void DisplayConsoleScreen(CRData data);
}
void DivideByZeroExceptionHandler(CPU::TrapFrame *Frame);
void DebugExceptionHandler(CPU::TrapFrame *Frame);
void NonMaskableInterruptExceptionHandler(CPU::TrapFrame *Frame);
void BreakpointExceptionHandler(CPU::TrapFrame *Frame);
void OverflowExceptionHandler(CPU::TrapFrame *Frame);
void BoundRangeExceptionHandler(CPU::TrapFrame *Frame);
void InvalidOpcodeExceptionHandler(CPU::TrapFrame *Frame);
void DeviceNotAvailableExceptionHandler(CPU::TrapFrame *Frame);
void DoubleFaultExceptionHandler(CPU::TrapFrame *Frame);
void CoprocessorSegmentOverrunExceptionHandler(CPU::TrapFrame *Frame);
void InvalidTSSExceptionHandler(CPU::TrapFrame *Frame);
void SegmentNotPresentExceptionHandler(CPU::TrapFrame *Frame);
void StackFaultExceptionHandler(CPU::TrapFrame *Frame);
void GeneralProtectionExceptionHandler(CPU::TrapFrame *Frame);
void PageFaultExceptionHandler(CPU::TrapFrame *Frame);
void x87FloatingPointExceptionHandler(CPU::TrapFrame *Frame);
void AlignmentCheckExceptionHandler(CPU::TrapFrame *Frame);
void MachineCheckExceptionHandler(CPU::TrapFrame *Frame);
void SIMDFloatingPointExceptionHandler(CPU::TrapFrame *Frame);
void VirtualizationExceptionHandler(CPU::TrapFrame *Frame);
void SecurityExceptionHandler(CPU::TrapFrame *Frame);
void UnknownExceptionHandler(CPU::TrapFrame *Frame);
bool UserModeExceptionHandler(CPU::TrapFrame *Frame);
#endif // !__FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
public:
CrashKeyboardDriver();
~CrashKeyboardDriver() {}
};

920
core/panic/ui.cpp Normal file
View File

@ -0,0 +1,920 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include <display.hpp>
#include <bitmap.hpp>
#include <convert.h>
#include <printf.h>
#include <lock.hpp>
#include <rand.hpp>
#include <uart.hpp>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#include <io.h>
#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"
#include "keyboard.hpp"
extern void ExPrint(const char *Format, ...);
extern Video::Font *CrashFont;
extern void DiagnosticDataCollection();
extern void InitFont();
struct StackFrame
{
struct StackFrame *bp;
uintptr_t ip;
};
struct x86ExceptionName
{
const char *Mnemonic;
const char *Name;
const char *Cause;
};
/* AMD64 Programmer's Manual Volume 2: 8.2 Vectors */
x86ExceptionName x86Exceptions[] = {
/* 0*/ {"#DE", "Divide-by-Zero-Error", "DIV, IDIV, AAM instructions"},
/* 1*/ {"#DB", "Debug", "Instruction accesses and data accesses"},
/* 2*/ {"NMI", "Non-Maskable-Interrupt", "Non-maskable interrupt"},
/* 3*/ {"#BP", "Breakpoint", "INT3 instruction"},
/* 4*/ {"#OF", "Overflow", "INTO instruction"},
/* 5*/ {"#BR", "Bound-Range", "BOUND instruction"},
/* 6*/ {"#UD", "Invalid-Opcode", "Invalid instructions"},
/* 7*/ {"#NM", "Device-Not-Available", "x87 instructions"},
/* 8*/ {"#DF", "Double-Fault", "Exception during the handling of another exception or interrupt"},
/* 9*/ {"#--", "Coprocessor-Segment-Overrun", "Unsupported (Reserved)"},
/*10*/ {"#TS", "Invalid-TSS", "Task-state segment access and task switch"},
/*11*/ {"#NP", "Segment-Not-Present", "Segment register loads"},
/*12*/ {"#SS", "Stack", "SS register loads and stack references"},
/*13*/ {"#GP", "General-Protection", "Memory accesses and protection checks"},
/*14*/ {"#PF", "Page-Fault", "Memory accesses when paging enabled"},
/*15*/ {"#r0", "Reserved", "Reserved"},
/*16*/ {"#MF", "x87 Floating-Point Exception-Pending", "x87 floating-point instructions"},
/*17*/ {"#AC", "Alignment-Check", "Misaligned memory accesses"},
/*18*/ {"#MC", "Machine-Check", "Model specific"},
/*19*/ {"#XF", "SIMD Floating-Point", "SSE floating-point instructions"},
/*20*/ {"#VE", "Virtualization Exception", "Virtualization event"}, /* AMD says this is reserved */
/*21*/ {"#CP", "Control-Protection Exception", "RET/IRET or other control transfer"},
/*22*/ {"#r1", "Reserved", "Reserved"},
/*23*/ {"#r2", "Reserved", "Reserved"},
/*24*/ {"#r3", "Reserved", "Reserved"},
/*25*/ {"#r4", "Reserved", "Reserved"},
/*26*/ {"#r5", "Reserved", "Reserved"},
/*27*/ {"#r6", "Reserved", "Reserved"},
/*28*/ {"#HV", "Hypervisor Injection Exception", "Event injection"},
/*29*/ {"#VC", "VMM Communication Exception", "Virtualization event"},
/*30*/ {"#SX", "Security Exception", "Security-sensitive event in host"},
/*31*/ {"#r7", "Reserved", "Reserved"},
};
static const char *x86PageFaultDescriptions[9] = {
"Supervisor tried to read a non-present page entry\n",
"Supervisor tried to read a page and caused a protection fault\n",
"Supervisor tried to write to a non-present page entry\n",
"Supervisor tried to write a page and caused a protection fault\n",
"User tried to read a non-present page entry\n",
"User tried to read a page and caused a protection fault\n",
"User tried to write to a non-present page entry\n",
"User tried to write a page and caused a protection fault\n",
"One or more page directory entries contain reserved bits which are set to 1.\n"};
int ActiveScreen = 0;
nsa const char *ExGetKSymbol(CPU::ExceptionFrame *Frame)
{
if (Frame->rip < (uintptr_t)&_kernel_start &&
Frame->rip > (uintptr_t)&_kernel_end)
return "<OUTSIDE KERNEL>";
if (KernelSymbolTable)
#if defined(a64)
return KernelSymbolTable->GetSymbol(Frame->rip);
#elif defined(a32)
return KernelSymbolTable->GetSymbol(Frame->eip);
#elif defined(aa64)
return KernelSymbolTable->GetSymbol(Frame->pc);
#endif
return "<UNKNOWN>";
}
nsa 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;
}
nsa void ExDumpData(void *Address, unsigned long Length)
{
ExPrint("\eAAAAAA-------------------------------------------------------------------------\n");
Display->UpdateBuffer();
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)
ExPrint(" \e8A78FF%s\eAABBCC\n", Buffer);
ExPrint(" \e9E9E9E%04x\eAABBCC ", Iterate);
Display->UpdateBuffer();
}
ExPrint(" \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)
{
ExPrint(" ");
Display->UpdateBuffer();
Iterate++;
}
ExPrint(" \e8A78FF%s\eAAAAAA\n", Buffer);
ExPrint("-------------------------------------------------------------------------\n\n.");
Display->UpdateBuffer();
}
nsa void DisplayTopOverlay()
{
Video::Font *f = Display->GetCurrentFont();
Video::FontInfo fi = f->GetInfo();
for (uint32_t i = 0; i < Display->GetWidth; i++)
{
for (uint32_t j = 0; j < fi.Height + 8; j++)
{
// uint32_t grayValue = 0x505050 - (j * 0x020202);
// Display->SetPixel(i, j, grayValue);
Display->SetPixel(i, j, 0x202020);
}
}
for (uint32_t i = 0; i < Display->GetWidth; i++)
Display->SetPixel(i, fi.Height + 8, 0x404040);
Display->SetBufferCursor(8, (fi.Height + 8) / 6);
/* This wouldn't have enough space for a 640x480 screen */
// ExPrint("%sMAIN %sDETAILS %sSTACK %sPROCESS \eAAAAAA| ",
// ActiveScreen == 0 ? "\e00AAFF" : "\eAAAAAA",
// ActiveScreen == 1 ? "\e00AAFF" : "\eAAAAAA",
// ActiveScreen == 2 ? "\e00AAFF" : "\eAAAAAA",
// ActiveScreen == 3 ? "\e00AAFF" : "\eAAAAAA");
ExPrint("%s %s %s %s \eAAAAAA| ",
ActiveScreen == 0 ? "\eAAAAAA"
"MAIN "
: "\e5A5A5A"
"M",
ActiveScreen == 1 ? "\eAAAAAA"
"DETAIL "
: "\e5A5A5A"
"D",
ActiveScreen == 2 ? "\eAAAAAA"
"STACK "
: "\e5A5A5A"
"S",
ActiveScreen == 3 ? "\eAAAAAA"
"PROCESS"
: "\e5A5A5A"
"P");
ExPrint("%s %s %s | ", KERNEL_NAME, KERNEL_ARCH, KERNEL_VERSION);
ExPrint("%ld | ", TO_MiB(KernelAllocator.GetFreeMemory()));
ExPrint("%s %s", CPU::Hypervisor(), CPU::Vendor());
Display->SetBufferCursor(0, fi.Height + 10);
/* https://imgflip.com/i/77slbl */
if ((Random::rand32() % 100) >= 98)
{
debug("Easter egg activated!");
int BaseXOffset = Display->GetWidth - 14;
int BaseYOffset = 8;
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 0, 0x21852E);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 0, 0x21852E);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 0, 0x21852E);
Display->SetPixel(BaseXOffset + 7, BaseYOffset + 0, 0x21852E);
Display->SetPixel(BaseXOffset + 2, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 5, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 7, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 8, BaseYOffset + 1, 0x21852E);
Display->SetPixel(BaseXOffset + 1, BaseYOffset + 2, 0x21852E);
Display->SetPixel(BaseXOffset + 2, BaseYOffset + 2, 0x21852E);
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 2, 0xFFFFFF);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 2, 0x000000);
Display->SetPixel(BaseXOffset + 5, BaseYOffset + 2, 0x21852E);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 2, 0xFFFFFF);
Display->SetPixel(BaseXOffset + 7, BaseYOffset + 2, 0x000000);
Display->SetPixel(BaseXOffset + 8, BaseYOffset + 2, 0x21852E);
Display->SetPixel(BaseXOffset + 1, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 2, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 5, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 7, BaseYOffset + 3, 0x21852E);
Display->SetPixel(BaseXOffset + 0, BaseYOffset + 4, 0x21852E);
Display->SetPixel(BaseXOffset + 1, BaseYOffset + 4, 0x21852E);
Display->SetPixel(BaseXOffset + 2, BaseYOffset + 4, 0x21852E);
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 4, 0x21852E);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 4, 0xA84832);
Display->SetPixel(BaseXOffset + 5, BaseYOffset + 4, 0xA84832);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 4, 0xA84832);
Display->SetPixel(BaseXOffset + 7, BaseYOffset + 4, 0xA84832);
Display->SetPixel(BaseXOffset + 0, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 1, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 2, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 5, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 5, 0x21852E);
Display->SetPixel(BaseXOffset + 0, BaseYOffset + 6, 0x1216FF);
Display->SetPixel(BaseXOffset + 1, BaseYOffset + 6, 0x1216FF);
Display->SetPixel(BaseXOffset + 2, BaseYOffset + 6, 0x1216FF);
Display->SetPixel(BaseXOffset + 3, BaseYOffset + 6, 0x1216FF);
Display->SetPixel(BaseXOffset + 4, BaseYOffset + 6, 0x1216FF);
Display->SetPixel(BaseXOffset + 5, BaseYOffset + 6, 0x1216FF);
Display->SetPixel(BaseXOffset + 6, BaseYOffset + 6, 0x1216FF);
Display->UpdateBuffer();
}
}
nsa void DisplayBottomOverlay()
{
Video::Font *f = Display->GetCurrentFont();
Video::FontInfo fi = f->GetInfo();
for (uint32_t i = 0; i < Display->GetWidth; i++)
for (uint32_t j = Display->GetHeight - fi.Height - 8; j < Display->GetHeight; j++)
Display->SetPixel(i, j, 0x202020);
for (uint32_t i = 0; i < Display->GetWidth; i++)
Display->SetPixel(i, Display->GetHeight - fi.Height - 8, 0x404040);
Display->SetBufferCursor(8, Display->GetHeight - fi.Height - 4);
ExPrint("\eAAAAAA> \eFAFAFA");
}
nsa void DisplayMainScreen(CPU::ExceptionFrame *Frame)
{
ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n");
ExPrint("\nError: %s (%s 0x%x)\n",
#if defined(a86)
x86Exceptions[Frame->InterruptNumber].Name,
x86Exceptions[Frame->InterruptNumber].Mnemonic,
#elif defined(aa64)
#error "AA64 not implemented"
#endif
Frame->InterruptNumber);
#if defined(a86)
ExPrint("Cause: %s\n", x86Exceptions[Frame->InterruptNumber].Cause);
#endif
ExPrint("Exception occurred in function %s (%#lx)\n",
ExGetKSymbol(Frame),
#if defined(a64)
Frame->rip);
#elif defined(a32)
Frame->eip);
#elif defined(aa64)
Frame->pc);
#endif
CPUData *core = GetCurrentCPU();
if (TaskManager)
{
ExPrint("Core: %d / pid: %d / tid: %d\n", core->ID,
core->CurrentProcess->ID, core->CurrentThread->ID);
}
else if (core->IsActive)
ExPrint("Core: %d\n", core->ID);
ExPrint("\nWhat to do:\n");
ExPrint(" 1. Restart your device and see if the problem persists.\n");
ExPrint(" 2. Remove any newly installed hardware.\n");
ExPrint(" 3. Check for any available updates for your operating system.\n");
ExPrint(" 4. Uninstall any recently installed drivers or software.\n");
ExPrint(" If none of the above steps resolve the issue, create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n");
ExPrint("\nUse command 'diag' to create a diagnostic report.\n");
}
nsa void DisplayDetailsScreen(CPU::ExceptionFrame *Frame)
{
ExPrint("\n\eFAFAFAException Frame:\n");
ExPrint(" General Purpose Registers:\n\eAAAAAA");
ExPrint(" RAX: %#lx RBX: %#lx RCX: %#lx RDX: %#lx\n",
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
ExPrint(" RSI: %#lx RDI: %#lx R8: %#lx R9: %#lx\n",
Frame->rsi, Frame->rdi, Frame->r8, Frame->r9);
ExPrint(" R10: %#lx R11: %#lx R12: %#lx R13: %#lx\n",
Frame->r10, Frame->r11, Frame->r12, Frame->r13);
ExPrint(" R14: %#lx R15: %#lx\n", Frame->r14, Frame->r15);
ExPrint("\eFAFAFA Control Registers:\n\eAAAAAA");
ExPrint(" CR0: %#lx CR2: %#lx CR3: %#lx CR4: %#lx\n",
Frame->cr0, Frame->cr2, Frame->cr3, Frame->cr4);
ExPrint(" CR8: %#lx\n", Frame->cr8);
ExPrint("\eFAFAFA Segment Registers:\n\eAAAAAA");
ExPrint(" CS: %#lx SS: %#lx DS: %#lx ES: %#lx FS: %#lx GS: %#lx\n",
Frame->cs, Frame->ss, Frame->ds, Frame->es, Frame->fs, Frame->gs);
ExPrint("\eFAFAFA Debug Registers:\n\eAAAAAA");
ExPrint(" DR0: %#lx DR1: %#lx DR2: %#lx DR3: %#lx\n",
Frame->dr0, Frame->dr1, Frame->dr2, Frame->dr3);
ExPrint(" DR6: %#lx DR7: %#lx\n", Frame->dr6, Frame->dr7);
ExPrint("\eFAFAFA Other:\n\eAAAAAA");
ExPrint(" INT: %#lx ERR: %#lx RIP: %#lx RFLAGS: %#lx\n",
Frame->InterruptNumber, Frame->ErrorCode,
Frame->rip, Frame->rflags.raw);
ExPrint(" RSP: %#lx RBP: %#lx\n",
Frame->rsp, Frame->rbp);
ExPrint("\eFAFAFAException Details:\n");
switch (Frame->InterruptNumber)
{
case CPU::x86::PageFault:
{
CPU::x64::PageFaultErrorCode pfCode = {.raw = (uint32_t)Frame->ErrorCode};
ExPrint("P:%d W:%d U:%d R:%d I:%d PK:%d SS:%d SGX:%d\n",
pfCode.P, pfCode.W, pfCode.U, pfCode.R,
pfCode.I, pfCode.PK, pfCode.SS, pfCode.SGX);
ExPrint("%s", x86PageFaultDescriptions[Frame->ErrorCode & 0b111]);
if (Frame->ErrorCode & 0x8)
ExPrint("%s", x86PageFaultDescriptions[8]);
break;
}
case CPU::x86::StackSegmentFault:
case CPU::x86::GeneralProtectionFault:
{
CPU::x64::SelectorErrorCode sCode = {.raw = Frame->ErrorCode};
ExPrint("Kernel performed an illegal operation.\n");
ExPrint("External: %d\n", sCode.External);
ExPrint("Table: %d\n", sCode.Table);
ExPrint("Index: %#x\n", sCode.Idx);
break;
}
default:
ExPrint("No additional information available for this exception.\n");
break;
}
if (!TaskManager)
return;
CPUData *core = GetCurrentCPU();
Tasking::PCB *proc = core->CurrentProcess.load();
Tasking::TCB *thread = core->CurrentThread.load();
ExPrint("Exception in %s process %s(%d) thread %s(%d)\n",
proc->Security.ExecutionMode == Tasking::User ? "user" : "kernel",
proc->Name, proc->ID,
thread->Name, thread->ID);
}
nsa void DisplayStackScreen(CPU::ExceptionFrame *Frame)
{
Memory::Virtual vmm;
struct StackFrame *sf;
#if defined(a64)
sf = (struct StackFrame *)Frame->rbp;
#elif defined(a32)
sf = (struct StackFrame *)Frame->ebp;
#endif
ExPrint("\n\eFAFAFAStack trace (%#lx):\n", sf);
if (!vmm.Check(sf))
{
void *ptr = ((Memory::PageTable *)Frame->cr3)->Get(sf);
debug("Virtual pointer %#lx -> %#lx", sf, ptr);
if (vmm.Check(ptr))
sf = (struct StackFrame *)ptr;
else
{
ExPrint("\eFF0000< No stack trace available. >\n");
return;
}
}
/* FIXME: Get symbol offset more efficiently */
uintptr_t fIP;
#if defined(a64)
fIP = Frame->rip;
#elif defined(a32)
fIP = Frame->eip;
#elif defined(aa64)
fIP = Frame->pc;
#endif
ExPrint("\eAAAAAA%p", (void *)fIP);
ExPrint("\e5A5A5A in ");
if ((fIP >= (uintptr_t)&_kernel_start &&
fIP <= (uintptr_t)&_kernel_end))
{
const char *sym = KernelSymbolTable->GetSymbol(fIP);
ssize_t offset = fIP - KernelSymbolTable->GetSymbol(sym);
if (offset < 0)
offset = -offset;
ExPrint("\eFAFAFA%s\e5A5A5A+%#lx \eFFAAAA<- Exception\n",
sym, offset);
}
else
ExPrint("\eFF5555???\n");
if (!sf || !sf->ip || !sf->bp)
{
ExPrint("\n\eFF0000< No stack trace available. >\n");
return;
}
for (int i = 0; i < 16; ++i)
{
if (!sf->ip)
break;
ExPrint("\eAAAAAA%p", (void *)sf->ip);
ExPrint("\e5A5A5A in ");
if ((sf->ip >= (uintptr_t)&_kernel_start &&
sf->ip <= (uintptr_t)&_kernel_end))
{
const char *sym = KernelSymbolTable->GetSymbol(sf->ip);
ssize_t offset = sf->ip - KernelSymbolTable->GetSymbol(sym);
if (offset < 0)
offset = -offset;
ExPrint("\eFAFAFA%s\e5A5A5A+%#lx\n", sym, offset);
}
else
ExPrint("\eFF5555???\n");
if (!vmm.Check(sf->bp))
return;
sf = sf->bp;
}
}
nsa void DisplayProcessScreen(CPU::ExceptionFrame *Frame)
{
const char *StatusColor[] = {
"FF0000", // Unknown
"AAFF00", // Ready
"00AA00", // Running
"FFAA00", // Sleeping
"FFAA00", // Blocked
"FFAA00", // Stopped
"FFAA00", // Waiting
"FF00FF", // Core dump
"FF0088", // Zombie
"FF0000", // Terminated
};
const char *StatusString[] = {
"UNK", // Unknown
"RDY", // Ready
"RUN", // Running
"SLP", // Sleeping
"BLK", // Blocked
"STP", // Stopped
"WTG", // Waiting
"CRD", // Core dump
"ZMB", // Zombie
"TRM", // Terminated
};
if (!TaskManager)
{
ExPrint("\eFF5555Scheduler is not initialized\n");
return;
}
size_t textLimit = 32;
if (Display->GetWidth > 800 && Display->GetHeight > 600)
textLimit = 128;
std::list<Tasking::PCB *> Plist = TaskManager->GetProcessList();
ExPrint("\n\eFAFAFAProcess list (%ld):\n", Plist.size());
bool pRdy = false;
foreach (auto Process in Plist)
{
if (Process->State == Tasking::Ready)
{
pRdy = true;
debug("Ignoring ready process %s(%d)",
Process->Name, Process->ID);
continue;
}
ExPrint("\eAAAAAA-> \eFAFAFA%.*s%s\e8A8A8A(%ld) \e%s%s\n",
textLimit, Process->Name,
strlen(Process->Name) > textLimit ? "\e8A8A8A..." : "",
Process->ID, StatusColor[Process->State.load()],
StatusString[Process->State.load()]);
bool tRdy = false;
foreach (auto Thread in Process->Threads)
{
if (Thread->State == Tasking::Ready)
{
tRdy = true;
debug("Ignoring ready thread %s(%d)",
Thread->Name, Thread->ID);
continue;
}
ExPrint("\eAAAAAA -> \eFAFAFA%.*s%s\e8A8A8A(%ld) \e%s%s\n",
textLimit, Thread->Name,
strlen(Thread->Name) > textLimit ? "\e8A8A8A..." : "",
Thread->ID, StatusColor[Thread->State.load()],
StatusString[Thread->State.load()]);
}
if (tRdy)
ExPrint("\eAAAAAA%s -> \e8A8A8A...\n");
}
if (pRdy)
ExPrint("\eAAAAAA-> \e8A8A8A...\n");
ExPrint("\e5A5A5ANote: Some processes may not be displayed.\n");
}
CPU::ExceptionFrame *ExFrame;
nsa void DisplayCrashScreen(CPU::ExceptionFrame *Frame)
{
ExFrame = Frame;
/* TODO */
// void *BufferBeforeUpdate = KernelAllocator.RequestPages(TO_PAGES(Display->GetSize));
// if (BufferBeforeUpdate)
// memcpy(BufferBeforeUpdate, Display->GetBuffer, Display->GetSize);
Display->ClearBuffer();
if (Config.InterruptsOnCrash == false)
{
Display->SetBufferCursor(0, 0);
DisplayMainScreen(Frame);
Display->UpdateBuffer();
CPU::Stop();
}
DisplayTopOverlay();
DisplayMainScreen(Frame);
Display->UpdateBuffer();
new CrashKeyboardDriver;
DisplayBottomOverlay();
Display->UpdateBuffer();
CPU::Halt(true);
}
nsa void DisplayStackSmashing()
{
InitFont();
Display->ClearBuffer();
DisplayTopOverlay();
ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n");
ExPrint("\nError: Stack Smashing In Kernel Mode\n");
CPUData *core = GetCurrentCPU();
if (TaskManager)
{
ExPrint("Core: %d / pid: %d / tid: %d\n", core->ID,
core->CurrentProcess->ID, core->CurrentThread->ID);
}
else if (core->IsActive)
ExPrint("Core: %d\n", core->ID);
ExPrint("\nWhat to do:\n");
ExPrint(" This is a kernel bug.\n");
ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n");
Display->UpdateBuffer();
/* TODO: Add additional info */
}
nsa void DisplayBufferOverflow()
{
InitFont();
Display->ClearBuffer();
DisplayTopOverlay();
ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n");
ExPrint("\nError: Buffer Overflow In Kernel Mode\n");
CPUData *core = GetCurrentCPU();
if (TaskManager)
{
ExPrint("Core: %d / pid: %d / tid: %d\n", core->ID,
core->CurrentProcess->ID, core->CurrentThread->ID);
}
else if (core->IsActive)
ExPrint("Core: %d\n", core->ID);
ExPrint("\nWhat to do:\n");
ExPrint(" This is a kernel bug.\n");
ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n");
Display->UpdateBuffer();
/* TODO: Add additional info */
}
EXTERNC nsa __noreturn void DisplayAssertionFailed(const char *File, int Line,
const char *Expression)
{
InitFont();
Display->ClearBuffer();
DisplayTopOverlay();
ExPrint("\n\eFAFAFAWe're sorry, but the system has encountered a critical error and needs to restart.\n");
ExPrint("\nError: Assertion Failed\n");
ExPrint("In file \"%s\" at line %d, \"%s\" failed\n",
File, Line, Expression);
CPUData *core = GetCurrentCPU();
if (TaskManager)
{
ExPrint("Core: %d / pid: %d / tid: %d\n", core->ID,
core->CurrentProcess->ID, core->CurrentThread->ID);
}
else if (core->IsActive)
ExPrint("Core: %d\n", core->ID);
ExPrint("\nWhat to do:\n");
ExPrint(" This is a kernel bug.\n");
ExPrint(" Please create a new issue on \e00AAFFhttps://github.com/Fennix-Project/Fennix\eFAFAFA for further assistance.\n");
Display->UpdateBuffer();
CPU::Stop();
}
nsa void ArrowInput(uint8_t key)
{
switch (key)
{
case KEY_D_RIGHT:
if (ActiveScreen < 3)
ActiveScreen++;
else
return;
break;
case KEY_D_LEFT:
if (ActiveScreen > 0)
ActiveScreen--;
else
return;
break;
case KEY_D_DOWN:
case KEY_D_UP:
default:
return;
}
Display->ClearBuffer();
DisplayTopOverlay();
switch (ActiveScreen)
{
case 0:
DisplayMainScreen(ExFrame);
break;
case 1:
DisplayDetailsScreen(ExFrame);
break;
case 2:
DisplayStackScreen(ExFrame);
break;
case 3:
DisplayProcessScreen(ExFrame);
break;
default:
break;
}
DisplayBottomOverlay();
Display->UpdateBuffer();
}
nsa void UserInput(char *Input)
{
debug("User input: %s", Input);
Display->ClearBuffer();
DisplayTopOverlay();
if (strcmp(Input, "help") == 0)
{
ExPrint("Commands:\n");
ExPrint("\eAAAAAA help - Display this help message.\n");
ExPrint("\eCACACA clear - Clear the screen.\n");
ExPrint("\eAAAAAA exit - Shutdown the device.\n");
ExPrint("\eCACACA reboot - Reboot the device.\n");
ExPrint("\eAAAAAA bitmap - Display the kernel's bitmap.\n");
ExPrint("\eCACACA mem - Display memory information.\n");
ExPrint("\eAAAAAA dump [addr] [len] - Dump [len] bytes from [addr].\n");
ExPrint("\eCACACA diag - Collect diagnostic information.\n");
}
else if (strcmp(Input, "clear") == 0)
{
Display->ClearBuffer();
DisplayTopOverlay();
}
else if (strcmp(Input, "exit") == 0)
{
Display->ClearBuffer();
const char msg[] = "Shutting down...";
size_t msgLen = strlen(msg);
size_t msgPixels = msgLen * CrashFont->GetInfo().Width;
uint32_t x = uint32_t((Display->GetWidth - msgPixels) / 2);
uint32_t y = uint32_t((Display->GetHeight - CrashFont->GetInfo().Height) / 2);
Display->SetBufferCursor(x, y);
Display->PrintString("\eAAAAAA");
Display->PrintString(msg, CrashFont);
Display->UpdateBuffer();
PowerManager->Shutdown();
CPU::Stop();
}
else if (strcmp(Input, "reboot") == 0)
{
Display->ClearBuffer();
const char msg[] = "Rebooting...";
size_t msgLen = strlen(msg);
size_t msgPixels = msgLen * CrashFont->GetInfo().Width;
uint32_t x = uint32_t((Display->GetWidth - msgPixels) / 2);
uint32_t y = uint32_t((Display->GetHeight - CrashFont->GetInfo().Height) / 2);
Display->SetBufferCursor(x, y);
Display->PrintString("\eAAAAAA");
Display->PrintString(msg, CrashFont);
Display->UpdateBuffer();
PowerManager->Reboot();
CPU::Stop();
}
else if (strncmp(Input, "bitmap", 6) == 0)
{
Bitmap bm = KernelAllocator.GetPageBitmap();
Video::Font *oldFont = CrashFont;
CrashFont = Display->GetDefaultFont();
ExPrint("\n\eAAAAAA[0%%] %08ld: ", 0);
for (size_t i = 0; i < bm.Size; i++)
{
if (bm.Get(i))
Display->PrintString("\eFF0000");
else
Display->PrintString("\e00FF00");
Display->Print('0');
if (i % 128 == 127)
{
short Percentage = s_cst(short, (i * 100) / bm.Size);
ExPrint("\n\eAAAAAA[%03ld%%] %08ld: ", Percentage, i);
Display->UpdateBuffer();
}
}
ExPrint("\n\eAAAAAA--- END OF BITMAP ---\nBitmap size: %ld\n\n.", bm.Size);
DisplayTopOverlay();
Display->UpdateBuffer();
CrashFont = oldFont;
}
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();
ExPrint("\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);
ExPrint("\e22AA44%3d%% \eCCCCCC[", Progress);
for (int i = 0; i < Progress; i++)
ExPrint("\eFF0000|");
for (int i = 0; i < 100 - Progress; i++)
ExPrint("\e00FF00|");
for (int i = 0; i < ReservedProgress; i++)
ExPrint("\eFF00FF|");
ExPrint("\eCCCCCC]\eAAAAAA\n");
}
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)
{
ExPrint("\eFF0000Invalid arguments\n");
goto End;
}
uintptr_t Address = strtoul(addr, NULL, 16);
size_t Length = strtoul(len, NULL, 10);
uintptr_t AlignedAddress = ROUND_DOWN(Address, PAGE_SIZE);
bool IsRangeValid = true;
{
Memory::Virtual vmm;
for (uintptr_t adr = AlignedAddress;
adr < Address + Length;
adr += PAGE_SIZE)
{
if (!vmm.Check((void *)adr))
{
ExPrint("\eFFA500Address %#lx is not mapped\n", adr);
IsRangeValid = false;
}
}
}
if (IsRangeValid)
{
debug("Dumping %ld bytes from %#lx\n", Length, Address);
Video::Font *oldFont = CrashFont;
CrashFont = Display->GetDefaultFont();
ExDumpData((void *)Address, (unsigned long)Length);
CrashFont = oldFont;
}
}
else if (strcmp(Input, "diag") == 0)
{
DiagnosticDataCollection();
}
#ifdef DEBUG
else if (strcmp(Input, "pt") == 0)
{
/* Helpful for qemu "info tlb" command */
CPU::PageTable((void *)ExFrame->cr3);
ExPrint("Here be dragons\n");
}
#endif // DEBUG
else if (strlen(Input) > 0)
ExPrint("Unknown command: %s", Input);
else
ExPrint("Use the 'help' command to display a list of available commands.");
End:
DisplayBottomOverlay();
Display->UpdateBuffer();
}

225
core/panic/user.cpp Normal file
View File

@ -0,0 +1,225 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
#include <display.hpp>
#include <printf.h>
#include <debug.h>
#include <smp.hpp>
#include <cpu.hpp>
#if defined(a64)
#include "../../arch/amd64/cpu/gdt.hpp"
#elif defined(a32)
#elif defined(aa64)
#endif
#include "../../kernel.h"
#ifdef DEBUG
nsa void dbgPrint(CPU::ExceptionFrame *Frame)
{
#if defined(a64)
CPU::x64::CR0 cr0 = CPU::x64::readcr0();
CPU::x64::CR2 cr2 = CPU::x64::CR2{.PFLA = Frame->cr2};
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));
#elif defined(a32)
CPU::x32::CR0 cr0 = CPU::x32::readcr0();
CPU::x32::CR2 cr2 = CPU::x32::CR2{.PFLA = CrashHandler::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));
#elif defined(aa64)
#endif
#if defined(a64)
debug("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
debug("R8=%#lx R9=%#lx R10=%#lx R11=%#lx", Frame->r8, Frame->r9, Frame->r10, Frame->r11);
debug("R12=%#lx R13=%#lx R14=%#lx R15=%#lx", Frame->r12, Frame->r13, Frame->r14, Frame->r15);
debug("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
debug("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
debug("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx EFER=%#lx", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
#elif defined(a32)
debug("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);
debug("EAX=%#x EBX=%#x ECX=%#x EDX=%#x", Frame->eax, Frame->ebx, Frame->ecx, Frame->edx);
debug("ESI=%#x EDI=%#x EBP=%#x ESP=%#x", Frame->esi, Frame->edi, Frame->ebp, Frame->esp);
debug("EIP=%#x EFL=%#x INT=%#x ERR=%#x", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode);
#elif defined(aa64)
#endif
#if defined(a86)
debug("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw);
debug("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",
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);
debug("CR2: PFLA: %#lx",
cr2.PFLA);
debug("CR3: PWT:%s PCD:%s PDBR:%#llx",
cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR);
#endif // defined(a86)
#if defined(a64)
debug("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",
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);
#elif defined(a32)
debug("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",
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);
#endif
#if defined(a86)
debug("CR8: TPL:%d", cr8.TPL);
#endif // defined(a86)
#if defined(a64)
debug("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);
#elif defined(a32)
debug("EFL: 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);
#elif defined(aa64)
#endif
#if defined(a64)
debug("EFER: SCE:%s LME:%s LMA:%s NXE:%s SVME:%s LMSLE:%s FFXSR:%s TCE:%s R0:%#x R1:%#x R2:%#x",
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
}
#endif
nsa bool UserModeExceptionHandler(CPU::ExceptionFrame *Frame)
{
CPUData *core = GetCurrentCPU();
Tasking::PCB *proc = core->CurrentProcess;
Tasking::TCB *thread = core->CurrentThread;
debug("Current process %s(%d) and thread %s(%d)",
proc->Name, proc->ID, thread->Name, thread->ID);
thread->SetState(Tasking::Waiting);
#ifdef DEBUG
dbgPrint(Frame);
#endif
switch (Frame->InterruptNumber)
{
case CPU::x86::PageFault:
{
bool Handled = proc->vma->HandleCoW(Frame->cr2);
if (!Handled)
Handled = thread->Stack->Expand(Frame->cr2);
if (Handled)
{
debug("Page fault handled");
thread->SetState(Tasking::Ready);
return true;
}
proc->Signals->SendSignal(SIGSEGV,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::Debug:
case CPU::x86::Breakpoint:
{
proc->Signals->SendSignal(SIGTRAP,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::DivideByZero:
case CPU::x86::Overflow:
case CPU::x86::BoundRange:
case CPU::x86::x87FloatingPoint:
case CPU::x86::SIMDFloatingPoint:
{
proc->Signals->SendSignal(SIGFPE,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::InvalidOpcode:
case CPU::x86::GeneralProtectionFault:
{
proc->Signals->SendSignal(SIGILL,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::DeviceNotAvailable:
{
proc->Signals->SendSignal(SIGBUS,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::NonMaskableInterrupt:
case CPU::x86::DoubleFault:
case CPU::x86::CoprocessorSegmentOverrun:
case CPU::x86::InvalidTSS:
case CPU::x86::SegmentNotPresent:
case CPU::x86::StackSegmentFault:
case CPU::x86::AlignmentCheck:
case CPU::x86::MachineCheck:
case CPU::x86::Virtualization:
case CPU::x86::Security:
default:
{
error("Unhandled exception %d on CPU %d",
Frame->InterruptNumber, core->ID);
break;
}
}
error("User mode exception handler failed");
return false;
}

View File

@ -21,9 +21,12 @@
#include "../kernel.h"
/* EXTERNC */ __weak uintptr_t __stack_chk_guard = 0;
extern __noreturn void HandleStackSmashing();
extern __noreturn void HandleBufferOverflow();
EXTERNC __weak __no_stack_protector uintptr_t __stack_chk_guard_init(void)
/* EXTERNC */ uintptr_t __stack_chk_guard = 0;
EXTERNC __no_stack_protector uintptr_t __stack_chk_guard_init(void)
{
int MaxRetries = 0;
#if UINTPTR_MAX == UINT32_MAX
@ -52,55 +55,26 @@ EXTERNC __constructor __no_stack_protector void __guard_setup(void)
debug("Stack guard value: %ld", __stack_chk_guard);
}
EXTERNC __weak __noreturn __no_stack_protector void __stack_chk_fail(void)
EXTERNC __noreturn __no_stack_protector void __stack_chk_fail(void)
{
TaskingPanic();
for (short i = 0; i < 10; i++)
error("Stack smashing detected!");
debug("Current stack check guard value: %#lx", __stack_chk_guard);
KPrint("\eFF0000Stack smashing detected!");
void *Stack = nullptr;
#if defined(a86)
#if defined(a64)
asmv("movq %%rsp, %0"
: "=r"(Stack));
#elif defined(a32)
asmv("movl %%esp, %0"
: "=r"(Stack));
#endif
#elif defined(aa64)
asmv("mov %%sp, %0"
: "=r"(Stack));
#endif
error("Stack address: %#lx", Stack);
if (DebuggerIsAttached)
#ifdef a86
asmv("int $0x3");
#elif defined(aa64)
asmv("brk #0");
#endif
CPU::Stop();
HandleStackSmashing();
}
// https://github.com/gcc-mirror/gcc/blob/master/libssp/ssp.c
EXTERNC __weak __noreturn __no_stack_protector void __chk_fail(void)
EXTERNC __noreturn nsa void __chk_fail(void)
{
TaskingPanic();
for (short i = 0; i < 10; i++)
error("Buffer overflow detected!");
KPrint("\eFF0000Buffer overflow detected!");
#if defined(a86)
while (1)
asmv("cli; hlt");
#elif defined(aa64)
asmv("wfe");
#endif
HandleBufferOverflow();
}

View File

@ -38,7 +38,6 @@ namespace Interrupts
/* APIC::Timer */ extern void *apicTimer[255]; // MAX_CPU
#elif defined(aa64)
#endif
extern void *InterruptFrames[INT_FRAMES_MAX];
void Initialize(int Core);
void Enable(int Core);

View File

@ -20,15 +20,18 @@
#include <debug.h>
#define assert(x) \
do \
{ \
if (__builtin_expect(!!(!(x)), 0)) \
{ \
error("Assertion failed! [%s]", #x); \
int3; \
__builtin_unreachable(); \
} \
EXTERNC void __attribute__((noreturn)) DisplayAssertionFailed(const char *File, int Line,
const char *Expression);
#define assert(x) \
do \
{ \
if (__builtin_expect(!!(!(x)), 0)) \
{ \
error("Assertion failed! [%s]", #x); \
DisplayAssertionFailed(__FILE__, __LINE__, #x); \
__builtin_unreachable(); \
} \
} while (0)
#define assert_allow_continue(x) \