mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-07-13 16:29:17 +00:00
Merge remote-tracking branch 'Kernel/multiboot2_64' into Kernel-multiboot2_64
This commit is contained in:
489
Kernel/Core/CPU.cpp
Normal file
489
Kernel/Core/CPU.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
#include <smp.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace CPU
|
||||
{
|
||||
static bool SSEEnabled = false;
|
||||
|
||||
char *Vendor()
|
||||
{
|
||||
static char Vendor[13];
|
||||
#if defined(a64)
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x64::cpuid(0x0, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Vendor + 0, &ebx, 4);
|
||||
memcpy_unsafe(Vendor + 4, &edx, 4);
|
||||
memcpy_unsafe(Vendor + 8, &ecx, 4);
|
||||
#elif defined(a32)
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x32::cpuid(0x0, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Vendor + 0, &ebx, 4);
|
||||
memcpy_unsafe(Vendor + 4, &edx, 4);
|
||||
memcpy_unsafe(Vendor + 8, &ecx, 4);
|
||||
#elif defined(aa64)
|
||||
asmv("mrs %0, MIDR_EL1"
|
||||
: "=r"(Vendor[0]));
|
||||
#endif
|
||||
return Vendor;
|
||||
}
|
||||
|
||||
char *Name()
|
||||
{
|
||||
static char Name[49];
|
||||
#if defined(a64)
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x64::cpuid(0x80000002, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Name + 0, &eax, 4);
|
||||
memcpy_unsafe(Name + 4, &ebx, 4);
|
||||
memcpy_unsafe(Name + 8, &ecx, 4);
|
||||
memcpy_unsafe(Name + 12, &edx, 4);
|
||||
x64::cpuid(0x80000003, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Name + 16, &eax, 4);
|
||||
memcpy_unsafe(Name + 20, &ebx, 4);
|
||||
memcpy_unsafe(Name + 24, &ecx, 4);
|
||||
memcpy_unsafe(Name + 28, &edx, 4);
|
||||
x64::cpuid(0x80000004, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Name + 32, &eax, 4);
|
||||
memcpy_unsafe(Name + 36, &ebx, 4);
|
||||
memcpy_unsafe(Name + 40, &ecx, 4);
|
||||
memcpy_unsafe(Name + 44, &edx, 4);
|
||||
#elif defined(a32)
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x32::cpuid(0x80000002, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Name + 0, &eax, 4);
|
||||
memcpy_unsafe(Name + 4, &ebx, 4);
|
||||
memcpy_unsafe(Name + 8, &ecx, 4);
|
||||
memcpy_unsafe(Name + 12, &edx, 4);
|
||||
x32::cpuid(0x80000003, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Name + 16, &eax, 4);
|
||||
memcpy_unsafe(Name + 20, &ebx, 4);
|
||||
memcpy_unsafe(Name + 24, &ecx, 4);
|
||||
memcpy_unsafe(Name + 28, &edx, 4);
|
||||
x32::cpuid(0x80000004, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Name + 32, &eax, 4);
|
||||
memcpy_unsafe(Name + 36, &ebx, 4);
|
||||
memcpy_unsafe(Name + 40, &ecx, 4);
|
||||
memcpy_unsafe(Name + 44, &edx, 4);
|
||||
#elif defined(aa64)
|
||||
asmv("mrs %0, MIDR_EL1"
|
||||
: "=r"(Name[0]));
|
||||
#endif
|
||||
return Name;
|
||||
}
|
||||
|
||||
char *Hypervisor()
|
||||
{
|
||||
static char Hypervisor[13];
|
||||
#if defined(a64)
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x64::cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Hypervisor + 0, &ebx, 4);
|
||||
memcpy_unsafe(Hypervisor + 4, &ecx, 4);
|
||||
memcpy_unsafe(Hypervisor + 8, &edx, 4);
|
||||
#elif defined(a32)
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x64::cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
|
||||
memcpy_unsafe(Hypervisor + 0, &ebx, 4);
|
||||
memcpy_unsafe(Hypervisor + 4, &ecx, 4);
|
||||
memcpy_unsafe(Hypervisor + 8, &edx, 4);
|
||||
#elif defined(aa64)
|
||||
asmv("mrs %0, MIDR_EL1"
|
||||
: "=r"(Hypervisor[0]));
|
||||
#endif
|
||||
return Hypervisor;
|
||||
}
|
||||
|
||||
bool Interrupts(InterruptsType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case Check:
|
||||
{
|
||||
uintptr_t Flags;
|
||||
#if defined(a64)
|
||||
asmv("pushfq");
|
||||
asmv("popq %0"
|
||||
: "=r"(Flags));
|
||||
return Flags & (1 << 9);
|
||||
#elif defined(a32)
|
||||
asmv("pushfl");
|
||||
asmv("popl %0"
|
||||
: "=r"(Flags));
|
||||
return Flags & (1 << 9);
|
||||
#elif defined(aa64)
|
||||
asmv("mrs %0, daif"
|
||||
: "=r"(Flags));
|
||||
return !(Flags & (1 << 2));
|
||||
#endif
|
||||
}
|
||||
case Enable:
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("sti");
|
||||
#elif defined(aa64)
|
||||
asmv("msr daifclr, #2");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
case Disable:
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cli");
|
||||
#elif defined(aa64)
|
||||
asmv("msr daifset, #2");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void *PageTable(void *PT)
|
||||
{
|
||||
#if defined(a64)
|
||||
if (PT)
|
||||
asmv("movq %0, %%cr3"
|
||||
:
|
||||
: "r"(PT));
|
||||
else
|
||||
asmv("movq %%cr3, %0"
|
||||
: "=r"(PT));
|
||||
#elif defined(a32)
|
||||
if (PT)
|
||||
asmv("movl %0, %%cr3"
|
||||
:
|
||||
: "r"(PT));
|
||||
else
|
||||
asmv("movl %%cr3, %0"
|
||||
: "=r"(PT));
|
||||
#elif defined(aa64)
|
||||
if (PT)
|
||||
asmv("msr ttbr0_el1, %0"
|
||||
:
|
||||
: "r"(PT));
|
||||
else
|
||||
asmv("mrs %0, ttbr0_el1"
|
||||
: "=r"(PT));
|
||||
#endif
|
||||
return PT;
|
||||
}
|
||||
|
||||
void InitializeFeatures(long Core)
|
||||
{
|
||||
bool PGESupport = false;
|
||||
bool SSESupport = false;
|
||||
#if defined(a64)
|
||||
static int BSP = 0;
|
||||
x64::CR0 cr0 = x64::readcr0();
|
||||
x64::CR4 cr4 = x64::readcr4();
|
||||
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::AMD::CPUID0x1 cpuid1amd;
|
||||
#elif defined(a32)
|
||||
CPU::x32::AMD::CPUID0x1 cpuid1amd;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1amd.EAX.raw), "=b"(cpuid1amd.EBX.raw), "=c"(cpuid1amd.ECX.raw), "=d"(cpuid1amd.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
if (cpuid1amd.EDX.PGE)
|
||||
PGESupport = true;
|
||||
if (cpuid1amd.EDX.SSE)
|
||||
SSESupport = true;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::Intel::CPUID0x1 cpuid1intel;
|
||||
#elif defined(a32)
|
||||
CPU::x32::Intel::CPUID0x1 cpuid1intel;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1intel.EAX.raw), "=b"(cpuid1intel.EBX.raw), "=c"(cpuid1intel.ECX.raw), "=d"(cpuid1intel.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
if (cpuid1intel.EDX.PGE)
|
||||
PGESupport = true;
|
||||
if (cpuid1intel.EDX.SSE)
|
||||
SSESupport = true;
|
||||
}
|
||||
|
||||
if (Config.SIMD == false)
|
||||
{
|
||||
debug("Disabling SSE support...");
|
||||
SSESupport = false;
|
||||
}
|
||||
|
||||
if (PGESupport)
|
||||
{
|
||||
debug("Enabling global pages support...");
|
||||
if (!BSP)
|
||||
KPrint("Global Pages is supported.");
|
||||
cr4.PGE = 1;
|
||||
}
|
||||
|
||||
bool SSEEnableAfter = false;
|
||||
|
||||
/* Not sure if my code is not working properly or something else is the issue. */
|
||||
if ((strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) != 0 &&
|
||||
strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0) &&
|
||||
SSESupport)
|
||||
{
|
||||
debug("Enabling SSE support...");
|
||||
if (!BSP)
|
||||
KPrint("SSE is supported.");
|
||||
cr0.EM = 0;
|
||||
cr0.MP = 1;
|
||||
cr4.OSFXSR = 1;
|
||||
cr4.OSXMMEXCPT = 1;
|
||||
|
||||
CPUData *CoreData = GetCPU(Core);
|
||||
CoreData->Data.FPU = (CPU::x64::FXState *)KernelAllocator.RequestPages(TO_PAGES(sizeof(CPU::x64::FXState)));
|
||||
memset(CoreData->Data.FPU, 0, FROM_PAGES(TO_PAGES(sizeof(CPU::x64::FXState))));
|
||||
CoreData->Data.FPU->mxcsr = 0b0001111110000000;
|
||||
CoreData->Data.FPU->mxcsrmask = 0b1111111110111111;
|
||||
CoreData->Data.FPU->fcw = 0b0000001100111111;
|
||||
CPU::x64::fxrstor(CoreData->Data.FPU);
|
||||
|
||||
SSEEnableAfter = true;
|
||||
}
|
||||
|
||||
if (!BSP)
|
||||
KPrint("Enabling CPU cache.");
|
||||
|
||||
cr0.NW = 0;
|
||||
cr0.CD = 0;
|
||||
cr0.WP = 1;
|
||||
|
||||
x64::writecr0(cr0);
|
||||
|
||||
// FIXME: I don't think this is reporting correctly. This has to be fixed asap.
|
||||
debug("Enabling UMIP, SMEP & SMAP support...");
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
x64::cpuid(0x1, &eax, &ebx, &ecx, &edx);
|
||||
if (edx & (1 << 2)) // https://en.wikipedia.org/wiki/Control_register
|
||||
{
|
||||
if (!BSP)
|
||||
KPrint("UMIP is supported.");
|
||||
debug("UMIP is supported.");
|
||||
// cr4.UMIP = 1;
|
||||
}
|
||||
if (edx & (1 << 7)) // https://en.wikipedia.org/wiki/Control_register#SMEP
|
||||
// https://web.archive.org/web/20160312223150/http://ncsi.com/nsatc11/presentations/wednesday/emerging_technologies/fischer.pdf
|
||||
{
|
||||
if (!BSP)
|
||||
KPrint("SMEP is supported.");
|
||||
debug("SMEP is supported.");
|
||||
// cr4.SMEP = 1;
|
||||
}
|
||||
if (edx & (1 << 20)) // https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention
|
||||
{
|
||||
if (!BSP)
|
||||
KPrint("SMAP is supported.");
|
||||
debug("SMAP is supported.");
|
||||
// cr4.SMAP = 1;
|
||||
}
|
||||
if (strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0 &&
|
||||
strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
|
||||
{
|
||||
debug("Writing CR4...");
|
||||
x64::writecr4(cr4);
|
||||
debug("Wrote CR4.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!BSP)
|
||||
{
|
||||
if (strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) == 0)
|
||||
KPrint("VirtualBox detected. Not using UMIP, SMEP & SMAP");
|
||||
else if (strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) == 0)
|
||||
KPrint("QEMU (TCG) detected. Not using UMIP, SMEP & SMAP");
|
||||
}
|
||||
}
|
||||
debug("Enabling PAT support...");
|
||||
x64::wrmsr(x64::MSR_CR_PAT, 0x6 | (0x0 << 8) | (0x1 << 16));
|
||||
if (!BSP++)
|
||||
trace("Features for BSP initialized.");
|
||||
if (SSEEnableAfter)
|
||||
SSEEnabled = true;
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t Counter()
|
||||
{
|
||||
// TODO: Get the counter from the x2APIC or any other timer that is available. (TSC is not available on all CPUs)
|
||||
uintptr_t Counter;
|
||||
#if defined(a64)
|
||||
asmv("rdtsc"
|
||||
: "=A"(Counter));
|
||||
#elif defined(a32)
|
||||
asmv("rdtsc"
|
||||
: "=A"(Counter));
|
||||
#elif defined(aa64)
|
||||
asmv("mrs %0, cntvct_el0"
|
||||
: "=r"(Counter));
|
||||
#endif
|
||||
return Counter;
|
||||
}
|
||||
|
||||
x86SIMDType CheckSIMD()
|
||||
{
|
||||
#if defined(a32)
|
||||
return SIMD_NONE; /* TODO: Support x86 SIMD on x32 */
|
||||
#endif
|
||||
|
||||
if (unlikely(!SSEEnabled))
|
||||
return SIMD_NONE;
|
||||
|
||||
static x86SIMDType SIMDType = SIMD_NONE;
|
||||
|
||||
if (likely(SIMDType != SIMD_NONE))
|
||||
return SIMDType;
|
||||
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::AMD::CPUID0x1 cpuid1amd;
|
||||
#elif defined(a32)
|
||||
CPU::x32::AMD::CPUID0x1 cpuid1amd;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1amd.EAX.raw), "=b"(cpuid1amd.EBX.raw), "=c"(cpuid1amd.ECX.raw), "=d"(cpuid1amd.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
if (cpuid1amd.ECX.SSE4_2)
|
||||
SIMDType = SIMD_SSE42;
|
||||
else if (cpuid1amd.ECX.SSE4_1)
|
||||
SIMDType = SIMD_SSE41;
|
||||
else if (cpuid1amd.ECX.SSE3)
|
||||
SIMDType = SIMD_SSE3;
|
||||
else if (cpuid1amd.EDX.SSE2)
|
||||
SIMDType = SIMD_SSE2;
|
||||
else if (cpuid1amd.EDX.SSE)
|
||||
SIMDType = SIMD_SSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (cpuid1amd.ECX.SSE4_2)
|
||||
debug("SSE4.2 is supported.");
|
||||
if (cpuid1amd.ECX.SSE4_1)
|
||||
debug("SSE4.1 is supported.");
|
||||
if (cpuid1amd.ECX.SSE3)
|
||||
debug("SSE3 is supported.");
|
||||
if (cpuid1amd.EDX.SSE2)
|
||||
debug("SSE2 is supported.");
|
||||
if (cpuid1amd.EDX.SSE)
|
||||
debug("SSE is supported.");
|
||||
#endif
|
||||
|
||||
return SIMDType;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::Intel::CPUID0x1 cpuid1intel;
|
||||
#elif defined(a32)
|
||||
CPU::x32::Intel::CPUID0x1 cpuid1intel;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1intel.EAX.raw), "=b"(cpuid1intel.EBX.raw), "=c"(cpuid1intel.ECX.raw), "=d"(cpuid1intel.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
if (cpuid1intel.ECX.SSE4_2)
|
||||
SIMDType = SIMD_SSE42;
|
||||
else if (cpuid1intel.ECX.SSE4_1)
|
||||
SIMDType = SIMD_SSE41;
|
||||
else if (cpuid1intel.ECX.SSE3)
|
||||
SIMDType = SIMD_SSE3;
|
||||
else if (cpuid1intel.EDX.SSE2)
|
||||
SIMDType = SIMD_SSE2;
|
||||
else if (cpuid1intel.EDX.SSE)
|
||||
SIMDType = SIMD_SSE;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (cpuid1intel.ECX.SSE4_2)
|
||||
debug("SSE4.2 is supported.");
|
||||
if (cpuid1intel.ECX.SSE4_1)
|
||||
debug("SSE4.1 is supported.");
|
||||
if (cpuid1intel.ECX.SSE3)
|
||||
debug("SSE3 is supported.");
|
||||
if (cpuid1intel.EDX.SSE2)
|
||||
debug("SSE2 is supported.");
|
||||
if (cpuid1intel.EDX.SSE)
|
||||
debug("SSE is supported.");
|
||||
#endif
|
||||
|
||||
return SIMDType;
|
||||
}
|
||||
|
||||
return SIMD_NONE;
|
||||
}
|
||||
|
||||
bool CheckSIMD(x86SIMDType Type)
|
||||
{
|
||||
if (unlikely(!SSEEnabled))
|
||||
return false;
|
||||
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::AMD::CPUID0x1 cpuid1amd;
|
||||
#elif defined(a32)
|
||||
CPU::x32::AMD::CPUID0x1 cpuid1amd;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1amd.EAX.raw), "=b"(cpuid1amd.EBX.raw), "=c"(cpuid1amd.ECX.raw), "=d"(cpuid1amd.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
if (Type == SIMD_SSE42)
|
||||
return cpuid1amd.ECX.SSE4_2;
|
||||
else if (Type == SIMD_SSE41)
|
||||
return cpuid1amd.ECX.SSE4_1;
|
||||
else if (Type == SIMD_SSE3)
|
||||
return cpuid1amd.ECX.SSE3;
|
||||
else if (Type == SIMD_SSE2)
|
||||
return cpuid1amd.EDX.SSE2;
|
||||
else if (Type == SIMD_SSE)
|
||||
return cpuid1amd.EDX.SSE;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::Intel::CPUID0x1 cpuid1intel;
|
||||
#elif defined(a32)
|
||||
CPU::x32::Intel::CPUID0x1 cpuid1intel;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1intel.EAX.raw), "=b"(cpuid1intel.EBX.raw), "=c"(cpuid1intel.ECX.raw), "=d"(cpuid1intel.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
if (Type == SIMD_SSE42)
|
||||
return cpuid1intel.ECX.SSE4_2;
|
||||
else if (Type == SIMD_SSE41)
|
||||
return cpuid1intel.ECX.SSE4_1;
|
||||
else if (Type == SIMD_SSE3)
|
||||
return cpuid1intel.ECX.SSE3;
|
||||
else if (Type == SIMD_SSE2)
|
||||
return cpuid1intel.EDX.SSE2;
|
||||
else if (Type == SIMD_SSE)
|
||||
return cpuid1intel.EDX.SSE;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
324
Kernel/Core/Crash/CrashDetails.cpp
Normal file
324
Kernel/Core/Crash/CrashDetails.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
#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 DivideByZeroExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Divide by zero exception\n");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void DebugExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
CrashHandler::EHPrint("Kernel triggered debug exception.\n");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void NonMaskableInterruptExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("NMI exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void BreakpointExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Breakpoint exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void OverflowExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Overflow exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void BoundRangeExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Bound range exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void InvalidOpcodeExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
CrashHandler::EHPrint("Kernel tried to execute an invalid opcode.\n");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void DeviceNotAvailableExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Device not available exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void DoubleFaultExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Double fault exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void CoprocessorSegmentOverrunExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Coprocessor segment overrun exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void InvalidTSSExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Invalid TSS exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void SegmentNotPresentExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Segment not present exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void StackFaultExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
|
||||
#if defined(a64)
|
||||
CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->rip);
|
||||
#elif defined(a32)
|
||||
CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->eip);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
CrashHandler::EHPrint("External: %d\n", SelCode.External);
|
||||
CrashHandler::EHPrint("Table: %d\n", SelCode.Table);
|
||||
CrashHandler::EHPrint("Index: %#x\n", SelCode.Idx);
|
||||
CrashHandler::EHPrint("Error code: %#lx\n", Frame->ErrorCode);
|
||||
}
|
||||
|
||||
SafeFunction void GeneralProtectionExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
|
||||
// switch (SelCode.Table)
|
||||
// {
|
||||
// case CPU::x64::0b00:
|
||||
// memcpy(desc_tmp, "GDT", 3);
|
||||
// break;
|
||||
// case CPU::x64::0b01:
|
||||
// memcpy(desc_tmp, "IDT", 3);
|
||||
// break;
|
||||
// case CPU::x64::0b10:
|
||||
// memcpy(desc_tmp, "LDT", 3);
|
||||
// break;
|
||||
// case CPU::x64::0b11:
|
||||
// memcpy(desc_tmp, "IDT", 3);
|
||||
// break;
|
||||
// default:
|
||||
// memcpy(desc_tmp, "Unknown", 7);
|
||||
// break;
|
||||
// }
|
||||
CrashHandler::EHPrint("Kernel performed an illegal operation.\n");
|
||||
CrashHandler::EHPrint("External: %d\n", SelCode.External);
|
||||
CrashHandler::EHPrint("Table: %d\n", SelCode.Table);
|
||||
CrashHandler::EHPrint("Index: %#x\n", SelCode.Idx);
|
||||
}
|
||||
|
||||
SafeFunction void PageFaultExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
|
||||
#if defined(a64)
|
||||
CrashHandler::EHPrint("\eAFAFAFAn exception occurred at %#lx by %#lx\n", CrashHandler::PageFaultAddress, Frame->rip);
|
||||
#elif defined(a32)
|
||||
CrashHandler::EHPrint("\eAFAFAFAn exception occurred at %#lx by %#lx\n", CrashHandler::PageFaultAddress, Frame->eip);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
CrashHandler::EHPrint("Page: %s\n", params.P ? "Present" : "Not Present");
|
||||
CrashHandler::EHPrint("Write Operation: %s\n", params.W ? "Read-Only" : "Read-Write");
|
||||
CrashHandler::EHPrint("Processor Mode: %s\n", params.U ? "User-Mode" : "Kernel-Mode");
|
||||
CrashHandler::EHPrint("CPU Reserved Bits: %s\n", params.R ? "Reserved" : "Unreserved");
|
||||
CrashHandler::EHPrint("Caused By An Instruction Fetch: %s\n", params.I ? "Yes" : "No");
|
||||
CrashHandler::EHPrint("Caused By A Protection-Key Violation: %s\n", params.PK ? "Yes" : "No");
|
||||
CrashHandler::EHPrint("Caused By A Shadow Stack Access: %s\n", params.SS ? "Yes" : "No");
|
||||
CrashHandler::EHPrint("Caused By An SGX Violation: %s\n", params.SGX ? "Yes" : "No");
|
||||
if (Frame->ErrorCode & 0x00000008)
|
||||
CrashHandler::EHPrint("One or more page directory entries contain reserved bits which are set to 1.\n");
|
||||
else
|
||||
CrashHandler::EHPrint(PageFaultDescriptions[Frame->ErrorCode & 0b111]);
|
||||
|
||||
#ifdef DEBUG
|
||||
uintptr_t CheckPageFaultAddress = 0;
|
||||
CheckPageFaultAddress = CrashHandler::PageFaultAddress;
|
||||
if (CheckPageFaultAddress == 0)
|
||||
#ifdef a64
|
||||
CheckPageFaultAddress = Frame->rip;
|
||||
#elif defined(a32)
|
||||
CheckPageFaultAddress = Frame->eip;
|
||||
#elif defined(aa64)
|
||||
CheckPageFaultAddress = 0;
|
||||
#endif
|
||||
|
||||
#if defined(a64)
|
||||
Memory::Virtual vma = Memory::Virtual(((Memory::PageTable4 *)CPU::x64::readcr3().raw));
|
||||
#elif defined(a32)
|
||||
Memory::Virtual vma = Memory::Virtual(((Memory::PageTable4 *)CPU::x32::readcr3().raw));
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
bool PageAvailable = vma.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 = vma.Check((void *)CheckPageFaultAddress);
|
||||
bool ReadWrite = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW);
|
||||
bool User = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US);
|
||||
bool WriteThrough = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT);
|
||||
bool CacheDisabled = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD);
|
||||
bool Accessed = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A);
|
||||
bool Dirty = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D);
|
||||
bool Global = vma.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)
|
||||
{
|
||||
uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress;
|
||||
CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000;
|
||||
debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress);
|
||||
|
||||
Memory::Virtual::PageMapIndexer Index = Memory::Virtual::PageMapIndexer((uintptr_t)CheckPageFaultLinearAddress);
|
||||
debug("Index for %#lx is PML:%d PDPTE:%d PDE:%d PTE:%d",
|
||||
CheckPageFaultLinearAddress,
|
||||
Index.PMLIndex,
|
||||
Index.PDPTEIndex,
|
||||
Index.PDEIndex,
|
||||
Index.PTEIndex);
|
||||
#if defined(a64)
|
||||
Memory::PageMapLevel4 PML4 = ((Memory::PageTable4 *)CPU::x64::readcr3().raw)->Entries[Index.PMLIndex];
|
||||
#elif defined(a32)
|
||||
Memory::PageMapLevel4 PML4 = ((Memory::PageTable4 *)CPU::x32::readcr3().raw)->Entries[Index.PMLIndex];
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
Memory::PageDirectoryPointerTableEntryPtr *PDPTE = (Memory::PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
|
||||
Memory::PageDirectoryEntryPtr *PDE = (Memory::PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
Memory::PageTableEntryPtr *PTE = (Memory::PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
|
||||
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
|
||||
Index.PMLIndex, 0, 0, 0,
|
||||
PML4.Present ? "1" : "0",
|
||||
PML4.ReadWrite ? "1" : "0",
|
||||
PML4.UserSupervisor ? "1" : "0",
|
||||
PML4.WriteThrough ? "1" : "0",
|
||||
PML4.CacheDisable ? "1" : "0",
|
||||
PML4.Accessed ? "1" : "0",
|
||||
PML4.ExecuteDisable ? "1" : "0",
|
||||
PML4.GetAddress() << 12);
|
||||
|
||||
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
|
||||
Index.PMLIndex, Index.PDPTEIndex, 0, 0,
|
||||
PDPTE->Entries[Index.PDPTEIndex].Present ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].ReadWrite ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].UserSupervisor ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].WriteThrough ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].CacheDisable ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].Accessed ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].ExecuteDisable ? "1" : "0",
|
||||
PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
|
||||
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
|
||||
Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, 0,
|
||||
PDE->Entries[Index.PDEIndex].Present ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].ReadWrite ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].UserSupervisor ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].WriteThrough ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].CacheDisable ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].Accessed ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].ExecuteDisable ? "1" : "0",
|
||||
PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
|
||||
debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s D:%s PAT:%s G:%s PK:%d NX:%s Address:%#lx",
|
||||
Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, Index.PTEIndex,
|
||||
PTE->Entries[Index.PTEIndex].Present ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].ReadWrite ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].UserSupervisor ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].WriteThrough ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].CacheDisable ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].Accessed ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].Dirty ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].PageAttributeTable ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].Global ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].ProtectionKey,
|
||||
PTE->Entries[Index.PTEIndex].ExecuteDisable ? "1" : "0",
|
||||
PTE->Entries[Index.PTEIndex].GetAddress() << 12);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SafeFunction void x87FloatingPointExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("x87 floating point exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void AlignmentCheckExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Alignment check exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void MachineCheckExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Machine check exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void SIMDFloatingPointExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("SIMD floating point exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void VirtualizationExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Virtualization exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void SecurityExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Security exception");
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
SafeFunction void UnknownExceptionHandler(CHArchTrapFrame *Frame)
|
||||
{
|
||||
fixme("Unknown exception");
|
||||
UNUSED(Frame);
|
||||
}
|
1063
Kernel/Core/Crash/CrashHandler.cpp
Normal file
1063
Kernel/Core/Crash/CrashHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
165
Kernel/Core/Crash/KBDrv.cpp
Normal file
165
Kernel/Core/Crash/KBDrv.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
#include "../crashhandler.hpp"
|
||||
#include "chfcts.hpp"
|
||||
|
||||
#include <display.hpp>
|
||||
#include <convert.h>
|
||||
#include <printf.h>
|
||||
#include <debug.h>
|
||||
#include <smp.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#if defined(a64)
|
||||
#include "../../Architecture/amd64/cpu/gdt.hpp"
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y',
|
||||
'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g',
|
||||
'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v',
|
||||
'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '};
|
||||
|
||||
const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^',
|
||||
'&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
|
||||
'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G',
|
||||
'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V',
|
||||
'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '};
|
||||
|
||||
static int LowerCase = true;
|
||||
|
||||
static inline int GetLetterFromScanCode(uint8_t ScanCode)
|
||||
{
|
||||
if (ScanCode & 0x80)
|
||||
{
|
||||
switch (ScanCode)
|
||||
{
|
||||
case KEY_U_LSHIFT:
|
||||
LowerCase = true;
|
||||
return KEY_INVALID;
|
||||
case KEY_U_RSHIFT:
|
||||
LowerCase = true;
|
||||
return KEY_INVALID;
|
||||
default:
|
||||
return KEY_INVALID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ScanCode)
|
||||
{
|
||||
case KEY_D_RETURN:
|
||||
return '\n';
|
||||
case KEY_D_LSHIFT:
|
||||
LowerCase = false;
|
||||
return KEY_INVALID;
|
||||
case KEY_D_RSHIFT:
|
||||
LowerCase = false;
|
||||
return KEY_INVALID;
|
||||
case KEY_D_BACKSPACE:
|
||||
return ScanCode;
|
||||
default:
|
||||
{
|
||||
if (ScanCode > 0x39)
|
||||
break;
|
||||
if (LowerCase)
|
||||
return sc_ascii_low[ScanCode];
|
||||
else
|
||||
return sc_ascii_high[ScanCode];
|
||||
}
|
||||
}
|
||||
}
|
||||
return KEY_INVALID;
|
||||
}
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(CPU::x86::IRQ1)
|
||||
{
|
||||
while (inb(0x64) & 0x1)
|
||||
inb(0x60);
|
||||
|
||||
outb(0x64, 0xAE);
|
||||
outb(0x64, 0x20);
|
||||
uint8_t ret = (inb(0x60) | 1) & ~0x10;
|
||||
outb(0x64, 0x60);
|
||||
outb(0x60, ret);
|
||||
outb(0x60, 0xF4);
|
||||
|
||||
outb(0x21, 0xFD);
|
||||
outb(0xA1, 0xFF);
|
||||
CPU::Interrupts(CPU::Enable); // Just to be sure.
|
||||
}
|
||||
|
||||
CrashKeyboardDriver::~CrashKeyboardDriver()
|
||||
{
|
||||
error("CrashKeyboardDriver::~CrashKeyboardDriver() called!");
|
||||
}
|
||||
|
||||
int BackSpaceLimit = 0;
|
||||
static char UserInputBuffer[1024];
|
||||
|
||||
#if defined(a64)
|
||||
SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
|
||||
#elif defined(a32)
|
||||
SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
|
||||
#elif defined(aa64)
|
||||
SafeFunction void CrashKeyboardDriver::OnInterruptReceived(void *Frame)
|
||||
#endif
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
int key = GetLetterFromScanCode(scanCode);
|
||||
if (key != KEY_INVALID)
|
||||
{
|
||||
if (key == KEY_D_BACKSPACE)
|
||||
{
|
||||
if (BackSpaceLimit > 0)
|
||||
{
|
||||
Display->Print('\b', SBIdx);
|
||||
backspace(UserInputBuffer);
|
||||
BackSpaceLimit--;
|
||||
}
|
||||
}
|
||||
else if (key == '\n')
|
||||
{
|
||||
UserInput(UserInputBuffer);
|
||||
BackSpaceLimit = 0;
|
||||
UserInputBuffer[0] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
append(UserInputBuffer, key);
|
||||
Display->Print(key, SBIdx);
|
||||
BackSpaceLimit++;
|
||||
}
|
||||
Display->SetBuffer(SBIdx); // Update as we type.
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction void HookKeyboard()
|
||||
{
|
||||
CrashKeyboardDriver kbd; // We don't want to allocate memory.
|
||||
asmv("KeyboardHookLoop: nop; jmp KeyboardHookLoop;");
|
||||
// CPU::Halt(true); // This is an infinite loop.
|
||||
}
|
||||
}
|
120
Kernel/Core/Crash/SFrame.cpp
Normal file
120
Kernel/Core/Crash/SFrame.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#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"
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
struct StackFrame
|
||||
{
|
||||
struct StackFrame *rbp;
|
||||
uintptr_t rip;
|
||||
};
|
||||
|
||||
SafeFunction void TraceFrames(CHArchTrapFrame *Frame, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel)
|
||||
{
|
||||
if (!Memory::Virtual().Check(Frame))
|
||||
{
|
||||
EHPrint("Invalid frame pointer: %p\n", Frame);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(a64)
|
||||
struct StackFrame *frames = (struct StackFrame *)Frame->rbp; // (struct StackFrame *)__builtin_frame_address(0);
|
||||
if (!Memory::Virtual().Check((void *)Frame->rbp))
|
||||
#elif defined(a32)
|
||||
struct StackFrame *frames = (struct StackFrame *)Frame->ebp; // (struct StackFrame *)__builtin_frame_address(0);
|
||||
if (!Memory::Virtual().Check((void *)Frame->ebp))
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
{
|
||||
#if defined(a64)
|
||||
EHPrint("Invalid rbp pointer: %p\n", Frame->rbp);
|
||||
#elif defined(a32)
|
||||
EHPrint("Invalid ebp pointer: %p\n", Frame->ebp);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Memory::Virtual().Check(SymHandle))
|
||||
{
|
||||
EHPrint("Invalid symbol handle: %p\n", SymHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("\nStack tracing... %p %d %p %d", Frame, Count, frames, Kernel);
|
||||
EHPrint("\e7981FC\nStack Trace:\n");
|
||||
if (!frames || !frames->rip || !frames->rbp)
|
||||
{
|
||||
#if defined(a64)
|
||||
EHPrint("\e2565CC%p", (void *)Frame->rip);
|
||||
#elif defined(a32)
|
||||
EHPrint("\e2565CC%p", (void *)Frame->eip);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("\e7925CC-");
|
||||
#if defined(a64)
|
||||
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(Frame->rip));
|
||||
#elif defined(a32)
|
||||
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(Frame->eip));
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("\e7981FC <- Exception");
|
||||
EHPrint("\eFF0000\n< No stack trace available. >\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(a64)
|
||||
EHPrint("\e2565CC%p", (void *)Frame->rip);
|
||||
EHPrint("\e7925CC-");
|
||||
if ((Frame->rip >= 0xFFFFFFFF80000000 && Frame->rip <= (uintptr_t)&_kernel_end) || !Kernel)
|
||||
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(Frame->rip));
|
||||
else
|
||||
EHPrint("Outside Kernel");
|
||||
#elif defined(a32)
|
||||
EHPrint("\e2565CC%p", (void *)Frame->eip);
|
||||
EHPrint("\e7925CC-");
|
||||
if ((Frame->eip >= 0xC0000000 && Frame->eip <= (uintptr_t)&_kernel_end) || !Kernel)
|
||||
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(Frame->eip));
|
||||
else
|
||||
EHPrint("Outside Kernel");
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("\e7981FC <- Exception");
|
||||
for (int frame = 0; frame < Count; ++frame)
|
||||
{
|
||||
if (!frames->rip)
|
||||
break;
|
||||
EHPrint("\n\e2565CC%p", (void *)frames->rip);
|
||||
EHPrint("\e7925CC-");
|
||||
#if defined(a64)
|
||||
if ((frames->rip >= 0xFFFFFFFF80000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel)
|
||||
#elif defined(a32)
|
||||
if ((frames->rip >= 0xC0000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("\e25CCC9%s", SymHandle->GetSymbolFromAddress(frames->rip));
|
||||
else
|
||||
EHPrint("\eFF4CA9Outside Kernel");
|
||||
|
||||
if (!Memory::Virtual().Check(frames->rbp))
|
||||
return;
|
||||
frames = frames->rbp;
|
||||
}
|
||||
}
|
||||
EHPrint("\n");
|
||||
}
|
||||
}
|
25
Kernel/Core/Crash/Screens/Console.cpp
Normal file
25
Kernel/Core/Crash/Screens/Console.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#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"
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
SafeFunction void DisplayConsoleScreen(CRData data)
|
||||
{
|
||||
EHPrint("TODO");
|
||||
UNUSED(data);
|
||||
}
|
||||
}
|
247
Kernel/Core/Crash/Screens/Details.cpp
Normal file
247
Kernel/Core/Crash/Screens/Details.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
#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"
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
SafeFunction void DisplayDetailsScreen(CRData data)
|
||||
{
|
||||
if (data.Process)
|
||||
EHPrint("\e7981FCCurrent Process: %s(%ld)\n",
|
||||
data.Process->Name,
|
||||
data.Process->ID);
|
||||
if (data.Thread)
|
||||
EHPrint("\e7981FCCurrent Thread: %s(%ld)\n",
|
||||
data.Thread->Name,
|
||||
data.Thread->ID);
|
||||
EHPrint("\e7981FCTechnical Informations on CPU %lld:\n", data.ID);
|
||||
uintptr_t ds;
|
||||
#if defined(a64)
|
||||
|
||||
CPUData *cpu = (CPUData *)data.CPUData;
|
||||
if (cpu)
|
||||
{
|
||||
EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu);
|
||||
EHPrint("Syscalls Stack: %#lx, TempStack: %#lx\n", cpu->SystemCallStack, cpu->TempStack);
|
||||
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n", cpu->Stack, cpu->ID, cpu->ErrorCode);
|
||||
EHPrint("Is Active: %s\n", cpu->IsActive ? "true" : "false");
|
||||
EHPrint("Current Process: %#lx, Current Thread: %#lx\n", cpu->CurrentProcess, cpu->CurrentThread);
|
||||
EHPrint("Arch Specific Data: %#lx\n", cpu->Data);
|
||||
EHPrint("Checksum: 0x%X\n", cpu->Checksum);
|
||||
}
|
||||
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
#elif defined(a32)
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#if defined(a64)
|
||||
EHPrint("\e7981FCFS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx\n",
|
||||
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||
data.Frame->ss, data.Frame->cs, ds);
|
||||
EHPrint("R8=%#llx R9=%#llx R10=%#llx R11=%#llx\n", data.Frame->r8, data.Frame->r9, data.Frame->r10, data.Frame->r11);
|
||||
EHPrint("R12=%#llx R13=%#llx R14=%#llx R15=%#llx\n", data.Frame->r12, data.Frame->r13, data.Frame->r14, data.Frame->r15);
|
||||
EHPrint("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx\n", data.Frame->rax, data.Frame->rbx, data.Frame->rcx, data.Frame->rdx);
|
||||
EHPrint("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx\n", data.Frame->rsi, data.Frame->rdi, data.Frame->rbp, data.Frame->rsp);
|
||||
EHPrint("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx\n", data.Frame->rip, data.Frame->rflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw);
|
||||
#elif defined(a32)
|
||||
EHPrint("\e7981FCFS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx\n",
|
||||
CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE),
|
||||
data.Frame->ss, data.Frame->cs, ds);
|
||||
EHPrint("EAX=%#llx EBX=%#llx ECX=%#llx EDX=%#llx\n", data.Frame->eax, data.Frame->ebx, data.Frame->ecx, data.Frame->edx);
|
||||
EHPrint("ESI=%#llx EDI=%#llx EBP=%#llx ESP=%#llx\n", data.Frame->esi, data.Frame->edi, data.Frame->ebp, data.Frame->esp);
|
||||
EHPrint("EIP=%#llx EFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx\n", data.Frame->eip, data.Frame->eflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx\n", data.cr0.raw, data.cr2.raw, data.cr3.raw, data.cr4.raw, data.cr8.raw);
|
||||
EHPrint("DR0=%#llx DR1=%#llx DR2=%#llx DR3=%#llx DR6=%#llx DR7=%#llx\n", data.dr0, data.dr1, data.dr2, data.dr3, data.dr6, data.dr7.raw);
|
||||
|
||||
EHPrint("\eFC797BCR0: PE:%s MP:%s EM:%s TS:%s\n ET:%s NE:%s WP:%s AM:%s\n NW:%s CD:%s PG:%s\n R0:%#x R1:%#x R2:%#x\n",
|
||||
data.cr0.PE ? "True " : "False", data.cr0.MP ? "True " : "False", data.cr0.EM ? "True " : "False", data.cr0.TS ? "True " : "False",
|
||||
data.cr0.ET ? "True " : "False", data.cr0.NE ? "True " : "False", data.cr0.WP ? "True " : "False", data.cr0.AM ? "True " : "False",
|
||||
data.cr0.NW ? "True " : "False", data.cr0.CD ? "True " : "False", data.cr0.PG ? "True " : "False",
|
||||
data.cr0.Reserved0, data.cr0.Reserved1, data.cr0.Reserved2);
|
||||
|
||||
EHPrint("\eFCBD79CR2: PFLA: %#llx\n",
|
||||
data.cr2.PFLA);
|
||||
|
||||
EHPrint("\e79FC84CR3: PWT:%s PCD:%s PDBR:%#llx\n",
|
||||
data.cr3.PWT ? "True " : "False", data.cr3.PCD ? "True " : "False", data.cr3.PDBR);
|
||||
|
||||
EHPrint("\eBD79FCCR4: VME:%s PVI:%s TSD:%s DE:%s\n PSE:%s PAE:%s MCE:%s PGE:%s\n PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s\n LA57:%s VMXE:%s SMXE:%s PCIDE:%s\n OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s\n R0:%#x R1:%#x R2:%#x\n",
|
||||
data.cr4.VME ? "True " : "False", data.cr4.PVI ? "True " : "False", data.cr4.TSD ? "True " : "False", data.cr4.DE ? "True " : "False",
|
||||
data.cr4.PSE ? "True " : "False", data.cr4.PAE ? "True " : "False", data.cr4.MCE ? "True " : "False", data.cr4.PGE ? "True " : "False",
|
||||
data.cr4.PCE ? "True " : "False", data.cr4.UMIP ? "True " : "False", data.cr4.OSFXSR ? "True " : "False", data.cr4.OSXMMEXCPT ? "True " : "False",
|
||||
data.cr4.LA57 ? "True " : "False", data.cr4.VMXE ? "True " : "False", data.cr4.SMXE ? "True " : "False", data.cr4.PCIDE ? "True " : "False",
|
||||
data.cr4.OSXSAVE ? "True " : "False", data.cr4.SMEP ? "True " : "False", data.cr4.SMAP ? "True " : "False", data.cr4.PKE ? "True " : "False",
|
||||
#if defined(a64)
|
||||
data.cr4.Reserved0, data.cr4.Reserved1, data.cr4.Reserved2);
|
||||
#elif defined(a32)
|
||||
data.cr4.Reserved0, data.cr4.Reserved1, 0);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
EHPrint("\e79FCF5CR8: TPL:%d\n", data.cr8.TPL);
|
||||
|
||||
#if defined(a64)
|
||||
EHPrint("\eFCFC02RFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x R3:%#x\n",
|
||||
data.Frame->rflags.CF ? "True " : "False", data.Frame->rflags.PF ? "True " : "False", data.Frame->rflags.AF ? "True " : "False", data.Frame->rflags.ZF ? "True " : "False",
|
||||
data.Frame->rflags.SF ? "True " : "False", data.Frame->rflags.TF ? "True " : "False", data.Frame->rflags.IF ? "True " : "False", data.Frame->rflags.DF ? "True " : "False",
|
||||
data.Frame->rflags.OF ? "True " : "False", data.Frame->rflags.IOPL ? "True " : "False", data.Frame->rflags.NT ? "True " : "False", data.Frame->rflags.RF ? "True " : "False",
|
||||
data.Frame->rflags.VM ? "True " : "False", data.Frame->rflags.AC ? "True " : "False", data.Frame->rflags.VIF ? "True " : "False", data.Frame->rflags.VIP ? "True " : "False",
|
||||
data.Frame->rflags.ID ? "True " : "False", data.Frame->rflags.AlwaysOne,
|
||||
data.Frame->rflags.Reserved0, data.Frame->rflags.Reserved1, data.Frame->rflags.Reserved2, data.Frame->rflags.Reserved3);
|
||||
#elif defined(a32)
|
||||
EHPrint("\eFCFC02EFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x\n",
|
||||
data.Frame->eflags.CF ? "True " : "False", data.Frame->eflags.PF ? "True " : "False", data.Frame->eflags.AF ? "True " : "False", data.Frame->eflags.ZF ? "True " : "False",
|
||||
data.Frame->eflags.SF ? "True " : "False", data.Frame->eflags.TF ? "True " : "False", data.Frame->eflags.IF ? "True " : "False", data.Frame->eflags.DF ? "True " : "False",
|
||||
data.Frame->eflags.OF ? "True " : "False", data.Frame->eflags.IOPL ? "True " : "False", data.Frame->eflags.NT ? "True " : "False", data.Frame->eflags.RF ? "True " : "False",
|
||||
data.Frame->eflags.VM ? "True " : "False", data.Frame->eflags.AC ? "True " : "False", data.Frame->eflags.VIF ? "True " : "False", data.Frame->eflags.VIP ? "True " : "False",
|
||||
data.Frame->eflags.ID ? "True " : "False", data.Frame->eflags.AlwaysOne,
|
||||
data.Frame->eflags.Reserved0, data.Frame->eflags.Reserved1, data.Frame->eflags.Reserved2);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
EHPrint("\eA0F0F0DR7: LDR0:%s GDR0:%s LDR1:%s GDR1:%s\n LDR2:%s GDR2:%s LDR3:%s GDR3:%s\n CDR0:%s SDR0:%s CDR1:%s SDR1:%s\n CDR2:%s SDR2:%s CDR3:%s SDR3:%s\n R:%#x\n",
|
||||
data.dr7.LocalDR0 ? "True " : "False", data.dr7.GlobalDR0 ? "True " : "False", data.dr7.LocalDR1 ? "True " : "False", data.dr7.GlobalDR1 ? "True " : "False",
|
||||
data.dr7.LocalDR2 ? "True " : "False", data.dr7.GlobalDR2 ? "True " : "False", data.dr7.LocalDR3 ? "True " : "False", data.dr7.GlobalDR3 ? "True " : "False",
|
||||
data.dr7.ConditionsDR0 ? "True " : "False", data.dr7.SizeDR0 ? "True " : "False", data.dr7.ConditionsDR1 ? "True " : "False", data.dr7.SizeDR1 ? "True " : "False",
|
||||
data.dr7.ConditionsDR2 ? "True " : "False", data.dr7.SizeDR2 ? "True " : "False", data.dr7.ConditionsDR3 ? "True " : "False", data.dr7.SizeDR3 ? "True " : "False",
|
||||
data.dr7.Reserved);
|
||||
|
||||
EHPrint("\e009FF0EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n R0:%#x R1:%#x R2:%#x\n",
|
||||
data.efer.SCE ? "True " : "False", data.efer.LME ? "True " : "False", data.efer.LMA ? "True " : "False", data.efer.NXE ? "True " : "False",
|
||||
data.efer.SVME ? "True " : "False", data.efer.LMSLE ? "True " : "False", data.efer.FFXSR ? "True " : "False", data.efer.TCE ? "True " : "False",
|
||||
data.efer.Reserved0, data.efer.Reserved1, data.efer.Reserved2);
|
||||
|
||||
switch (data.Frame->InterruptNumber)
|
||||
{
|
||||
case CPU::x86::DivideByZero:
|
||||
{
|
||||
DivideByZeroExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Debug:
|
||||
{
|
||||
DebugExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::NonMaskableInterrupt:
|
||||
{
|
||||
NonMaskableInterruptExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Breakpoint:
|
||||
{
|
||||
BreakpointExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Overflow:
|
||||
{
|
||||
OverflowExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::BoundRange:
|
||||
{
|
||||
BoundRangeExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::InvalidOpcode:
|
||||
{
|
||||
InvalidOpcodeExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::DeviceNotAvailable:
|
||||
{
|
||||
DeviceNotAvailableExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::DoubleFault:
|
||||
{
|
||||
DoubleFaultExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::CoprocessorSegmentOverrun:
|
||||
{
|
||||
CoprocessorSegmentOverrunExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::InvalidTSS:
|
||||
{
|
||||
InvalidTSSExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::SegmentNotPresent:
|
||||
{
|
||||
SegmentNotPresentExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::StackSegmentFault:
|
||||
{
|
||||
StackFaultExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::GeneralProtectionFault:
|
||||
{
|
||||
GeneralProtectionExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::PageFault:
|
||||
{
|
||||
PageFaultExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::x87FloatingPoint:
|
||||
{
|
||||
x87FloatingPointExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::AlignmentCheck:
|
||||
{
|
||||
AlignmentCheckExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::MachineCheck:
|
||||
{
|
||||
MachineCheckExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::SIMDFloatingPoint:
|
||||
{
|
||||
SIMDFloatingPointExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Virtualization:
|
||||
{
|
||||
VirtualizationExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Security:
|
||||
{
|
||||
SecurityExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
UnknownExceptionHandler(data.Frame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
345
Kernel/Core/Crash/Screens/Main.cpp
Normal file
345
Kernel/Core/Crash/Screens/Main.cpp
Normal file
@ -0,0 +1,345 @@
|
||||
#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"};
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
SafeFunction void DisplayMainScreen(CRData data)
|
||||
{
|
||||
CHArchTrapFrame *Frame = data.Frame;
|
||||
|
||||
/*
|
||||
_______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____
|
||||
| __| | | __|_ _| ___| | | | | __ \ _ | __| | | ___| \
|
||||
|__ |\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |
|
||||
|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/
|
||||
*/
|
||||
EHPrint("\eFF5500 _______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____ \n");
|
||||
EHPrint("| __| | | __|_ _| ___| | | | | __ \\ _ | __| | | ___| \\ \n");
|
||||
EHPrint("|__ |\\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |\n");
|
||||
EHPrint("|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/ \n\eFAFAFA");
|
||||
|
||||
switch (Frame->InterruptNumber)
|
||||
{
|
||||
case CPU::x86::DivideByZero:
|
||||
{
|
||||
EHPrint("Exception: Divide By Zero\n");
|
||||
EHPrint("The processor attempted to divide a number by zero.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Debug:
|
||||
{
|
||||
EHPrint("Exception: Debug\n");
|
||||
EHPrint("A debug exception has occurred.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::NonMaskableInterrupt:
|
||||
{
|
||||
EHPrint("Exception: Non-Maskable Interrupt\n");
|
||||
EHPrint("A non-maskable interrupt was received.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Breakpoint:
|
||||
{
|
||||
EHPrint("Exception: Breakpoint\n");
|
||||
EHPrint("The processor encountered a breakpoint.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Overflow:
|
||||
{
|
||||
EHPrint("Exception: Overflow\n");
|
||||
EHPrint("The processor attempted to add a number to a number that was too large.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::BoundRange:
|
||||
{
|
||||
EHPrint("Exception: Bound Range\n");
|
||||
EHPrint("The processor attempted to access an array element that is out of bounds.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::InvalidOpcode:
|
||||
{
|
||||
EHPrint("Exception: Invalid Opcode\n");
|
||||
EHPrint("The processor attempted to execute an invalid opcode.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::DeviceNotAvailable:
|
||||
{
|
||||
EHPrint("Exception: Device Not Available\n");
|
||||
EHPrint("The processor attempted to use a device that is not available.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::DoubleFault:
|
||||
{
|
||||
EHPrint("Exception: Double Fault\n");
|
||||
EHPrint("The processor encountered a double fault.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::CoprocessorSegmentOverrun:
|
||||
{
|
||||
EHPrint("Exception: Coprocessor Segment Overrun\n");
|
||||
EHPrint("The processor attempted to access a segment that is not available.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::InvalidTSS:
|
||||
{
|
||||
EHPrint("Exception: Invalid TSS\n");
|
||||
EHPrint("The processor attempted to access a task state segment that is not available or valid.\n");
|
||||
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
|
||||
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
|
||||
EHPrint("GDT IDT LDT IDT\n");
|
||||
switch (SelCode.Table)
|
||||
{
|
||||
case 0b00:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b01:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b10:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b11:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CPU::x86::SegmentNotPresent:
|
||||
{
|
||||
EHPrint("Exception: Segment Not Present\n");
|
||||
EHPrint("The processor attempted to access a segment that is not present.\n");
|
||||
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
|
||||
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
|
||||
EHPrint("GDT IDT LDT IDT\n");
|
||||
switch (SelCode.Table)
|
||||
{
|
||||
case 0b00:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b01:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b10:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b11:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CPU::x86::StackSegmentFault:
|
||||
{
|
||||
EHPrint("Exception: Stack Segment Fault\n");
|
||||
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
|
||||
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
|
||||
EHPrint("GDT IDT LDT IDT\n");
|
||||
switch (SelCode.Table)
|
||||
{
|
||||
case 0b00:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b01:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b10:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b11:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CPU::x86::GeneralProtectionFault:
|
||||
{
|
||||
EHPrint("Exception: General Protection Fault\n");
|
||||
EHPrint("Kernel performed an illegal operation.\n");
|
||||
CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
|
||||
EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
|
||||
EHPrint("GDT IDT LDT IDT\n");
|
||||
switch (SelCode.Table)
|
||||
{
|
||||
case 0b00:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b01:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b10:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
case 0b11:
|
||||
{
|
||||
EHPrint(" ^ \n");
|
||||
EHPrint(" | \n");
|
||||
EHPrint(" %ld\n", SelCode.Idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CPU::x86::PageFault:
|
||||
{
|
||||
EHPrint("Exception: Page Fault\n");
|
||||
EHPrint("The processor attempted to access a page that is not present.\n");
|
||||
|
||||
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
|
||||
#if defined(a64)
|
||||
EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->rip);
|
||||
#elif defined(a32)
|
||||
EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->eip);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("Page: %s\eFAFAFA\n", params.P ? "\e058C19Present" : "\eE85230Not Present");
|
||||
EHPrint("Write Operation: \e8888FF%s\eFAFAFA\n", params.W ? "Read-Only" : "Read-Write");
|
||||
EHPrint("Processor Mode: \e8888FF%s\eFAFAFA\n", params.U ? "User-Mode" : "Kernel-Mode");
|
||||
EHPrint("CPU Reserved Bits: %s\eFAFAFA\n", params.R ? "\eE85230Reserved" : "\e058C19Unreserved");
|
||||
EHPrint("Caused By An Instruction Fetch: %s\eFAFAFA\n", params.I ? "\eE85230Yes" : "\e058C19No");
|
||||
EHPrint("Caused By A Protection-Key Violation: %s\eFAFAFA\n", params.PK ? "\eE85230Yes" : "\e058C19No");
|
||||
EHPrint("Caused By A Shadow Stack Access: %s\eFAFAFA\n", params.SS ? "\eE85230Yes" : "\e058C19No");
|
||||
EHPrint("Caused By An SGX Violation: %s\eFAFAFA\n", params.SGX ? "\eE85230Yes" : "\e058C19No");
|
||||
EHPrint("More Info: \e8888FF");
|
||||
if (Frame->ErrorCode & 0x00000008)
|
||||
EHPrint("One or more page directory entries contain reserved bits which are set to 1.\n");
|
||||
else
|
||||
EHPrint(PagefaultDescriptions[Frame->ErrorCode & 0b111]);
|
||||
EHPrint("\eFAFAFA");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::x87FloatingPoint:
|
||||
{
|
||||
EHPrint("Exception: x87 Floating Point\n");
|
||||
EHPrint("The x87 FPU generated an error.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::AlignmentCheck:
|
||||
{
|
||||
EHPrint("Exception: Alignment Check\n");
|
||||
EHPrint("The CPU detected an unaligned memory access.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::MachineCheck:
|
||||
{
|
||||
EHPrint("Exception: Machine Check\n");
|
||||
EHPrint("The CPU detected a hardware error.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::SIMDFloatingPoint:
|
||||
{
|
||||
EHPrint("Exception: SIMD Floating Point\n");
|
||||
EHPrint("The CPU detected an error in the SIMD unit.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Virtualization:
|
||||
{
|
||||
EHPrint("Exception: Virtualization\n");
|
||||
EHPrint("The CPU detected a virtualization error.\n");
|
||||
break;
|
||||
}
|
||||
case CPU::x86::Security:
|
||||
{
|
||||
EHPrint("Exception: Security\n");
|
||||
EHPrint("The CPU detected a security violation.\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
EHPrint("Exception: Unknown\n");
|
||||
EHPrint("The CPU generated an unknown exception.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(a64)
|
||||
EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->rip);
|
||||
#elif defined(a32)
|
||||
EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->eip);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
}
|
81
Kernel/Core/Crash/Screens/StackFrame.cpp
Normal file
81
Kernel/Core/Crash/Screens/StackFrame.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include "../../crashhandler.hpp"
|
||||
#include "../chfcts.hpp"
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <display.hpp>
|
||||
#include <printf.h>
|
||||
#include <debug.h>
|
||||
#include <smp.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
#if defined(a64)
|
||||
#include "../../../Architecture/amd64/cpu/gdt.hpp"
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
SafeFunction void DisplayStackFrameScreen(CRData data)
|
||||
{
|
||||
EHPrint("\eFAFAFATracing 10 frames...");
|
||||
TraceFrames(data.Frame, 10, KernelSymbolTable, true);
|
||||
if (data.Process)
|
||||
{
|
||||
EHPrint("\n\eFAFAFATracing 10 process frames...");
|
||||
SymbolResolver::Symbols *sh = data.Process->ELFSymbolTable;
|
||||
if (!sh)
|
||||
EHPrint("\n\eFF0000< No symbol table available. >\n");
|
||||
else
|
||||
TraceFrames(data.Frame, 10, sh, false);
|
||||
}
|
||||
EHPrint("\n\eFAFAFATracing interrupt frames...");
|
||||
for (short i = 0; i < 8; i++)
|
||||
{
|
||||
if (EHIntFrames[i])
|
||||
{
|
||||
if (!Memory::Virtual().Check(EHIntFrames[i]))
|
||||
continue;
|
||||
EHPrint("\n\e2565CC%p", EHIntFrames[i]);
|
||||
EHPrint("\e7925CC-");
|
||||
#if defined(a64)
|
||||
if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
|
||||
#elif defined(a32)
|
||||
if ((uintptr_t)EHIntFrames[i] >= 0xC0000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbolFromAddress((uintptr_t)EHIntFrames[i]));
|
||||
else
|
||||
EHPrint("\eFF4CA9Outside Kernel");
|
||||
}
|
||||
}
|
||||
if (data.Process && data.Thread)
|
||||
{
|
||||
EHPrint("\n\n\eFAFAFATracing thread instruction pointer history...");
|
||||
SymbolResolver::Symbols *sh = data.Process->ELFSymbolTable;
|
||||
if (!sh)
|
||||
EHPrint("\n\eFFA500Warning: No symbol table available.");
|
||||
int SameItr = 0;
|
||||
uintptr_t LastRIP = 0;
|
||||
for (size_t i = 0; i < sizeof(data.Thread->IPHistory) / sizeof(data.Thread->IPHistory[0]); i++)
|
||||
{
|
||||
if (data.Thread->IPHistory[i] == LastRIP)
|
||||
{
|
||||
SameItr++;
|
||||
if (SameItr > 2)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
SameItr = 0;
|
||||
LastRIP = data.Thread->IPHistory[i];
|
||||
if (!sh)
|
||||
EHPrint("\n\eCCCCCC%d: \e2565CC%p", i, data.Thread->IPHistory[i]);
|
||||
else
|
||||
EHPrint("\n\eCCCCCC%d: \e2565CC%p\e7925CC-\e25CCC9%s", i, data.Thread->IPHistory[i], sh->GetSymbolFromAddress(data.Thread->IPHistory[i]));
|
||||
}
|
||||
EHPrint("\n\e7925CCNote: \e2565CCSame instruction pointers are not shown more than 3 times.\n");
|
||||
}
|
||||
}
|
||||
}
|
70
Kernel/Core/Crash/Screens/Tasks.cpp
Normal file
70
Kernel/Core/Crash/Screens/Tasks.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#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"
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
SafeFunction void DisplayTasksScreen(CRData data)
|
||||
{
|
||||
const char *StatusColor[7] = {
|
||||
"FF0000", // Unknown
|
||||
"AAFF00", // Ready
|
||||
"00AA00", // Running
|
||||
"FFAA00", // Sleeping
|
||||
"FFAA00", // Waiting
|
||||
"FF0088", // Stopped
|
||||
"FF0000", // Terminated
|
||||
};
|
||||
|
||||
const char *StatusString[7] = {
|
||||
"Unknown", // Unknown
|
||||
"Ready", // Ready
|
||||
"Running", // Running
|
||||
"Sleeping", // Sleeping
|
||||
"Waiting", // Waiting
|
||||
"Stopped", // Stopped
|
||||
"Terminated", // Terminated
|
||||
};
|
||||
|
||||
Vector<Tasking::PCB *> Plist = TaskManager->GetProcessList();
|
||||
|
||||
if (TaskManager)
|
||||
{
|
||||
if (data.Thread)
|
||||
#if defined(a64)
|
||||
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n", data.Thread->Name, data.Thread->ID, data.Frame->rip);
|
||||
#elif defined(a32)
|
||||
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n", data.Thread->Name, data.Thread->ID, data.Frame->eip);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
EHPrint("\eFAFAFAProcess list (%ld):\n", Plist.size());
|
||||
foreach (auto Process in Plist)
|
||||
{
|
||||
EHPrint("\e%s-> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA PT:\e00AAAA%#lx\n",
|
||||
StatusColor[Process->Status], Process->Name, Process->ID, StatusString[Process->Status],
|
||||
Process->PageTable);
|
||||
|
||||
foreach (auto Thread in Process->Threads)
|
||||
EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n",
|
||||
StatusColor[Thread->Status], Thread->Name, Thread->ID, StatusString[Thread->Status],
|
||||
Thread->Stack);
|
||||
}
|
||||
}
|
||||
else
|
||||
EHPrint("\eFAFAFATaskManager is not initialized!\n");
|
||||
}
|
||||
}
|
374
Kernel/Core/Crash/UserHandler.cpp
Normal file
374
Kernel/Core/Crash/UserHandler.cpp
Normal file
@ -0,0 +1,374 @@
|
||||
#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");
|
||||
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Stopped;
|
||||
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();
|
||||
CPU::x32::EFER efer;
|
||||
efer.raw = CPU::x32::rdmsr(CPU::x32::MSR_EFER);
|
||||
|
||||
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 EFER=%#llx", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
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);
|
||||
|
||||
#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
|
||||
|
||||
error("CR8: TPL:%d", cr8.TPL);
|
||||
|
||||
#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
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 vma = Memory::Virtual(CurCPU->CurrentProcess->PageTable);
|
||||
bool PageAvailable = vma.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 = vma.Check((void *)CheckPageFaultAddress);
|
||||
bool ReadWrite = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW);
|
||||
bool User = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US);
|
||||
bool WriteThrough = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT);
|
||||
bool CacheDisabled = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD);
|
||||
bool Accessed = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A);
|
||||
bool Dirty = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D);
|
||||
bool Global = vma.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)
|
||||
{
|
||||
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
|
||||
|
||||
if (CurCPU)
|
||||
if (CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress))
|
||||
{
|
||||
debug("Stack expanded");
|
||||
TaskManager->GetCurrentThread()->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;
|
||||
}
|
||||
}
|
||||
|
||||
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated;
|
||||
__sync;
|
||||
error("End of report.");
|
||||
CPU::Interrupts(CPU::Enable);
|
||||
debug("Interrupts enabled back.");
|
||||
return;
|
||||
}
|
296
Kernel/Core/Crash/chfcts.hpp
Normal file
296
Kernel/Core/Crash/chfcts.hpp
Normal file
@ -0,0 +1,296 @@
|
||||
#ifndef __FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
|
||||
#define __FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
#if defined(a64)
|
||||
typedef struct CPU::x64::TrapFrame CHArchTrapFrame;
|
||||
|
||||
struct CRData
|
||||
{
|
||||
CHArchTrapFrame *Frame;
|
||||
|
||||
CPU::x64::CR0 cr0;
|
||||
CPU::x64::CR2 cr2;
|
||||
CPU::x64::CR3 cr3;
|
||||
CPU::x64::CR4 cr4;
|
||||
CPU::x64::CR8 cr8;
|
||||
CPU::x64::EFER efer;
|
||||
uintptr_t dr0, dr1, dr2, dr3, dr6;
|
||||
CPU::x64::DR7 dr7;
|
||||
|
||||
long ID;
|
||||
void *CPUData;
|
||||
Tasking::PCB *Process;
|
||||
Tasking::TCB *Thread;
|
||||
};
|
||||
|
||||
#elif defined(a32)
|
||||
typedef struct CPU::x32::TrapFrame CHArchTrapFrame;
|
||||
|
||||
struct CRData
|
||||
{
|
||||
CHArchTrapFrame *Frame;
|
||||
|
||||
CPU::x32::CR0 cr0;
|
||||
CPU::x32::CR2 cr2;
|
||||
CPU::x32::CR3 cr3;
|
||||
CPU::x32::CR4 cr4;
|
||||
CPU::x32::CR8 cr8;
|
||||
CPU::x32::EFER efer;
|
||||
uintptr_t dr0, dr1, dr2, dr3, dr6;
|
||||
CPU::x32::DR7 dr7;
|
||||
|
||||
long ID;
|
||||
Tasking::PCB *Process;
|
||||
Tasking::TCB *Thread;
|
||||
};
|
||||
#elif defined(aa64)
|
||||
typedef struct CPU::aarch64::TrapFrame CHArchTrapFrame;
|
||||
#endif
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
extern int SBIdx;
|
||||
|
||||
class CrashKeyboardDriver : public Interrupts::Handler
|
||||
{
|
||||
private:
|
||||
#if defined(a64)
|
||||
void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
|
||||
#elif defined(a32)
|
||||
void OnInterruptReceived(CPU::x32::TrapFrame *Frame);
|
||||
#elif defined(aa64)
|
||||
void OnInterruptReceived(void *Frame);
|
||||
#endif
|
||||
public:
|
||||
CrashKeyboardDriver();
|
||||
~CrashKeyboardDriver();
|
||||
};
|
||||
|
||||
void TraceFrames(CHArchTrapFrame *Frame, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel);
|
||||
|
||||
void ArrowInput(uint8_t key);
|
||||
void UserInput(char *Input);
|
||||
void HookKeyboard();
|
||||
|
||||
void DisplayMainScreen(CRData data);
|
||||
void DisplayDetailsScreen(CRData data);
|
||||
void DisplayStackFrameScreen(CRData data);
|
||||
void DisplayTasksScreen(CRData data);
|
||||
void DisplayConsoleScreen(CRData data);
|
||||
}
|
||||
|
||||
void DivideByZeroExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void DebugExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void NonMaskableInterruptExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void BreakpointExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void OverflowExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void BoundRangeExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void InvalidOpcodeExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void DeviceNotAvailableExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void DoubleFaultExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void CoprocessorSegmentOverrunExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void InvalidTSSExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void SegmentNotPresentExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void StackFaultExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void GeneralProtectionExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void PageFaultExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void x87FloatingPointExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void AlignmentCheckExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void MachineCheckExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void SIMDFloatingPointExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void VirtualizationExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void SecurityExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void UnknownExceptionHandler(CHArchTrapFrame *Frame);
|
||||
void UserModeExceptionHandler(CHArchTrapFrame *Frame);
|
||||
|
||||
#endif // !__FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
|
138
Kernel/Core/Debugger.cpp
Normal file
138
Kernel/Core/Debugger.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include <debug.h>
|
||||
|
||||
#include <uart.hpp>
|
||||
#include <printf.h>
|
||||
#include <lock.hpp>
|
||||
|
||||
NewLock(DebuggerLock);
|
||||
|
||||
using namespace UniversalAsynchronousReceiverTransmitter;
|
||||
|
||||
static inline NIF void uart_wrapper(char c, void *unused)
|
||||
{
|
||||
UART(COM1).Write(c);
|
||||
UNUSED(unused);
|
||||
}
|
||||
|
||||
static inline NIF void WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function)
|
||||
{
|
||||
const char *DbgLvlString;
|
||||
switch (Level)
|
||||
{
|
||||
case DebugLevelError:
|
||||
DbgLvlString = "ERROR";
|
||||
break;
|
||||
case DebugLevelWarning:
|
||||
DbgLvlString = "WARN ";
|
||||
break;
|
||||
case DebugLevelInfo:
|
||||
DbgLvlString = "INFO ";
|
||||
break;
|
||||
case DebugLevelDebug:
|
||||
DbgLvlString = "DEBUG";
|
||||
break;
|
||||
case DebugLevelTrace:
|
||||
DbgLvlString = "TRACE";
|
||||
break;
|
||||
case DebugLevelFixme:
|
||||
DbgLvlString = "FIXME";
|
||||
break;
|
||||
case DebugLevelUbsan:
|
||||
{
|
||||
DbgLvlString = "UBSAN";
|
||||
fctprintf(uart_wrapper, nullptr, "%s|%s: ", DbgLvlString, Function);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
DbgLvlString = "UNKNW";
|
||||
break;
|
||||
}
|
||||
fctprintf(uart_wrapper, nullptr, "%s|%s->%s:%d: ", DbgLvlString, File, Function, Line);
|
||||
}
|
||||
|
||||
namespace SysDbg
|
||||
{
|
||||
NIF void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
NIF void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
uart_wrapper('\n', nullptr);
|
||||
}
|
||||
|
||||
NIF void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
NIF void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
uart_wrapper('\n', nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
uart_wrapper('\n', nullptr);
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// C compatibility
|
||||
extern "C" NIF void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
|
||||
{
|
||||
SmartTimeoutLock(DebuggerLock, 1000);
|
||||
WritePrefix(Level, File, Line, Function);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vfctprintf(uart_wrapper, nullptr, Format, args);
|
||||
va_end(args);
|
||||
uart_wrapper('\n', nullptr);
|
||||
}
|
158
Kernel/Core/Disk.cpp
Normal file
158
Kernel/Core/Disk.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
#include <disk.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <printf.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
#include "../DAPI.hpp"
|
||||
#include "../Fex.hpp"
|
||||
|
||||
namespace Disk
|
||||
{
|
||||
void Manager::FetchDisks(unsigned long DriverUID)
|
||||
{
|
||||
KernelCallback *callback = (KernelCallback *)KernelAllocator.RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
memset(callback, 0, sizeof(KernelCallback));
|
||||
callback->Reason = FetchReason;
|
||||
DriverManager->IOCB(DriverUID, (void *)callback);
|
||||
this->AvailablePorts = callback->DiskCallback.Fetch.Ports;
|
||||
this->BytesPerSector = callback->DiskCallback.Fetch.BytesPerSector;
|
||||
debug("AvailablePorts:%ld BytesPerSector:%ld", this->AvailablePorts, this->BytesPerSector);
|
||||
|
||||
if (this->AvailablePorts <= 0)
|
||||
{
|
||||
KernelAllocator.FreePages((void *)callback, TO_PAGES(sizeof(KernelCallback)));
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *RWBuffer = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(this->BytesPerSector));
|
||||
|
||||
for (unsigned char ItrPort = 0; ItrPort < this->AvailablePorts; ItrPort++)
|
||||
{
|
||||
Drive *drive = new Drive;
|
||||
sprintf(drive->Name, "sd%ld-%d", DriverUID, this->AvailablePorts);
|
||||
debug("Drive Name: %s", drive->Name);
|
||||
// TODO: Implement disk type detection. Very useful in the future.
|
||||
drive->MechanicalDisk = true;
|
||||
|
||||
memset(RWBuffer, 0, this->BytesPerSector);
|
||||
memset(callback, 0, sizeof(KernelCallback));
|
||||
callback->Reason = ReceiveReason;
|
||||
callback->DiskCallback.RW = {
|
||||
.Sector = 0,
|
||||
.SectorCount = 2,
|
||||
.Port = ItrPort,
|
||||
.Buffer = RWBuffer,
|
||||
.Write = false,
|
||||
};
|
||||
DriverManager->IOCB(DriverUID, (void *)callback);
|
||||
memcpy(&drive->Table, RWBuffer, sizeof(PartitionTable));
|
||||
|
||||
/*
|
||||
TODO: Add to devfs the disk
|
||||
*/
|
||||
|
||||
if (drive->Table.GPT.Signature == GPT_MAGIC)
|
||||
{
|
||||
drive->Style = GPT;
|
||||
uint32_t Entries = 512 / drive->Table.GPT.EntrySize;
|
||||
uint32_t Sectors = drive->Table.GPT.PartCount / Entries;
|
||||
for (uint32_t Block = 0; Block < Sectors; Block++)
|
||||
{
|
||||
memset(RWBuffer, 0, this->BytesPerSector);
|
||||
memset(callback, 0, sizeof(KernelCallback));
|
||||
callback->Reason = ReceiveReason;
|
||||
callback->DiskCallback.RW = {
|
||||
.Sector = 2 + Block,
|
||||
.SectorCount = 1,
|
||||
.Port = ItrPort,
|
||||
.Buffer = RWBuffer,
|
||||
.Write = false,
|
||||
};
|
||||
DriverManager->IOCB(DriverUID, (void *)callback);
|
||||
|
||||
for (uint32_t e = 0; e < Entries; e++)
|
||||
{
|
||||
GUIDPartitionTablePartition GPTPartition = reinterpret_cast<GUIDPartitionTablePartition *>(RWBuffer)[e];
|
||||
if (GPTPartition.TypeLow || GPTPartition.TypeHigh)
|
||||
{
|
||||
Partition *partition = new Partition;
|
||||
memcpy(partition->Label, GPTPartition.Label, sizeof(partition->Label));
|
||||
partition->StartLBA = GPTPartition.StartLBA;
|
||||
partition->EndLBA = GPTPartition.EndLBA;
|
||||
partition->Sectors = partition->EndLBA - partition->StartLBA;
|
||||
partition->Port = ItrPort;
|
||||
partition->Flags = Present;
|
||||
partition->Style = GPT;
|
||||
if (GPTPartition.Attributes & 1)
|
||||
partition->Flags |= EFISystemPartition;
|
||||
partition->Index = drive->Partitions.size();
|
||||
// why there is NUL (\0) between every char?????
|
||||
char PartName[72];
|
||||
memcpy(PartName, GPTPartition.Label, 72);
|
||||
for (int i = 0; i < 72; i++)
|
||||
if (PartName[i] == '\0')
|
||||
PartName[i] = ' ';
|
||||
PartName[71] = '\0';
|
||||
trace("GPT partition \"%s\" found with %lld sectors", PartName, partition->Sectors);
|
||||
drive->Partitions.push_back(partition);
|
||||
|
||||
char *PartitionName = new char[64];
|
||||
sprintf(PartitionName, "sd%ldp%ld", drives.size() - 1, partition->Index);
|
||||
|
||||
/*
|
||||
TODO: Add to devfs the disk
|
||||
*/
|
||||
|
||||
delete[] PartitionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
trace("%d GPT partitions found.", drive->Partitions.size());
|
||||
}
|
||||
else if (drive->Table.MBR.Signature[0] == MBR_MAGIC0 && drive->Table.MBR.Signature[1] == MBR_MAGIC1)
|
||||
{
|
||||
drive->Style = MBR;
|
||||
for (size_t p = 0; p < 4; p++)
|
||||
if (drive->Table.MBR.Partitions[p].LBAFirst != 0)
|
||||
{
|
||||
Partition *partition = new Partition;
|
||||
partition->StartLBA = drive->Table.MBR.Partitions[p].LBAFirst;
|
||||
partition->EndLBA = drive->Table.MBR.Partitions[p].LBAFirst + drive->Table.MBR.Partitions[p].Sectors;
|
||||
partition->Sectors = drive->Table.MBR.Partitions[p].Sectors;
|
||||
partition->Port = ItrPort;
|
||||
partition->Flags = Present;
|
||||
partition->Style = MBR;
|
||||
partition->Index = drive->Partitions.size();
|
||||
trace("Partition \"%#llx\" found with %lld sectors.", drive->Table.MBR.UniqueID, partition->Sectors);
|
||||
drive->Partitions.push_back(partition);
|
||||
|
||||
char *PartitionName = new char[64];
|
||||
sprintf(PartitionName, "sd%ldp%ld", drives.size() - 1, partition->Index);
|
||||
|
||||
/*
|
||||
TODO: Add to devfs the disk
|
||||
*/
|
||||
|
||||
delete[] PartitionName;
|
||||
}
|
||||
trace("%d MBR partitions found.", drive->Partitions.size());
|
||||
}
|
||||
else
|
||||
warn("No partition table found on port %d!", ItrPort);
|
||||
|
||||
drives.push_back(drive);
|
||||
}
|
||||
|
||||
KernelAllocator.FreePages((void *)callback, TO_PAGES(sizeof(KernelCallback)));
|
||||
}
|
||||
|
||||
Manager::Manager()
|
||||
{
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
debug("Destructor called");
|
||||
}
|
||||
}
|
234
Kernel/Core/Driver/Driver.cpp
Normal file
234
Kernel/Core/Driver/Driver.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
#include <driver.hpp>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <task.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../DAPI.hpp"
|
||||
#include "../../Fex.hpp"
|
||||
#include "api.hpp"
|
||||
|
||||
NewLock(DriverInitLock);
|
||||
NewLock(DriverInterruptLock);
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
const char *DriverTypesName[] = {
|
||||
"Unknown",
|
||||
"Generic",
|
||||
"Display",
|
||||
"Network",
|
||||
"Storage",
|
||||
"FileSystem",
|
||||
"Input",
|
||||
"Audio"};
|
||||
|
||||
void Driver::UnloadAllDrivers()
|
||||
{
|
||||
size_t DriversNum = Drivers.size();
|
||||
debug("%ld drivers loaded, [DUIDs: %ld]", DriversNum, DriverUIDs);
|
||||
debug("driver size %ld", DriversNum);
|
||||
for (size_t i = 0; i < DriversNum; i++)
|
||||
{
|
||||
DriverFile *drv = Drivers[i];
|
||||
KernelCallback callback;
|
||||
callback.Reason = StopReason;
|
||||
debug("Stopping & unloading driver %ld [%#lx]", drv->DriverUID, drv->Address);
|
||||
DriverManager->IOCB(drv->DriverUID, (void *)&callback);
|
||||
|
||||
delete drv->MemTrk, drv->MemTrk = nullptr;
|
||||
for (size_t j = 0; j < sizeof(drv->InterruptHook) / sizeof(drv->InterruptHook[0]); j++)
|
||||
{
|
||||
if (!drv->InterruptHook[j])
|
||||
continue;
|
||||
delete drv->InterruptHook[j], drv->InterruptHook[j] = nullptr;
|
||||
}
|
||||
delete drv, drv = nullptr;
|
||||
Drivers.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool Driver::UnloadDriver(unsigned long DUID)
|
||||
{
|
||||
debug("Searching for driver %ld", DUID);
|
||||
for (size_t i = 0; i < Drivers.size(); i++)
|
||||
{
|
||||
DriverFile *drv = Drivers[i];
|
||||
if (drv->DriverUID == DUID)
|
||||
{
|
||||
KernelCallback callback;
|
||||
callback.Reason = StopReason;
|
||||
debug("Stopping and unloading driver %ld [%#lx]", drv->DriverUID, drv->Address);
|
||||
this->IOCB(drv->DriverUID, (void *)&callback);
|
||||
|
||||
delete drv->MemTrk, drv->MemTrk = nullptr;
|
||||
for (size_t i = 0; i < sizeof(drv->InterruptHook) / sizeof(drv->InterruptHook[0]); i++)
|
||||
{
|
||||
if (!drv->InterruptHook[i])
|
||||
continue;
|
||||
delete drv->InterruptHook[i], drv->InterruptHook[i] = nullptr;
|
||||
}
|
||||
delete drv, drv = nullptr;
|
||||
Drivers.remove(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Driver::IOCB(unsigned long DUID, void *KCB)
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
if (Drv->DriverUID == DUID)
|
||||
{
|
||||
FexExtended *DrvExtHdr = (FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS);
|
||||
int ret = ((int (*)(void *))((uintptr_t)DrvExtHdr->Driver.Callback + (uintptr_t)Drv->Address))(KCB);
|
||||
__sync;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
DriverCode Driver::CallDriverEntryPoint(void *fex, void *KAPIAddress)
|
||||
{
|
||||
memcpy(KAPIAddress, &KernelAPITemplate, sizeof(KernelAPI));
|
||||
|
||||
((KernelAPI *)KAPIAddress)->Info.Offset = (unsigned long)fex;
|
||||
((KernelAPI *)KAPIAddress)->Info.DriverUID = DriverUIDs++;
|
||||
|
||||
debug("Calling driver entry point ( %#lx %ld )", (unsigned long)fex, ((KernelAPI *)KAPIAddress)->Info.DriverUID);
|
||||
int ret = ((int (*)(KernelAPI *))((uintptr_t)((Fex *)fex)->EntryPoint + (uintptr_t)fex))(((KernelAPI *)KAPIAddress));
|
||||
|
||||
if (DriverReturnCode::OK != ret)
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::LoadDriver(uintptr_t DriverAddress, uintptr_t Size)
|
||||
{
|
||||
Fex *DrvHdr = (Fex *)DriverAddress;
|
||||
if (DrvHdr->Magic[0] != 'F' || DrvHdr->Magic[1] != 'E' || DrvHdr->Magic[2] != 'X' || DrvHdr->Magic[3] != '\0')
|
||||
{
|
||||
if (Size > 0x1000)
|
||||
{
|
||||
Fex *ElfDrvHdr = (Fex *)(DriverAddress + 0x1000);
|
||||
if (ElfDrvHdr->Magic[0] != 'F' || ElfDrvHdr->Magic[1] != 'E' || ElfDrvHdr->Magic[2] != 'X' || ElfDrvHdr->Magic[3] != '\0')
|
||||
return DriverCode::INVALID_FEX_HEADER;
|
||||
else
|
||||
{
|
||||
debug("Fex Magic: \"%s\"; Type: %d; OS: %d; EntryPoint: %#lx", ElfDrvHdr->Magic, ElfDrvHdr->Type, ElfDrvHdr->OS, ElfDrvHdr->EntryPoint);
|
||||
|
||||
if (ElfDrvHdr->Type == FexFormatType::FexFormatType_Driver)
|
||||
{
|
||||
FexExtended *ElfDrvExtHdr = (FexExtended *)((uintptr_t)ElfDrvHdr + EXTENDED_SECTION_ADDRESS);
|
||||
debug("Name: \"%s\"; Type: %d; Callback: %#lx", ElfDrvExtHdr->Driver.Name, ElfDrvExtHdr->Driver.Type, ElfDrvExtHdr->Driver.Callback);
|
||||
|
||||
if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PCI)
|
||||
return this->DriverLoadBindPCI(ElfDrvExtHdr, DriverAddress, Size, true);
|
||||
else if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INTERRUPT)
|
||||
return this->DriverLoadBindInterrupt(ElfDrvExtHdr, DriverAddress, Size, true);
|
||||
else if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PROCESS)
|
||||
return this->DriverLoadBindProcess(ElfDrvExtHdr, DriverAddress, Size, true);
|
||||
else if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INPUT)
|
||||
return this->DriverLoadBindInput(ElfDrvExtHdr, DriverAddress, Size, true);
|
||||
else
|
||||
error("Unknown driver bind type: %d", ElfDrvExtHdr->Driver.Bind.Type);
|
||||
}
|
||||
else
|
||||
return DriverCode::NOT_DRIVER;
|
||||
}
|
||||
}
|
||||
else
|
||||
return DriverCode::INVALID_FEX_HEADER;
|
||||
}
|
||||
debug("Fex Magic: \"%s\"; Type: %d; OS: %d; EntryPoint: %#lx", DrvHdr->Magic, DrvHdr->Type, DrvHdr->OS, DrvHdr->EntryPoint);
|
||||
|
||||
if (DrvHdr->Type == FexFormatType::FexFormatType_Driver)
|
||||
{
|
||||
FexExtended *DrvExtHdr = (FexExtended *)((uintptr_t)DrvHdr + EXTENDED_SECTION_ADDRESS);
|
||||
debug("Name: \"%s\"; Type: %d; Callback: %#lx", DrvExtHdr->Driver.Name, DrvExtHdr->Driver.Type, DrvExtHdr->Driver.Callback);
|
||||
|
||||
if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PCI)
|
||||
return this->DriverLoadBindPCI(DrvExtHdr, DriverAddress, Size);
|
||||
else if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INTERRUPT)
|
||||
return this->DriverLoadBindInterrupt(DrvExtHdr, DriverAddress, Size);
|
||||
else if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PROCESS)
|
||||
return this->DriverLoadBindProcess(DrvExtHdr, DriverAddress, Size);
|
||||
else if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INPUT)
|
||||
return this->DriverLoadBindInput(DrvExtHdr, DriverAddress, Size);
|
||||
else
|
||||
error("Unknown driver bind type: %d", DrvExtHdr->Driver.Bind.Type);
|
||||
}
|
||||
else
|
||||
return DriverCode::NOT_DRIVER;
|
||||
return DriverCode::ERROR;
|
||||
}
|
||||
|
||||
Driver::Driver()
|
||||
{
|
||||
SmartCriticalSection(DriverInitLock);
|
||||
shared_ptr<VirtualFileSystem::File> DriverDirectory = vfs->Open(Config.DriverDirectory);
|
||||
if (DriverDirectory->Status == VirtualFileSystem::FileStatus::OK)
|
||||
{
|
||||
foreach (auto driver in DriverDirectory->node->Children)
|
||||
if (driver->Flags == VirtualFileSystem::NodeFlags::FILE)
|
||||
if (cwk_path_has_extension(driver->Name))
|
||||
{
|
||||
const char *extension;
|
||||
cwk_path_get_extension(driver->Name, &extension, nullptr);
|
||||
debug("Driver: %s; Extension: %s", driver->Name, extension);
|
||||
if (strcmp(extension, ".fex") == 0 || strcmp(extension, ".elf") == 0)
|
||||
{
|
||||
uintptr_t ret = this->LoadDriver(driver->Address, driver->Length);
|
||||
char RetString[128];
|
||||
if (ret == DriverCode::OK)
|
||||
strncpy(RetString, "\e058C19OK", 10);
|
||||
else if (ret == DriverCode::NOT_AVAILABLE)
|
||||
strncpy(RetString, "\eFF7900NOT AVAILABLE", 21);
|
||||
else
|
||||
sprintf(RetString, "\eE85230FAILED (%#lx)", ret);
|
||||
KPrint("%s %s", driver->Name, RetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrint("\eE85230Failed to open driver directory: %s! (Status: %#lx)", Config.DriverDirectory, DriverDirectory->Status);
|
||||
CPU::Stop();
|
||||
}
|
||||
vfs->Close(DriverDirectory);
|
||||
}
|
||||
|
||||
Driver::~Driver()
|
||||
{
|
||||
debug("Destructor called");
|
||||
this->UnloadAllDrivers();
|
||||
}
|
||||
|
||||
#if defined(a64)
|
||||
SafeFunction void DriverInterruptHook::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
|
||||
#elif defined(a32)
|
||||
SafeFunction void DriverInterruptHook::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
|
||||
#elif defined(aa64)
|
||||
SafeFunction void DriverInterruptHook::OnInterruptReceived(void *Frame)
|
||||
#endif
|
||||
{
|
||||
SmartLock(DriverInterruptLock);
|
||||
((int (*)(void *))(Handle))(Data);
|
||||
UNUSED(Frame);
|
||||
}
|
||||
|
||||
DriverInterruptHook::DriverInterruptHook(int Interrupt, void *Address, void *ParamData) : Interrupts::Handler(Interrupt)
|
||||
{
|
||||
trace("Interrupt %d Hooked", Interrupt - 32); // x86
|
||||
Handle = Address;
|
||||
Data = ParamData;
|
||||
}
|
||||
}
|
185
Kernel/Core/Driver/DriverAPI.cpp
Normal file
185
Kernel/Core/Driver/DriverAPI.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include <driver.hpp>
|
||||
|
||||
#include <dumper.hpp>
|
||||
#include <lock.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../Fex.hpp"
|
||||
#include "api.hpp"
|
||||
|
||||
// show debug messages
|
||||
// #define DEBUG_DRIVER_API 1
|
||||
|
||||
#ifdef DEBUG_DRIVER_API
|
||||
#define drvdbg(m, ...) debug(m, ##__VA_ARGS__)
|
||||
#else
|
||||
#define drvdbg(m, ...)
|
||||
#endif
|
||||
|
||||
NewLock(DriverDisplayPrintLock);
|
||||
|
||||
void DriverDebugPrint(char *String, unsigned long DriverUID) { trace("[%ld] %s", DriverUID, String); }
|
||||
|
||||
void DriverDisplayPrint(char *String)
|
||||
{
|
||||
SmartLock(DriverDisplayPrintLock);
|
||||
for (unsigned long i = 0; i < strlen(String); i++)
|
||||
Display->Print(String[i], 0, true);
|
||||
}
|
||||
|
||||
void *RequestPage(unsigned long Size)
|
||||
{
|
||||
void *ret = KernelAllocator.RequestPages(Size);
|
||||
drvdbg("Allocated %ld pages (%#lx-%#lx)", Size, (unsigned long)ret, (unsigned long)ret + FROM_PAGES(Size));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreePage(void *Page, unsigned long Size)
|
||||
{
|
||||
drvdbg("Freeing %ld pages (%#lx-%#lx)", Size, (unsigned long)Page, (unsigned long)Page + FROM_PAGES(Size));
|
||||
KernelAllocator.FreePages(Page, Size);
|
||||
}
|
||||
|
||||
void MapMemory(void *VirtualAddress, void *PhysicalAddress, unsigned long Flags)
|
||||
{
|
||||
SmartLock(DriverDisplayPrintLock);
|
||||
drvdbg("Mapping %#lx to %#lx with flags %#lx...", (unsigned long)VirtualAddress, (unsigned long)PhysicalAddress, Flags);
|
||||
Memory::Virtual().Map(VirtualAddress, PhysicalAddress, Flags);
|
||||
}
|
||||
|
||||
void UnmapMemory(void *VirtualAddress)
|
||||
{
|
||||
SmartLock(DriverDisplayPrintLock);
|
||||
drvdbg("Unmapping %#lx...", (unsigned long)VirtualAddress);
|
||||
Memory::Virtual().Unmap(VirtualAddress);
|
||||
}
|
||||
|
||||
void *Drivermemcpy(void *Destination, void *Source, unsigned long Size)
|
||||
{
|
||||
SmartLock(DriverDisplayPrintLock);
|
||||
drvdbg("Copying %ld bytes from %#lx-%#lx to %#lx-%#lx...", Size,
|
||||
(unsigned long)Source, (unsigned long)Source + Size,
|
||||
(unsigned long)Destination, (unsigned long)Destination + Size);
|
||||
return memcpy(Destination, Source, Size);
|
||||
}
|
||||
|
||||
void *Drivermemset(void *Destination, int Value, unsigned long Size)
|
||||
{
|
||||
SmartLock(DriverDisplayPrintLock);
|
||||
drvdbg("Setting value %#x at %#lx-%#lx (%ld bytes)...", Value,
|
||||
(unsigned long)Destination, (unsigned long)Destination + Size,
|
||||
Size);
|
||||
return memset(Destination, Value, Size);
|
||||
}
|
||||
|
||||
void DriverNetSend(unsigned int DriverID, unsigned char *Data, unsigned short Size)
|
||||
{
|
||||
// This is useless I guess...
|
||||
if (NIManager)
|
||||
NIManager->DrvSend(DriverID, Data, Size);
|
||||
}
|
||||
|
||||
void DriverNetReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size)
|
||||
{
|
||||
if (NIManager)
|
||||
NIManager->DrvReceive(DriverID, Data, Size);
|
||||
}
|
||||
|
||||
void DriverAHCIDiskRead(unsigned int DriverID, unsigned long Sector, unsigned char *Data, unsigned int SectorCount, unsigned char Port)
|
||||
{
|
||||
DumpData("DriverDiskRead", Data, SectorCount * 512);
|
||||
UNUSED(DriverID);
|
||||
UNUSED(Sector);
|
||||
UNUSED(Port);
|
||||
}
|
||||
|
||||
void DriverAHCIDiskWrite(unsigned int DriverID, unsigned long Sector, unsigned char *Data, unsigned int SectorCount, unsigned char Port)
|
||||
{
|
||||
DumpData("DriverDiskWrite", Data, SectorCount * 512);
|
||||
UNUSED(DriverID);
|
||||
UNUSED(Sector);
|
||||
UNUSED(Port);
|
||||
}
|
||||
|
||||
char *DriverPCIGetDeviceName(unsigned int VendorID, unsigned int DeviceID)
|
||||
{
|
||||
UNUSED(VendorID);
|
||||
UNUSED(DeviceID);
|
||||
return (char *)"Unknown";
|
||||
}
|
||||
|
||||
unsigned int DriverGetWidth()
|
||||
{
|
||||
/* TODO: We won't rely only on display buffers, what about graphics drivers and changing resolutions? */
|
||||
return Display->GetBuffer(0)->Width;
|
||||
}
|
||||
|
||||
unsigned int DriverGetHeight()
|
||||
{
|
||||
/* TODO: We won't rely only on display buffers, what about graphics drivers and changing resolutions? */
|
||||
return Display->GetBuffer(0)->Height;
|
||||
}
|
||||
|
||||
void DriverSleep(unsigned long Milliseconds)
|
||||
{
|
||||
SmartLock(DriverDisplayPrintLock);
|
||||
drvdbg("Sleeping for %ld milliseconds...", Milliseconds);
|
||||
if (TaskManager)
|
||||
TaskManager->Sleep(Milliseconds);
|
||||
else
|
||||
TimeManager->Sleep(Milliseconds);
|
||||
}
|
||||
|
||||
int Driversprintf(char *Buffer, const char *Format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
int ret = vsprintf(Buffer, Format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
KernelAPI KernelAPITemplate = {
|
||||
.Version = {
|
||||
.Major = 0,
|
||||
.Minor = 0,
|
||||
.Patch = 1},
|
||||
.Info = {
|
||||
.Offset = 0,
|
||||
.DriverUID = 0,
|
||||
},
|
||||
.Memory = {
|
||||
.PageSize = PAGE_SIZE,
|
||||
.RequestPage = RequestPage,
|
||||
.FreePage = FreePage,
|
||||
.Map = MapMemory,
|
||||
.Unmap = UnmapMemory,
|
||||
},
|
||||
.PCI = {
|
||||
.GetDeviceName = DriverPCIGetDeviceName,
|
||||
},
|
||||
.Util = {
|
||||
.DebugPrint = DriverDebugPrint,
|
||||
.DisplayPrint = DriverDisplayPrint,
|
||||
.memcpy = Drivermemcpy,
|
||||
.memset = Drivermemset,
|
||||
.Sleep = DriverSleep,
|
||||
.sprintf = Driversprintf,
|
||||
},
|
||||
.Command = {
|
||||
.Network = {
|
||||
.SendPacket = DriverNetSend,
|
||||
.ReceivePacket = DriverNetReceive,
|
||||
},
|
||||
.Disk = {
|
||||
.AHCI = {
|
||||
.ReadSector = DriverAHCIDiskRead,
|
||||
.WriteSector = DriverAHCIDiskWrite,
|
||||
},
|
||||
},
|
||||
},
|
||||
.Display = {
|
||||
.GetWidth = DriverGetWidth,
|
||||
.GetHeight = DriverGetHeight,
|
||||
},
|
||||
};
|
120
Kernel/Core/Driver/DriverLoading/BindInput.cpp
Normal file
120
Kernel/Core/Driver/DriverLoading/BindInput.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "../api.hpp"
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <task.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../../../DAPI.hpp"
|
||||
#include "../../../Fex.hpp"
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
DriverCode Driver::BindInputGeneric(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInputDisplay(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInputNetwork(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInputStorage(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInputFileSystem(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInputInput(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
KernelCallback *KCallback = (KernelCallback *)mem->RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
|
||||
fixme("Input driver: %s", fexExtended->Driver.Name);
|
||||
KCallback->RawPtr = nullptr;
|
||||
KCallback->Reason = CallbackReason::ConfigurationReason;
|
||||
int CallbackRet = ((int (*)(KernelCallback *))((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex))(KCallback);
|
||||
if (CallbackRet == DriverReturnCode::NOT_IMPLEMENTED)
|
||||
{
|
||||
delete mem, mem = nullptr;
|
||||
error("Driver %s is not implemented", fexExtended->Driver.Name);
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (CallbackRet != DriverReturnCode::OK)
|
||||
{
|
||||
delete mem, mem = nullptr;
|
||||
error("Driver %s returned error %d", fexExtended->Driver.Name, CallbackRet);
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
fixme("Input driver: %s", fexExtended->Driver.Name);
|
||||
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
DrvFile->InterruptHook[0] = nullptr;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInputAudio(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::DriverLoadBindInput(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
|
||||
{
|
||||
UNUSED(DrvExtHdr);
|
||||
UNUSED(IsElf);
|
||||
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
|
||||
Fex *fex = (Fex *)mem->RequestPages(TO_PAGES(Size));
|
||||
memcpy(fex, (void *)DriverAddress, Size);
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
debug("Driver allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size);
|
||||
#ifdef DEBUG
|
||||
uint8_t *result = md5File((uint8_t *)fex, Size);
|
||||
debug("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
|
||||
result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]);
|
||||
kfree(result);
|
||||
#endif
|
||||
KernelAPI *KAPI = (KernelAPI *)mem->RequestPages(TO_PAGES(sizeof(KernelAPI)));
|
||||
|
||||
if (CallDriverEntryPoint(fex, KAPI) != DriverCode::OK)
|
||||
{
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
debug("Starting driver %s (offset: %#lx)", fexExtended->Driver.Name, fex);
|
||||
|
||||
switch (fexExtended->Driver.Type)
|
||||
{
|
||||
case FexDriverType::FexDriverType_Input:
|
||||
return BindInputInput(mem, fex);
|
||||
default:
|
||||
{
|
||||
warn("Unknown driver type: %d", fexExtended->Driver.Type);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::UNKNOWN_DRIVER_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return DriverCode::OK;
|
||||
}
|
||||
}
|
469
Kernel/Core/Driver/DriverLoading/BindInterrupt.cpp
Normal file
469
Kernel/Core/Driver/DriverLoading/BindInterrupt.cpp
Normal file
@ -0,0 +1,469 @@
|
||||
#include "../api.hpp"
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <task.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../../../DAPI.hpp"
|
||||
#include "../../../Fex.hpp"
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
DriverCode Driver::BindInterruptGeneric(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Generic driver: %s", fexExtended->Driver.Name);
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInterruptDisplay(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Display driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInterruptNetwork(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Network driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInterruptStorage(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED; // FIXME
|
||||
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
KernelCallback *KCallback = (KernelCallback *)mem->RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
UNUSED(KCallback); // Shut up clang
|
||||
for (unsigned long i = 0; i < sizeof(fexExtended->Driver.Bind.Interrupt.Vector) / sizeof(fexExtended->Driver.Bind.Interrupt.Vector[0]); i++)
|
||||
{
|
||||
if (fexExtended->Driver.Bind.Interrupt.Vector[i] == 0)
|
||||
break;
|
||||
|
||||
fixme("TODO: MULTIPLE BIND INTERRUPT VECTORS %d", fexExtended->Driver.Bind.Interrupt.Vector[i]);
|
||||
}
|
||||
|
||||
KCallback->RawPtr = nullptr;
|
||||
KCallback->Reason = CallbackReason::ConfigurationReason;
|
||||
int CallbackRet = ((int (*)(KernelCallback *))((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex))(KCallback);
|
||||
if (CallbackRet == DriverReturnCode::NOT_IMPLEMENTED)
|
||||
{
|
||||
error("Driver %s is not implemented", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (CallbackRet != DriverReturnCode::OK)
|
||||
{
|
||||
error("Driver %s returned error %d", fexExtended->Driver.Name, CallbackRet);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInterruptFileSystem(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Filesystem driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInterruptInput(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
debug("Searching for conflicting drivers...");
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
if ((fe->Driver.TypeFlags & FexDriverInputTypes_Mouse &&
|
||||
fexExtended->Driver.TypeFlags & FexDriverInputTypes_Mouse) ||
|
||||
(fe->Driver.TypeFlags & FexDriverInputTypes_Keyboard &&
|
||||
fexExtended->Driver.TypeFlags & FexDriverInputTypes_Keyboard))
|
||||
{
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
if ((fe->Driver.TypeFlags & FexDriverInputTypes_Mouse &&
|
||||
fexExtended->Driver.TypeFlags & FexDriverInputTypes_Mouse) ||
|
||||
(fe->Driver.TypeFlags & FexDriverInputTypes_Keyboard &&
|
||||
fexExtended->Driver.TypeFlags & FexDriverInputTypes_Keyboard))
|
||||
{
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KernelCallback *KCallback = (KernelCallback *)mem->RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
|
||||
DriverInterruptHook *InterruptHook = nullptr;
|
||||
if (fexExtended->Driver.Bind.Interrupt.Vector[0] != 0)
|
||||
InterruptHook = new DriverInterruptHook(fexExtended->Driver.Bind.Interrupt.Vector[0] + 32, // x86
|
||||
(void *)((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex),
|
||||
KCallback);
|
||||
|
||||
for (unsigned long i = 0; i < sizeof(fexExtended->Driver.Bind.Interrupt.Vector) / sizeof(fexExtended->Driver.Bind.Interrupt.Vector[0]); i++)
|
||||
{
|
||||
if (fexExtended->Driver.Bind.Interrupt.Vector[i] == 0)
|
||||
break;
|
||||
// InterruptHook = new DriverInterruptHook((fexExtended->Driver.Bind.Interrupt.Vector[i] + 32, // x86
|
||||
// (void *)((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex),
|
||||
// KCallback);
|
||||
fixme("TODO: MULTIPLE BIND INTERRUPT VECTORS %d", fexExtended->Driver.Bind.Interrupt.Vector[i]);
|
||||
}
|
||||
|
||||
KCallback->RawPtr = nullptr;
|
||||
KCallback->Reason = CallbackReason::ConfigurationReason;
|
||||
int CallbackRet = ((int (*)(KernelCallback *))((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex))(KCallback);
|
||||
if (CallbackRet == DriverReturnCode::NOT_IMPLEMENTED)
|
||||
{
|
||||
error("Driver %s is not implemented", fexExtended->Driver.Name);
|
||||
delete InterruptHook, InterruptHook = nullptr;
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (CallbackRet != DriverReturnCode::OK)
|
||||
{
|
||||
error("Driver %s returned error %d", fexExtended->Driver.Name, CallbackRet);
|
||||
delete InterruptHook, InterruptHook = nullptr;
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
memset(KCallback, 0, sizeof(KernelCallback));
|
||||
KCallback->Reason = CallbackReason::InterruptReason;
|
||||
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
DrvFile->InterruptHook[0] = InterruptHook;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindInterruptAudio(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Audio driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::DriverLoadBindInterrupt(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
|
||||
{
|
||||
UNUSED(IsElf);
|
||||
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
|
||||
Fex *fex = (Fex *)mem->RequestPages(TO_PAGES(Size));
|
||||
memcpy(fex, (void *)DriverAddress, Size);
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
debug("Driver allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size);
|
||||
#ifdef DEBUG
|
||||
uint8_t *result = md5File((uint8_t *)fex, Size);
|
||||
debug("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
|
||||
result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]);
|
||||
kfree(result);
|
||||
#endif
|
||||
KernelAPI *KAPI = (KernelAPI *)mem->RequestPages(TO_PAGES(sizeof(KernelAPI)));
|
||||
|
||||
if (CallDriverEntryPoint(fex, KAPI) != DriverCode::OK)
|
||||
{
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
debug("Starting driver %s (offset: %#lx)", fexExtended->Driver.Name, fex);
|
||||
|
||||
switch (fexExtended->Driver.Type)
|
||||
{
|
||||
case FexDriverType::FexDriverType_Generic:
|
||||
return BindInterruptGeneric(mem, fex);
|
||||
case FexDriverType::FexDriverType_Display:
|
||||
return BindInterruptDisplay(mem, fex);
|
||||
case FexDriverType::FexDriverType_Network:
|
||||
return BindInterruptNetwork(mem, fex);
|
||||
case FexDriverType::FexDriverType_Storage:
|
||||
return BindInterruptStorage(mem, fex);
|
||||
case FexDriverType::FexDriverType_FileSystem:
|
||||
return BindInterruptFileSystem(mem, fex);
|
||||
case FexDriverType::FexDriverType_Input:
|
||||
return BindInterruptInput(mem, fex);
|
||||
case FexDriverType::FexDriverType_Audio:
|
||||
return BindInterruptAudio(mem, fex);
|
||||
default:
|
||||
{
|
||||
warn("Unknown driver type: %d", fexExtended->Driver.Type);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::UNKNOWN_DRIVER_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return DriverCode::OK;
|
||||
}
|
||||
}
|
600
Kernel/Core/Driver/DriverLoading/BindPCI.cpp
Normal file
600
Kernel/Core/Driver/DriverLoading/BindPCI.cpp
Normal file
@ -0,0 +1,600 @@
|
||||
#include "../api.hpp"
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <task.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../../../DAPI.hpp"
|
||||
#include "../../../Fex.hpp"
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
void Driver::MapPCIAddresses(PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
Memory::Virtual vma = Memory::Virtual(nullptr);
|
||||
|
||||
debug("Header Type: %d", PCIDevice->HeaderType);
|
||||
switch (PCIDevice->HeaderType)
|
||||
{
|
||||
case 0: // PCI Header 0
|
||||
{
|
||||
uint32_t BAR[6] = {0};
|
||||
size_t BARsSize[6] = {0};
|
||||
|
||||
BAR[0] = ((PCI::PCIHeader0 *)PCIDevice)->BAR0;
|
||||
BAR[1] = ((PCI::PCIHeader0 *)PCIDevice)->BAR1;
|
||||
BAR[2] = ((PCI::PCIHeader0 *)PCIDevice)->BAR2;
|
||||
BAR[3] = ((PCI::PCIHeader0 *)PCIDevice)->BAR3;
|
||||
BAR[4] = ((PCI::PCIHeader0 *)PCIDevice)->BAR4;
|
||||
BAR[5] = ((PCI::PCIHeader0 *)PCIDevice)->BAR5;
|
||||
|
||||
uintptr_t BAR_Type = BAR[0] & 1;
|
||||
uintptr_t BAR_IOBase = BAR[1] & (~3);
|
||||
uintptr_t BAR_MemoryBase = BAR[0] & (~15);
|
||||
|
||||
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", BAR_Type, BAR_IOBase, BAR_MemoryBase);
|
||||
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
{
|
||||
if (BAR[i] == 0)
|
||||
continue;
|
||||
debug("BAR%d: %#lx", i, BAR[i]);
|
||||
}
|
||||
|
||||
/* BARs Size */
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
{
|
||||
if (BAR[i] == 0)
|
||||
continue;
|
||||
|
||||
if ((BAR[i] & 1) == 0) // Memory Base
|
||||
{
|
||||
((PCI::PCIHeader0 *)PCIDevice)->BAR0 = 0xFFFFFFFF;
|
||||
size_t size = ((PCI::PCIHeader0 *)PCIDevice)->BAR0;
|
||||
((PCI::PCIHeader0 *)PCIDevice)->BAR0 = BAR[i];
|
||||
BARsSize[i] = size & (~15);
|
||||
BARsSize[i] = ~BARsSize[i] + 1;
|
||||
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
|
||||
debug("BAR%dSize: %#lx", i, BARsSize[i]);
|
||||
}
|
||||
else if ((BAR[i] & 1) == 1) // I/O Base
|
||||
{
|
||||
((PCI::PCIHeader0 *)PCIDevice)->BAR1 = 0xFFFFFFFF;
|
||||
size_t size = ((PCI::PCIHeader0 *)PCIDevice)->BAR1;
|
||||
((PCI::PCIHeader0 *)PCIDevice)->BAR1 = BAR[i];
|
||||
BARsSize[i] = size & (~3);
|
||||
BARsSize[i] = ~BARsSize[i] + 1;
|
||||
BARsSize[i] = BARsSize[i] & 0xFFFF;
|
||||
debug("BAR%dSize: %#lx", i, BARsSize[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mapping the BARs */
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
{
|
||||
if (BAR[i] == 0)
|
||||
continue;
|
||||
|
||||
if ((BAR[i] & 1) == 0) // Memory Base
|
||||
{
|
||||
uintptr_t BARBase = BAR[i] & (~15);
|
||||
size_t BARSize = BARsSize[i];
|
||||
|
||||
debug("Mapping BAR%d from %#lx to %#lx", i, BARBase, BARBase + BARSize);
|
||||
for (uintptr_t j = BARBase;
|
||||
j < (BARBase + BARSize);
|
||||
j += PAGE_SIZE)
|
||||
{
|
||||
vma.Map((void *)j, (void *)j, Memory::PTFlag::RW | Memory::PTFlag::PWT);
|
||||
}
|
||||
}
|
||||
else if ((BAR[i] & 1) == 1) // I/O Base
|
||||
{
|
||||
uintptr_t BARBase = BAR[i] & (~3);
|
||||
uintptr_t BARSize = BARsSize[i];
|
||||
|
||||
debug("Mapping BAR%d from %#x to %#x", i, BARBase, BARBase + BARSize);
|
||||
for (uintptr_t j = BARBase;
|
||||
j < (BARBase + BARSize);
|
||||
j += PAGE_SIZE)
|
||||
{
|
||||
vma.Map((void *)j, (void *)j, Memory::PTFlag::RW | Memory::PTFlag::PWT);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: // PCI Header 1 (PCI-to-PCI Bridge)
|
||||
{
|
||||
fixme("PCI Header 1 (PCI-to-PCI Bridge) not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 2: // PCI Header 2 (PCI-to-CardBus Bridge)
|
||||
{
|
||||
fixme("PCI Header 2 (PCI-to-CardBus Bridge) not implemented yet");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error("Unknown header type %d", PCIDevice->HeaderType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCIGeneric(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Generic driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCIDisplay(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Display driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCINetwork(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
KernelCallback *KCallback = (KernelCallback *)mem->RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
|
||||
DriverInterruptHook *InterruptHook = new DriverInterruptHook(((int)((PCI::PCIHeader0 *)PCIDevice)->InterruptLine) + 32, // x86
|
||||
(void *)((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex),
|
||||
KCallback);
|
||||
|
||||
KCallback->RawPtr = PCIDevice;
|
||||
KCallback->Reason = CallbackReason::ConfigurationReason;
|
||||
int CallbackRet = ((int (*)(KernelCallback *))((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex))(KCallback);
|
||||
if (CallbackRet == DriverReturnCode::NOT_IMPLEMENTED)
|
||||
{
|
||||
error("Driver %s is not implemented", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
delete InterruptHook, InterruptHook = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (CallbackRet == DriverReturnCode::OK)
|
||||
trace("Device found for driver: %s", fexExtended->Driver.Name);
|
||||
else
|
||||
{
|
||||
error("Driver %s returned error %d", fexExtended->Driver.Name, CallbackRet);
|
||||
delete mem, mem = nullptr;
|
||||
delete InterruptHook, InterruptHook = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
memset(KCallback, 0, sizeof(KernelCallback));
|
||||
KCallback->Reason = CallbackReason::InterruptReason;
|
||||
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
DrvFile->InterruptHook[0] = InterruptHook;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCIStorage(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
KernelCallback *KCallback = (KernelCallback *)mem->RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
|
||||
KCallback->RawPtr = PCIDevice;
|
||||
KCallback->Reason = CallbackReason::ConfigurationReason;
|
||||
int CallbackRet = ((int (*)(KernelCallback *))((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex))(KCallback);
|
||||
if (CallbackRet == DriverReturnCode::NOT_IMPLEMENTED)
|
||||
{
|
||||
error("Driver %s is not implemented", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (CallbackRet == DriverReturnCode::OK)
|
||||
trace("Device found for driver: %s", fexExtended->Driver.Name);
|
||||
else
|
||||
{
|
||||
error("Driver %s returned error %d", fexExtended->Driver.Name, CallbackRet);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
DrvFile->InterruptHook[0] = nullptr;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCIFileSystem(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Filesystem driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCIInput(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
fixme("Input driver: %s", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindPCIAudio(Memory::MemMgr *mem, void *fex, PCI::PCIDeviceHeader *PCIDevice)
|
||||
{
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
|
||||
if (fexExtended->Driver.OverrideOnConflict)
|
||||
{
|
||||
Vector<int> DriversToRemove = Vector<int>();
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
|
||||
DriversToRemove.push_back(Drv->DriverUID);
|
||||
}
|
||||
|
||||
foreach (auto DrvID in DriversToRemove)
|
||||
{
|
||||
if (!this->UnloadDriver(DrvID))
|
||||
{
|
||||
error("Failed to unload conflicting driver %d", DrvID);
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (auto Drv in Drivers)
|
||||
{
|
||||
FexExtended *fe = ((FexExtended *)((uintptr_t)Drv->Address + EXTENDED_SECTION_ADDRESS));
|
||||
|
||||
debug("Driver %s is conflicting with %s", fe->Driver.Name, fexExtended->Driver.Name);
|
||||
if (fe->Driver.OverrideOnConflict)
|
||||
return DriverCode::DRIVER_CONFLICT;
|
||||
}
|
||||
}
|
||||
|
||||
KernelCallback *KCallback = (KernelCallback *)mem->RequestPages(TO_PAGES(sizeof(KernelCallback)));
|
||||
|
||||
DriverInterruptHook *InterruptHook = new DriverInterruptHook(((int)((PCI::PCIHeader0 *)PCIDevice)->InterruptLine) + 32, // x86
|
||||
(void *)((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex),
|
||||
KCallback);
|
||||
|
||||
KCallback->RawPtr = PCIDevice;
|
||||
KCallback->Reason = CallbackReason::ConfigurationReason;
|
||||
int CallbackRet = ((int (*)(KernelCallback *))((uintptr_t)fexExtended->Driver.Callback + (uintptr_t)fex))(KCallback);
|
||||
if (CallbackRet == DriverReturnCode::NOT_IMPLEMENTED)
|
||||
{
|
||||
error("Driver %s is not implemented", fexExtended->Driver.Name);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (CallbackRet == DriverReturnCode::OK)
|
||||
trace("Device found for driver: %s", fexExtended->Driver.Name);
|
||||
else
|
||||
{
|
||||
error("Driver %s returned error %d", fexExtended->Driver.Name, CallbackRet);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
|
||||
memset(KCallback, 0, sizeof(KernelCallback));
|
||||
KCallback->Reason = CallbackReason::InterruptReason;
|
||||
|
||||
DriverFile *DrvFile = new DriverFile;
|
||||
DrvFile->Enabled = true;
|
||||
DrvFile->DriverUID = this->DriverUIDs - 1;
|
||||
DrvFile->Address = (void *)fex;
|
||||
DrvFile->MemTrk = mem;
|
||||
DrvFile->InterruptHook[0] = InterruptHook;
|
||||
Drivers.push_back(DrvFile);
|
||||
return DriverCode::OK;
|
||||
}
|
||||
|
||||
DriverCode Driver::DriverLoadBindPCI(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
|
||||
{
|
||||
UNUSED(IsElf);
|
||||
for (unsigned long Vidx = 0; Vidx < sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID) / sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID[0]); Vidx++)
|
||||
{
|
||||
for (unsigned long Didx = 0; Didx < sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID) / sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID[0]); Didx++)
|
||||
{
|
||||
if (Vidx >= sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID) && Didx >= sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID))
|
||||
break;
|
||||
|
||||
if (((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID[Vidx] == 0 || ((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID[Didx] == 0)
|
||||
continue;
|
||||
|
||||
Vector<PCI::PCIDeviceHeader *> devices = PCIManager->FindPCIDevice(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID[Vidx], ((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID[Didx]);
|
||||
if (devices.size() == 0)
|
||||
continue;
|
||||
|
||||
foreach (auto PCIDevice in devices)
|
||||
{
|
||||
debug("[%ld] VendorID: %#x; DeviceID: %#x", devices.size(), PCIDevice->VendorID, PCIDevice->DeviceID);
|
||||
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
|
||||
Fex *fex = (Fex *)mem->RequestPages(TO_PAGES(Size));
|
||||
memcpy(fex, (void *)DriverAddress, Size);
|
||||
FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
|
||||
debug("Driver allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size);
|
||||
#ifdef DEBUG
|
||||
uint8_t *result = md5File((uint8_t *)fex, Size);
|
||||
debug("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
|
||||
result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]);
|
||||
kfree(result);
|
||||
#endif
|
||||
KernelAPI *KAPI = (KernelAPI *)mem->RequestPages(TO_PAGES(sizeof(KernelAPI)));
|
||||
|
||||
if (CallDriverEntryPoint(fex, KAPI) != DriverCode::OK)
|
||||
{
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::DRIVER_RETURNED_ERROR;
|
||||
}
|
||||
debug("Starting driver %s", fexExtended->Driver.Name);
|
||||
|
||||
MapPCIAddresses(PCIDevice);
|
||||
|
||||
switch (fexExtended->Driver.Type)
|
||||
{
|
||||
case FexDriverType::FexDriverType_Generic:
|
||||
return BindPCIGeneric(mem, fex, PCIDevice);
|
||||
case FexDriverType::FexDriverType_Display:
|
||||
return BindPCIDisplay(mem, fex, PCIDevice);
|
||||
case FexDriverType::FexDriverType_Network:
|
||||
return BindPCINetwork(mem, fex, PCIDevice);
|
||||
case FexDriverType::FexDriverType_Storage:
|
||||
return BindPCIStorage(mem, fex, PCIDevice);
|
||||
case FexDriverType::FexDriverType_FileSystem:
|
||||
return BindPCIFileSystem(mem, fex, PCIDevice);
|
||||
case FexDriverType::FexDriverType_Input:
|
||||
return BindPCIInput(mem, fex, PCIDevice);
|
||||
case FexDriverType::FexDriverType_Audio:
|
||||
return BindPCIAudio(mem, fex, PCIDevice);
|
||||
default:
|
||||
{
|
||||
warn("Unknown driver type: %d", fexExtended->Driver.Type);
|
||||
delete mem, mem = nullptr;
|
||||
return DriverCode::UNKNOWN_DRIVER_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return DriverCode::PCI_DEVICE_NOT_FOUND;
|
||||
}
|
||||
}
|
60
Kernel/Core/Driver/DriverLoading/BindProcess.cpp
Normal file
60
Kernel/Core/Driver/DriverLoading/BindProcess.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "../api.hpp"
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <task.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "../../../DAPI.hpp"
|
||||
#include "../../../Fex.hpp"
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
DriverCode Driver::BindProcessGeneric(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindProcessDisplay(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindProcessNetwork(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindProcessStorage(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindProcessFileSystem(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindProcessInput(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::BindProcessAudio(Memory::MemMgr *mem, void *fex)
|
||||
{
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
DriverCode Driver::DriverLoadBindProcess(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
|
||||
{
|
||||
fixme("Process driver: %s", ((FexExtended *)DrvExtHdr)->Driver.Name);
|
||||
UNUSED(Size);
|
||||
UNUSED(DriverAddress);
|
||||
UNUSED(IsElf);
|
||||
return DriverCode::NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
10
Kernel/Core/Driver/api.hpp
Normal file
10
Kernel/Core/Driver/api.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef __FENNIX_KERNEL_DRIVER_API_H__
|
||||
#define __FENNIX_KERNEL_DRIVER_API_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include "../../DAPI.hpp"
|
||||
|
||||
extern KernelAPI KernelAPITemplate;
|
||||
|
||||
#endif // !__FENNIX_KERNEL_DRIVER_API_H__
|
214
Kernel/Core/InterruptsManager.cpp
Normal file
214
Kernel/Core/InterruptsManager.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
#include <ints.hpp>
|
||||
|
||||
#include <syscalls.hpp>
|
||||
#include <vector.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#if defined(a64)
|
||||
#include "../Architecture/amd64/cpu/gdt.hpp"
|
||||
#include "../Architecture/amd64/cpu/idt.hpp"
|
||||
#include "../Architecture/amd64/acpi.hpp"
|
||||
#include "../Architecture/amd64/cpu/apic.hpp"
|
||||
#elif defined(a32)
|
||||
#include "../Architecture/i686/cpu/gdt.hpp"
|
||||
#include "../Architecture/i686/cpu/idt.hpp"
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#include "crashhandler.hpp"
|
||||
#include "../kernel.h"
|
||||
|
||||
extern "C" SafeFunction void ExceptionHandler(void *Data) { CrashHandler::Handle(Data); }
|
||||
|
||||
namespace Interrupts
|
||||
{
|
||||
struct Event
|
||||
{
|
||||
int ID;
|
||||
void *Data;
|
||||
};
|
||||
Vector<Event> RegisteredEvents;
|
||||
|
||||
#if defined(a64)
|
||||
/* APIC::APIC */ void *apic[MAX_CPU];
|
||||
/* APIC::Timer */ void *apicTimer[MAX_CPU];
|
||||
#elif defined(a32)
|
||||
/* APIC::APIC */ void *apic[MAX_CPU];
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
void *InterruptFrames[INT_FRAMES_MAX];
|
||||
|
||||
void Initialize(int Core)
|
||||
{
|
||||
#if defined(a64)
|
||||
GlobalDescriptorTable::Init(Core);
|
||||
InterruptDescriptorTable::Init(Core);
|
||||
CPUData *CoreData = GetCPU(Core);
|
||||
CoreData->Checksum = CPU_DATA_CHECKSUM;
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, (uint64_t)CoreData);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, (uint64_t)CoreData);
|
||||
CoreData->ID = Core;
|
||||
CoreData->IsActive = true;
|
||||
CoreData->SystemCallStack = (uint8_t *)((uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE)) + STACK_SIZE);
|
||||
CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE)) + STACK_SIZE;
|
||||
if (CoreData->Checksum != CPU_DATA_CHECKSUM)
|
||||
{
|
||||
KPrint("CPU %d checksum mismatch! %x != %x", Core, CoreData->Checksum, CPU_DATA_CHECKSUM);
|
||||
CPU::Stop();
|
||||
}
|
||||
debug("Stack for core %d is %#lx (Address: %#lx)", Core, CoreData->Stack, CoreData->Stack - STACK_SIZE);
|
||||
asmv("movq %0, %%rsp" ::"r"(CoreData->Stack));
|
||||
InitializeSystemCalls();
|
||||
#elif defined(a32)
|
||||
warn("i386 is not supported yet");
|
||||
#elif defined(aa64)
|
||||
warn("aarch64 is not supported yet");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Enable(int Core)
|
||||
{
|
||||
#if defined(a64)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress != nullptr)
|
||||
{
|
||||
// TODO: This function is called by SMP too. Do not initialize timers that doesn't support multiple cores.
|
||||
apic[Core] = new APIC::APIC(Core);
|
||||
if (Core == Config.IOAPICInterruptCore) // Redirect IRQs to the specified core.
|
||||
((APIC::APIC *)apic[Core])->RedirectIRQs(Core);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("LAPIC not found");
|
||||
// TODO: PIC
|
||||
}
|
||||
#elif defined(a32)
|
||||
warn("i386 is not supported yet");
|
||||
#elif defined(aa64)
|
||||
warn("aarch64 is not supported yet");
|
||||
#endif
|
||||
}
|
||||
|
||||
void InitializeTimer(int Core)
|
||||
{
|
||||
// TODO: This function is called by SMP too. Do not initialize timers that doesn't support multiple cores.
|
||||
#if defined(a64)
|
||||
if (apic[Core] != nullptr)
|
||||
apicTimer[Core] = new APIC::Timer((APIC::APIC *)apic[Core]);
|
||||
else
|
||||
{
|
||||
fixme("apic not found");
|
||||
}
|
||||
#elif defined(a32)
|
||||
warn("i386 is not supported yet");
|
||||
#elif defined(aa64)
|
||||
warn("aarch64 is not supported yet");
|
||||
#endif
|
||||
}
|
||||
|
||||
SafeFunction void RemoveAll()
|
||||
{
|
||||
RegisteredEvents.clear();
|
||||
}
|
||||
|
||||
extern "C" SafeFunction void MainInterruptHandler(void *Data)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::TrapFrame *Frame = (CPU::x64::TrapFrame *)Data;
|
||||
|
||||
memmove(InterruptFrames + 1, InterruptFrames, sizeof(InterruptFrames) - sizeof(InterruptFrames[0]));
|
||||
InterruptFrames[0] = (void *)Frame->rip;
|
||||
|
||||
CPUData *CoreData = GetCurrentCPU();
|
||||
int Core = 0;
|
||||
if (likely(CoreData != nullptr))
|
||||
Core = CoreData->ID;
|
||||
|
||||
/* If this is false, we have a big problem. */
|
||||
if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 && Frame->InterruptNumber > CPU::x86::ISR0))
|
||||
{
|
||||
/* Halt core interrupt */
|
||||
if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ29))
|
||||
CPU::Stop();
|
||||
|
||||
bool InterruptHandled = false;
|
||||
foreach (auto ev in RegisteredEvents)
|
||||
{
|
||||
if (ev.ID == static_cast<int>(Frame->InterruptNumber))
|
||||
{
|
||||
((Handler *)ev.Data)->OnInterruptReceived(Frame);
|
||||
InterruptHandled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!InterruptHandled)
|
||||
{
|
||||
error("IRQ%ld is unhandled on CPU %d.", Frame->InterruptNumber - 32, Core);
|
||||
if (Frame->InterruptNumber == CPU::x86::IRQ1)
|
||||
{
|
||||
uint8_t scancode = inb(0x60);
|
||||
warn("IRQ1 is the keyboard interrupt. Scancode: %#x", scancode);
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(apic[Core]))
|
||||
{
|
||||
((APIC::APIC *)Interrupts::apic[Core])->EOI();
|
||||
// TODO: Handle PIC too
|
||||
return;
|
||||
}
|
||||
// TODO: PIC
|
||||
}
|
||||
#elif defined(a32)
|
||||
void *Frame = Data;
|
||||
#elif defined(aa64)
|
||||
void *Frame = Data;
|
||||
#endif
|
||||
error("HALT HALT HALT HALT HALT HALT HALT HALT HALT");
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
Handler::Handler(int InterruptNumber)
|
||||
{
|
||||
foreach (auto ev in RegisteredEvents)
|
||||
{
|
||||
if (ev.ID == InterruptNumber)
|
||||
{
|
||||
warn("IRQ%d is already registered.", InterruptNumber - 32);
|
||||
}
|
||||
}
|
||||
|
||||
debug("Registering interrupt handler for IRQ%d.", InterruptNumber - 32);
|
||||
this->InterruptNumber = InterruptNumber;
|
||||
RegisteredEvents.push_back({InterruptNumber, this});
|
||||
}
|
||||
|
||||
Handler::~Handler()
|
||||
{
|
||||
debug("Unregistering interrupt handler for IRQ%d.", InterruptNumber - 32);
|
||||
for (size_t i = 0; i < RegisteredEvents.size(); i++)
|
||||
{
|
||||
if (RegisteredEvents[i].ID == InterruptNumber)
|
||||
{
|
||||
RegisteredEvents.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
warn("Event %d not found.", InterruptNumber);
|
||||
}
|
||||
|
||||
#if defined(a64)
|
||||
void Handler::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
|
||||
{
|
||||
trace("Unhandled interrupt IRQ%d", Frame->InterruptNumber - 32);
|
||||
#elif defined(a32)
|
||||
void Handler::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
|
||||
{
|
||||
trace("Unhandled interrupt received");
|
||||
#elif defined(aa64)
|
||||
void Handler::OnInterruptReceived(void *Frame)
|
||||
{
|
||||
trace("Unhandled interrupt received");
|
||||
#endif
|
||||
}
|
||||
}
|
138
Kernel/Core/Lock.cpp
Normal file
138
Kernel/Core/Lock.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include <lock.hpp>
|
||||
|
||||
#include <debug.h>
|
||||
#include <smp.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
bool ForceUnlock = false;
|
||||
Atomic<size_t> LocksCount = 0;
|
||||
|
||||
size_t GetLocksCount() { return LocksCount; }
|
||||
|
||||
void LockClass::DeadLock(SpinLockData Lock)
|
||||
{
|
||||
if (ForceUnlock)
|
||||
{
|
||||
warn("Unlocking lock '%s' which it was held by '%s'...", Lock.AttemptingToGet, Lock.CurrentHolder);
|
||||
this->DeadLocks = 0;
|
||||
this->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
CPUData *CoreData = GetCurrentCPU();
|
||||
long CCore = 0xdead;
|
||||
if (CoreData != nullptr)
|
||||
CCore = CoreData->ID;
|
||||
|
||||
warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld is being held by %ld. (%ld times happened)",
|
||||
Lock.AttemptingToGet, Lock.CurrentHolder,
|
||||
Lock.Count, Lock.Count > 1 ? "locks" : "lock",
|
||||
CPU::Interrupts(CPU::Check) ? "enabled" : "disabled",
|
||||
CCore, Lock.Core, this->DeadLocks);
|
||||
|
||||
// TODO: Print on screen too.
|
||||
|
||||
this->DeadLocks++;
|
||||
|
||||
if (Config.UnlockDeadLock && this->DeadLocks.Load() > 10)
|
||||
{
|
||||
warn("Unlocking lock '%s' to prevent deadlock. (this is enabled in the kernel config)", Lock.AttemptingToGet);
|
||||
this->DeadLocks = 0;
|
||||
this->Unlock();
|
||||
}
|
||||
|
||||
if (TaskManager)
|
||||
TaskManager->Schedule();
|
||||
}
|
||||
|
||||
int LockClass::Lock(const char *FunctionName)
|
||||
{
|
||||
LockData.AttemptingToGet = FunctionName;
|
||||
LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0);
|
||||
Retry:
|
||||
unsigned int i = 0;
|
||||
while (IsLocked.Exchange(true, MemoryOrder::Acquire) && ++i < (DebuggerIsAttached ? 0x100000 : 0x10000000))
|
||||
CPU::Pause();
|
||||
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000))
|
||||
{
|
||||
DeadLock(LockData);
|
||||
goto Retry;
|
||||
}
|
||||
LockData.Count++;
|
||||
LockData.CurrentHolder = FunctionName;
|
||||
LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0);
|
||||
CPUData *CoreData = GetCurrentCPU();
|
||||
if (CoreData != nullptr)
|
||||
LockData.Core = CoreData->ID;
|
||||
LocksCount++;
|
||||
__sync;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LockClass::Unlock()
|
||||
{
|
||||
__sync;
|
||||
IsLocked.Store(false, MemoryOrder::Release);
|
||||
LockData.Count--;
|
||||
IsLocked = false;
|
||||
LocksCount--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LockClass::TimeoutDeadLock(SpinLockData Lock, uint64_t Timeout)
|
||||
{
|
||||
CPUData *CoreData = GetCurrentCPU();
|
||||
long CCore = 0xdead;
|
||||
if (CoreData != nullptr)
|
||||
CCore = CoreData->ID;
|
||||
|
||||
uint64_t Counter = TimeManager->GetCounter();
|
||||
|
||||
warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld is being held by %ld. Timeout in %ld (%ld ticks remaining).",
|
||||
Lock.AttemptingToGet, Lock.CurrentHolder,
|
||||
Lock.Count, Lock.Count > 1 ? "locks" : "lock",
|
||||
CPU::Interrupts(CPU::Check) ? "enabled" : "disabled",
|
||||
CCore, Lock.Core, Timeout, Timeout - Counter);
|
||||
|
||||
if (Timeout < Counter)
|
||||
{
|
||||
warn("Unlocking lock '%s' because of timeout. (%ld < %ld)", Lock.AttemptingToGet, Timeout, Counter);
|
||||
this->Unlock();
|
||||
}
|
||||
|
||||
if (TaskManager)
|
||||
TaskManager->Schedule();
|
||||
}
|
||||
|
||||
int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout)
|
||||
{
|
||||
if (!TimeManager)
|
||||
return Lock(FunctionName);
|
||||
LockData.AttemptingToGet = FunctionName;
|
||||
LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0);
|
||||
Atomic<uint64_t> Target = 0;
|
||||
Retry:
|
||||
unsigned int i = 0;
|
||||
while (IsLocked.Exchange(true, MemoryOrder::Acquire) && ++i < (DebuggerIsAttached ? 0x100000 : 0x10000000))
|
||||
CPU::Pause();
|
||||
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000))
|
||||
{
|
||||
if (Target.Load() == 0)
|
||||
Target.Store(TimeManager->CalculateTarget(Timeout));
|
||||
TimeoutDeadLock(LockData, Target.Load());
|
||||
goto Retry;
|
||||
}
|
||||
LockData.Count++;
|
||||
LockData.CurrentHolder = FunctionName;
|
||||
LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0);
|
||||
CPUData *CoreData = GetCurrentCPU();
|
||||
if (CoreData != nullptr)
|
||||
LockData.Core = CoreData->ID;
|
||||
LocksCount++;
|
||||
__sync;
|
||||
|
||||
return 0;
|
||||
}
|
137
Kernel/Core/Memory/HeapAllocators/Xalloc/README.md
Normal file
137
Kernel/Core/Memory/HeapAllocators/Xalloc/README.md
Normal file
@ -0,0 +1,137 @@
|
||||
# Xalloc
|
||||
|
||||
Xalloc is a custom memory allocator designed for hobby operating systems. It is written in C++ and provides a simple and efficient way to manage memory in your hobby OS.
|
||||
|
||||
#### ❗ This project is still in development and is not ready for use in production environments. ❗
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Simple API** - Xalloc provides a simple API for allocating and freeing memory. It is designed to be easy to use and understand.
|
||||
|
||||
- [ ] todo complete this
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Implementing missing functions
|
||||
|
||||
You will need to implement the following functions in your OS:
|
||||
|
||||
##### Wrapper.cpp
|
||||
```cpp
|
||||
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_MAP_MEMORY(void *VirtualAddress, void *PhysicalAddress, Xsize_t Flags)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_UNMAP_MEMORY(void *VirtualAddress)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
##### Xalloc.hpp
|
||||
```cpp
|
||||
#define Xalloc_PAGE_SIZE <page size> /* <-- Replace with your page size */
|
||||
#define Xalloc_trace(m, ...) <trace function>
|
||||
#define Xalloc_warn(m, ...) <warning function>
|
||||
#define Xalloc_err(m, ...) <error function>
|
||||
#define Xalloc_def <define a lock> /* eg. std::mutex Xalloc_lock; */
|
||||
#define Xalloc_lock <lock function>
|
||||
#define Xalloc_unlock <unlock function>
|
||||
```
|
||||
|
||||
### Typical usage
|
||||
|
||||
```cpp
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
Xalloc::V1 *XallocV1Allocator = nullptr;
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Virtual Base User SMAP */
|
||||
XallocV1Allocator = new Xalloc::V1((void *)0xFFFFA00000000000, false, false);
|
||||
|
||||
void *p = XallocV1Allocator->malloc(1234);
|
||||
/* ... */
|
||||
XallocV1Allocator->free(p);
|
||||
delete XallocV1Allocator;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```cpp
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
/* Virtual Base User SMAP */
|
||||
Xalloc::V1 XallocV1Allocator((void *)0xFFFFA00000000000, false, false);
|
||||
|
||||
void *p = XallocV1Allocator.malloc(1234);
|
||||
/* ... */
|
||||
XallocV1Allocator.free(p);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
### Xalloc::V1
|
||||
|
||||
```cpp
|
||||
void *malloc(Xsize_t Size);
|
||||
```
|
||||
Allocates a block of memory of size `Size` bytes.
|
||||
If `Size` is 0, then `nullptr` is returned.
|
||||
- `Size` - The size of the block to allocate in bytes.
|
||||
|
||||
<br><br>
|
||||
|
||||
```cpp
|
||||
void free(void *Address);
|
||||
```
|
||||
Frees the memory block pointed to by `Address`.
|
||||
If `Address` is `nullptr`, then no operation is performed.
|
||||
- `Address` - The address of the memory block to free.
|
||||
|
||||
<br><br>
|
||||
|
||||
```cpp
|
||||
void *calloc(Xsize_t NumberOfBlocks, Xsize_t Size);
|
||||
```
|
||||
Allocates a block of memory for an array of `NumberOfBlocks` elements, each of them `Size` bytes long.
|
||||
If `NumberOfBlocks` or `Size` is 0, then `nullptr` is returned.
|
||||
- `NumberOfBlocks` - The number of elements to allocate.
|
||||
- `Size` - The size of each element in bytes.
|
||||
|
||||
<br><br>
|
||||
|
||||
```cpp
|
||||
void *realloc(void *Address, Xsize_t Size);
|
||||
```
|
||||
Changes the size of the memory block pointed to by `Address` to `Size` bytes.
|
||||
If `Address` is `nullptr`, then the call is equivalent to `malloc(Size)`.
|
||||
If `Size` is equal to zero, and `Address` is not `nullptr`, then the call is equivalent to `free(Address)`.
|
||||
- `Address` - The address of the memory block to resize.
|
||||
- `Size` - The new size of the memory block in bytes.
|
||||
|
||||
---
|
23
Kernel/Core/Memory/HeapAllocators/Xalloc/Wrapper.cpp
Normal file
23
Kernel/Core/Memory/HeapAllocators/Xalloc/Wrapper.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
|
||||
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages)
|
||||
{
|
||||
return KernelAllocator.RequestPages(Pages);
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages)
|
||||
{
|
||||
KernelAllocator.FreePages(Address, Pages);
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_MAP_MEMORY(void *VirtualAddress, void *PhysicalAddress, Xsize_t Flags)
|
||||
{
|
||||
Memory::Virtual(KernelPageTable).Map(VirtualAddress, PhysicalAddress, Flags);
|
||||
}
|
||||
|
||||
extern "C" void Xalloc_UNMAP_MEMORY(void *VirtualAddress)
|
||||
{
|
||||
Memory::Virtual(KernelPageTable).Unmap(VirtualAddress);
|
||||
}
|
102
Kernel/Core/Memory/HeapAllocators/Xalloc/Xalloc.hpp
Normal file
102
Kernel/Core/Memory/HeapAllocators/Xalloc/Xalloc.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef __FENNIX_KERNEL_Xalloc_H__
|
||||
#define __FENNIX_KERNEL_Xalloc_H__
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
typedef long unsigned Xuint64_t;
|
||||
typedef long unsigned Xsize_t;
|
||||
|
||||
#define Xalloc_StopOnFail true
|
||||
#define Xalloc_PAGE_SIZE PAGE_SIZE
|
||||
#define Xalloc_trace(m, ...) trace(m, ##__VA_ARGS__)
|
||||
#define Xalloc_warn(m, ...) warn(m, ##__VA_ARGS__)
|
||||
#define Xalloc_err(m, ...) error(m, ##__VA_ARGS__)
|
||||
#define Xalloc_def NewLock(XallocLock)
|
||||
#define Xalloc_lock XallocLock.Lock(__FUNCTION__)
|
||||
#define Xalloc_unlock XallocLock.Unlock()
|
||||
|
||||
namespace Xalloc
|
||||
{
|
||||
class V1
|
||||
{
|
||||
private:
|
||||
void *BaseVirtualAddress = nullptr;
|
||||
void *FirstBlock = nullptr;
|
||||
void *LastBlock = nullptr;
|
||||
|
||||
bool UserMapping = false;
|
||||
bool SMAPUsed = false;
|
||||
|
||||
public:
|
||||
/** @brief Execute "stac" instruction if the kernel has SMAP enabled */
|
||||
void Xstac();
|
||||
|
||||
/** @brief Execute "clac" instruction if the kernel has SMAP enabled */
|
||||
void Xclac();
|
||||
|
||||
/**
|
||||
* @brief Arrange the blocks to optimize the memory usage
|
||||
* The allocator is not arranged by default
|
||||
* to avoid performance issues.
|
||||
* This function will defragment the memory
|
||||
* and free the unused blocks.
|
||||
*
|
||||
* You should call this function when the
|
||||
* kernel is idle or when is not using
|
||||
* the allocator.
|
||||
*/
|
||||
void Arrange();
|
||||
|
||||
/**
|
||||
* @brief Allocate a new memory block
|
||||
*
|
||||
* @param Size Size of the block to allocate.
|
||||
* @return void* Pointer to the allocated block.
|
||||
*/
|
||||
void *malloc(Xsize_t Size);
|
||||
|
||||
/**
|
||||
* @brief Free a previously allocated block
|
||||
*
|
||||
* @param Address Address of the block to free.
|
||||
*/
|
||||
void free(void *Address);
|
||||
|
||||
/**
|
||||
* @brief Allocate a new memory block
|
||||
*
|
||||
* @param NumberOfBlocks Number of blocks to allocate.
|
||||
* @param Size Size of the block to allocate.
|
||||
* @return void* Pointer to the allocated block.
|
||||
*/
|
||||
void *calloc(Xsize_t NumberOfBlocks, Xsize_t Size);
|
||||
|
||||
/**
|
||||
* @brief Reallocate a previously allocated block
|
||||
*
|
||||
* @param Address Address of the block to reallocate.
|
||||
* @param Size New size of the block.
|
||||
* @return void* Pointer to the reallocated block.
|
||||
*/
|
||||
void *realloc(void *Address, Xsize_t Size);
|
||||
|
||||
/**
|
||||
* @brief Construct a new Allocator object
|
||||
*
|
||||
* @param BaseVirtualAddress Virtual address to map the pages.
|
||||
* @param UserMode Map the new pages with USER flag?
|
||||
* @param SMAPEnabled Does the kernel has Supervisor Mode Access Prevention enabled?
|
||||
*/
|
||||
V1(void *BaseVirtualAddress, bool UserMode, bool SMAPEnabled);
|
||||
|
||||
/**
|
||||
* @brief Destroy the Allocator object
|
||||
*
|
||||
*/
|
||||
~V1();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_Xalloc_H__
|
271
Kernel/Core/Memory/HeapAllocators/Xalloc/XallocV1.cpp
Normal file
271
Kernel/Core/Memory/HeapAllocators/Xalloc/XallocV1.cpp
Normal file
@ -0,0 +1,271 @@
|
||||
#include "Xalloc.hpp"
|
||||
|
||||
Xalloc_def;
|
||||
|
||||
#define XALLOC_CONCAT(x, y) x##y
|
||||
#define XStoP(x) (x / Xalloc_PAGE_SIZE + 1)
|
||||
#define XPtoS(x) (x * Xalloc_PAGE_SIZE)
|
||||
#define Xalloc_BlockChecksum 0xA110C
|
||||
|
||||
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages);
|
||||
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages);
|
||||
extern "C" void Xalloc_MAP_MEMORY(void *VirtualAddress, void *PhysicalAddress, Xsize_t Flags);
|
||||
extern "C" void Xalloc_UNMAP_MEMORY(void *VirtualAddress);
|
||||
|
||||
// TODO: Change memcpy with an optimized version
|
||||
void *Xmemcpy(void *__restrict__ Destination, const void *__restrict__ Source, Xuint64_t Length)
|
||||
{
|
||||
unsigned char *dst = (unsigned char *)Destination;
|
||||
const unsigned char *src = (const unsigned char *)Source;
|
||||
for (Xuint64_t i = 0; i < Length; i++)
|
||||
dst[i] = src[i];
|
||||
return Destination;
|
||||
}
|
||||
|
||||
// TODO: Change memset with an optimized version
|
||||
void *Xmemset(void *__restrict__ Destination, int Data, Xuint64_t Length)
|
||||
{
|
||||
unsigned char *Buffer = (unsigned char *)Destination;
|
||||
for (Xuint64_t i = 0; i < Length; i++)
|
||||
Buffer[i] = (unsigned char)Data;
|
||||
return Destination;
|
||||
}
|
||||
|
||||
namespace Xalloc
|
||||
{
|
||||
class Block
|
||||
{
|
||||
public:
|
||||
void *Address = nullptr;
|
||||
|
||||
int Checksum = Xalloc_BlockChecksum;
|
||||
Xsize_t Size = 0;
|
||||
Block *Next = nullptr;
|
||||
Block *Last = nullptr;
|
||||
bool IsFree = true;
|
||||
|
||||
bool Check()
|
||||
{
|
||||
if (this->Checksum != Xalloc_BlockChecksum)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Block(Xsize_t Size)
|
||||
{
|
||||
this->Address = Xalloc_REQUEST_PAGES(XStoP(Size));
|
||||
this->Size = Size;
|
||||
Xmemset(this->Address, 0, Size);
|
||||
}
|
||||
|
||||
~Block()
|
||||
{
|
||||
Xalloc_FREE_PAGES(this->Address, XStoP(this->Size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overload new operator to allocate memory from the heap
|
||||
* @param Size Unused
|
||||
* @return void* Pointer to the allocated memory
|
||||
*/
|
||||
void *operator new(Xsize_t Size)
|
||||
{
|
||||
void *ptr = Xalloc_REQUEST_PAGES(XStoP(sizeof(Block)));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overload delete operator to free memory from the heap
|
||||
* @param Address Pointer to the memory to free
|
||||
*/
|
||||
void operator delete(void *Address)
|
||||
{
|
||||
Xalloc_FREE_PAGES(Address, XStoP(sizeof(Block)));
|
||||
}
|
||||
} __attribute__((packed, aligned((16))));
|
||||
|
||||
class SmartSMAPClass
|
||||
{
|
||||
private:
|
||||
V1 *allocator = nullptr;
|
||||
|
||||
public:
|
||||
SmartSMAPClass(V1 *allocator)
|
||||
{
|
||||
this->allocator = allocator;
|
||||
this->allocator->Xstac();
|
||||
}
|
||||
~SmartSMAPClass() { this->allocator->Xclac(); }
|
||||
};
|
||||
#define SmartSMAP SmartSMAPClass XALLOC_CONCAT(SmartSMAP##_, __COUNTER__)(this)
|
||||
|
||||
void V1::Xstac()
|
||||
{
|
||||
if (this->SMAPUsed)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
asm volatile("stac" ::
|
||||
: "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void V1::Xclac()
|
||||
{
|
||||
if (this->SMAPUsed)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
asm volatile("clac" ::
|
||||
: "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void V1::Arrange()
|
||||
{
|
||||
Xalloc_err("Arrange() is not implemented yet!");
|
||||
}
|
||||
|
||||
void *V1::malloc(Xsize_t Size)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
Xalloc_warn("Attempted to allocate 0 bytes!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
|
||||
if (this->FirstBlock == nullptr)
|
||||
{
|
||||
this->FirstBlock = new Block(Size);
|
||||
((Block *)this->FirstBlock)->IsFree = false;
|
||||
Xalloc_unlock;
|
||||
return ((Block *)this->FirstBlock)->Address;
|
||||
}
|
||||
|
||||
Block *CurrentBlock = ((Block *)this->FirstBlock);
|
||||
while (CurrentBlock != nullptr)
|
||||
{
|
||||
if (!CurrentBlock->Check())
|
||||
{
|
||||
Xalloc_err("Block %#lx has an invalid checksum! (%#x != %#x)",
|
||||
(Xuint64_t)CurrentBlock, CurrentBlock->Checksum, Xalloc_BlockChecksum);
|
||||
while (Xalloc_StopOnFail)
|
||||
;
|
||||
}
|
||||
else if (CurrentBlock->IsFree && CurrentBlock->Size >= Size)
|
||||
{
|
||||
CurrentBlock->IsFree = false;
|
||||
Xmemset(CurrentBlock->Address, 0, Size);
|
||||
Xalloc_unlock;
|
||||
return CurrentBlock->Address;
|
||||
}
|
||||
CurrentBlock = CurrentBlock->Next;
|
||||
}
|
||||
|
||||
CurrentBlock = ((Block *)this->FirstBlock);
|
||||
while (CurrentBlock->Next != nullptr)
|
||||
CurrentBlock = CurrentBlock->Next;
|
||||
|
||||
CurrentBlock->Next = new Block(Size);
|
||||
((Block *)CurrentBlock->Next)->Last = CurrentBlock;
|
||||
((Block *)CurrentBlock->Next)->IsFree = false;
|
||||
Xalloc_unlock;
|
||||
return ((Block *)CurrentBlock->Next)->Address;
|
||||
}
|
||||
|
||||
void V1::free(void *Address)
|
||||
{
|
||||
if (Address == nullptr)
|
||||
{
|
||||
Xalloc_warn("Attempted to free a null pointer!");
|
||||
return;
|
||||
}
|
||||
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
|
||||
Block *CurrentBlock = ((Block *)this->FirstBlock);
|
||||
while (CurrentBlock != nullptr)
|
||||
{
|
||||
if (!CurrentBlock->Check())
|
||||
{
|
||||
Xalloc_err("Block %#lx checksum failed!", (Xuint64_t)CurrentBlock);
|
||||
while (Xalloc_StopOnFail)
|
||||
;
|
||||
}
|
||||
else if (CurrentBlock->Address == Address)
|
||||
{
|
||||
if (CurrentBlock->IsFree)
|
||||
{
|
||||
Xalloc_warn("Attempted to free an already freed pointer!");
|
||||
Xalloc_unlock;
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentBlock->IsFree = true;
|
||||
Xalloc_unlock;
|
||||
return;
|
||||
}
|
||||
CurrentBlock = CurrentBlock->Next;
|
||||
}
|
||||
|
||||
Xalloc_err("Invalid address.");
|
||||
Xalloc_unlock;
|
||||
}
|
||||
|
||||
void *V1::calloc(Xsize_t NumberOfBlocks, Xsize_t Size)
|
||||
{
|
||||
if (NumberOfBlocks == 0 || Size == 0)
|
||||
{
|
||||
Xalloc_warn("The %s%s%s is 0!",
|
||||
NumberOfBlocks == 0 ? "NumberOfBlocks" : "",
|
||||
NumberOfBlocks == 0 && Size == 0 ? " and " : "",
|
||||
Size == 0 ? "Size" : "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return this->malloc(NumberOfBlocks * Size);
|
||||
}
|
||||
|
||||
void *V1::realloc(void *Address, Xsize_t Size)
|
||||
{
|
||||
if (Address == nullptr)
|
||||
return this->malloc(Size);
|
||||
|
||||
if (Size == 0)
|
||||
{
|
||||
this->free(Address);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// SmartSMAP;
|
||||
// Xalloc_lock;
|
||||
// ...
|
||||
// Xalloc_unlock;
|
||||
|
||||
// TODO: Implement realloc
|
||||
this->free(Address);
|
||||
return this->malloc(Size);
|
||||
}
|
||||
|
||||
V1::V1(void *BaseVirtualAddress, bool UserMode, bool SMAPEnabled)
|
||||
{
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
this->SMAPUsed = SMAPEnabled;
|
||||
this->UserMapping = UserMode;
|
||||
this->BaseVirtualAddress = BaseVirtualAddress;
|
||||
Xalloc_unlock;
|
||||
}
|
||||
|
||||
V1::~V1()
|
||||
{
|
||||
SmartSMAP;
|
||||
Xalloc_lock;
|
||||
Xalloc_trace("Destructor not implemented yet.");
|
||||
Xalloc_unlock;
|
||||
}
|
||||
}
|
679
Kernel/Core/Memory/Memory.cpp
Normal file
679
Kernel/Core/Memory/Memory.cpp
Normal file
@ -0,0 +1,679 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <lock.hpp>
|
||||
#include <debug.h>
|
||||
#ifdef DEBUG
|
||||
#include <uart.hpp>
|
||||
#endif
|
||||
|
||||
#include "HeapAllocators/Xalloc/Xalloc.hpp"
|
||||
#include "../Library/liballoc_1_1.h"
|
||||
#include "../../kernel.h"
|
||||
|
||||
// #define DEBUG_ALLOCATIONS_SL 1
|
||||
// #define DEBUG_ALLOCATIONS 1
|
||||
|
||||
#ifdef DEBUG_ALLOCATIONS
|
||||
#define memdbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync
|
||||
#else
|
||||
#define memdbg(m, ...)
|
||||
#endif
|
||||
|
||||
using namespace Memory;
|
||||
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
NewLock(AllocatorLock);
|
||||
NewLock(OperatorAllocatorLock);
|
||||
#endif
|
||||
|
||||
Physical KernelAllocator;
|
||||
PageTable4 *KernelPageTable = nullptr;
|
||||
PageTable4 *UserspaceKernelOnlyPageTable = nullptr;
|
||||
void *KPT = nullptr;
|
||||
|
||||
static MemoryAllocatorType AllocatorType = MemoryAllocatorType::None;
|
||||
Xalloc::V1 *XallocV1Allocator = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
NIF void tracepagetable(PageTable4 *pt)
|
||||
{
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
#if defined(a64)
|
||||
if (pt->Entries[i].Present)
|
||||
debug("Entry %03d: %x %x %x %x %x %x %x %p-%#llx", i,
|
||||
pt->Entries[i].Present, pt->Entries[i].ReadWrite,
|
||||
pt->Entries[i].UserSupervisor, pt->Entries[i].WriteThrough,
|
||||
pt->Entries[i].CacheDisable, pt->Entries[i].Accessed,
|
||||
pt->Entries[i].ExecuteDisable, pt->Entries[i].Address << 12,
|
||||
pt->Entries[i]);
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NIF void MapFromZero(PageTable4 *PT, BootInfo *Info)
|
||||
{
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
{
|
||||
Virtual va = Virtual(PT);
|
||||
void *NullAddress = KernelAllocator.RequestPage();
|
||||
memset(NullAddress, 0, PAGE_SIZE); // TODO: If the CPU instruction pointer hits this page, there should be function to handle it. (memcpy assembly code?)
|
||||
va.Map((void *)0, (void *)NullAddress, PTFlag::RW | PTFlag::US);
|
||||
uintptr_t VirtualOffsetNormalVMA = NORMAL_VMA_OFFSET;
|
||||
size_t MemSize = Info->Memory.Size;
|
||||
for (size_t t = 0; t < MemSize; t += PAGE_SIZE)
|
||||
{
|
||||
va.Map((void *)t, (void *)t, PTFlag::RW /* | PTFlag::US */);
|
||||
// va.Map((void *)VirtualOffsetNormalVMA, (void *)t, PTFlag::RW /* | PTFlag::US */);
|
||||
// VirtualOffsetNormalVMA += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error("MapFromZero() called more than once!");
|
||||
CPU::Stop();
|
||||
}
|
||||
}
|
||||
|
||||
NIF void MapFramebuffer(PageTable4 *PT, BootInfo *Info)
|
||||
{
|
||||
Virtual va = Virtual(PT);
|
||||
int itrfb = 0;
|
||||
while (1)
|
||||
{
|
||||
if (!Info->Framebuffer[itrfb].BaseAddress)
|
||||
break;
|
||||
|
||||
for (uintptr_t fb_base = (uintptr_t)Info->Framebuffer[itrfb].BaseAddress;
|
||||
fb_base < ((uintptr_t)Info->Framebuffer[itrfb].BaseAddress + ((Info->Framebuffer[itrfb].Pitch * Info->Framebuffer[itrfb].Height) + PAGE_SIZE));
|
||||
fb_base += PAGE_SIZE)
|
||||
va.Map((void *)fb_base, (void *)fb_base, PTFlag::RW | PTFlag::US | PTFlag::G);
|
||||
itrfb++;
|
||||
}
|
||||
}
|
||||
|
||||
NIF void MapKernel(PageTable4 *PT, BootInfo *Info)
|
||||
{
|
||||
/* KernelStart KernelTextEnd KernelRoDataEnd KernelEnd
|
||||
Kernel Start & Text Start ------ Text End ------ Kernel Rodata End ------ Kernel Data End & Kernel End
|
||||
*/
|
||||
Virtual va = Virtual(PT);
|
||||
uintptr_t KernelStart = (uintptr_t)&_kernel_start;
|
||||
uintptr_t KernelTextEnd = (uintptr_t)&_kernel_text_end;
|
||||
uintptr_t KernelDataEnd = (uintptr_t)&_kernel_data_end;
|
||||
uintptr_t KernelRoDataEnd = (uintptr_t)&_kernel_rodata_end;
|
||||
uintptr_t KernelEnd = (uintptr_t)&_kernel_end;
|
||||
|
||||
uintptr_t BaseKernelMapAddress = (uintptr_t)Info->Kernel.PhysicalBase;
|
||||
uintptr_t k;
|
||||
|
||||
for (k = KernelStart; k < KernelTextEnd; k += PAGE_SIZE)
|
||||
{
|
||||
va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
|
||||
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||
BaseKernelMapAddress += PAGE_SIZE;
|
||||
}
|
||||
|
||||
for (k = KernelTextEnd; k < KernelDataEnd; k += PAGE_SIZE)
|
||||
{
|
||||
va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW | PTFlag::G);
|
||||
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||
BaseKernelMapAddress += PAGE_SIZE;
|
||||
}
|
||||
|
||||
for (k = KernelDataEnd; k < KernelRoDataEnd; k += PAGE_SIZE)
|
||||
{
|
||||
va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::P | PTFlag::G);
|
||||
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||
BaseKernelMapAddress += PAGE_SIZE;
|
||||
}
|
||||
|
||||
for (k = KernelRoDataEnd; k < KernelEnd; k += PAGE_SIZE)
|
||||
{
|
||||
va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW | PTFlag::G);
|
||||
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
|
||||
BaseKernelMapAddress += PAGE_SIZE;
|
||||
}
|
||||
|
||||
debug("\nStart: %#llx - Text End: %#llx - RoEnd: %#llx - End: %#llx\nStart Physical: %#llx - End Physical: %#llx",
|
||||
KernelStart, KernelTextEnd, KernelRoDataEnd, KernelEnd, Info->Kernel.PhysicalBase, BaseKernelMapAddress - PAGE_SIZE);
|
||||
}
|
||||
|
||||
NIF void InitializeMemoryManagement(BootInfo *Info)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
|
||||
{
|
||||
uintptr_t Base = reinterpret_cast<uintptr_t>(Info->Memory.Entry[i].BaseAddress);
|
||||
uintptr_t Length = Info->Memory.Entry[i].Length;
|
||||
uintptr_t End = Base + Length;
|
||||
const char *Type = "Unknown";
|
||||
|
||||
switch (Info->Memory.Entry[i].Type)
|
||||
{
|
||||
case likely(Usable):
|
||||
Type = "Usable";
|
||||
break;
|
||||
case Reserved:
|
||||
Type = "Reserved";
|
||||
break;
|
||||
case ACPIReclaimable:
|
||||
Type = "ACPI Reclaimable";
|
||||
break;
|
||||
case ACPINVS:
|
||||
Type = "ACPI NVS";
|
||||
break;
|
||||
case BadMemory:
|
||||
Type = "Bad Memory";
|
||||
break;
|
||||
case BootloaderReclaimable:
|
||||
Type = "Bootloader Reclaimable";
|
||||
break;
|
||||
case KernelAndModules:
|
||||
Type = "Kernel and Modules";
|
||||
break;
|
||||
case Framebuffer:
|
||||
Type = "Framebuffer";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
debug("%lld: %#016llx-%#016llx %s",
|
||||
i,
|
||||
Base,
|
||||
End,
|
||||
Type);
|
||||
}
|
||||
#endif
|
||||
trace("Initializing Physical Memory Manager");
|
||||
// KernelAllocator = Physical(); <- Already called in the constructor
|
||||
KernelAllocator.Init(Info);
|
||||
debug("Memory Info: %lldMB / %lldMB (%lldMB reserved)",
|
||||
TO_MB(KernelAllocator.GetUsedMemory()),
|
||||
TO_MB(KernelAllocator.GetTotalMemory()),
|
||||
TO_MB(KernelAllocator.GetReservedMemory()));
|
||||
|
||||
AllocatorType = MemoryAllocatorType::Pages;
|
||||
|
||||
trace("Initializing Virtual Memory Manager");
|
||||
KernelPageTable = (PageTable4 *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE));
|
||||
memset(KernelPageTable, 0, PAGE_SIZE);
|
||||
|
||||
UserspaceKernelOnlyPageTable = (PageTable4 *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE));
|
||||
memset(UserspaceKernelOnlyPageTable, 0, PAGE_SIZE);
|
||||
|
||||
debug("Mapping from 0x0 to %#llx", Info->Memory.Size);
|
||||
MapFromZero(KernelPageTable, Info);
|
||||
debug("Mapping from 0x0 %#llx for Userspace Page Table", Info->Memory.Size);
|
||||
UserspaceKernelOnlyPageTable[0] = KernelPageTable[0];
|
||||
|
||||
/* Mapping Framebuffer address */
|
||||
debug("Mapping Framebuffer");
|
||||
MapFramebuffer(KernelPageTable, Info);
|
||||
debug("Mapping Framebuffer for Userspace Page Table");
|
||||
MapFramebuffer(UserspaceKernelOnlyPageTable, Info);
|
||||
|
||||
/* Kernel mapping */
|
||||
debug("Mapping Kernel");
|
||||
MapKernel(KernelPageTable, Info);
|
||||
debug("Mapping Kernel for Userspace Page Table");
|
||||
MapKernel(UserspaceKernelOnlyPageTable, Info);
|
||||
|
||||
trace("Applying new page table from address %p", KernelPageTable);
|
||||
#ifdef DEBUG
|
||||
debug("Kernel:");
|
||||
tracepagetable(KernelPageTable);
|
||||
debug("Userspace:");
|
||||
tracepagetable(UserspaceKernelOnlyPageTable);
|
||||
#endif
|
||||
KPT = KernelPageTable;
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("mov %0, %%cr3" ::"r"(KPT));
|
||||
#elif defined(aa64)
|
||||
asmv("msr ttbr0_el1, %0" ::"r"(KPT));
|
||||
#endif
|
||||
debug("Page table updated.");
|
||||
if (strstr(Info->Kernel.CommandLine, "xallocv1"))
|
||||
{
|
||||
XallocV1Allocator = new Xalloc::V1((void *)KERNEL_HEAP_BASE, false, false);
|
||||
AllocatorType = MemoryAllocatorType::XallocV1;
|
||||
trace("XallocV1 Allocator initialized (%p)", XallocV1Allocator);
|
||||
}
|
||||
else if (strstr(Info->Kernel.CommandLine, "liballoc11"))
|
||||
{
|
||||
AllocatorType = MemoryAllocatorType::liballoc11;
|
||||
}
|
||||
}
|
||||
|
||||
void *HeapMalloc(size_t Size)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("malloc(%d)->[%s]", Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
void *ret = nullptr;
|
||||
switch (AllocatorType)
|
||||
{
|
||||
case MemoryAllocatorType::Pages:
|
||||
{
|
||||
ret = KernelAllocator.RequestPages(TO_PAGES(Size));
|
||||
memset(ret, 0, Size);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
ret = XallocV1Allocator->malloc(Size);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
ret = PREFIX(malloc)(Size);
|
||||
memset(ret, 0, Size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "malloc( %ld )=%p~%p\n\r",
|
||||
Size,
|
||||
ret, __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *HeapCalloc(size_t n, size_t Size)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("calloc(%d, %d)->[%s]", n, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
void *ret = nullptr;
|
||||
switch (AllocatorType)
|
||||
{
|
||||
case MemoryAllocatorType::Pages:
|
||||
{
|
||||
ret = KernelAllocator.RequestPages(TO_PAGES(n * Size));
|
||||
memset(ret, 0, n * Size);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
ret = XallocV1Allocator->calloc(n, Size);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
void *ret = PREFIX(calloc)(n, Size);
|
||||
memset(ret, 0, Size);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
throw;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "calloc( %ld %ld )=%p~%p\n\r",
|
||||
n, Size,
|
||||
ret, __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *HeapRealloc(void *Address, size_t Size)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("realloc(%#lx, %d)->[%s]", Address, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
void *ret = nullptr;
|
||||
switch (AllocatorType)
|
||||
{
|
||||
case unlikely(MemoryAllocatorType::Pages):
|
||||
{
|
||||
ret = KernelAllocator.RequestPages(TO_PAGES(Size)); // WARNING: Potential memory leak
|
||||
memset(ret, 0, Size);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
ret = XallocV1Allocator->realloc(Address, Size);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
void *ret = PREFIX(realloc)(Address, Size);
|
||||
memset(ret, 0, Size);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
throw;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "realloc( %p %ld )=%p~%p\n\r",
|
||||
Address, Size,
|
||||
ret, __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HeapFree(void *Address)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("free(%#lx)->[%s]", Address, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
switch (AllocatorType)
|
||||
{
|
||||
case unlikely(MemoryAllocatorType::Pages):
|
||||
{
|
||||
KernelAllocator.FreePage(Address); // WARNING: Potential memory leak
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::XallocV1:
|
||||
{
|
||||
XallocV1Allocator->free(Address);
|
||||
break;
|
||||
}
|
||||
case MemoryAllocatorType::liballoc11:
|
||||
{
|
||||
PREFIX(free)
|
||||
(Address);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "free( %p )~%p\n\r",
|
||||
Address,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void *operator new(size_t Size)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("new(%d)->[%s]", Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
void *ret = HeapMalloc(Size);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "new( %ld )=%p~%p\n\r",
|
||||
Size,
|
||||
ret, __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *operator new[](size_t Size)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("new[](%d)->[%s]", Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
void *ret = HeapMalloc(Size);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "new[]( %ld )=%p~%p\n\r",
|
||||
Size,
|
||||
ret, __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *operator new(unsigned long Size, std::align_val_t Alignment)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("new(%d, %d)->[%s]", Size, Alignment, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
fixme("operator new with alignment(%#lx) is not implemented", Alignment);
|
||||
|
||||
void *ret = HeapMalloc(Size);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "new( %ld %#lx )=%p~%p\n\r",
|
||||
Size, (uintptr_t)Alignment,
|
||||
ret, __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void operator delete(void *Pointer)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("delete(%#lx)->[%s]", Pointer, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
HeapFree(Pointer);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "delete( %p )~%p\n\r",
|
||||
Pointer,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator delete[](void *Pointer)
|
||||
{
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("delete[](%#lx)->[%s]", Pointer, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
HeapFree(Pointer);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "delete[]( %p )~%p\n\r",
|
||||
Pointer,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator delete(void *Pointer, long unsigned int Size)
|
||||
{
|
||||
UNUSED(Size);
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("delete(%#lx, %d)->[%s]", Pointer, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
HeapFree(Pointer);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "delete( %p %ld )~%p\n\r",
|
||||
Pointer, Size,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator delete[](void *Pointer, long unsigned int Size)
|
||||
{
|
||||
UNUSED(Size);
|
||||
#ifdef DEBUG_ALLOCATIONS_SL
|
||||
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
|
||||
#endif
|
||||
memdbg("delete[](%#lx, %d)->[%s]", Pointer, Size, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown");
|
||||
|
||||
HeapFree(Pointer);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "delete[]( %p %ld )~%p\n\r",
|
||||
Pointer, Size,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
220
Kernel/Core/Memory/MemoryManager.cpp
Normal file
220
Kernel/Core/Memory/MemoryManager.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
ReadFSFunction(MEM_Read)
|
||||
{
|
||||
if (!Size)
|
||||
Size = node->Length;
|
||||
if (Offset > node->Length)
|
||||
return 0;
|
||||
if (Offset + Size > node->Length)
|
||||
Size = node->Length - Offset;
|
||||
memcpy(Buffer, (uint8_t *)(node->Address + Offset), Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
WriteFSFunction(MEM_Write)
|
||||
{
|
||||
if (!Size)
|
||||
Size = node->Length;
|
||||
if (Offset > node->Length)
|
||||
return 0;
|
||||
if (Offset + Size > node->Length)
|
||||
Size = node->Length - Offset;
|
||||
memcpy((uint8_t *)(node->Address + Offset), Buffer, Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
VirtualFileSystem::FileSystemOperations mem_op = {
|
||||
.Name = "mem",
|
||||
.Read = MEM_Read,
|
||||
.Write = MEM_Write,
|
||||
};
|
||||
|
||||
uint64_t MemMgr::GetAllocatedMemorySize()
|
||||
{
|
||||
uint64_t Size = 0;
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
Size += ap.PageCount;
|
||||
return FROM_PAGES(Size);
|
||||
}
|
||||
|
||||
bool MemMgr::Add(void *Address, size_t Count)
|
||||
{
|
||||
if (Address == nullptr)
|
||||
{
|
||||
error("Address is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
error("Count is 0!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
|
||||
{
|
||||
if (AllocatedPagesList[i].Address == Address)
|
||||
{
|
||||
error("Address already exists!");
|
||||
return false;
|
||||
}
|
||||
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
|
||||
{
|
||||
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
|
||||
{
|
||||
error("Address intersects with an allocated page!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address)
|
||||
{
|
||||
error("Address intersects with an allocated page!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
|
||||
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
|
||||
if (n)
|
||||
{
|
||||
n->Address = (uintptr_t)Address;
|
||||
n->Length = Count * PAGE_SIZE;
|
||||
n->Operator = &mem_op;
|
||||
}
|
||||
}
|
||||
|
||||
AllocatedPagesList.push_back({Address, Count});
|
||||
return true;
|
||||
}
|
||||
|
||||
void *MemMgr::RequestPages(size_t Count, bool User)
|
||||
{
|
||||
void *Address = KernelAllocator.RequestPages(Count);
|
||||
for (size_t i = 0; i < Count; i++)
|
||||
{
|
||||
int Flags = Memory::PTFlag::RW;
|
||||
if (User)
|
||||
Flags |= Memory::PTFlag::US;
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Flags);
|
||||
}
|
||||
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
|
||||
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
|
||||
if (n) // If null, error or file already exists
|
||||
{
|
||||
n->Address = (uintptr_t)Address;
|
||||
n->Length = Count * PAGE_SIZE;
|
||||
n->Operator = &mem_op;
|
||||
}
|
||||
}
|
||||
|
||||
AllocatedPagesList.push_back({Address, Count});
|
||||
|
||||
/* For security reasons, we clear the memory
|
||||
if the page is user accessible. */
|
||||
if (User)
|
||||
memset(Address, 0, Count * PAGE_SIZE);
|
||||
return Address;
|
||||
}
|
||||
|
||||
void MemMgr::FreePages(void *Address, size_t Count)
|
||||
{
|
||||
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
|
||||
if (AllocatedPagesList[i].Address == Address)
|
||||
{
|
||||
/** TODO: Advanced checks. Allow if the page count is less than the requested one.
|
||||
* This will allow the user to free only a part of the allocated pages.
|
||||
*
|
||||
* But this will be in a separate function because we need to specify if we
|
||||
* want to free from the start or from the end and return the new address.
|
||||
*/
|
||||
if (AllocatedPagesList[i].PageCount != Count)
|
||||
{
|
||||
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", AllocatedPagesList[i].PageCount, Count);
|
||||
return;
|
||||
}
|
||||
|
||||
KernelAllocator.FreePages(Address, Count);
|
||||
for (size_t i = 0; i < Count; i++)
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
|
||||
// Memory::Virtual(this->PageTable).Unmap((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
|
||||
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
|
||||
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
|
||||
if (s != VirtualFileSystem::FileStatus::OK)
|
||||
error("Failed to delete file %s", FileName);
|
||||
}
|
||||
|
||||
AllocatedPagesList.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MemMgr::DetachAddress(void *Address)
|
||||
{
|
||||
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
|
||||
if (AllocatedPagesList[i].Address == Address)
|
||||
{
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, AllocatedPagesList[i].PageCount);
|
||||
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
|
||||
if (s != VirtualFileSystem::FileStatus::OK)
|
||||
error("Failed to delete file %s", FileName);
|
||||
}
|
||||
|
||||
AllocatedPagesList.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MemMgr::MemMgr(PageTable4 *PageTable, VirtualFileSystem::Node *Directory)
|
||||
{
|
||||
if (PageTable)
|
||||
this->PageTable = PageTable;
|
||||
else
|
||||
#if defined(a64)
|
||||
this->PageTable = (PageTable4 *)CPU::x64::readcr3().raw;
|
||||
#elif defined(a32)
|
||||
this->PageTable = (PageTable4 *)CPU::x32::readcr3().raw;
|
||||
#endif
|
||||
|
||||
this->Directory = Directory;
|
||||
debug("+ %#lx", this);
|
||||
}
|
||||
|
||||
MemMgr::~MemMgr()
|
||||
{
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
{
|
||||
KernelAllocator.FreePages(ap.Address, ap.PageCount);
|
||||
for (size_t i = 0; i < ap.PageCount; i++)
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
|
||||
}
|
||||
|
||||
if (this->Directory)
|
||||
foreach (auto Child in this->Directory->Children)
|
||||
vfs->Delete(Child, true);
|
||||
|
||||
debug("- %#lx", this);
|
||||
}
|
||||
}
|
28
Kernel/Core/Memory/PageMapIndexer.cpp
Normal file
28
Kernel/Core/Memory/PageMapIndexer.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
Virtual::PageMapIndexer::PageMapIndexer(uintptr_t VirtualAddress)
|
||||
{
|
||||
#if defined(a64)
|
||||
uintptr_t Address = VirtualAddress;
|
||||
Address >>= 12;
|
||||
this->PTEIndex = Address & 0x1FF;
|
||||
Address >>= 9;
|
||||
this->PDEIndex = Address & 0x1FF;
|
||||
Address >>= 9;
|
||||
this->PDPTEIndex = Address & 0x1FF;
|
||||
Address >>= 9;
|
||||
this->PMLIndex = Address & 0x1FF;
|
||||
#elif defined(a32)
|
||||
uintptr_t Address = VirtualAddress;
|
||||
Address >>= 12;
|
||||
this->PTEIndex = Address & 0x3FF;
|
||||
Address >>= 10;
|
||||
this->PDEIndex = Address & 0x3FF;
|
||||
Address >>= 10;
|
||||
this->PDPTEIndex = Address & 0x3FF;
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
}
|
385
Kernel/Core/Memory/PhysicalMemoryManager.cpp
Normal file
385
Kernel/Core/Memory/PhysicalMemoryManager.cpp
Normal file
@ -0,0 +1,385 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
#include <debug.h>
|
||||
#ifdef DEBUG
|
||||
#include <uart.hpp>
|
||||
#endif
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
extern "C" char BootPageTable[]; // 0x10000 in length
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
uint64_t Physical::GetTotalMemory()
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
return this->TotalMemory;
|
||||
}
|
||||
|
||||
uint64_t Physical::GetFreeMemory()
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
return this->FreeMemory;
|
||||
}
|
||||
|
||||
uint64_t Physical::GetReservedMemory()
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
return this->ReservedMemory;
|
||||
}
|
||||
|
||||
uint64_t Physical::GetUsedMemory()
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
return this->UsedMemory;
|
||||
}
|
||||
|
||||
bool Physical::SwapPage(void *Address)
|
||||
{
|
||||
fixme("%p", Address);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Physical::SwapPages(void *Address, size_t PageCount)
|
||||
{
|
||||
for (size_t i = 0; i < PageCount; i++)
|
||||
if (!this->SwapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Physical::UnswapPage(void *Address)
|
||||
{
|
||||
fixme("%p", Address);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Physical::UnswapPages(void *Address, size_t PageCount)
|
||||
{
|
||||
for (size_t i = 0; i < PageCount; i++)
|
||||
if (!this->UnswapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void *Physical::RequestPage()
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
|
||||
{
|
||||
if (PageBitmap[PageBitmapIndex] == true)
|
||||
continue;
|
||||
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
|
||||
return (void *)(PageBitmapIndex * PAGE_SIZE);
|
||||
}
|
||||
|
||||
if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE)))
|
||||
{
|
||||
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "RequestPage( )=%p~%p\n\r",
|
||||
(void *)(PageBitmapIndex * PAGE_SIZE), __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return (void *)(PageBitmapIndex * PAGE_SIZE);
|
||||
}
|
||||
|
||||
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
|
||||
CPU::Stop();
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void *Physical::RequestPages(size_t Count)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
|
||||
{
|
||||
if (PageBitmap[PageBitmapIndex] == true)
|
||||
continue;
|
||||
|
||||
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
|
||||
{
|
||||
if (PageBitmap[Index] == true)
|
||||
continue;
|
||||
|
||||
for (size_t i = 0; i < Count; i++)
|
||||
if (PageBitmap[Index + i] == true)
|
||||
goto NextPage;
|
||||
|
||||
this->LockPages((void *)(Index * PAGE_SIZE), Count);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "RequestPages( %ld )=%p~%p\n\r",
|
||||
Count,
|
||||
(void *)(Index * PAGE_SIZE), __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return (void *)(Index * PAGE_SIZE);
|
||||
|
||||
NextPage:
|
||||
Index += Count;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count))
|
||||
{
|
||||
this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count);
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "RequestPages( %ld )=%p~%p\n\r",
|
||||
Count,
|
||||
(void *)(PageBitmapIndex * PAGE_SIZE), __builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
return (void *)(PageBitmapIndex * PAGE_SIZE);
|
||||
}
|
||||
|
||||
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
|
||||
CPU::Halt(true);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void Physical::FreePage(void *Address)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (unlikely(Address == nullptr))
|
||||
{
|
||||
warn("Null pointer passed to FreePage.");
|
||||
return;
|
||||
}
|
||||
size_t Index = (size_t)Address / PAGE_SIZE;
|
||||
if (unlikely(PageBitmap[Index] == false))
|
||||
return;
|
||||
|
||||
if (PageBitmap.Set(Index, false))
|
||||
{
|
||||
FreeMemory += PAGE_SIZE;
|
||||
UsedMemory -= PAGE_SIZE;
|
||||
if (PageBitmapIndex > Index)
|
||||
PageBitmapIndex = Index;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "FreePage( %p )~%p\n\r",
|
||||
Address,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Physical::FreePages(void *Address, size_t Count)
|
||||
{
|
||||
if (unlikely(Address == nullptr || Count == 0))
|
||||
{
|
||||
warn("%s%s%s passed to FreePages.", Address == nullptr ? "Null pointer " : "", Address == nullptr && Count == 0 ? "and " : "", Count == 0 ? "Zero count" : "");
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (EnableExternalMemoryTracer)
|
||||
{
|
||||
char LockTmpStr[64];
|
||||
strcpy_unsafe(LockTmpStr, __FUNCTION__);
|
||||
strcat_unsafe(LockTmpStr, "_memTrk");
|
||||
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
|
||||
sprintf(mExtTrkLog, "!FreePages( %p %ld )~%p\n\r",
|
||||
Address, Count,
|
||||
__builtin_return_address(0));
|
||||
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
|
||||
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
|
||||
{
|
||||
if (mExtTrkLog[i] == '\r')
|
||||
break;
|
||||
mTrkUART.Write(mExtTrkLog[i]);
|
||||
}
|
||||
mExtTrkLock.Unlock();
|
||||
}
|
||||
#endif
|
||||
for (size_t t = 0; t < Count; t++)
|
||||
this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
|
||||
}
|
||||
|
||||
void Physical::LockPage(void *Address)
|
||||
{
|
||||
if (unlikely(Address == nullptr))
|
||||
warn("Trying to lock null address.");
|
||||
|
||||
uintptr_t Index = (uintptr_t)Address / PAGE_SIZE;
|
||||
if (unlikely(PageBitmap[Index] == true))
|
||||
return;
|
||||
if (PageBitmap.Set(Index, true))
|
||||
{
|
||||
FreeMemory -= PAGE_SIZE;
|
||||
UsedMemory += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void Physical::LockPages(void *Address, size_t PageCount)
|
||||
{
|
||||
if (unlikely(Address == nullptr || PageCount == 0))
|
||||
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
|
||||
|
||||
for (size_t i = 0; i < PageCount; i++)
|
||||
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
|
||||
}
|
||||
|
||||
void Physical::ReservePage(void *Address)
|
||||
{
|
||||
if (unlikely(Address == nullptr))
|
||||
warn("Trying to reserve null address.");
|
||||
|
||||
uintptr_t Index = (uintptr_t)Address / PAGE_SIZE;
|
||||
if (unlikely(PageBitmap[Index] == true))
|
||||
return;
|
||||
|
||||
if (PageBitmap.Set(Index, true))
|
||||
{
|
||||
FreeMemory -= PAGE_SIZE;
|
||||
ReservedMemory += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void Physical::ReservePages(void *Address, size_t PageCount)
|
||||
{
|
||||
if (unlikely(Address == nullptr || PageCount == 0))
|
||||
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
|
||||
|
||||
for (size_t t = 0; t < PageCount; t++)
|
||||
this->ReservePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
|
||||
}
|
||||
|
||||
void Physical::UnreservePage(void *Address)
|
||||
{
|
||||
if (unlikely(Address == nullptr))
|
||||
warn("Trying to unreserve null address.");
|
||||
|
||||
uintptr_t Index = (uintptr_t)Address / PAGE_SIZE;
|
||||
if (unlikely(PageBitmap[Index] == false))
|
||||
return;
|
||||
|
||||
if (PageBitmap.Set(Index, false))
|
||||
{
|
||||
FreeMemory += PAGE_SIZE;
|
||||
ReservedMemory -= PAGE_SIZE;
|
||||
if (PageBitmapIndex > Index)
|
||||
PageBitmapIndex = Index;
|
||||
}
|
||||
}
|
||||
|
||||
void Physical::UnreservePages(void *Address, size_t PageCount)
|
||||
{
|
||||
if (unlikely(Address == nullptr || PageCount == 0))
|
||||
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
|
||||
|
||||
for (size_t t = 0; t < PageCount; t++)
|
||||
this->UnreservePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
|
||||
}
|
||||
|
||||
void Physical::Init(BootInfo *Info)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
void *LargestFreeMemorySegment = nullptr;
|
||||
uint64_t LargestFreeMemorySegmentSize = 0;
|
||||
uint64_t MemorySize = Info->Memory.Size;
|
||||
|
||||
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
|
||||
if (Info->Memory.Entry[i].Type == Usable)
|
||||
if (Info->Memory.Entry[i].Length > LargestFreeMemorySegmentSize)
|
||||
{
|
||||
// We don't want to use 0 as a memory address.
|
||||
if (Info->Memory.Entry[i].BaseAddress == nullptr)
|
||||
continue;
|
||||
LargestFreeMemorySegment = (void *)Info->Memory.Entry[i].BaseAddress;
|
||||
LargestFreeMemorySegmentSize = Info->Memory.Entry[i].Length;
|
||||
debug("Largest free memory segment: %llp (%lldMB)",
|
||||
(void *)Info->Memory.Entry[i].BaseAddress,
|
||||
TO_MB(Info->Memory.Entry[i].Length));
|
||||
}
|
||||
TotalMemory = MemorySize;
|
||||
FreeMemory = MemorySize;
|
||||
|
||||
if (LargestFreeMemorySegment == nullptr)
|
||||
{
|
||||
error("No free memory found!");
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
size_t BitmapSize = (MemorySize / PAGE_SIZE) / 8 + 1;
|
||||
trace("Initializing Bitmap at %llp-%llp (%lld Bytes)",
|
||||
LargestFreeMemorySegment,
|
||||
(void *)((uintptr_t)LargestFreeMemorySegment + BitmapSize),
|
||||
BitmapSize);
|
||||
PageBitmap.Size = BitmapSize;
|
||||
PageBitmap.Buffer = (uint8_t *)LargestFreeMemorySegment;
|
||||
for (size_t i = 0; i < BitmapSize; i++)
|
||||
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
|
||||
|
||||
trace("Reserving pages...");
|
||||
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
|
||||
if (Info->Memory.Entry[i].Type != Usable)
|
||||
this->ReservePages((void *)Info->Memory.Entry[i].BaseAddress, Info->Memory.Entry[i].Length / PAGE_SIZE + 1);
|
||||
|
||||
this->ReservePages(0, 0x100);
|
||||
this->ReservePages(BootPageTable, TO_PAGES(0x10000));
|
||||
trace("Locking bitmap pages...");
|
||||
this->LockPages(PageBitmap.Buffer, PageBitmap.Size / PAGE_SIZE + 1);
|
||||
}
|
||||
|
||||
Physical::Physical() {}
|
||||
Physical::~Physical() {}
|
||||
}
|
83
Kernel/Core/Memory/StackGuard.cpp
Normal file
83
Kernel/Core/Memory/StackGuard.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
StackGuard::StackGuard(bool User, PageTable4 *Table)
|
||||
{
|
||||
this->UserMode = User;
|
||||
this->Table = Table;
|
||||
if (this->UserMode)
|
||||
{
|
||||
void *AllocatedStack = KernelAllocator.RequestPages(TO_PAGES(USER_STACK_SIZE));
|
||||
debug("AllocatedStack: %p", AllocatedStack);
|
||||
memset(AllocatedStack, 0, USER_STACK_SIZE);
|
||||
for (size_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++)
|
||||
{
|
||||
Virtual(Table).Map((void *)(USER_STACK_BASE + (i * PAGE_SIZE)),
|
||||
(void *)((uintptr_t)AllocatedStack + (i * PAGE_SIZE)),
|
||||
PTFlag::RW | PTFlag::US);
|
||||
debug("Mapped %p to %p", (void *)(USER_STACK_BASE + (i * PAGE_SIZE)),
|
||||
(void *)((uintptr_t)AllocatedStack + (i * PAGE_SIZE)));
|
||||
}
|
||||
this->StackBottom = (void *)USER_STACK_BASE;
|
||||
this->StackTop = (void *)(USER_STACK_BASE + USER_STACK_SIZE);
|
||||
this->StackPhyiscalBottom = AllocatedStack;
|
||||
this->StackPhyiscalTop = (void *)((uintptr_t)AllocatedStack + USER_STACK_SIZE);
|
||||
this->Size = USER_STACK_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->StackBottom = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE));
|
||||
this->StackPhyiscalBottom = this->StackBottom;
|
||||
debug("StackBottom: %p", this->StackBottom);
|
||||
memset(this->StackBottom, 0, STACK_SIZE);
|
||||
this->StackTop = (void *)((uintptr_t)this->StackBottom + STACK_SIZE);
|
||||
this->StackPhyiscalTop = this->StackTop;
|
||||
this->Size = STACK_SIZE;
|
||||
}
|
||||
trace("Allocated stack at %p", this->StackBottom);
|
||||
}
|
||||
|
||||
StackGuard::~StackGuard()
|
||||
{
|
||||
fixme("Temporarily disabled stack guard deallocation");
|
||||
// KernelAllocator.FreePages(this->StackBottom, TO_PAGES(this->Size));
|
||||
// debug("Freed stack at %p", this->StackBottom);
|
||||
}
|
||||
|
||||
bool StackGuard::Expand(uintptr_t FaultAddress)
|
||||
{
|
||||
if (this->UserMode)
|
||||
{
|
||||
if (FaultAddress < (uintptr_t)this->StackBottom - USER_STACK_SIZE ||
|
||||
FaultAddress > (uintptr_t)this->StackTop)
|
||||
{
|
||||
return false; // It's not about the stack.
|
||||
}
|
||||
else
|
||||
{
|
||||
void *AllocatedStack = KernelAllocator.RequestPages(TO_PAGES(USER_STACK_SIZE));
|
||||
debug("AllocatedStack: %p", AllocatedStack);
|
||||
memset(AllocatedStack, 0, USER_STACK_SIZE);
|
||||
for (uintptr_t i = 0; i < TO_PAGES(USER_STACK_SIZE); i++)
|
||||
{
|
||||
Virtual(this->Table).Map((void *)((uintptr_t)this->StackBottom - (i * PAGE_SIZE)), (void *)((uintptr_t)AllocatedStack + (i * PAGE_SIZE)), PTFlag::RW | PTFlag::US);
|
||||
debug("Mapped %p to %p", (void *)((uintptr_t)this->StackBottom - (i * PAGE_SIZE)), (void *)((uintptr_t)AllocatedStack + (i * PAGE_SIZE)));
|
||||
}
|
||||
this->StackBottom = (void *)((uintptr_t)this->StackBottom - USER_STACK_SIZE);
|
||||
this->Size += USER_STACK_SIZE;
|
||||
info("Stack expanded to %p", this->StackBottom);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fixme("Not implemented and probably not needed");
|
||||
return false;
|
||||
}
|
||||
error("Reached end of function! How?");
|
||||
return false;
|
||||
}
|
||||
}
|
219
Kernel/Core/Memory/VirtualMemoryManager.cpp
Normal file
219
Kernel/Core/Memory/VirtualMemoryManager.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
bool Virtual::Check(void *VirtualAddress, PTFlag Flag)
|
||||
{
|
||||
// 0x1000 aligned
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex];
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
|
||||
PageDirectoryEntryPtr *PDE = nullptr;
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
if ((PML4.raw & Flag) > 0)
|
||||
{
|
||||
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
|
||||
if (PDPTE)
|
||||
if ((PDPTE->Entries[Index.PDPTEIndex].Present))
|
||||
{
|
||||
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
if (PDE)
|
||||
if ((PDE->Entries[Index.PDEIndex].Present))
|
||||
{
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
if (PTE)
|
||||
if ((PTE->Entries[Index.PTEIndex].Present))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (unlikely(!this->Table))
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
|
||||
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
|
||||
uint64_t DirectoryFlags = Flags & 0x3F;
|
||||
|
||||
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex];
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
|
||||
if (!PML4.Present)
|
||||
{
|
||||
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPage();
|
||||
memset(PDPTEPtr, 0, PAGE_SIZE);
|
||||
PML4.Present = true;
|
||||
PML4.SetAddress((uintptr_t)PDPTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
|
||||
PML4.raw |= DirectoryFlags;
|
||||
this->Table->Entries[Index.PMLIndex] = PML4;
|
||||
|
||||
PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
PageDirectoryEntryPtr *PDEPtr = nullptr;
|
||||
if (!PDPTE.Present)
|
||||
{
|
||||
PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPage();
|
||||
memset(PDEPtr, 0, PAGE_SIZE);
|
||||
PDPTE.Present = true;
|
||||
PDPTE.SetAddress((uintptr_t)PDEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.GetAddress() << 12);
|
||||
PDPTE.raw |= DirectoryFlags;
|
||||
PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE;
|
||||
|
||||
PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex];
|
||||
PageTableEntryPtr *PTEPtr = nullptr;
|
||||
if (!PDE.Present)
|
||||
{
|
||||
PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPage();
|
||||
memset(PTEPtr, 0, PAGE_SIZE);
|
||||
PDE.Present = true;
|
||||
PDE.SetAddress((uintptr_t)PTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12);
|
||||
PDE.raw |= DirectoryFlags;
|
||||
PDEPtr->Entries[Index.PDEIndex] = PDE;
|
||||
|
||||
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
|
||||
PTE.Present = true;
|
||||
PTE.raw |= Flags;
|
||||
PTE.SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
PTEPtr->Entries[Index.PTEIndex] = PTE;
|
||||
|
||||
#if defined(a64)
|
||||
CPU::x64::invlpg(VirtualAddress);
|
||||
#elif defined(a32)
|
||||
CPU::x32::invlpg(VirtualAddress);
|
||||
#elif defined(aa64)
|
||||
asmv("dsb sy");
|
||||
asmv("tlbi vae1is, %0"
|
||||
:
|
||||
: "r"(VirtualAddress)
|
||||
: "memory");
|
||||
asmv("dsb sy");
|
||||
asmv("isb");
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
/* https://stackoverflow.com/a/3208376/9352057 */
|
||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||
#define BYTE_TO_BINARY(byte) \
|
||||
(byte & 0x80 ? '1' : '0'), \
|
||||
(byte & 0x40 ? '1' : '0'), \
|
||||
(byte & 0x20 ? '1' : '0'), \
|
||||
(byte & 0x10 ? '1' : '0'), \
|
||||
(byte & 0x08 ? '1' : '0'), \
|
||||
(byte & 0x04 ? '1' : '0'), \
|
||||
(byte & 0x02 ? '1' : '0'), \
|
||||
(byte & 0x01 ? '1' : '0')
|
||||
|
||||
if (!this->Check(VirtualAddress, (PTFlag)Flags)) // quick workaround just to see where it fails
|
||||
warn("Failed to map %#lx - %#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, size_t PageCount, uint64_t Flags)
|
||||
{
|
||||
for (size_t i = 0; i < PageCount; i++)
|
||||
this->Map((void *)((uintptr_t)VirtualAddress + (i * PAGE_SIZE)), (void *)((uintptr_t)PhysicalAddress + (i * PAGE_SIZE)), Flags);
|
||||
}
|
||||
|
||||
void Virtual::Unmap(void *VirtualAddress)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (!this->Table)
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
|
||||
PageMapLevel4 PML4 = this->Table->Entries[Index.PMLIndex];
|
||||
if (!PML4.Present)
|
||||
{
|
||||
error("Page not present");
|
||||
return;
|
||||
}
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.Address << 12);
|
||||
PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (!PDPTE.Present)
|
||||
{
|
||||
error("Page not present");
|
||||
return;
|
||||
}
|
||||
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.Address << 12);
|
||||
PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex];
|
||||
if (!PDE.Present)
|
||||
{
|
||||
error("Page not present");
|
||||
return;
|
||||
}
|
||||
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.Address << 12);
|
||||
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
|
||||
if (!PTE.Present)
|
||||
{
|
||||
error("Page not present");
|
||||
return;
|
||||
}
|
||||
|
||||
PTE.Present = false;
|
||||
PTEPtr->Entries[Index.PTEIndex] = PTE;
|
||||
|
||||
#if defined(a64)
|
||||
CPU::x64::invlpg(VirtualAddress);
|
||||
#elif defined(a32)
|
||||
CPU::x32::invlpg(VirtualAddress);
|
||||
#elif defined(aa64)
|
||||
asmv("dsb sy");
|
||||
asmv("tlbi vae1is, %0"
|
||||
:
|
||||
: "r"(VirtualAddress)
|
||||
: "memory");
|
||||
asmv("dsb sy");
|
||||
asmv("isb");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Virtual::Unmap(void *VirtualAddress, size_t PageCount)
|
||||
{
|
||||
for (size_t i = 0; i < PageCount; i++)
|
||||
this->Unmap((void *)((uintptr_t)VirtualAddress + (i * PAGE_SIZE)));
|
||||
}
|
||||
|
||||
void Virtual::Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
|
||||
{
|
||||
this->Unmap(VirtualAddress);
|
||||
this->Map(VirtualAddress, PhysicalAddress, Flags);
|
||||
}
|
||||
|
||||
Virtual::Virtual(PageTable4 *Table)
|
||||
{
|
||||
if (Table)
|
||||
this->Table = Table;
|
||||
else
|
||||
this->Table = (PageTable4 *)CPU::PageTable();
|
||||
}
|
||||
|
||||
Virtual::~Virtual() {}
|
||||
}
|
861
Kernel/Core/PeripheralComponentInterconnect.cpp
Normal file
861
Kernel/Core/PeripheralComponentInterconnect.cpp
Normal file
@ -0,0 +1,861 @@
|
||||
#include <pci.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <power.hpp>
|
||||
#if defined(a64)
|
||||
#include "../Architecture/amd64/acpi.hpp"
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace PCI
|
||||
{
|
||||
namespace Descriptors
|
||||
{
|
||||
const char *u8ToHexString(uint8_t Value)
|
||||
{
|
||||
static char Buffer[3];
|
||||
memset(Buffer, 0, 3);
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
uint8_t Digit = (Value >> (4 - (i * 4))) & 0xF;
|
||||
if (Digit < 10)
|
||||
Buffer[i] = '0' + Digit;
|
||||
else
|
||||
Buffer[i] = 'A' + (Digit - 10);
|
||||
}
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
const char *u32ToHexString(uint32_t Value)
|
||||
{
|
||||
static char Buffer[9];
|
||||
memset(Buffer, 0, 9);
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
{
|
||||
uint8_t Digit = (Value >> (28 - (i * 4))) & 0xF;
|
||||
if (Digit < 10)
|
||||
Buffer[i] = '0' + Digit;
|
||||
else
|
||||
Buffer[i] = 'A' + (Digit - 10);
|
||||
}
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
const char *MassStorageControllerSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "SCSI Bus Controller";
|
||||
case 0x01:
|
||||
return "IDE Controller";
|
||||
case 0x02:
|
||||
return "Floppy Disk Controller";
|
||||
case 0x03:
|
||||
return "IPI Bus Controller";
|
||||
case 0x04:
|
||||
return "RAID Controller";
|
||||
case 0x05:
|
||||
return "ATA Controller";
|
||||
case 0x06:
|
||||
return "Serial ATA";
|
||||
case 0x07:
|
||||
return "Serial Attached SCSI Controller";
|
||||
case 0x08:
|
||||
return "Non-Volatile Memory Controller";
|
||||
case 0x80:
|
||||
return "Mass Storage Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown mass storage controller %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *NetworkControllerSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "Ethernet Controller";
|
||||
case 0x01:
|
||||
return "Token Ring Controller";
|
||||
case 0x02:
|
||||
return "FDDI Controller";
|
||||
case 0x03:
|
||||
return "ATM Controller";
|
||||
case 0x04:
|
||||
return "ISDN Controller";
|
||||
case 0x05:
|
||||
return "WorldFip Controller";
|
||||
case 0x06:
|
||||
return "PICMG HyperCard Controller";
|
||||
case 0x07:
|
||||
return "Infiniband Controller";
|
||||
case 0x08:
|
||||
return "Fabric Controller";
|
||||
case 0x80:
|
||||
return "Network Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown network controller %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *DisplayControllerSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "VGA Compatible Controller";
|
||||
case 0x01:
|
||||
return "XGA Controller";
|
||||
case 0x02:
|
||||
return "3D Controller";
|
||||
case 0x80:
|
||||
return "Display Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown display controller %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *CommunicationControllerSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "Serial Controller";
|
||||
case 0x01:
|
||||
return "Parallel Controller";
|
||||
case 0x02:
|
||||
return "Multi-Serial Controller";
|
||||
case 0x03:
|
||||
return "IEEE-1284 Controller";
|
||||
case 0x04:
|
||||
return "ATM Controller";
|
||||
case 0x05:
|
||||
return "Object Storage Controller";
|
||||
case 0x80:
|
||||
return "Communication controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown communication controller %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *BaseSystemPeripheralSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
// not sure if it's right
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "Unclassified";
|
||||
case 0x01:
|
||||
return "Keyboard";
|
||||
case 0x02:
|
||||
return "Pointing Device";
|
||||
case 0x03:
|
||||
return "Mouse";
|
||||
case 0x04:
|
||||
return "Scanner";
|
||||
case 0x05:
|
||||
return "Gameport";
|
||||
case 0x80:
|
||||
return "Unclassified";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown base system peripheral %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *SerialBusControllerSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "FireWire (IEEE 1394) Controller";
|
||||
case 0x01:
|
||||
return "ACCESS Bus Controller";
|
||||
case 0x02:
|
||||
return "SSA Controller";
|
||||
case 0x03:
|
||||
return "USB Controller";
|
||||
case 0x04:
|
||||
return "Fibre Channel Controller";
|
||||
case 0x05:
|
||||
return "SMBus Controller";
|
||||
case 0x06:
|
||||
return "Infiniband Controller";
|
||||
case 0x07:
|
||||
return "IPMI Interface Controller";
|
||||
case 0x08:
|
||||
return "SERCOS Interface (IEC 61491) Controller";
|
||||
case 0x09:
|
||||
return "CANbus Controller";
|
||||
case 0x80:
|
||||
return "Serial Bus Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown serial bus controller %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *BridgeDeviceSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "Host Bridge";
|
||||
case 0x01:
|
||||
return "ISA Bridge";
|
||||
case 0x02:
|
||||
return "EISA Bridge";
|
||||
case 0x03:
|
||||
return "MCA Bridge";
|
||||
case 0x04:
|
||||
return "PCI-to-PCI Bridge";
|
||||
case 0x05:
|
||||
return "PCMCIA Bridge";
|
||||
case 0x06:
|
||||
return "NuBus Bridge";
|
||||
case 0x07:
|
||||
return "CardBus Bridge";
|
||||
case 0x08:
|
||||
return "RACEway Bridge";
|
||||
case 0x09:
|
||||
return "PCI-to-PCI Bridge";
|
||||
case 0x0A:
|
||||
return "InfiniBand-to-PCI Host Bridge";
|
||||
case 0x80:
|
||||
return "Bridge Device";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown bridge device %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *WirelessControllerSubclassName(uint8_t SubclassCode)
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x11:
|
||||
return "Bluetooth";
|
||||
case 0x20:
|
||||
return "802.1a controller";
|
||||
case 0x21:
|
||||
return "802.1b controller";
|
||||
case 0x80:
|
||||
return "Wireless controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown wireless controller %02x", SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *GetVendorName(uint32_t VendorID)
|
||||
{
|
||||
switch (VendorID)
|
||||
{
|
||||
case 0x1000:
|
||||
return "Symbios Logic";
|
||||
case 0x1B36:
|
||||
case 0x1AF4:
|
||||
return "Red Hat, Inc.";
|
||||
case 0x10EC:
|
||||
return "Realtek Semiconductor Co., Ltd.";
|
||||
case 0x80EE:
|
||||
return "VirtualBox";
|
||||
case 0x1274:
|
||||
return "Ensoniq";
|
||||
case 0x1234:
|
||||
return "QEMU";
|
||||
case 0x15AD:
|
||||
return "VMware";
|
||||
case 0x8086:
|
||||
return "Intel Corporation";
|
||||
case 0x1022:
|
||||
return "Advanced Micro Devices, Inc.";
|
||||
case 0x10DE:
|
||||
return "NVIDIA Corporation";
|
||||
case 0x1AE0:
|
||||
return "Google, Inc.";
|
||||
case 0x1a58:
|
||||
return "Razer USA Ltd.";
|
||||
case 0x1414:
|
||||
return "Microsoft Corporation";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown vendor %04x", VendorID);
|
||||
return u32ToHexString(VendorID);
|
||||
}
|
||||
|
||||
const char *GetDeviceName(uint32_t VendorID, uint32_t DeviceID)
|
||||
{
|
||||
switch (VendorID)
|
||||
{
|
||||
case SymbiosLogic:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x30:
|
||||
return "53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI";
|
||||
case 0x1000:
|
||||
return "63C815";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RedHat:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x1000:
|
||||
case 0x1041:
|
||||
return "Virtio network device";
|
||||
case 0x1001:
|
||||
case 0x1042:
|
||||
return "Virtio block device";
|
||||
case 0x1002:
|
||||
case 0x1045:
|
||||
return "Virtio memory balloon";
|
||||
case 0x1003:
|
||||
case 0x1043:
|
||||
return "Virtio console";
|
||||
case 0x1004:
|
||||
case 0x1048:
|
||||
return "Virtio SCSI";
|
||||
case 0x1005:
|
||||
case 0x1044:
|
||||
return "Virtio RNG";
|
||||
case 0x1009:
|
||||
case 0x1049:
|
||||
case 0x105a:
|
||||
return "Virtio filesystem";
|
||||
case 0x1050:
|
||||
return "Virtio GPU";
|
||||
case 0x1052:
|
||||
return "Virtio input";
|
||||
case 0x1053:
|
||||
return "Virtio socket";
|
||||
case 1110:
|
||||
return "Inter-VM shared memory";
|
||||
case 0x1af41100:
|
||||
return "QEMU Virtual Machine";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REDHat2:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x0001:
|
||||
return "QEMU PCI-PCI bridge";
|
||||
case 0x0002:
|
||||
return "QEMU PCI 16550A Adapter";
|
||||
case 0x0003:
|
||||
return "QEMU PCI Dual-port 16550A Adapter";
|
||||
case 0x0004:
|
||||
return "QEMU PCI Quad-port 16550A Adapter";
|
||||
case 0x0005:
|
||||
return "QEMU PCI Test Device";
|
||||
case 0x0006:
|
||||
return "PCI Rocker Ethernet switch device";
|
||||
case 0x0007:
|
||||
return "PCI SD Card Host Controller Interface";
|
||||
case 0x0008:
|
||||
return "QEMU PCIe Host bridge";
|
||||
case 0x0009:
|
||||
return "QEMU PCI Expander bridge";
|
||||
case 0x000A:
|
||||
return "PCI-PCI bridge (multiseat)";
|
||||
case 0x000B:
|
||||
return "QEMU PCIe Expander bridge";
|
||||
case 0x000C:
|
||||
return "QEMU PCIe Root Port";
|
||||
case 0x000D:
|
||||
return "QEMU XHCI Host Controller";
|
||||
case 0x0010:
|
||||
return "QEMU NVM Express Controller";
|
||||
case 0x0100:
|
||||
return "QXL Paravirtual Graphic Card";
|
||||
case 0x1AF41100:
|
||||
return "QEMU Virtual Machine";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Realtek:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x8029:
|
||||
return "RTL-8029(AS)";
|
||||
case 0x8139:
|
||||
return "RTL-8139/8139C/8139C+ Ethernet Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VirtualBox:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0xCAFE:
|
||||
return "VirtualBox Guest Service";
|
||||
case 0xBEEF:
|
||||
return "VirtualBox Graphics Adapter";
|
||||
case 0x0021:
|
||||
return "USB Tablet";
|
||||
case 0x0022:
|
||||
return "Multitouch tablet";
|
||||
case 0x4E56:
|
||||
return "NVM Express";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Ensoniq:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x1371:
|
||||
return "ES1371/ES1373 / Creative Labs CT2518";
|
||||
case 0x5000:
|
||||
return "ES1370 [AudioPCI]";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEMU:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x1111:
|
||||
return "QEMU Display";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VMware:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x0740:
|
||||
return "Virtual Machine Communication Interface";
|
||||
case 0x0405:
|
||||
return "SVGA II Adapter";
|
||||
case 0x0790:
|
||||
return "PCI bridge";
|
||||
case 0x07A0:
|
||||
return "PCI Express Root Port";
|
||||
case 0x0774:
|
||||
return "USB1.1 UHCI Controller";
|
||||
case 0x0770:
|
||||
return "USB2 EHCI Controller";
|
||||
case 0x0779:
|
||||
return "USB3 xHCI 1.0 Controller";
|
||||
case 0x07E0:
|
||||
return "SATA AHCI controller";
|
||||
case 0x07F0:
|
||||
return "NVM Express";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IntelCorporation:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x1229:
|
||||
return "82557/8/9/0/1 Ethernet Pro 100";
|
||||
case 0x1209:
|
||||
return "8255xER/82551IT Fast Ethernet Controller";
|
||||
case 0x100E:
|
||||
return "82540EM Gigabit Ethernet Controller";
|
||||
case 0x7190:
|
||||
return "440BX/ZX/DX - 82443BX/ZX/DX Host bridge";
|
||||
case 0x7191:
|
||||
return "440BX/ZX/DX - 82443BX/ZX/DX AGP bridge";
|
||||
case 0x7110:
|
||||
return "82371AB/EB/MB PIIX4 ISA";
|
||||
case 0x7111:
|
||||
return "82371AB/EB/MB PIIX4 IDE";
|
||||
case 0x7113:
|
||||
return "82371AB/EB/MB PIIX4 ACPI";
|
||||
case 0x1e31:
|
||||
return "7 Series/C210 Series Chipset Family USB xHCI Host Controller";
|
||||
case 0x100F:
|
||||
return "82545EM Gigabit Ethernet Controller (Copper)";
|
||||
case 0x1371:
|
||||
return "ES1371/ES1373 / Creative Labs CT2518";
|
||||
case 0x27b9:
|
||||
return "82801GBM (ICH7-M) LPC Interface Bridge";
|
||||
case 0x07E0:
|
||||
return "SATA AHCI controller";
|
||||
case 0x293E:
|
||||
return "82801I (ICH9 Family) HD Audio Controller";
|
||||
case 0x2935:
|
||||
return "82801I (ICH9 Family) USB UHCI Controller #2";
|
||||
case 0x2936:
|
||||
return "82801I (ICH9 Family) USB UHCI Controller #3";
|
||||
case 0x293A:
|
||||
return "82801I (ICH9 Family) USB2 EHCI Controller #1";
|
||||
case 0x2934:
|
||||
return "82801I (ICH9 Family) USB UHCI Controller #1";
|
||||
case 0x2668:
|
||||
return "82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller";
|
||||
case 0x2415:
|
||||
return "82801AA AC'97 Audio Controller";
|
||||
case 0x10D3:
|
||||
return "82574L Gigabit Network Connection";
|
||||
case 0x29C0:
|
||||
return "82G33/G31/P35/P31 Express DRAM Controller";
|
||||
case 0x2918:
|
||||
return "82801IB (ICH9) LPC Interface Controller";
|
||||
case 0x2829:
|
||||
return "82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode]";
|
||||
case 0x2922:
|
||||
return "82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]";
|
||||
case 0x2930:
|
||||
return "82801I (ICH9 Family) SMBus Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AdvancedMicroDevices:
|
||||
{
|
||||
switch (DeviceID)
|
||||
{
|
||||
case 0x2000:
|
||||
return "79C970 [PCnet32 LANCE]";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fixme("Unknown device %04x:%04x", VendorID, DeviceID);
|
||||
return u32ToHexString(DeviceID);
|
||||
}
|
||||
|
||||
const char *GetSubclassName(uint8_t ClassCode, uint8_t SubclassCode)
|
||||
{
|
||||
switch (ClassCode)
|
||||
{
|
||||
case 0x00:
|
||||
return "Unclassified";
|
||||
case 0x01:
|
||||
return MassStorageControllerSubclassName(SubclassCode);
|
||||
case 0x02:
|
||||
return NetworkControllerSubclassName(SubclassCode);
|
||||
case 0x03:
|
||||
return DisplayControllerSubclassName(SubclassCode);
|
||||
case 0x04:
|
||||
return "Multimedia controller";
|
||||
case 0x05:
|
||||
return "Memory Controller";
|
||||
case 0x06:
|
||||
return BridgeDeviceSubclassName(SubclassCode);
|
||||
case 0x07:
|
||||
return CommunicationControllerSubclassName(SubclassCode);
|
||||
case 0x08:
|
||||
return BaseSystemPeripheralSubclassName(SubclassCode);
|
||||
case 0x09:
|
||||
return "Input device controller";
|
||||
case 0x0A:
|
||||
return "Docking station";
|
||||
case 0x0B:
|
||||
return "Processor";
|
||||
case 0x0C:
|
||||
return SerialBusControllerSubclassName(SubclassCode);
|
||||
case 0x0D:
|
||||
return WirelessControllerSubclassName(SubclassCode);
|
||||
case 0x0E:
|
||||
return "Intelligent controller";
|
||||
case 0x0F:
|
||||
return "Satellite communication controller";
|
||||
case 0x10:
|
||||
return "Encryption controller";
|
||||
case 0x11:
|
||||
return "Signal processing accelerators";
|
||||
case 0x12:
|
||||
return "Processing accelerators";
|
||||
case 0x13:
|
||||
return "Non-Essential Instrumentation";
|
||||
case 0x40:
|
||||
return "Coprocessor";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fixme("Unknown subclass name %02x:%02x", ClassCode, SubclassCode);
|
||||
return u8ToHexString(SubclassCode);
|
||||
}
|
||||
|
||||
const char *GetProgIFName(uint8_t ClassCode, uint8_t SubclassCode, uint8_t ProgIF)
|
||||
{
|
||||
switch (ClassCode)
|
||||
{
|
||||
case 0x01:
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x06:
|
||||
{
|
||||
switch (ProgIF)
|
||||
{
|
||||
case 0:
|
||||
return "Vendor Specific SATA Controller";
|
||||
case 1:
|
||||
return "AHCI SATA Controller";
|
||||
case 2:
|
||||
return "Serial Storage Bus SATA Controller";
|
||||
default:
|
||||
return "SATA controller";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x08:
|
||||
{
|
||||
switch (ProgIF)
|
||||
{
|
||||
case 0x01:
|
||||
return "NVMHCI Controller";
|
||||
case 0x02:
|
||||
return "NVM Express Controller";
|
||||
default:
|
||||
return "Non-Volatile Memory Controller";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x03:
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
switch (ProgIF)
|
||||
{
|
||||
case 0x00:
|
||||
return "VGA Controller";
|
||||
case 0x01:
|
||||
return "8514-Compatible Controller";
|
||||
default:
|
||||
return "VGA Compatible Controller";
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x07:
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
switch (ProgIF)
|
||||
{
|
||||
case 0x00:
|
||||
return "Serial controller <8250>";
|
||||
case 0x01:
|
||||
return "Serial controller <16450>";
|
||||
case 0x02:
|
||||
return "Serial controller <16550>";
|
||||
case 0x03:
|
||||
return "Serial controller <16650>";
|
||||
case 0x04:
|
||||
return "Serial controller <16750>";
|
||||
case 0x05:
|
||||
return "Serial controller <16850>";
|
||||
case 0x06:
|
||||
return "Serial controller <16950";
|
||||
default:
|
||||
return "Serial controller";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0C:
|
||||
{
|
||||
switch (SubclassCode)
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
switch (ProgIF)
|
||||
{
|
||||
case 0x00:
|
||||
return "Generic FireWire (IEEE 1394) Controller";
|
||||
case 0x10:
|
||||
return "OHCI FireWire (IEEE 1394) Controller";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x03:
|
||||
{
|
||||
switch (ProgIF)
|
||||
{
|
||||
case 0x00:
|
||||
return "UHCI (USB1) Controller";
|
||||
case 0x10:
|
||||
return "OHCI (USB1) Controller";
|
||||
case 0x20:
|
||||
return "EHCI (USB2) Controller";
|
||||
case 0x30:
|
||||
return "XHCI (USB3) Controller";
|
||||
case 0x80:
|
||||
return "Unspecified";
|
||||
case 0xFE:
|
||||
return "USB Device";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// not really a fixme
|
||||
// fixme("Unknown prog IF name %02x:%02x:%02x", ClassCode, SubclassCode, ProgIF);
|
||||
return u8ToHexString(ProgIF);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void e(PCIDeviceHeader *hdr)
|
||||
{
|
||||
debug("%#x:%#x\t\t%s / %s / %s / %s / %s",
|
||||
hdr->VendorID, hdr->DeviceID,
|
||||
Descriptors::GetVendorName(hdr->VendorID),
|
||||
Descriptors::GetDeviceName(hdr->VendorID, hdr->DeviceID),
|
||||
Descriptors::DeviceClasses[hdr->Class],
|
||||
Descriptors::GetSubclassName(hdr->Class, hdr->Subclass),
|
||||
Descriptors::GetProgIFName(hdr->Class, hdr->Subclass, hdr->ProgIF));
|
||||
}
|
||||
#endif
|
||||
|
||||
void PCI::EnumerateFunction(uintptr_t DeviceAddress, uint64_t Function)
|
||||
{
|
||||
uintptr_t Offset = Function << 12;
|
||||
uintptr_t FunctionAddress = DeviceAddress + Offset;
|
||||
Memory::Virtual().Map((void *)FunctionAddress, (void *)FunctionAddress, Memory::PTFlag::RW);
|
||||
PCIDeviceHeader *PCIDeviceHdr = (PCIDeviceHeader *)FunctionAddress;
|
||||
if (PCIDeviceHdr->DeviceID == 0)
|
||||
return;
|
||||
if (PCIDeviceHdr->DeviceID == 0xFFFF)
|
||||
return;
|
||||
Devices.push_back(PCIDeviceHdr);
|
||||
#ifdef DEBUG
|
||||
e(PCIDeviceHdr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PCI::EnumerateDevice(uintptr_t BusAddress, uint64_t Device)
|
||||
{
|
||||
uintptr_t Offset = Device << 15;
|
||||
uintptr_t DeviceAddress = BusAddress + Offset;
|
||||
Memory::Virtual().Map((void *)DeviceAddress, (void *)DeviceAddress, Memory::PTFlag::RW);
|
||||
PCIDeviceHeader *PCIDeviceHdr = (PCIDeviceHeader *)DeviceAddress;
|
||||
if (PCIDeviceHdr->DeviceID == 0)
|
||||
return;
|
||||
if (PCIDeviceHdr->DeviceID == 0xFFFF)
|
||||
return;
|
||||
for (uintptr_t Function = 0; Function < 8; Function++)
|
||||
EnumerateFunction(DeviceAddress, Function);
|
||||
}
|
||||
|
||||
void PCI::EnumerateBus(uintptr_t BaseAddress, uint64_t Bus)
|
||||
{
|
||||
uintptr_t Offset = Bus << 20;
|
||||
uintptr_t BusAddress = BaseAddress + Offset;
|
||||
Memory::Virtual().Map((void *)BusAddress, (void *)BusAddress, Memory::PTFlag::RW);
|
||||
PCIDeviceHeader *PCIDeviceHdr = (PCIDeviceHeader *)BusAddress;
|
||||
if (Bus != 0) // TODO: VirtualBox workaround (UNTESTED ON REAL HARDWARE!)
|
||||
{
|
||||
if (PCIDeviceHdr->DeviceID == 0)
|
||||
return;
|
||||
if (PCIDeviceHdr->DeviceID == 0xFFFF)
|
||||
return;
|
||||
}
|
||||
debug("PCI Bus DeviceID:%#llx VendorID:%#llx BIST:%#llx Cache:%#llx Class:%#llx Cmd:%#llx HdrType:%#llx LatencyTimer:%#llx ProgIF:%#llx RevID:%#llx Status:%#llx SubClass:%#llx ",
|
||||
PCIDeviceHdr->DeviceID, PCIDeviceHdr->VendorID, PCIDeviceHdr->BIST,
|
||||
PCIDeviceHdr->CacheLineSize, PCIDeviceHdr->Class, PCIDeviceHdr->Command,
|
||||
PCIDeviceHdr->HeaderType, PCIDeviceHdr->LatencyTimer, PCIDeviceHdr->ProgIF,
|
||||
PCIDeviceHdr->RevisionID, PCIDeviceHdr->Status, PCIDeviceHdr->Subclass);
|
||||
for (uintptr_t Device = 0; Device < 32; Device++)
|
||||
EnumerateDevice(BusAddress, Device);
|
||||
}
|
||||
|
||||
Vector<PCIDeviceHeader *> PCI::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF)
|
||||
{
|
||||
Vector<PCIDeviceHeader *> DeviceFound;
|
||||
for (auto var : Devices)
|
||||
if (var->Class == Class && var->Subclass == Subclass && var->ProgIF == ProgIF)
|
||||
DeviceFound.push_back(var);
|
||||
return DeviceFound;
|
||||
}
|
||||
|
||||
Vector<PCIDeviceHeader *> PCI::FindPCIDevice(int VendorID, int DeviceID)
|
||||
{
|
||||
Vector<PCIDeviceHeader *> DeviceFound;
|
||||
for (auto var : Devices)
|
||||
if (var->VendorID == VendorID && var->DeviceID == DeviceID)
|
||||
DeviceFound.push_back(var);
|
||||
return DeviceFound;
|
||||
}
|
||||
|
||||
PCI::PCI()
|
||||
{
|
||||
#if defined(a64)
|
||||
int Entries = ((((ACPI::ACPI *)PowerManager->GetACPI())->MCFG->Header.Length) - sizeof(ACPI::ACPI::MCFGHeader)) / sizeof(DeviceConfig);
|
||||
for (int t = 0; t < Entries; t++)
|
||||
{
|
||||
DeviceConfig *NewDeviceConfig = (DeviceConfig *)((uintptr_t)((ACPI::ACPI *)PowerManager->GetACPI())->MCFG + sizeof(ACPI::ACPI::MCFGHeader) + (sizeof(DeviceConfig) * t));
|
||||
Memory::Virtual().Map((void *)NewDeviceConfig->BaseAddress, (void *)NewDeviceConfig->BaseAddress, Memory::PTFlag::RW);
|
||||
debug("PCI Entry %d Address:%#llx BUS:%#llx-%#llx", t, NewDeviceConfig->BaseAddress,
|
||||
NewDeviceConfig->StartBus, NewDeviceConfig->EndBus);
|
||||
for (uintptr_t Bus = NewDeviceConfig->StartBus; Bus < NewDeviceConfig->EndBus; Bus++)
|
||||
EnumerateBus(NewDeviceConfig->BaseAddress, Bus);
|
||||
}
|
||||
#elif defined(a32)
|
||||
error("PCI not implemented on i386");
|
||||
#elif defined(aa64)
|
||||
error("PCI not implemented on aarch64");
|
||||
#endif
|
||||
}
|
||||
|
||||
PCI::~PCI()
|
||||
{
|
||||
}
|
||||
}
|
126
Kernel/Core/Power.cpp
Normal file
126
Kernel/Core/Power.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include <power.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
#if defined(a64)
|
||||
#include <io.h>
|
||||
|
||||
#include "../Architecture/amd64/acpi.hpp"
|
||||
|
||||
namespace Power
|
||||
{
|
||||
void Power::Reboot()
|
||||
{
|
||||
BeforeShutdown();
|
||||
|
||||
if (((ACPI::ACPI *)this->acpi)->FADT)
|
||||
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
|
||||
((ACPI::DSDT *)this->dsdt)->Reboot();
|
||||
|
||||
uint8_t val = 0x02;
|
||||
while (val & 0x02)
|
||||
val = inb(0x64);
|
||||
outb(0x64, 0xFE);
|
||||
|
||||
warn("Executing the second attempt to reboot...");
|
||||
|
||||
// second attempt to reboot
|
||||
// https://wiki.osdev.org/Reboot
|
||||
uint8_t temp;
|
||||
asmv("cli");
|
||||
do
|
||||
{
|
||||
temp = inb(0x64);
|
||||
if (((temp) & (1 << (0))) != 0)
|
||||
inb(0x60);
|
||||
} while (((temp) & (1 << (1))) != 0);
|
||||
outb(0x64, 0xFE);
|
||||
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
void Power::Shutdown()
|
||||
{
|
||||
BeforeShutdown();
|
||||
|
||||
if (((ACPI::ACPI *)this->acpi)->FADT)
|
||||
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
|
||||
((ACPI::DSDT *)this->dsdt)->Shutdown();
|
||||
|
||||
outl(0xB004, 0x2000); // for qemu
|
||||
outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu
|
||||
outl(0x4004, 0x3400); // virtual box
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
void Power::InitDSDT()
|
||||
{
|
||||
if (((ACPI::ACPI *)this->acpi)->FADT)
|
||||
this->dsdt = new ACPI::DSDT((ACPI::ACPI *)acpi);
|
||||
}
|
||||
|
||||
Power::Power()
|
||||
{
|
||||
this->acpi = new ACPI::ACPI(bInfo);
|
||||
this->madt = new ACPI::MADT(((ACPI::ACPI *)acpi)->MADT);
|
||||
trace("Power manager initialized");
|
||||
}
|
||||
|
||||
Power::~Power()
|
||||
{
|
||||
debug("Destructor called");
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(a32)
|
||||
|
||||
namespace Power
|
||||
{
|
||||
void Power::Reboot()
|
||||
{
|
||||
warn("Reboot not implemented for i386");
|
||||
}
|
||||
|
||||
void Power::Shutdown()
|
||||
{
|
||||
warn("Shutdown not implemented for i386");
|
||||
}
|
||||
|
||||
Power::Power()
|
||||
{
|
||||
error("Power not implemented for i386");
|
||||
}
|
||||
|
||||
Power::~Power()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(aa64)
|
||||
|
||||
namespace Power
|
||||
{
|
||||
void Power::Reboot()
|
||||
{
|
||||
warn("Reboot not implemented for aarch64");
|
||||
}
|
||||
|
||||
void Power::Shutdown()
|
||||
{
|
||||
warn("Shutdown not implemented for aarch64");
|
||||
}
|
||||
|
||||
Power::Power()
|
||||
{
|
||||
error("Power not implemented for aarch64");
|
||||
}
|
||||
|
||||
Power::~Power()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
22
Kernel/Core/README.md
Normal file
22
Kernel/Core/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Core components
|
||||
|
||||
This directory contains the core components of the project. These components are used by the kernel to provide the basic functionality of the operating system.
|
||||
|
||||
---
|
||||
|
||||
## 💾 Memory
|
||||
|
||||
Contains the memory management code.
|
||||
It is responsible for allocating and freeing memory.
|
||||
It also provides the `kmalloc`, `kcalloc`, `krealloc` and `kfree` functions that are used by the rest of the kernel.
|
||||
|
||||
## 📺 Video
|
||||
|
||||
Contains the video management code.
|
||||
It is responsible for printing text to the screen.
|
||||
|
||||
## 🖥 CPU
|
||||
|
||||
Contains the CPU management code.
|
||||
It is responsible for initializing the GDT and IDT.
|
||||
More code related is in the `Architecture` directory.
|
156
Kernel/Core/Random.cpp
Normal file
156
Kernel/Core/Random.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#include <rand.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
namespace Random
|
||||
{
|
||||
static uint64_t Seed = 0xdeadbeef;
|
||||
|
||||
uint16_t rand16()
|
||||
{
|
||||
int RDRANDFlag = 0;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::AMD::CPUID0x1 cpuid1amd;
|
||||
#elif defined(a32)
|
||||
CPU::x32::AMD::CPUID0x1 cpuid1amd;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1amd.EAX.raw), "=b"(cpuid1amd.EBX.raw), "=c"(cpuid1amd.ECX.raw), "=d"(cpuid1amd.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
RDRANDFlag = cpuid1amd.ECX.RDRAND;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::Intel::CPUID0x1 cpuid1intel;
|
||||
#elif defined(a32)
|
||||
CPU::x32::Intel::CPUID0x1 cpuid1intel;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1intel.EAX.raw), "=b"(cpuid1intel.EBX.raw), "=c"(cpuid1intel.ECX.raw), "=d"(cpuid1intel.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
RDRANDFlag = cpuid1intel.ECX.RDRAND;
|
||||
}
|
||||
|
||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) == 0)
|
||||
RDRANDFlag = 0;
|
||||
|
||||
#if defined(a64) || defined(a32)
|
||||
if (RDRANDFlag)
|
||||
{
|
||||
uint16_t RDRANDValue = 0;
|
||||
asmv("1: rdrand %0; jnc 1b"
|
||||
: "=r"(RDRANDValue));
|
||||
return RDRANDValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
Seed = Seed * 1103515245 + 12345;
|
||||
return (uint16_t)(Seed / 65536) % __UINT16_MAX__;
|
||||
}
|
||||
|
||||
uint32_t rand32()
|
||||
{
|
||||
int RDRANDFlag = 0;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::AMD::CPUID0x1 cpuid1amd;
|
||||
#elif defined(a32)
|
||||
CPU::x32::AMD::CPUID0x1 cpuid1amd;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1amd.EAX.raw), "=b"(cpuid1amd.EBX.raw), "=c"(cpuid1amd.ECX.raw), "=d"(cpuid1amd.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
RDRANDFlag = cpuid1amd.ECX.RDRAND;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::Intel::CPUID0x1 cpuid1intel;
|
||||
#elif defined(a32)
|
||||
CPU::x32::Intel::CPUID0x1 cpuid1intel;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1intel.EAX.raw), "=b"(cpuid1intel.EBX.raw), "=c"(cpuid1intel.ECX.raw), "=d"(cpuid1intel.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
RDRANDFlag = cpuid1intel.ECX.RDRAND;
|
||||
}
|
||||
|
||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) == 0)
|
||||
RDRANDFlag = 0;
|
||||
|
||||
#if defined(a64) || defined(a32)
|
||||
if (RDRANDFlag)
|
||||
{
|
||||
uint32_t RDRANDValue = 0;
|
||||
asmv("1: rdrand %0; jnc 1b"
|
||||
: "=r"(RDRANDValue));
|
||||
return RDRANDValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
Seed = Seed * 1103515245 + 12345;
|
||||
return (uint32_t)(Seed / 65536) % __UINT16_MAX__;
|
||||
}
|
||||
|
||||
uint64_t rand64()
|
||||
{
|
||||
int RDRANDFlag = 0;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::AMD::CPUID0x1 cpuid1amd;
|
||||
#elif defined(a32)
|
||||
CPU::x32::AMD::CPUID0x1 cpuid1amd;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1amd.EAX.raw), "=b"(cpuid1amd.EBX.raw), "=c"(cpuid1amd.ECX.raw), "=d"(cpuid1amd.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
RDRANDFlag = cpuid1amd.ECX.RDRAND;
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::Intel::CPUID0x1 cpuid1intel;
|
||||
#elif defined(a32)
|
||||
CPU::x32::Intel::CPUID0x1 cpuid1intel;
|
||||
#endif
|
||||
#if defined(a64) || defined(a32)
|
||||
asmv("cpuid"
|
||||
: "=a"(cpuid1intel.EAX.raw), "=b"(cpuid1intel.EBX.raw), "=c"(cpuid1intel.ECX.raw), "=d"(cpuid1intel.EDX.raw)
|
||||
: "a"(0x1));
|
||||
#endif
|
||||
RDRANDFlag = cpuid1intel.ECX.RDRAND;
|
||||
}
|
||||
|
||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) == 0)
|
||||
RDRANDFlag = 0;
|
||||
|
||||
#if defined(a64) || defined(a32)
|
||||
if (RDRANDFlag)
|
||||
{
|
||||
uint64_t RDRANDValue = 0;
|
||||
asmv("1: rdrand %0; jnc 1b"
|
||||
: "=r"(RDRANDValue));
|
||||
return RDRANDValue;
|
||||
}
|
||||
#endif
|
||||
|
||||
Seed = Seed * 1103515245 + 12345;
|
||||
return (uint64_t)(Seed / 65536) % __UINT16_MAX__;
|
||||
}
|
||||
|
||||
void ChangeSeed(uint64_t CustomSeed) { Seed = CustomSeed; }
|
||||
}
|
79
Kernel/Core/StackGuard.cpp
Normal file
79
Kernel/Core/StackGuard.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include <types.h>
|
||||
#include <debug.h>
|
||||
#include <rand.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
/* EXTERNC */ __attribute__((weak)) uintptr_t __stack_chk_guard = 0;
|
||||
|
||||
EXTERNC __attribute__((weak, no_stack_protector)) uintptr_t __stack_chk_guard_init(void)
|
||||
{
|
||||
int MaxRetries = 0;
|
||||
#if UINTPTR_MAX == UINT32_MAX
|
||||
uint32_t num;
|
||||
Retry:
|
||||
num = Random::rand32();
|
||||
if (num < 0x1000 && MaxRetries++ < 10)
|
||||
goto Retry;
|
||||
return num;
|
||||
|
||||
#else
|
||||
uint64_t num;
|
||||
Retry:
|
||||
num = Random::rand64();
|
||||
if (num < 0x100000 && MaxRetries++ < 10)
|
||||
goto Retry;
|
||||
return num;
|
||||
#endif
|
||||
}
|
||||
|
||||
EXTERNC __attribute__((constructor, no_stack_protector)) void __guard_setup(void)
|
||||
{
|
||||
debug("StackGuard: __guard_setup");
|
||||
if (__stack_chk_guard == 0)
|
||||
__stack_chk_guard = __stack_chk_guard_init();
|
||||
debug("Stack guard value: %ld", __stack_chk_guard);
|
||||
}
|
||||
|
||||
EXTERNC __attribute__((weak, noreturn, no_stack_protector)) void __stack_chk_fail(void)
|
||||
{
|
||||
TaskingPanic();
|
||||
for (short i = 0; i < 10; i++)
|
||||
error("Stack smashing detected!");
|
||||
debug("Current stack check guard value: %#lx", __stack_chk_guard);
|
||||
KPrint("\eFF0000Stack smashing detected!");
|
||||
|
||||
#if defined(a64) || defined(a32)
|
||||
void *Stack = nullptr;
|
||||
#if defined(a64)
|
||||
asmv("movq %%rsp, %0"
|
||||
: "=r"(Stack));
|
||||
#elif defined(a32)
|
||||
asmv("movl %%esp, %0"
|
||||
: "=r"(Stack));
|
||||
#endif
|
||||
error("Stack address: %#lx", Stack);
|
||||
|
||||
while (1)
|
||||
asmv("cli; hlt");
|
||||
#elif defined(aa64)
|
||||
asmv("wfe");
|
||||
#endif
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libssp/ssp.c
|
||||
EXTERNC __attribute__((weak, noreturn, no_stack_protector)) void __chk_fail(void)
|
||||
{
|
||||
TaskingPanic();
|
||||
for (short i = 0; i < 10; i++)
|
||||
error("Buffer overflow detected!");
|
||||
KPrint("\eFF0000Buffer overflow detected!");
|
||||
|
||||
#if defined(a64) || defined(a32)
|
||||
while (1)
|
||||
asmv("cli; hlt");
|
||||
#elif defined(aa64)
|
||||
asmv("wfe");
|
||||
#endif
|
||||
}
|
116
Kernel/Core/Symbols.cpp
Normal file
116
Kernel/Core/Symbols.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include <symbols.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
#include <elf.h>
|
||||
|
||||
// #pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
|
||||
namespace SymbolResolver
|
||||
{
|
||||
Symbols::Symbols(uintptr_t ImageAddress)
|
||||
{
|
||||
debug("Solving symbols for address: %#llx", ImageAddress);
|
||||
Elf64_Ehdr *Header = (Elf64_Ehdr *)ImageAddress;
|
||||
if (Header->e_ident[0] != 0x7F &&
|
||||
Header->e_ident[1] != 'E' &&
|
||||
Header->e_ident[2] != 'L' &&
|
||||
Header->e_ident[3] != 'F')
|
||||
{
|
||||
error("Invalid ELF header");
|
||||
return;
|
||||
}
|
||||
Elf64_Shdr *ElfSections = (Elf64_Shdr *)(ImageAddress + Header->e_shoff);
|
||||
Elf64_Sym *ElfSymbols = nullptr;
|
||||
char *strtab = nullptr;
|
||||
|
||||
for (uint16_t i = 0; i < Header->e_shnum; i++)
|
||||
switch (ElfSections[i].sh_type)
|
||||
{
|
||||
case SHT_SYMTAB:
|
||||
ElfSymbols = (Elf64_Sym *)(ImageAddress + ElfSections[i].sh_offset);
|
||||
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
|
||||
if (this->TotalEntries >= 0x10000)
|
||||
this->TotalEntries = 0x10000 - 1;
|
||||
|
||||
debug("Symbol table found, %d entries", this->TotalEntries);
|
||||
break;
|
||||
case SHT_STRTAB:
|
||||
if (Header->e_shstrndx == i)
|
||||
{
|
||||
debug("String table found, %d entries", ElfSections[i].sh_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
strtab = (char *)(ImageAddress + ElfSections[i].sh_offset);
|
||||
debug("String table found, %d entries", ElfSections[i].sh_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ElfSymbols != nullptr && strtab != nullptr)
|
||||
{
|
||||
uintptr_t Index, MinimumIndex;
|
||||
for (uintptr_t i = 0; i < this->TotalEntries - 1; i++)
|
||||
{
|
||||
MinimumIndex = i;
|
||||
for (Index = i + 1; Index < this->TotalEntries; Index++)
|
||||
if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value)
|
||||
MinimumIndex = Index;
|
||||
Elf64_Sym tmp = ElfSymbols[MinimumIndex];
|
||||
ElfSymbols[MinimumIndex] = ElfSymbols[i];
|
||||
ElfSymbols[i] = tmp;
|
||||
}
|
||||
|
||||
while (ElfSymbols[0].st_value == 0)
|
||||
{
|
||||
ElfSymbols++;
|
||||
this->TotalEntries--;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int once = 0;
|
||||
#endif
|
||||
|
||||
trace("Symbol table loaded, %d entries (%ldKB)", this->TotalEntries, TO_KB(this->TotalEntries * sizeof(SymbolTable)));
|
||||
for (uintptr_t i = 0, g = this->TotalEntries; i < g; i++)
|
||||
{
|
||||
this->SymTable[i].Address = ElfSymbols[i].st_value;
|
||||
this->SymTable[i].FunctionName = &strtab[ElfSymbols[i].st_name];
|
||||
#ifdef DEBUG
|
||||
if (once)
|
||||
debug("Symbol %d: %#llx %s", i, this->SymTable[i].Address, this->SymTable[i].FunctionName);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!once)
|
||||
once++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Symbols::~Symbols() {}
|
||||
|
||||
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address)
|
||||
{
|
||||
Symbols::SymbolTable Result{0, (char *)"<unknown>"};
|
||||
for (uintptr_t i = 0; i < this->TotalEntries; i++)
|
||||
if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address)
|
||||
Result = this->SymTable[i];
|
||||
return Result.FunctionName;
|
||||
}
|
||||
|
||||
NIF void Symbols::AddSymbol(uintptr_t Address, const char *Name)
|
||||
{
|
||||
if (this->TotalEntries >= 0x10000)
|
||||
{
|
||||
error("Symbol table is full");
|
||||
return;
|
||||
}
|
||||
|
||||
this->SymTable[this->TotalEntries].Address = Address;
|
||||
strcpy(this->SymTable[this->TotalEntries].FunctionName, Name);
|
||||
this->TotalEntries++;
|
||||
}
|
||||
}
|
70
Kernel/Core/SystemManagementBIOS.cpp
Normal file
70
Kernel/Core/SystemManagementBIOS.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "smbios.hpp"
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
/* https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf */
|
||||
|
||||
namespace SMBIOS
|
||||
{
|
||||
bool CheckSMBIOS()
|
||||
{
|
||||
if (bInfo->SMBIOSPtr != nullptr && bInfo->SMBIOSPtr < (void *)0xffffffffffff0000)
|
||||
{
|
||||
debug("SMBIOS is available (%#lx).", bInfo->SMBIOSPtr);
|
||||
return true;
|
||||
}
|
||||
debug("SMBIOS is not available. (%#lx)", bInfo->SMBIOSPtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
SMBIOSEntryPoint *GetSMBIOSEntryPoint() { return (SMBIOSEntryPoint *)bInfo->SMBIOSPtr; }
|
||||
|
||||
static inline int SMBIOSTableLength(SMBIOSHeader *Hdr)
|
||||
{
|
||||
int i;
|
||||
const char *strtab = (char *)Hdr + Hdr->Length;
|
||||
for (i = 1; strtab[i - 1] != '\0' || strtab[i] != '\0'; i++)
|
||||
;
|
||||
return Hdr->Length + i + 1;
|
||||
}
|
||||
|
||||
void *GetSMBIOSHeader(SMBIOSType Type)
|
||||
{
|
||||
if (!CheckSMBIOS())
|
||||
return nullptr;
|
||||
|
||||
SMBIOSEntryPoint *Header = (SMBIOSEntryPoint *)bInfo->SMBIOSPtr;
|
||||
debug("Getting SMBIOS header for type %d", Type);
|
||||
|
||||
struct SMBIOSHeader *hdr = (SMBIOSHeader *)(uintptr_t)Header->TableAddress;
|
||||
for (int i = 0; i <= 11; i++)
|
||||
{
|
||||
if (hdr < (void *)(uintptr_t)(Header->TableAddress + Header->TableLength))
|
||||
if (hdr->Type == Type)
|
||||
{
|
||||
debug("Found SMBIOS header for type %d at %#lx", Type, hdr);
|
||||
return hdr;
|
||||
}
|
||||
hdr = (struct SMBIOSHeader *)((uintptr_t)hdr + SMBIOSTableLength(hdr));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SMBIOSBIOSInformation *GetBIOSInformation() { return (SMBIOSBIOSInformation *)GetSMBIOSHeader(SMBIOSTypeBIOSInformation); }
|
||||
|
||||
SMBIOSSystemInformation *GetSystemInformation() { return (SMBIOSSystemInformation *)GetSMBIOSHeader(SMBIOSTypeSystemInformation); }
|
||||
|
||||
SMBIOSBaseBoardInformation *GetBaseBoardInformation() { return (SMBIOSBaseBoardInformation *)GetSMBIOSHeader(SMBIOSTypeBaseBoardInformation); }
|
||||
|
||||
SMBIOSProcessorInformation *GetProcessorInformation() { return (SMBIOSProcessorInformation *)GetSMBIOSHeader(SMBIOSTypeProcessorInformation); }
|
||||
|
||||
SMBIOSMemoryArray *GetMemoryArray() { return (SMBIOSMemoryArray *)GetSMBIOSHeader(SMBIOSTypePhysicalMemoryArray); }
|
||||
|
||||
SMBIOSMemoryDevice *GetMemoryDevice() { return (SMBIOSMemoryDevice *)GetSMBIOSHeader(SMBIOSTypeMemoryDevice); }
|
||||
|
||||
SMBIOSMemoryArrayMappedAddress *GetMemoryArrayMappedAddress() { return (SMBIOSMemoryArrayMappedAddress *)GetSMBIOSHeader(SMBIOSTypeMemoryArrayMappedAddress); }
|
||||
|
||||
SMBIOSMemoryDeviceMappedAddress *GetMemoryDeviceMappedAddress() { return (SMBIOSMemoryDeviceMappedAddress *)GetSMBIOSHeader(SMBIOSTypeMemoryDeviceMappedAddress); }
|
||||
}
|
88
Kernel/Core/Time.cpp
Normal file
88
Kernel/Core/Time.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include <time.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
namespace Time
|
||||
{
|
||||
Clock ReadClock()
|
||||
{
|
||||
Clock tm;
|
||||
#if defined(a64) || defined(a32)
|
||||
uint32_t t = 0;
|
||||
outb(0x70, 0x00);
|
||||
t = inb(0x71);
|
||||
tm.Second = ((t & 0x0F) + ((t >> 4) * 10));
|
||||
outb(0x70, 0x02);
|
||||
t = inb(0x71);
|
||||
tm.Minute = ((t & 0x0F) + ((t >> 4) * 10));
|
||||
outb(0x70, 0x04);
|
||||
t = inb(0x71);
|
||||
tm.Hour = ((t & 0x0F) + ((t >> 4) * 10));
|
||||
outb(0x70, 0x07);
|
||||
t = inb(0x71);
|
||||
tm.Day = ((t & 0x0F) + ((t >> 4) * 10));
|
||||
outb(0x70, 0x08);
|
||||
t = inb(0x71);
|
||||
tm.Month = ((t & 0x0F) + ((t >> 4) * 10));
|
||||
outb(0x70, 0x09);
|
||||
t = inb(0x71);
|
||||
tm.Year = ((t & 0x0F) + ((t >> 4) * 10));
|
||||
tm.Counter = 0;
|
||||
#elif defined(aa64)
|
||||
tm.Year = 0;
|
||||
tm.Month = 0;
|
||||
tm.Day = 0;
|
||||
tm.Hour = 0;
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
tm.Counter = 0;
|
||||
#endif
|
||||
return tm;
|
||||
}
|
||||
|
||||
Clock ConvertFromUnix(int Timestamp)
|
||||
{
|
||||
Clock result;
|
||||
|
||||
uint64_t Seconds = Timestamp;
|
||||
uint64_t Minutes = Seconds / 60;
|
||||
uint64_t Hours = Minutes / 60;
|
||||
uint64_t Days = Hours / 24;
|
||||
|
||||
result.Year = 1970;
|
||||
while (Days >= 365)
|
||||
{
|
||||
if (result.Year % 4 == 0 && (result.Year % 100 != 0 || result.Year % 400 == 0))
|
||||
{
|
||||
if (Days >= 366)
|
||||
{
|
||||
Days -= 366;
|
||||
result.Year++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Days -= 365;
|
||||
result.Year++;
|
||||
}
|
||||
}
|
||||
|
||||
int DaysInMonth[] = {31, result.Year % 4 == 0 ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
for (result.Month = 0; result.Month < 12; result.Month++)
|
||||
{
|
||||
if (Days < static_cast<uint64_t>(DaysInMonth[result.Month]))
|
||||
break;
|
||||
Days -= DaysInMonth[result.Month];
|
||||
}
|
||||
result.Month++;
|
||||
|
||||
result.Day = static_cast<int>(Days) + 1;
|
||||
result.Hour = static_cast<int>(Hours % 24);
|
||||
result.Minute = static_cast<int>(Minutes % 60);
|
||||
result.Second = static_cast<int>(Seconds % 60);
|
||||
result.Counter = static_cast<uint64_t>(Timestamp);
|
||||
return result;
|
||||
}
|
||||
}
|
89
Kernel/Core/Timer.cpp
Normal file
89
Kernel/Core/Timer.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include <time.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
#if defined(a64)
|
||||
#include "../Architecture/amd64/acpi.hpp"
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace Time
|
||||
{
|
||||
void time::Sleep(uint64_t Milliseconds)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Milliseconds * 1000000000000) / clk;
|
||||
#ifdef DEBUG
|
||||
uint64_t Counter = mminq(&((HPET *)hpet)->MainCounterValue);
|
||||
while (Counter < Target)
|
||||
{
|
||||
Counter = mminq(&((HPET *)hpet)->MainCounterValue);
|
||||
CPU::Pause();
|
||||
}
|
||||
#else
|
||||
while (mminq(&((HPET *)hpet)->MainCounterValue) < Target)
|
||||
CPU::Pause();
|
||||
#endif
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t time::GetCounter()
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
return mminq(&((HPET *)hpet)->MainCounterValue);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t time::CalculateTarget(uint64_t Milliseconds)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
return mminq(&((HPET *)hpet)->MainCounterValue) + (Milliseconds * 1000000000000) / clk;
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
|
||||
time::time(void *_acpi)
|
||||
{
|
||||
if (_acpi)
|
||||
{
|
||||
#if defined(a64)
|
||||
this->acpi = _acpi;
|
||||
ACPI::ACPI *acpi = (ACPI::ACPI *)this->acpi;
|
||||
if (acpi->HPET)
|
||||
{
|
||||
Memory::Virtual().Map((void *)acpi->HPET->Address.Address,
|
||||
(void *)acpi->HPET->Address.Address,
|
||||
Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
||||
this->hpet = (void *)acpi->HPET->Address.Address;
|
||||
HPET *hpet = (HPET *)this->hpet;
|
||||
trace("%s timer is at address %016p", acpi->HPET->Header.OEMID, (void *)acpi->HPET->Address.Address);
|
||||
clk = hpet->GeneralCapabilities >> 32;
|
||||
mmoutq(&hpet->GeneralConfiguration, 0);
|
||||
mmoutq(&hpet->MainCounterValue, 0);
|
||||
mmoutq(&hpet->GeneralConfiguration, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For now, we need HPET.
|
||||
error("HPET not found");
|
||||
KPrint("\eFF2200HPET not found");
|
||||
CPU::Stop();
|
||||
}
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
time::~time()
|
||||
{
|
||||
debug("Destructor called");
|
||||
}
|
||||
}
|
537
Kernel/Core/UndefinedBehaviorSanitization.c
Normal file
537
Kernel/Core/UndefinedBehaviorSanitization.c
Normal file
@ -0,0 +1,537 @@
|
||||
#include "ubsan.h"
|
||||
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
|
||||
// TODO: implement:
|
||||
/*
|
||||
__ubsan_handle_type_mismatch_v1_abort
|
||||
__ubsan_handle_add_overflow_abort
|
||||
__ubsan_handle_sub_overflow_abort
|
||||
__ubsan_handle_mul_overflow_abort
|
||||
__ubsan_handle_negate_overflow_abort
|
||||
__ubsan_handle_divrem_overflow_abort
|
||||
__ubsan_handle_shift_out_of_bounds_abort
|
||||
__ubsan_handle_out_of_bounds_abort
|
||||
__ubsan_handle_vla_bound_not_positive_abort
|
||||
__ubsan_handle_float_cast_overflow
|
||||
__ubsan_handle_float_cast_overflow_abort
|
||||
__ubsan_handle_load_invalid_value_abort
|
||||
__ubsan_handle_invalid_builtin_abort
|
||||
__ubsan_handle_function_type_mismatch_abort
|
||||
__ubsan_handle_nonnull_return_v1
|
||||
__ubsan_handle_nonnull_return_v1_abort
|
||||
__ubsan_handle_nullability_return_v1
|
||||
__ubsan_handle_nullability_return_v1_abort
|
||||
__ubsan_handle_nonnull_arg_abort
|
||||
__ubsan_handle_nullability_arg
|
||||
__ubsan_handle_nullability_arg_abort
|
||||
__ubsan_handle_pointer_overflow_abort
|
||||
__ubsan_handle_cfi_check_fail
|
||||
*/
|
||||
|
||||
extern void __asan_report_load1(void *unknown)
|
||||
{
|
||||
ubsan("load1");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load2(void *unknown)
|
||||
{
|
||||
ubsan("load2");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load4(void *unknown)
|
||||
{
|
||||
ubsan("load4");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load8(void *unknown)
|
||||
{
|
||||
ubsan("load8");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load16(void *unknown)
|
||||
{
|
||||
ubsan("load16");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load_n(void *unknown, uintptr_t size)
|
||||
{
|
||||
ubsan("loadn");
|
||||
UNUSED(unknown);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_report_store1(void *unknown)
|
||||
{
|
||||
ubsan("store1");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store2(void *unknown)
|
||||
{
|
||||
ubsan("store2");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store4(void *unknown)
|
||||
{
|
||||
ubsan("store4");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store8(void *unknown)
|
||||
{
|
||||
ubsan("store8");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store16(void *unknown)
|
||||
{
|
||||
ubsan("store16");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store_n(void *unknown, uintptr_t size)
|
||||
{
|
||||
ubsan("storen");
|
||||
UNUSED(unknown);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_report_load1_noabort(void *unknown)
|
||||
{
|
||||
ubsan("load1");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load2_noabort(void *unknown)
|
||||
{
|
||||
ubsan("load2");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load4_noabort(void *unknown)
|
||||
{
|
||||
ubsan("load4");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load8_noabort(void *unknown)
|
||||
{
|
||||
ubsan("load8");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load16_noabort(void *unknown)
|
||||
{
|
||||
ubsan("load16");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_load_n_noabort(void *unknown, uintptr_t size)
|
||||
{
|
||||
ubsan("loadn");
|
||||
UNUSED(unknown);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_report_store1_noabort(void *unknown)
|
||||
{
|
||||
ubsan("store1");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store2_noabort(void *unknown)
|
||||
{
|
||||
ubsan("store2");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store4_noabort(void *unknown)
|
||||
{
|
||||
ubsan("store4");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store8_noabort(void *unknown)
|
||||
{
|
||||
ubsan("store8");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store16_noabort(void *unknown)
|
||||
{
|
||||
ubsan("store16");
|
||||
UNUSED(unknown);
|
||||
}
|
||||
|
||||
extern void __asan_report_store_n_noabort(void *unknown, uintptr_t size)
|
||||
{
|
||||
ubsan("storen");
|
||||
UNUSED(unknown);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_0(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 0");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_1(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 1");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_2(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 2");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_3(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 3");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_4(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 4");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_5(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 5");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_6(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 6");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_7(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 7");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_8(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 8");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_malloc_9(uintptr_t size)
|
||||
{
|
||||
ubsan("stack malloc 9");
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_0(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 0");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_1(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 1");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_2(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 2");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_3(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 3");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_4(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 4");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_5(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 5");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_6(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 6");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_7(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 7");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_8(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 8");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_stack_free_9(void *ptr, uintptr_t size)
|
||||
{
|
||||
ubsan("stack free 9");
|
||||
UNUSED(ptr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_poison_stack_memory(void *addr, uintptr_t size)
|
||||
{
|
||||
ubsan("poison stack memory");
|
||||
UNUSED(addr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_unpoison_stack_memory(void *addr, uintptr_t size)
|
||||
{
|
||||
ubsan("unpoison stack memory");
|
||||
UNUSED(addr);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_before_dynamic_init(const char *module_name)
|
||||
{
|
||||
ubsan("before dynamic init");
|
||||
UNUSED(module_name);
|
||||
}
|
||||
|
||||
extern void __asan_after_dynamic_init(void) { ubsan("after dynamic init"); }
|
||||
|
||||
extern void __asan_register_globals(void *unknown, size_t size)
|
||||
{
|
||||
ubsan("register_globals");
|
||||
UNUSED(unknown);
|
||||
UNUSED(size);
|
||||
}
|
||||
|
||||
extern void __asan_unregister_globals(void) { ubsan("unregister_globals"); }
|
||||
|
||||
extern void __asan_init(void) { ubsan("init"); }
|
||||
extern void __asan_version_mismatch_check_v8(void) { ubsan("version_mismatch_check_v8"); }
|
||||
extern void __asan_option_detect_stack_use_after_return(void) { ubsan("stack use after return"); }
|
||||
|
||||
extern __noreturn void __asan_handle_no_return(void)
|
||||
{
|
||||
ubsan("no_return");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
#define is_aligned(value, alignment) !(value & (alignment - 1))
|
||||
|
||||
const char *Type_Check_Kinds[] = {
|
||||
"Load of",
|
||||
"Store to",
|
||||
"Reference binding to",
|
||||
"Member access within",
|
||||
"Member call on",
|
||||
"Constructor call on",
|
||||
"Downcast of",
|
||||
"Downcast of",
|
||||
"Upcast of",
|
||||
"Cast to virtual base of",
|
||||
};
|
||||
|
||||
bool UBSANMsg(const char *file, uint32_t line, uint32_t column)
|
||||
{
|
||||
// blacklist
|
||||
// if (strstr(file, "liballoc") ||
|
||||
// strstr(file, "cwalk") ||
|
||||
// strstr(file, "AdvancedConfigurationAndPowerInterface") ||
|
||||
// strstr(file, "SystemManagementBIOS"))
|
||||
// return false;
|
||||
|
||||
if (strstr(file, "AdvancedConfigurationAndPowerInterface.cpp") &&
|
||||
(line == 17 && column == 47))
|
||||
return false;
|
||||
|
||||
if (strstr(file, "SystemManagementBIOS.cpp") &&
|
||||
((line == 30 && column == 21) ||
|
||||
(line == 27 && column == 49) ||
|
||||
(line == 45 && column == 26)))
|
||||
return false;
|
||||
|
||||
if (strstr(file, "cwalk.c") &&
|
||||
((line == 1047 && column == 15)))
|
||||
return false;
|
||||
|
||||
if (strstr(file, "liballoc_1_1.c"))
|
||||
return false;
|
||||
|
||||
if (strstr(file, "display.hpp") &&
|
||||
((line == 113 && column == 43)))
|
||||
return false;
|
||||
|
||||
if (strstr(file, "Xalloc.hpp") &&
|
||||
(line == 48 && column == 28))
|
||||
return false;
|
||||
|
||||
if (strstr(file, "Task.cpp") && line > 500)
|
||||
return false;
|
||||
|
||||
ubsan("\t\tIn File: %s:%i:%i", file, line, column);
|
||||
return true;
|
||||
}
|
||||
|
||||
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_v1_data *type_mismatch, uintptr_t pointer)
|
||||
{
|
||||
struct source_location *location = &type_mismatch->location;
|
||||
if (pointer == 0)
|
||||
{
|
||||
if (UBSANMsg(location->file, location->line, location->column))
|
||||
ubsan("Null pointer access.");
|
||||
}
|
||||
else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment))
|
||||
{
|
||||
if (UBSANMsg(location->file, location->line, location->column))
|
||||
ubsan("Unaligned memory access %#llx.", pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UBSANMsg(location->file, location->line, location->column))
|
||||
ubsan("%s address %#llx with insufficient space for object of type %s",
|
||||
Type_Check_Kinds[type_mismatch->type_check_kind], (void *)pointer, type_mismatch->type->name);
|
||||
}
|
||||
}
|
||||
|
||||
void __ubsan_handle_add_overflow(struct overflow_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Addition overflow.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_sub_overflow(struct overflow_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Subtraction overflow.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_mul_overflow(struct overflow_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Multiplication overflow.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_divrem_overflow(struct overflow_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Division overflow.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_negate_overflow(struct overflow_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Negation overflow.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_pointer_overflow(struct overflow_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Pointer overflow.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Shift out of bounds.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Invalid load value.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_out_of_bounds(struct array_out_of_bounds_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Array out of bounds.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_vla_bound_not_positive(struct negative_vla_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Variable-length argument is negative.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Non-null return is null.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_nonnull_return_v1(struct nonnull_return_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Non-null return is null.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Non-null argument is null.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Unreachable code reached.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Invalid builtin.");
|
||||
}
|
||||
|
||||
void __ubsan_handle_missing_return(struct unreachable_data *data)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Missing return.");
|
||||
}
|
||||
|
||||
void __ubsan_vptr_type_cache(uintptr_t *cache, uintptr_t ptr)
|
||||
{
|
||||
ubsan("Vptr type cache.");
|
||||
*cache = ptr;
|
||||
}
|
||||
|
||||
void __ubsan_handle_dynamic_type_cache_miss(struct dynamic_type_cache_miss_data *data, uintptr_t ptr)
|
||||
{
|
||||
if (UBSANMsg(data->location.file, data->location.line, data->location.column))
|
||||
ubsan("Dynamic type cache miss.");
|
||||
UNUSED(ptr);
|
||||
}
|
154
Kernel/Core/UniversalAsynchronousReceiverTransmitter.cpp
Normal file
154
Kernel/Core/UniversalAsynchronousReceiverTransmitter.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include <uart.hpp>
|
||||
|
||||
#include <vector.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
volatile bool serialports[8] = {false, false, false, false, false, false, false, false};
|
||||
Vector<UniversalAsynchronousReceiverTransmitter::Events *> RegisteredEvents;
|
||||
|
||||
#if defined(a64) || defined(a32)
|
||||
NIF __always_inline inline uint8_t NoProfiler_inportb(uint16_t Port)
|
||||
{
|
||||
uint8_t Result;
|
||||
asm("in %%dx, %%al"
|
||||
: "=a"(Result)
|
||||
: "d"(Port));
|
||||
return Result;
|
||||
}
|
||||
|
||||
NIF __always_inline inline void NoProfiler_outportb(uint16_t Port, uint8_t Data)
|
||||
{
|
||||
asmv("out %%al, %%dx"
|
||||
:
|
||||
: "a"(Data), "d"(Port));
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace UniversalAsynchronousReceiverTransmitter
|
||||
{
|
||||
#define SERIAL_ENABLE_DLAB 0x80
|
||||
#define SERIAL_RATE_115200_LO 0x01
|
||||
#define SERIAL_RATE_115200_HI 0x00
|
||||
#define SERIAL_RATE_57600_LO 0x02
|
||||
#define SERIAL_RATE_57600_HI 0x00
|
||||
#define SERIAL_RATE_38400_LO 0x03
|
||||
#define SERIAL_RATE_38400_HI 0x00
|
||||
#define SERIAL_BUFFER_EMPTY 0x20
|
||||
|
||||
/* TODO: Serial Port implementation needs reword. https://wiki.osdev.org/Serial_Ports */
|
||||
|
||||
SafeFunction NIF UART::UART(SerialPorts Port)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
if (Port == COMNULL)
|
||||
return;
|
||||
|
||||
this->Port = Port;
|
||||
int PortNumber = 0;
|
||||
|
||||
switch (Port)
|
||||
{
|
||||
case COM1:
|
||||
PortNumber = 0;
|
||||
break;
|
||||
case COM2:
|
||||
PortNumber = 1;
|
||||
break;
|
||||
case COM3:
|
||||
PortNumber = 2;
|
||||
break;
|
||||
case COM4:
|
||||
PortNumber = 3;
|
||||
break;
|
||||
case COM5:
|
||||
PortNumber = 4;
|
||||
break;
|
||||
case COM6:
|
||||
PortNumber = 5;
|
||||
break;
|
||||
case COM7:
|
||||
PortNumber = 6;
|
||||
break;
|
||||
case COM8:
|
||||
PortNumber = 7;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (serialports[PortNumber])
|
||||
return;
|
||||
|
||||
// Initialize the serial port
|
||||
NoProfiler_outportb(Port + 1, 0x00); // Disable all interrupts
|
||||
NoProfiler_outportb(Port + 3, SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor)
|
||||
NoProfiler_outportb(Port + 0, SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud
|
||||
NoProfiler_outportb(Port + 1, SERIAL_RATE_115200_HI); // (hi byte)
|
||||
NoProfiler_outportb(Port + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
NoProfiler_outportb(Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
NoProfiler_outportb(Port + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
|
||||
// Check if the serial port is faulty.
|
||||
if (NoProfiler_inportb(Port + 0) != 0xAE)
|
||||
{
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
warn("Serial port %#llx is faulty.", Port);
|
||||
// serialports[Port] = false; // ignore for now
|
||||
// return;
|
||||
}
|
||||
|
||||
// Set to normal operation mode.
|
||||
NoProfiler_outportb(Port + 4, 0x0F);
|
||||
serialports[PortNumber] = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
SafeFunction NIF UART::~UART() {}
|
||||
|
||||
SafeFunction NIF void UART::Write(uint8_t Char)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
while ((NoProfiler_inportb(Port + 5) & SERIAL_BUFFER_EMPTY) == 0)
|
||||
;
|
||||
NoProfiler_outportb(Port, Char);
|
||||
#endif
|
||||
foreach (auto e in RegisteredEvents)
|
||||
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
|
||||
e->OnSent(Char);
|
||||
}
|
||||
|
||||
SafeFunction NIF uint8_t UART::Read()
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
while ((NoProfiler_inportb(Port + 5) & 1) == 0)
|
||||
;
|
||||
return NoProfiler_inportb(Port);
|
||||
#endif
|
||||
foreach (auto e in RegisteredEvents)
|
||||
{
|
||||
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
|
||||
{
|
||||
#if defined(a64) || defined(a32)
|
||||
e->OnReceived(NoProfiler_inportb(Port));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction NIF Events::Events(SerialPorts Port)
|
||||
{
|
||||
this->Port = Port;
|
||||
RegisteredEvents.push_back(this);
|
||||
}
|
||||
|
||||
SafeFunction NIF Events::~Events()
|
||||
{
|
||||
for (uintptr_t i = 0; i < RegisteredEvents.size(); i++)
|
||||
if (RegisteredEvents[i] == this)
|
||||
{
|
||||
RegisteredEvents.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
365
Kernel/Core/Video/Display.cpp
Normal file
365
Kernel/Core/Video/Display.cpp
Normal file
@ -0,0 +1,365 @@
|
||||
#include <display.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <uart.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start;
|
||||
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end;
|
||||
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_size;
|
||||
|
||||
NewLock(PrintLock);
|
||||
|
||||
namespace Video
|
||||
{
|
||||
Font *Display::GetCurrentFont()
|
||||
{
|
||||
return CurrentFont;
|
||||
}
|
||||
|
||||
void Display::SetCurrentFont(Font *Font)
|
||||
{
|
||||
CurrentFont = Font;
|
||||
}
|
||||
|
||||
void Display::CreateBuffer(uint32_t Width, uint32_t Height, int Index)
|
||||
{
|
||||
if (Width == 0 && Height == 0)
|
||||
{
|
||||
Width = this->framebuffer.Width;
|
||||
Height = this->framebuffer.Height;
|
||||
debug("No width and height specified, using %ldx%lld", Width, Height);
|
||||
}
|
||||
|
||||
size_t Size = this->framebuffer.Pitch * Height;
|
||||
if (this->Buffers[Index])
|
||||
{
|
||||
if (this->Buffers[Index]->Checksum == 0xDEAD)
|
||||
{
|
||||
warn("Buffer %d already exists, skipping creation", Index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ScreenBuffer *buffer = new ScreenBuffer;
|
||||
buffer->Buffer = KernelAllocator.RequestPages(TO_PAGES(Size));
|
||||
buffer->Width = Width;
|
||||
buffer->Height = Height;
|
||||
buffer->Size = Size;
|
||||
buffer->Color = 0xFFFFFF;
|
||||
buffer->CursorX = 0;
|
||||
buffer->CursorY = 0;
|
||||
buffer->Brightness = 100;
|
||||
this->Buffers[Index] = buffer;
|
||||
memset(this->Buffers[Index]->Buffer, 0, Size);
|
||||
this->Buffers[Index]->Checksum = 0xDEAD;
|
||||
debug("Created buffer %d, address %#lx", Index, buffer);
|
||||
}
|
||||
|
||||
void Display::SetBuffer(int Index)
|
||||
{
|
||||
if (this->Buffers[Index]->Brightness != 100)
|
||||
this->SetBrightness(this->Buffers[Index]->Brightness, Index);
|
||||
|
||||
if (this->Buffers[Index]->Brightness == 0) /* Just clear the buffer */
|
||||
memset(this->Buffers[Index]->Buffer, 0, this->Buffers[Index]->Size);
|
||||
|
||||
memcpy(this->framebuffer.BaseAddress, this->Buffers[Index]->Buffer, this->Buffers[Index]->Size);
|
||||
}
|
||||
|
||||
ScreenBuffer *Display::GetBuffer(int Index)
|
||||
{
|
||||
return this->Buffers[Index];
|
||||
}
|
||||
|
||||
void Display::ClearBuffer(int Index)
|
||||
{
|
||||
memset(this->Buffers[Index]->Buffer, 0, this->Buffers[Index]->Size);
|
||||
}
|
||||
|
||||
void Display::DeleteBuffer(int Index)
|
||||
{
|
||||
if (this->Buffers[Index] == nullptr)
|
||||
return;
|
||||
KernelAllocator.FreePages(this->Buffers[Index]->Buffer, TO_PAGES(this->Buffers[Index]->Size));
|
||||
this->Buffers[Index]->Buffer = nullptr;
|
||||
this->Buffers[Index]->Checksum = 0; // Making sure that the buffer is not used anymore
|
||||
delete this->Buffers[Index], this->Buffers[Index] = nullptr;
|
||||
}
|
||||
|
||||
void Display::SetBrightness(int Value, int Index)
|
||||
{
|
||||
if (this->Buffers[Index] == nullptr)
|
||||
return;
|
||||
|
||||
if (Value > 100)
|
||||
Value = 100;
|
||||
else if (Value < 0)
|
||||
Value = 0;
|
||||
|
||||
ScreenBuffer *buffer = this->Buffers[Index];
|
||||
uint32_t *pixel = (uint32_t *)buffer->Buffer;
|
||||
|
||||
for (uint32_t y = 0; y < buffer->Height; y++)
|
||||
{
|
||||
for (uint32_t x = 0; x < buffer->Width; x++)
|
||||
{
|
||||
uint32_t color = pixel[y * buffer->Width + x];
|
||||
|
||||
uint8_t r = color & 0xff;
|
||||
uint8_t g = (color >> 8) & 0xff;
|
||||
uint8_t b = (color >> 16) & 0xff;
|
||||
|
||||
r = (r * Value) / 100;
|
||||
g = (g * Value) / 100;
|
||||
b = (b * Value) / 100;
|
||||
|
||||
pixel[y * buffer->Width + x] = (b << 16) | (g << 8) | r;
|
||||
}
|
||||
}
|
||||
buffer->Brightness = Value;
|
||||
}
|
||||
|
||||
void Display::SetBufferCursor(int Index, uint32_t X, uint32_t Y)
|
||||
{
|
||||
this->Buffers[Index]->CursorX = X;
|
||||
this->Buffers[Index]->CursorY = Y;
|
||||
}
|
||||
|
||||
void Display::GetBufferCursor(int Index, uint32_t *X, uint32_t *Y)
|
||||
{
|
||||
*X = this->Buffers[Index]->CursorX;
|
||||
*Y = this->Buffers[Index]->CursorY;
|
||||
}
|
||||
|
||||
void Display::SetPixel(uint32_t X, uint32_t Y, uint32_t Color, int Index)
|
||||
{
|
||||
if (unlikely(X >= this->Buffers[Index]->Width))
|
||||
X = this->Buffers[Index]->Width - 1;
|
||||
if (unlikely(Y >= this->Buffers[Index]->Height))
|
||||
Y = this->Buffers[Index]->Height - 1;
|
||||
uint32_t *Pixel = (uint32_t *)((uintptr_t)this->Buffers[Index]->Buffer + (Y * this->Buffers[Index]->Width + X) * (this->framebuffer.BitsPerPixel / 8));
|
||||
*Pixel = Color;
|
||||
}
|
||||
|
||||
uint32_t Display::GetPixel(uint32_t X, uint32_t Y, int Index)
|
||||
{
|
||||
if (unlikely(X >= this->Buffers[Index]->Width || Y >= this->Buffers[Index]->Height))
|
||||
return 0;
|
||||
uint32_t *Pixel = (uint32_t *)((uintptr_t)this->Buffers[Index]->Buffer + (Y * this->Buffers[Index]->Width + X) * (this->framebuffer.BitsPerPixel / 8));
|
||||
return *Pixel;
|
||||
}
|
||||
|
||||
uint16_t Display::GetBitsPerPixel()
|
||||
{
|
||||
return this->framebuffer.BitsPerPixel;
|
||||
}
|
||||
|
||||
uint64_t Display::GetPitch()
|
||||
{
|
||||
return this->framebuffer.Pitch;
|
||||
}
|
||||
|
||||
void Display::Scroll(int Index, int Lines)
|
||||
{
|
||||
if (Lines == 0)
|
||||
return;
|
||||
|
||||
if (Lines > 0)
|
||||
{
|
||||
uint32_t LineSize = this->Buffers[Index]->Width * (this->framebuffer.BitsPerPixel / 8);
|
||||
uint32_t BytesToMove = LineSize * Lines * this->CurrentFont->GetInfo().Height;
|
||||
uint32_t BytesToClear = this->Buffers[Index]->Size - BytesToMove;
|
||||
memmove(this->Buffers[Index]->Buffer, (uint8_t *)this->Buffers[Index]->Buffer + BytesToMove, BytesToClear);
|
||||
memset((uint8_t *)this->Buffers[Index]->Buffer + BytesToClear, 0, BytesToMove);
|
||||
}
|
||||
}
|
||||
|
||||
char Display::Print(char Char, int Index, bool WriteToUART)
|
||||
{
|
||||
// SmartLock(PrintLock);
|
||||
|
||||
if (this->ColorIteration)
|
||||
{
|
||||
// RRGGBB
|
||||
if (Char >= '0' && Char <= '9')
|
||||
this->Buffers[Index]->Color = (this->Buffers[Index]->Color << 4) | (Char - '0');
|
||||
else if (Char >= 'a' && Char <= 'f')
|
||||
this->Buffers[Index]->Color = (this->Buffers[Index]->Color << 4) | (Char - 'a' + 10);
|
||||
else if (Char >= 'A' && Char <= 'F')
|
||||
this->Buffers[Index]->Color = (this->Buffers[Index]->Color << 4) | (Char - 'A' + 10);
|
||||
else
|
||||
this->Buffers[Index]->Color = 0xFFFFFF;
|
||||
if (WriteToUART)
|
||||
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char);
|
||||
this->ColorPickerIteration++;
|
||||
if (this->ColorPickerIteration == 6)
|
||||
{
|
||||
this->ColorPickerIteration = 0;
|
||||
if (WriteToUART)
|
||||
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(']');
|
||||
this->ColorIteration = false;
|
||||
}
|
||||
return Char;
|
||||
}
|
||||
|
||||
if (WriteToUART)
|
||||
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char);
|
||||
|
||||
switch (Char)
|
||||
{
|
||||
case '\e':
|
||||
{
|
||||
if (WriteToUART)
|
||||
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write('[');
|
||||
this->ColorIteration = true;
|
||||
return Char;
|
||||
}
|
||||
case '\b':
|
||||
{
|
||||
switch (this->CurrentFont->GetInfo().Type)
|
||||
{
|
||||
case FontType::PCScreenFont1:
|
||||
{
|
||||
fixme("PCScreenFont1");
|
||||
break;
|
||||
}
|
||||
case FontType::PCScreenFont2:
|
||||
{
|
||||
uint32_t fonthdrWidth = this->CurrentFont->GetInfo().PSF2Font->Header->width;
|
||||
uint32_t fonthdrHeight = this->CurrentFont->GetInfo().PSF2Font->Header->height;
|
||||
|
||||
for (unsigned long Y = this->Buffers[Index]->CursorY; Y < this->Buffers[Index]->CursorY + fonthdrHeight; Y++)
|
||||
for (unsigned long X = this->Buffers[Index]->CursorX - fonthdrWidth; X < this->Buffers[Index]->CursorX; X++)
|
||||
*(uint32_t *)((uintptr_t)this->Buffers[Index]->Buffer +
|
||||
(Y * this->Buffers[Index]->Width + X) * (this->framebuffer.BitsPerPixel / 8)) = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
warn("Unsupported font type");
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->Buffers[Index]->CursorX > 0)
|
||||
this->Buffers[Index]->CursorX -= this->GetCurrentFont()->GetInfo().Width;
|
||||
|
||||
return Char;
|
||||
}
|
||||
case '\t':
|
||||
{
|
||||
this->Buffers[Index]->CursorX = (this->Buffers[Index]->CursorX + 8) & ~(8 - 1);
|
||||
return Char;
|
||||
}
|
||||
case '\r':
|
||||
{
|
||||
this->Buffers[Index]->CursorX = 0;
|
||||
return Char;
|
||||
}
|
||||
case '\n':
|
||||
{
|
||||
this->Buffers[Index]->CursorX = 0;
|
||||
this->Buffers[Index]->CursorY += this->GetCurrentFont()->GetInfo().Height;
|
||||
return Char;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t FontHeight = this->GetCurrentFont()->GetInfo().Height;
|
||||
|
||||
if (this->Buffers[Index]->CursorX + this->GetCurrentFont()->GetInfo().Width >= this->Buffers[Index]->Width)
|
||||
{
|
||||
this->Buffers[Index]->CursorX = 0;
|
||||
this->Buffers[Index]->CursorY += FontHeight;
|
||||
}
|
||||
|
||||
if (this->Buffers[Index]->CursorY + FontHeight >= this->Buffers[Index]->Height)
|
||||
{
|
||||
this->Buffers[Index]->CursorY -= FontHeight;
|
||||
this->Scroll(Index, 1);
|
||||
}
|
||||
|
||||
switch (this->CurrentFont->GetInfo().Type)
|
||||
{
|
||||
case FontType::PCScreenFont1:
|
||||
{
|
||||
uint32_t *PixelPtr = (uint32_t *)this->Buffers[Index]->Buffer;
|
||||
char *FontPtr = (char *)this->CurrentFont->GetInfo().PSF1Font->GlyphBuffer + (Char * this->CurrentFont->GetInfo().PSF1Font->Header->charsize);
|
||||
for (uint64_t Y = this->Buffers[Index]->CursorY; Y < this->Buffers[Index]->CursorY + 16; Y++)
|
||||
{
|
||||
for (uint64_t X = this->Buffers[Index]->CursorX; X < this->Buffers[Index]->CursorX + 8; X++)
|
||||
if ((*FontPtr & (0b10000000 >> (X - this->Buffers[Index]->CursorX))) > 0)
|
||||
*(unsigned int *)(PixelPtr + X + (Y * this->Buffers[Index]->Width)) = this->Buffers[Index]->Color;
|
||||
FontPtr++;
|
||||
}
|
||||
this->Buffers[Index]->CursorX += 8;
|
||||
|
||||
break;
|
||||
}
|
||||
case FontType::PCScreenFont2:
|
||||
{
|
||||
// if (this->CurrentFont->PSF2Font->GlyphBuffer == (uint16_t *)0x01) // HAS UNICODE TABLE
|
||||
// Char = this->CurrentFont->PSF2Font->GlyphBuffer[Char];
|
||||
int BytesPerLine = (this->CurrentFont->GetInfo().PSF2Font->Header->width + 7) / 8;
|
||||
char *FontAddress = (char *)this->CurrentFont->GetInfo().StartAddress;
|
||||
uint32_t FontHeaderSize = this->CurrentFont->GetInfo().PSF2Font->Header->headersize;
|
||||
uint32_t FontCharSize = this->CurrentFont->GetInfo().PSF2Font->Header->charsize;
|
||||
uint32_t FontLength = this->CurrentFont->GetInfo().PSF2Font->Header->length;
|
||||
char *FontPtr = FontAddress + FontHeaderSize + (Char > 0 && (uint32_t)Char < FontLength ? Char : 0) * FontCharSize;
|
||||
|
||||
uint32_t FontHdrWidth = this->CurrentFont->GetInfo().PSF2Font->Header->width;
|
||||
uint32_t FontHdrHeight = this->CurrentFont->GetInfo().PSF2Font->Header->height;
|
||||
|
||||
for (size_t Y = this->Buffers[Index]->CursorY; Y < this->Buffers[Index]->CursorY + FontHdrHeight; Y++)
|
||||
{
|
||||
for (size_t X = this->Buffers[Index]->CursorX; X < this->Buffers[Index]->CursorX + FontHdrWidth; X++)
|
||||
{
|
||||
if ((*FontPtr & (0b10000000 >> (X - this->Buffers[Index]->CursorX))) > 0)
|
||||
{
|
||||
void *FramebufferAddress = (void *)((uintptr_t)this->Buffers[Index]->Buffer +
|
||||
(Y * this->Buffers[Index]->Width + X) *
|
||||
(this->framebuffer.BitsPerPixel / 8));
|
||||
*(uint32_t *)FramebufferAddress = this->Buffers[Index]->Color;
|
||||
}
|
||||
}
|
||||
FontPtr += BytesPerLine;
|
||||
}
|
||||
this->Buffers[Index]->CursorX += FontHdrWidth;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
warn("Unsupported font type");
|
||||
break;
|
||||
}
|
||||
return Char;
|
||||
}
|
||||
|
||||
void Display::DrawString(const char *String, uint32_t X, uint32_t Y, int Index, bool WriteToUART)
|
||||
{
|
||||
this->Buffers[Index]->CursorX = X;
|
||||
this->Buffers[Index]->CursorY = Y;
|
||||
|
||||
for (int i = 0; String[i] != '\0'; i++)
|
||||
this->Print(String[i], Index, WriteToUART);
|
||||
}
|
||||
|
||||
Display::Display(BootInfo::FramebufferInfo Info, bool LoadDefaultFont)
|
||||
{
|
||||
this->framebuffer = Info;
|
||||
if (LoadDefaultFont)
|
||||
{
|
||||
this->CurrentFont = new Font(&_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, FontType::PCScreenFont2);
|
||||
FontInfo Info = this->CurrentFont->GetInfo();
|
||||
debug("Font loaded: %dx%d %s",
|
||||
Info.Width, Info.Height, Info.Type == FontType::PCScreenFont1 ? "PSF1" : "PSF2");
|
||||
}
|
||||
this->CreateBuffer(Info.Width, Info.Height, 0);
|
||||
}
|
||||
|
||||
Display::~Display()
|
||||
{
|
||||
debug("Destructor called");
|
||||
this->ClearBuffer(0);
|
||||
this->SetBuffer(0);
|
||||
|
||||
for (size_t i = 0; i < sizeof(this->Buffers) / sizeof(this->Buffers[0]); i++)
|
||||
this->DeleteBuffer(i);
|
||||
}
|
||||
}
|
54
Kernel/Core/Video/Font.cpp
Normal file
54
Kernel/Core/Video/Font.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include <display.hpp>
|
||||
#include <debug.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace Video
|
||||
{
|
||||
Font::Font(uintptr_t *Start, uintptr_t *End, FontType Type)
|
||||
{
|
||||
trace("Initializing font with start %#llx and end %#llx Type: %d", Start, End, Type);
|
||||
this->Info.StartAddress = Start;
|
||||
this->Info.EndAddress = End;
|
||||
this->Info.Type = Type;
|
||||
if (Type == FontType::PCScreenFont2)
|
||||
{
|
||||
this->Info.PSF2Font = new PSF2_FONT;
|
||||
|
||||
uintptr_t FontDataLength = End - Start;
|
||||
PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(FontDataLength / PAGE_SIZE + 1);
|
||||
for (uintptr_t i = 0; i < FontDataLength / PAGE_SIZE + 1; i++)
|
||||
Memory::Virtual().Map((void *)(font2 + (i * PAGE_SIZE)), (void *)(font2 + (i * PAGE_SIZE)), Memory::PTFlag::RW);
|
||||
memcpy((void *)font2, Start, FontDataLength);
|
||||
|
||||
this->Info.Width = font2->width;
|
||||
this->Info.Height = font2->height;
|
||||
if (font2->magic[0] != PSF2_MAGIC0 || font2->magic[1] != PSF2_MAGIC1 || font2->magic[2] != PSF2_MAGIC2 || font2->magic[3] != PSF2_MAGIC3)
|
||||
error("Font2 magic mismatch.");
|
||||
|
||||
this->Info.PSF2Font->Header = font2;
|
||||
this->Info.PSF2Font->GlyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF2_HEADER));
|
||||
}
|
||||
else if (Type == FontType::PCScreenFont1)
|
||||
{
|
||||
this->Info.PSF1Font = new PSF1_FONT;
|
||||
PSF1_HEADER *font1 = (PSF1_HEADER *)Start;
|
||||
if (font1->magic[0] != PSF1_MAGIC0 || font1->magic[1] != PSF1_MAGIC1)
|
||||
error("Font1 magic mismatch.");
|
||||
uint32_t glyphBufferSize = font1->charsize * 256;
|
||||
if (font1->mode == 1) // 512 glyph mode
|
||||
glyphBufferSize = font1->charsize * 512;
|
||||
void *glyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF1_HEADER));
|
||||
this->Info.PSF1Font->Header = font1;
|
||||
this->Info.PSF1Font->GlyphBuffer = glyphBuffer;
|
||||
UNUSED(glyphBufferSize); // TODO: Use this in the future?
|
||||
|
||||
// TODO: Get font size.
|
||||
this->Info.Width = 16;
|
||||
this->Info.Height = 8;
|
||||
}
|
||||
}
|
||||
|
||||
Font::~Font()
|
||||
{
|
||||
}
|
||||
}
|
18
Kernel/Core/crashhandler.hpp
Normal file
18
Kernel/Core/crashhandler.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __FENNIX_KERNEL_CRASH_HANDLER_H__
|
||||
#define __FENNIX_KERNEL_CRASH_HANDLER_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
namespace CrashHandler
|
||||
{
|
||||
extern uintptr_t PageFaultAddress;
|
||||
extern void *EHIntFrames[INT_FRAMES_MAX];
|
||||
|
||||
void EHPrint(const char *Format, ...);
|
||||
void Handle(void *Data);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_CRASH_HANDLER_H__
|
340
Kernel/Core/smbios.hpp
Normal file
340
Kernel/Core/smbios.hpp
Normal file
@ -0,0 +1,340 @@
|
||||
#ifndef __FENNIX_KERNEL_SMBIOS_H__
|
||||
#define __FENNIX_KERNEL_SMBIOS_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace SMBIOS
|
||||
{
|
||||
enum SMBIOSType
|
||||
{
|
||||
SMBIOSTypeBIOSInformation = 0,
|
||||
SMBIOSTypeSystemInformation = 1,
|
||||
SMBIOSTypeBaseBoardInformation = 2,
|
||||
SMBIOSTypeSystemEnclosure = 3,
|
||||
SMBIOSTypeProcessorInformation = 4,
|
||||
SMBIOSTypeMemoryControllerInformation = 5,
|
||||
SMBIOSTypeMemoryModuleInformation = 6,
|
||||
SMBIOSTypeCacheInformation = 7,
|
||||
SMBIOSTypePortConnectorInformation = 8,
|
||||
SMBIOSTypeSystemSlots = 9,
|
||||
SMBIOSTypeOnBoardDevicesInformation = 10,
|
||||
SMBIOSTypeOEMStrings = 11,
|
||||
SMBIOSTypeSystemConfigurationOptions = 12,
|
||||
SMBIOSTypeBIOSLanguageInformation = 13,
|
||||
SMBIOSTypeGroupAssociations = 14,
|
||||
SMBIOSTypeSystemEventLog = 15,
|
||||
SMBIOSTypePhysicalMemoryArray = 16,
|
||||
SMBIOSTypeMemoryDevice = 17,
|
||||
SMBIOSType32BitMemoryErrorInformation = 18,
|
||||
SMBIOSTypeMemoryArrayMappedAddress = 19,
|
||||
SMBIOSTypeMemoryDeviceMappedAddress = 20,
|
||||
SMBIOSTypeBuiltInPointingDevice = 21,
|
||||
SMBIOSTypePortableBattery = 22,
|
||||
SMBIOSTypeSystemReset = 23,
|
||||
SMBIOSTypeHardwareSecurity = 24,
|
||||
SMBIOSTypeSystemPowerControls = 25,
|
||||
SMBIOSTypeVoltageProbe = 26,
|
||||
SMBIOSTypeCoolingDevice = 27,
|
||||
SMBIOSTypeTemperatureProbe = 28,
|
||||
SMBIOSTypeElectricalCurrentProbe = 29,
|
||||
SMBIOSTypeOutofBandRemoteAccess = 30,
|
||||
SMBIOSTypeBootIntegrityServices = 31,
|
||||
SMBIOSTypeSystemBoot = 32,
|
||||
SMBIOSType64BitMemoryErrorInformation = 33,
|
||||
SMBIOSTypeManagementDevice = 34,
|
||||
SMBIOSTypeManagementDeviceComponent = 35,
|
||||
SMBIOSTypeManagementDeviceThresholdData = 36,
|
||||
SMBIOSTypeMemoryChannel = 37,
|
||||
SMBIOSTypeIPMIDevice = 38,
|
||||
SMBIOSTypePowerSupply = 39,
|
||||
SMBIOSTypeAdditionalInformation = 40,
|
||||
SMBIOSTypeOnboardDevicesExtendedInformation = 41,
|
||||
SMBIOSTypeManagementControllerHostInterface = 42,
|
||||
SMBIOSTypeTPMDevice = 43,
|
||||
SMBIOSTypeProcessorAdditionalInformation = 44,
|
||||
SMBIOSTypeInactive = 126,
|
||||
SMBIOSTypeEndOfTable = 127
|
||||
};
|
||||
|
||||
struct SMBIOSHeader
|
||||
{
|
||||
unsigned char Type;
|
||||
unsigned char Length;
|
||||
unsigned short Handle;
|
||||
};
|
||||
|
||||
struct SMBIOSEntryPoint
|
||||
{
|
||||
char EntryPointString[4];
|
||||
unsigned char Checksum;
|
||||
unsigned char Length;
|
||||
unsigned char MajorVersion;
|
||||
unsigned char MinorVersion;
|
||||
unsigned short MaxStructureSize;
|
||||
unsigned char EntryPointRevision;
|
||||
char FormattedArea[5];
|
||||
char EntryPointString2[5];
|
||||
unsigned char Checksum2;
|
||||
unsigned short TableLength;
|
||||
unsigned int TableAddress;
|
||||
unsigned short NumberOfStructures;
|
||||
unsigned char BCDRevision;
|
||||
};
|
||||
|
||||
static inline char *SMBIOSNextString(char *Str)
|
||||
{
|
||||
while (*Str != '\0')
|
||||
Str++;
|
||||
return Str + 1;
|
||||
}
|
||||
|
||||
struct SMBIOSBIOSInformation
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned char Vendor;
|
||||
unsigned char Version;
|
||||
unsigned short StartingAddressSegment;
|
||||
unsigned char ReleaseDate;
|
||||
unsigned char ROMSize;
|
||||
unsigned long Characteristics;
|
||||
unsigned char CharacteristicsExtensionBytes[2];
|
||||
unsigned char SystemBIOSMajorRelease;
|
||||
unsigned char SystemBIOSMinorRelease;
|
||||
unsigned char EmbeddedControllerFirmwareMajorRelease;
|
||||
unsigned char EmbeddedControllerFirmwareMinorRelease;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSSystemInformation
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned char Manufacturer;
|
||||
unsigned char ProductName;
|
||||
unsigned char Version;
|
||||
unsigned char SerialNumber;
|
||||
unsigned char UUID[16];
|
||||
unsigned char WakeUpType;
|
||||
unsigned char SKU;
|
||||
unsigned char Family;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSBaseBoardInformation
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned char Manufacturer;
|
||||
unsigned char Product;
|
||||
unsigned char Version;
|
||||
unsigned char SerialNumber;
|
||||
unsigned char AssetTag;
|
||||
unsigned char FeatureFlags;
|
||||
unsigned char LocationInChassis;
|
||||
unsigned short ChassisHandle;
|
||||
unsigned char BoardType;
|
||||
unsigned char NumberOfContainedObjectHandles;
|
||||
unsigned short ContainedObjectHandles[0];
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSProcessorInformation
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned char SocketDesignation;
|
||||
unsigned char ProcessorType;
|
||||
unsigned char ProcessorFamily;
|
||||
unsigned char ProcessorManufacturer;
|
||||
unsigned long ProcessorID[2];
|
||||
unsigned char ProcessorVersion;
|
||||
unsigned char Voltage;
|
||||
unsigned short ExternalClock;
|
||||
unsigned short MaxSpeed;
|
||||
unsigned short CurrentSpeed;
|
||||
unsigned char Status;
|
||||
unsigned char ProcessorUpgrade;
|
||||
unsigned short L1CacheHandle;
|
||||
unsigned short L2CacheHandle;
|
||||
unsigned short L3CacheHandle;
|
||||
unsigned char SerialNumber;
|
||||
unsigned char AssetTag;
|
||||
unsigned char PartNumber;
|
||||
unsigned char CoreCount;
|
||||
unsigned char CoreEnabled;
|
||||
unsigned char ThreadCount;
|
||||
unsigned short ProcessorCharacteristics;
|
||||
unsigned short ProcessorFamily2;
|
||||
unsigned short CoreCount2;
|
||||
unsigned short CoreEnabled2;
|
||||
unsigned short ThreadCount2;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSMemoryDevice
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned char PhysicalMemoryArrayHandle;
|
||||
unsigned char MemoryErrorInformationHandle;
|
||||
unsigned short TotalWidth;
|
||||
unsigned short DataWidth;
|
||||
unsigned short Size;
|
||||
unsigned char FormFactor;
|
||||
unsigned char DeviceSet;
|
||||
unsigned char DeviceLocator;
|
||||
unsigned char BankLocator;
|
||||
unsigned char MemoryType;
|
||||
unsigned short TypeDetail;
|
||||
unsigned short Speed;
|
||||
unsigned char Manufacturer;
|
||||
unsigned char SerialNumber;
|
||||
unsigned char AssetTag;
|
||||
unsigned char PartNumber;
|
||||
unsigned char Attributes;
|
||||
unsigned short ExtendedSize;
|
||||
unsigned short ConfiguredMemoryClockSpeed;
|
||||
unsigned short MinimumVoltage;
|
||||
unsigned short MaximumVoltage;
|
||||
unsigned short ConfiguredVoltage;
|
||||
unsigned char MemoryTechnology;
|
||||
unsigned char OperatingModeCapability;
|
||||
unsigned char FirmwareVersion;
|
||||
unsigned char ModuleManufacturerID;
|
||||
unsigned char ModuleProductID;
|
||||
unsigned char MemorySubsystemControllerManufacturerID;
|
||||
unsigned char MemorySubsystemControllerProductID;
|
||||
unsigned short NonVolatileSize;
|
||||
unsigned short VolatileSize;
|
||||
unsigned short CacheSize;
|
||||
unsigned short LogicalSize;
|
||||
unsigned char ExtendedSpeed;
|
||||
unsigned char ExtendedConfiguredMemorySpeed;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSMemoryArrayMappedAddress
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned int StartingAddress;
|
||||
unsigned int EndingAddress;
|
||||
unsigned short MemoryArrayHandle;
|
||||
unsigned char PartitionWidth;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSMemoryDeviceMappedAddress
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned int StartingAddress;
|
||||
unsigned int EndingAddress;
|
||||
unsigned short MemoryDeviceHandle;
|
||||
unsigned short MemoryArrayMappedAddressHandle;
|
||||
unsigned char PartitionRowPosition;
|
||||
unsigned char InterleavePosition;
|
||||
unsigned char InterleavedDataDepth;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
struct SMBIOSMemoryArray
|
||||
{
|
||||
SMBIOSHeader Header;
|
||||
unsigned char Location;
|
||||
unsigned char Use;
|
||||
unsigned char MemoryErrorCorrection;
|
||||
unsigned int MaximumCapacity;
|
||||
unsigned short MemoryErrorInformationHandle;
|
||||
unsigned short NumberOfMemoryDevices;
|
||||
|
||||
const char *GetString(unsigned char Index)
|
||||
{
|
||||
char *Str = (char *)((unsigned long)this + this->Header.Length);
|
||||
Index--;
|
||||
if (Index == 0 || Index > 10)
|
||||
return Str;
|
||||
for (unsigned char i = 0; i < Index; i++)
|
||||
Str = SMBIOSNextString(Str);
|
||||
return Str;
|
||||
}
|
||||
};
|
||||
|
||||
bool CheckSMBIOS();
|
||||
SMBIOSEntryPoint *GetSMBIOSEntryPoint();
|
||||
void *GetSMBIOSHeader(SMBIOSType Type);
|
||||
SMBIOSBIOSInformation *GetBIOSInformation();
|
||||
SMBIOSSystemInformation *GetSystemInformation();
|
||||
SMBIOSBaseBoardInformation *GetBaseBoardInformation();
|
||||
SMBIOSProcessorInformation *GetProcessorInformation();
|
||||
SMBIOSMemoryArray *GetMemoryArray();
|
||||
SMBIOSMemoryDevice *GetMemoryDevice();
|
||||
SMBIOSMemoryArrayMappedAddress *GetMemoryArrayMappedAddress();
|
||||
SMBIOSMemoryDeviceMappedAddress *GetMemoryDeviceMappedAddress();
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_SMBIOS_H__
|
94
Kernel/Core/ubsan.h
Normal file
94
Kernel/Core/ubsan.h
Normal file
@ -0,0 +1,94 @@
|
||||
#ifndef __FENNIX_KERNEL_UBSAN_H__
|
||||
#define __FENNIX_KERNEL_UBSAN_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
struct source_location
|
||||
{
|
||||
const char *file;
|
||||
uint32_t line;
|
||||
uint32_t column;
|
||||
};
|
||||
|
||||
struct type_descriptor
|
||||
{
|
||||
uint16_t kind;
|
||||
uint16_t info;
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct type_mismatch_v1_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *type;
|
||||
uint8_t alignment;
|
||||
uint8_t type_check_kind;
|
||||
};
|
||||
|
||||
struct out_of_bounds_info
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor left_type;
|
||||
struct type_descriptor right_type;
|
||||
};
|
||||
|
||||
struct overflow_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
struct negative_vla_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
struct invalid_value_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
struct nonnull_return_data
|
||||
{
|
||||
struct source_location location;
|
||||
};
|
||||
|
||||
struct nonnull_arg_data
|
||||
{
|
||||
struct source_location location;
|
||||
};
|
||||
|
||||
struct unreachable_data
|
||||
{
|
||||
struct source_location location;
|
||||
};
|
||||
|
||||
struct invalid_builtin_data
|
||||
{
|
||||
struct source_location location;
|
||||
uint8_t kind;
|
||||
};
|
||||
|
||||
struct array_out_of_bounds_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *array_type;
|
||||
struct type_descriptor *index_type;
|
||||
};
|
||||
|
||||
struct shift_out_of_bounds_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *left_type;
|
||||
struct type_descriptor *right_type;
|
||||
};
|
||||
|
||||
struct dynamic_type_cache_miss_data
|
||||
{
|
||||
struct source_location location;
|
||||
struct type_descriptor *type;
|
||||
};
|
||||
|
||||
#endif // !__FENNIX_KERNEL_UBSAN_H__
|
Reference in New Issue
Block a user