Files
.github
.vscode
Architecture
Core
Crash
Screens
CrashDetails.cpp
CrashHandler.cpp
KBDrv.cpp
SFrame.cpp
UserHandler.cpp
chfcts.hpp
Driver
Memory
Time
Video
CPU.cpp
Debugger.cpp
Disk.cpp
InterruptsManager.cpp
Lock.cpp
PeripheralComponentInterconnect.cpp
Power.cpp
README.md
Random.cpp
StackCheck.cpp
Symbols.cpp
SystemManagementBIOS.cpp
UndefinedBehaviorSanitization.c
UniversalAsynchronousReceiverTransmitter.cpp
crashhandler.hpp
smbios.hpp
ubsan.h
ExecutionLayer
FileSystem
Files
KernelShell
Library
Modules
Network
Profiling
SystemCalls
Tasking
Tests
Virtualization
include
include_std
.gitignore
DAPI.hpp
Doxyfile
Fex.hpp
Kernel.cpp
KernelConfig.cpp
KernelThread.cpp
LICENSE
Makefile
README.md
dump.sh
ipc.h
kernel.h
syscalls.h
Kernel/Core/Crash/UserHandler.cpp
2023-08-06 04:53:14 +03:00

399 lines
19 KiB
C++

/*
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 "../../Architecture/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"};
SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
{
CriticalSection cs;
debug("Interrupts? %s.", cs.IsInterruptsEnabled() ? "Yes" : "No");
fixme("Handling user mode exception");
thisThread->Status = Tasking::TaskStatus::Zombie;
CPUData *CurCPU = GetCurrentCPU();
{
#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);
error("Technical Informations on CPU %lld:", CurCPU->ID);
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();
error("Technical Informations on CPU %lld:", CurCPU->ID);
uintptr_t ds;
asmv("mov %%ds, %0"
: "=r"(ds));
#elif defined(aa64)
#endif
#if defined(a64)
error("FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
error("R8=%#llx R9=%#llx R10=%#llx R11=%#llx", Frame->r8, Frame->r9, Frame->r10, Frame->r11);
error("R12=%#llx R13=%#llx R14=%#llx R15=%#llx", Frame->r12, Frame->r13, Frame->r14, Frame->r15);
error("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
error("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
error("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
#elif defined(a32)
error("FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx",
CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
error("EAX=%#llx EBX=%#llx ECX=%#llx EDX=%#llx", Frame->eax, Frame->ebx, Frame->ecx, Frame->edx);
error("ESI=%#llx EDI=%#llx EBP=%#llx ESP=%#llx", Frame->esi, Frame->edi, Frame->ebp, Frame->esp);
error("EIP=%#llx EFL=%#llx INT=%#llx ERR=%#llx", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode);
#elif defined(aa64)
#endif
#if defined(a86)
error("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw);
error("CR0: PE:%s MP:%s EM:%s TS:%s ET:%s NE:%s WP:%s AM:%s NW:%s CD:%s PG:%s R0:%#x R1:%#x R2:%#x",
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);
error("CR2: PFLA: %#llx",
cr2.PFLA);
error("CR3: PWT:%s PCD:%s PDBR:%#llx",
cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR);
#endif // defined(a86)
#if defined(a64)
error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x R2:%#x",
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)
error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x",
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)
error("CR8: TPL:%d", cr8.TPL);
#endif // defined(a86)
#if defined(a64)
error("RFL: CF:%s PF:%s AF:%s ZF:%s SF:%s TF:%s IF:%s DF:%s OF:%s IOPL:%s NT:%s RF:%s VM:%s AC:%s VIF:%s VIP:%s ID:%s AlwaysOne:%d R0:%#x R1:%#x R2:%#x R3:%#x",
Frame->rflags.CF ? "True " : "False", Frame->rflags.PF ? "True " : "False", Frame->rflags.AF ? "True " : "False", Frame->rflags.ZF ? "True " : "False",
Frame->rflags.SF ? "True " : "False", Frame->rflags.TF ? "True " : "False", Frame->rflags.IF ? "True " : "False", Frame->rflags.DF ? "True " : "False",
Frame->rflags.OF ? "True " : "False", Frame->rflags.IOPL ? "True " : "False", Frame->rflags.NT ? "True " : "False", Frame->rflags.RF ? "True " : "False",
Frame->rflags.VM ? "True " : "False", Frame->rflags.AC ? "True " : "False", Frame->rflags.VIF ? "True " : "False", Frame->rflags.VIP ? "True " : "False",
Frame->rflags.ID ? "True " : "False", Frame->rflags.AlwaysOne,
Frame->rflags.Reserved0, Frame->rflags.Reserved1, Frame->rflags.Reserved2, Frame->rflags.Reserved3);
#elif defined(a32)
error("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)
error("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
}
switch (Frame->InterruptNumber)
{
case CPU::x86::DivideByZero:
{
break;
}
case CPU::x86::Debug:
{
break;
}
case CPU::x86::NonMaskableInterrupt:
{
break;
}
case CPU::x86::Breakpoint:
{
break;
}
case CPU::x86::Overflow:
{
break;
}
case CPU::x86::BoundRange:
{
break;
}
case CPU::x86::InvalidOpcode:
{
break;
}
case CPU::x86::DeviceNotAvailable:
{
break;
}
case CPU::x86::DoubleFault:
{
break;
}
case CPU::x86::CoprocessorSegmentOverrun:
{
break;
}
case CPU::x86::InvalidTSS:
{
break;
}
case CPU::x86::SegmentNotPresent:
{
break;
}
case CPU::x86::StackSegmentFault:
{
break;
}
case CPU::x86::GeneralProtectionFault:
{
break;
}
case CPU::x86::PageFault:
{
uintptr_t CheckPageFaultAddress = 0;
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
#if defined(a64)
CheckPageFaultAddress = CrashHandler::PageFaultAddress;
if (CheckPageFaultAddress == 0)
CheckPageFaultAddress = Frame->rip;
error("An exception occurred at %#lx by %#lx", CrashHandler::PageFaultAddress, Frame->rip);
#elif defined(a32)
error("An exception occurred at %#lx by %#lx", CrashHandler::PageFaultAddress, Frame->eip);
#elif defined(aa64)
#endif
error("Page: %s", params.P ? "Present" : "Not Present");
error("Write Operation: %s", params.W ? "Read-Only" : "Read-Write");
error("Processor Mode: %s", params.U ? "User-Mode" : "Kernel-Mode");
error("CPU Reserved Bits: %s", params.R ? "Reserved" : "Unreserved");
error("Caused By An Instruction Fetch: %s", params.I ? "Yes" : "No");
error("Caused By A Protection-Key Violation: %s", params.PK ? "Yes" : "No");
error("Caused By A Shadow Stack Access: %s", params.SS ? "Yes" : "No");
error("Caused By An SGX Violation: %s", params.SGX ? "Yes" : "No");
if (Frame->ErrorCode & 0x00000008)
error("One or more page directory entries contain reserved bits which are set to 1.");
else
error(PageFaultDescriptions[Frame->ErrorCode & 0b111]);
#ifdef DEBUG
if (CurCPU)
{
Memory::Virtual vmm = Memory::Virtual(CurCPU->CurrentProcess->PageTable);
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);
Memory::PageMapLevel4 PML4 = CurCPU->CurrentProcess->PageTable->Entries[Index.PMLIndex];
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
if (CurCPU)
if (CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress))
{
debug("Stack expanded");
thisThread->Status = Tasking::TaskStatus::Ready;
return;
}
break;
}
case CPU::x86::x87FloatingPoint:
{
break;
}
case CPU::x86::AlignmentCheck:
{
break;
}
case CPU::x86::MachineCheck:
{
break;
}
case CPU::x86::SIMDFloatingPoint:
{
break;
}
case CPU::x86::Virtualization:
{
break;
}
case CPU::x86::Security:
{
break;
}
default:
{
break;
}
}
thisThread->Status = Tasking::TaskStatus::Terminated;
__sync;
error("End of report.");
CPU::Interrupts(CPU::Enable);
debug("Interrupts enabled back.");
return;
}