mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 07:19:20 +00:00
Revamped kernel panic functions with significant improvements
This commit is contained in:
145
core/panic/diag.cpp
Normal file
145
core/panic/diag.cpp
Normal 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
336
core/panic/handler.cpp
Normal 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
388
core/panic/keyboard.cpp
Normal 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
|
||||
}
|
219
core/panic/keyboard.hpp
Normal file
219
core/panic/keyboard.hpp
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
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 <ints.hpp>
|
||||
|
||||
#pragma once
|
||||
|
||||
enum Keys
|
||||
{
|
||||
KEY_INVALID = 0x0,
|
||||
KEY_D_ESCAPE = 0x1,
|
||||
KEY_D_1 = 0x2,
|
||||
KEY_D_2 = 0x3,
|
||||
KEY_D_3 = 0x4,
|
||||
KEY_D_4 = 0x5,
|
||||
KEY_D_5 = 0x6,
|
||||
KEY_D_6 = 0x7,
|
||||
KEY_D_7 = 0x8,
|
||||
KEY_D_8 = 0x9,
|
||||
KEY_D_9 = 0xa,
|
||||
KEY_D_0 = 0xb,
|
||||
KEY_D_MINUS = 0xc,
|
||||
KEY_D_EQUALS = 0xd,
|
||||
KEY_D_BACKSPACE = 0xe,
|
||||
KEY_D_TAB = 0xf,
|
||||
KEY_D_Q = 0x10,
|
||||
KEY_D_W = 0x11,
|
||||
KEY_D_E = 0x12,
|
||||
KEY_D_R = 0x13,
|
||||
KEY_D_T = 0x14,
|
||||
KEY_D_Y = 0x15,
|
||||
KEY_D_U = 0x16,
|
||||
KEY_D_I = 0x17,
|
||||
KEY_D_O = 0x18,
|
||||
KEY_D_P = 0x19,
|
||||
KEY_D_LBRACKET = 0x1a,
|
||||
KEY_D_RBRACKET = 0x1b,
|
||||
KEY_D_RETURN = 0x1c,
|
||||
KEY_D_LCTRL = 0x1d,
|
||||
KEY_D_A = 0x1e,
|
||||
KEY_D_S = 0x1f,
|
||||
KEY_D_D = 0x20,
|
||||
KEY_D_F = 0x21,
|
||||
KEY_D_G = 0x22,
|
||||
KEY_D_H = 0x23,
|
||||
KEY_D_J = 0x24,
|
||||
KEY_D_K = 0x25,
|
||||
KEY_D_L = 0x26,
|
||||
KEY_D_SEMICOLON = 0x27,
|
||||
KEY_D_APOSTROPHE = 0x28,
|
||||
KEY_D_GRAVE = 0x29,
|
||||
KEY_D_LSHIFT = 0x2a,
|
||||
KEY_D_BACKSLASH = 0x2b,
|
||||
KEY_D_Z = 0x2c,
|
||||
KEY_D_X = 0x2d,
|
||||
KEY_D_C = 0x2e,
|
||||
KEY_D_V = 0x2f,
|
||||
KEY_D_B = 0x30,
|
||||
KEY_D_N = 0x31,
|
||||
KEY_D_M = 0x32,
|
||||
KEY_D_COMMA = 0x33,
|
||||
KEY_D_PERIOD = 0x34,
|
||||
KEY_D_SLASH = 0x35,
|
||||
KEY_D_RSHIFT = 0x36,
|
||||
KEY_D_PRTSC = 0x37,
|
||||
KEY_D_LALT = 0x38,
|
||||
KEY_D_SPACE = 0x39,
|
||||
KEY_D_CAPSLOCK = 0x3a,
|
||||
KEY_D_NUMLOCK = 0x45,
|
||||
KEY_D_SCROLLLOCK = 0x46,
|
||||
|
||||
KEY_D_KP_MULTIPLY = 0x37,
|
||||
KEY_D_KP_7 = 0x47,
|
||||
KEY_D_KP_8 = 0x48,
|
||||
KEY_D_KP_9 = 0x49,
|
||||
KEY_D_KP_MINUS = 0x4a,
|
||||
KEY_D_KP_4 = 0x4b,
|
||||
KEY_D_KP_5 = 0x4c,
|
||||
KEY_D_KP_6 = 0x4d,
|
||||
KEY_D_KP_PLUS = 0x4e,
|
||||
KEY_D_KP_1 = 0x4f,
|
||||
KEY_D_KP_2 = 0x50,
|
||||
KEY_D_KP_3 = 0x51,
|
||||
KEY_D_KP_0 = 0x52,
|
||||
KEY_D_KP_PERIOD = 0x53,
|
||||
|
||||
KEY_D_F1 = 0x3b,
|
||||
KEY_D_F2 = 0x3c,
|
||||
KEY_D_F3 = 0x3d,
|
||||
KEY_D_F4 = 0x3e,
|
||||
KEY_D_F5 = 0x3f,
|
||||
KEY_D_F6 = 0x40,
|
||||
KEY_D_F7 = 0x41,
|
||||
KEY_D_F8 = 0x42,
|
||||
KEY_D_F9 = 0x43,
|
||||
KEY_D_F10 = 0x44,
|
||||
KEY_D_F11 = 0x57,
|
||||
KEY_D_F12 = 0x58,
|
||||
|
||||
KEY_D_UP = 0x48,
|
||||
KEY_D_LEFT = 0x4b,
|
||||
KEY_D_RIGHT = 0x4d,
|
||||
KEY_D_DOWN = 0x50,
|
||||
|
||||
KEY_U_ESCAPE = 0x81,
|
||||
KEY_U_1 = 0x82,
|
||||
KEY_U_2 = 0x83,
|
||||
KEY_U_3 = 0x84,
|
||||
KEY_U_4 = 0x85,
|
||||
KEY_U_5 = 0x86,
|
||||
KEY_U_6 = 0x87,
|
||||
KEY_U_7 = 0x88,
|
||||
KEY_U_8 = 0x89,
|
||||
KEY_U_9 = 0x8a,
|
||||
KEY_U_0 = 0x8b,
|
||||
KEY_U_MINUS = 0x8c,
|
||||
KEY_U_EQUALS = 0x8d,
|
||||
KEY_U_BACKSPACE = 0x8e,
|
||||
KEY_U_TAB = 0x8f,
|
||||
KEY_U_Q = 0x90,
|
||||
KEY_U_W = 0x91,
|
||||
KEY_U_E = 0x92,
|
||||
KEY_U_R = 0x93,
|
||||
KEY_U_T = 0x94,
|
||||
KEY_U_Y = 0x95,
|
||||
KEY_U_U = 0x96,
|
||||
KEY_U_I = 0x97,
|
||||
KEY_U_O = 0x98,
|
||||
KEY_U_P = 0x99,
|
||||
KEY_U_LBRACKET = 0x9a,
|
||||
KEY_U_RBRACKET = 0x9b,
|
||||
KEY_U_RETURN = 0x9c,
|
||||
KEY_U_LCTRL = 0x9d,
|
||||
KEY_U_A = 0x9e,
|
||||
KEY_U_S = 0x9f,
|
||||
KEY_U_D = 0xa0,
|
||||
KEY_U_F = 0xa1,
|
||||
KEY_U_G = 0xa2,
|
||||
KEY_U_H = 0xa3,
|
||||
KEY_U_J = 0xa4,
|
||||
KEY_U_K = 0xa5,
|
||||
KEY_U_L = 0xa6,
|
||||
KEY_U_SEMICOLON = 0xa7,
|
||||
KEY_U_APOSTROPHE = 0xa8,
|
||||
KEY_U_GRAVE = 0xa9,
|
||||
KEY_U_LSHIFT = 0xaa,
|
||||
KEY_U_BACKSLASH = 0xab,
|
||||
KEY_U_Z = 0xac,
|
||||
KEY_U_X = 0xad,
|
||||
KEY_U_C = 0xae,
|
||||
KEY_U_V = 0xaf,
|
||||
KEY_U_B = 0xb0,
|
||||
KEY_U_N = 0xb1,
|
||||
KEY_U_M = 0xb2,
|
||||
KEY_U_COMMA = 0xb3,
|
||||
KEY_U_PERIOD = 0xb4,
|
||||
KEY_U_SLASH = 0xb5,
|
||||
KEY_U_RSHIFT = 0xb6,
|
||||
KEY_U_KP_MULTIPLY = 0xb7,
|
||||
KEY_U_LALT = 0xb8,
|
||||
KEY_U_SPACE = 0xb9,
|
||||
KEY_U_CAPSLOCK = 0xba,
|
||||
KEY_U_F1 = 0xbb,
|
||||
KEY_U_F2 = 0xbc,
|
||||
KEY_U_F3 = 0xbd,
|
||||
KEY_U_F4 = 0xbe,
|
||||
KEY_U_F5 = 0xbf,
|
||||
KEY_U_F6 = 0xc0,
|
||||
KEY_U_F7 = 0xc1,
|
||||
KEY_U_F8 = 0xc2,
|
||||
KEY_U_F9 = 0xc3,
|
||||
KEY_U_F10 = 0xc4,
|
||||
KEY_U_NUMLOCK = 0xc5,
|
||||
KEY_U_SCROLLLOCK = 0xc6,
|
||||
KEY_U_KP_7 = 0xc7,
|
||||
KEY_U_KP_8 = 0xc8,
|
||||
KEY_U_KP_9 = 0xc9,
|
||||
KEY_U_KP_MINUS = 0xca,
|
||||
KEY_U_KP_4 = 0xcb,
|
||||
KEY_U_KP_5 = 0xcc,
|
||||
KEY_U_KP_6 = 0xcd,
|
||||
KEY_U_KP_PLUS = 0xce,
|
||||
KEY_U_KP_1 = 0xcf,
|
||||
KEY_U_KP_2 = 0xd0,
|
||||
KEY_U_KP_3 = 0xd1,
|
||||
KEY_U_KP_0 = 0xd2,
|
||||
KEY_U_KP_PERIOD = 0xd3,
|
||||
KEY_U_F11 = 0xd7,
|
||||
KEY_U_F12 = 0xd8,
|
||||
};
|
||||
|
||||
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() {}
|
||||
};
|
920
core/panic/ui.cpp
Normal file
920
core/panic/ui.cpp
Normal 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
225
core/panic/user.cpp
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user