Update kernel

This commit is contained in:
Alex 2023-08-06 04:53:14 +03:00
parent 3b65386399
commit 2c51e4432f
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
181 changed files with 21873 additions and 21475 deletions

View File

@ -42,6 +42,18 @@
], ],
"description": "Create kernel documentation brief." "description": "Create kernel documentation brief."
}, },
"For Iteratoion": {
"prefix": [
"foritr",
],
"body": [
"forItr(${1:itr}, ${2:container})",
"{",
"\t$0",
"}"
],
"description": "Create for loop with iterator."
},
"License": { "License": {
"prefix": [ "prefix": [
"license", "license",
@ -66,4 +78,4 @@
], ],
"description": "Create kernel license." "description": "Create kernel license."
} }
} }

View File

@ -11,6 +11,7 @@
"defines": [ "defines": [
"__debug_vscode__", "__debug_vscode__",
"KERNEL_NAME=\"Fennix\"", "KERNEL_NAME=\"Fennix\"",
"KERNEL_ARCH=\"amd64\"",
"KERNEL_VERSION=\"1.0\"", "KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"", "GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"", "GIT_COMMIT_SHORT=\"0000000\"",
@ -84,6 +85,7 @@
"defines": [ "defines": [
"__debug_vscode__", "__debug_vscode__",
"KERNEL_NAME=\"Fennix\"", "KERNEL_NAME=\"Fennix\"",
"KERNEL_ARCH=\"i386\"",
"KERNEL_VERSION=\"1.0\"", "KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"", "GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"", "GIT_COMMIT_SHORT=\"0000000\"",
@ -160,6 +162,7 @@
"defines": [ "defines": [
"__debug_vscode__", "__debug_vscode__",
"KERNEL_NAME=\"Fennix\"", "KERNEL_NAME=\"Fennix\"",
"KERNEL_ARCH=\"aarch64\"",
"KERNEL_VERSION=\"1.0\"", "KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"", "GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"", "GIT_COMMIT_SHORT=\"0000000\"",

78
.vscode/launch.json vendored
View File

@ -74,8 +74,82 @@
"description": "Load /bin/init." "description": "Load /bin/init."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/lib/ld.so", "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom",
"description": "Load /lib/ld.so." "description": "Load /usr/bin/doom."
},
],
},
{
"name": "Attach to VM w/init",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/kernel.fsys",
"cwd": "${workspaceFolder}",
"args": [],
"targetArchitecture": "x64",
"MIMode": "gdb",
"miDebuggerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gdb",
"miDebuggerArgs": "",
"externalConsole": false,
"additionalSOLibSearchPath": "${workspaceFolder}",
"customLaunchSetupCommands": [
{
"text": "target remote localhost:1234",
"description": "Connect to QEMU remote debugger"
}
],
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "set breakpoint pending on",
"description": "Make breakpoint pending on future shared library load."
},
{
"text": "file ${workspaceFolder}/kernel.fsys",
"description": "Load binary."
},
{
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/init",
"description": "Load /bin/init."
},
],
},
{
"name": "Attach to VM w/doom",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/kernel.fsys",
"cwd": "${workspaceFolder}",
"args": [],
"targetArchitecture": "x64",
"MIMode": "gdb",
"miDebuggerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gdb",
"miDebuggerArgs": "",
"externalConsole": false,
"additionalSOLibSearchPath": "${workspaceFolder}",
"customLaunchSetupCommands": [
{
"text": "target remote localhost:1234",
"description": "Connect to QEMU remote debugger"
}
],
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "set breakpoint pending on",
"description": "Make breakpoint pending on future shared library load."
},
{
"text": "file ${workspaceFolder}/kernel.fsys",
"description": "Load binary."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom", "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom",

View File

@ -18,6 +18,7 @@
#include <types.h> #include <types.h>
#include <memory.hpp> #include <memory.hpp>
#include <elf.h>
#include <io.h> #include <io.h>
#include "multiboot2.h" #include "multiboot2.h"
@ -50,7 +51,6 @@ EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info)
if (tmp != (tmp | 3)) if (tmp != (tmp | 3))
outb(0x61, tmp | 3); outb(0x61, tmp | 3);
int pos = 0;
auto InfoAddress = Info; auto InfoAddress = Info;
for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8); for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
; ;
@ -220,7 +220,7 @@ EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info)
mb2binfo.Kernel.Symbols.Num = elf->num; mb2binfo.Kernel.Symbols.Num = elf->num;
mb2binfo.Kernel.Symbols.EntSize = elf->entsize; mb2binfo.Kernel.Symbols.EntSize = elf->entsize;
mb2binfo.Kernel.Symbols.Shndx = elf->shndx; mb2binfo.Kernel.Symbols.Shndx = elf->shndx;
mb2binfo.Kernel.Symbols.Sections = (uintptr_t)&elf->sections; mb2binfo.Kernel.Symbols.Sections = r_cst(uintptr_t, elf->sections);
break; break;
} }
case MULTIBOOT_TAG_TYPE_APM: case MULTIBOOT_TAG_TYPE_APM:

View File

@ -82,8 +82,8 @@ namespace ACPI
{ {
TaskManager->CreateThread(TaskManager->CreateProcess(nullptr, TaskManager->CreateThread(TaskManager->CreateProcess(nullptr,
"Shutdown", "Shutdown",
Tasking::TaskTrustLevel::Kernel), Tasking::TaskExecutionMode::Kernel),
(Tasking::IP)KST_Shutdown); Tasking::IP(KST_Shutdown));
} }
else else
KernelShutdownThread(false); KernelShutdownThread(false);

View File

@ -22,402 +22,408 @@
namespace Memory namespace Memory
{ {
bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type) bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type)
{ {
// 0x1000 aligned // 0x1000 aligned
uintptr_t Address = (uintptr_t)VirtualAddress; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr; PageDirectoryEntryPtr *PDE = nullptr;
PageTableEntryPtr *PTE = nullptr; PageTableEntryPtr *PTE = nullptr;
if ((PML4->raw & Flag) > 0) if ((PML4->raw & Flag) > 0)
{ {
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12); PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12);
if (PDPTE) if (PDPTE)
{ {
if ((PDPTE->Entries[Index.PDPTEIndex].Present)) if ((PDPTE->Entries[Index.PDPTEIndex].Present))
{ {
if (Type == MapType::OneGB && PDPTE->Entries[Index.PDPTEIndex].PageSize) if (Type == MapType::OneGiB && PDPTE->Entries[Index.PDPTEIndex].PageSize)
return true; return true;
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE) if (PDE)
{ {
if (Type == MapType::TwoMB && PDE->Entries[Index.PDEIndex].PageSize) if (Type == MapType::TwoMiB && PDE->Entries[Index.PDEIndex].PageSize)
return true; return true;
if ((PDE->Entries[Index.PDEIndex].Present)) if ((PDE->Entries[Index.PDEIndex].Present))
{ {
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
if (PTE) if (PTE)
{ {
if ((PTE->Entries[Index.PTEIndex].Present)) if ((PTE->Entries[Index.PTEIndex].Present))
return true; return true;
} }
} }
} }
} }
} }
} }
return false; return false;
} }
void *Virtual::GetPhysical(void *VirtualAddress) void *Virtual::GetPhysical(void *VirtualAddress)
{ {
// 0x1000 aligned // 0x1000 aligned
uintptr_t Address = (uintptr_t)VirtualAddress; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr; PageDirectoryEntryPtr *PDE = nullptr;
PageTableEntryPtr *PTE = nullptr; PageTableEntryPtr *PTE = nullptr;
if (PML4->Present) if (PML4->Present)
{ {
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12); PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12);
if (PDPTE) if (PDPTE)
{ {
if (PDPTE->Entries[Index.PDPTEIndex].Present) if (PDPTE->Entries[Index.PDPTEIndex].Present)
{ {
if (PDPTE->Entries[Index.PDPTEIndex].PageSize) if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
return (void *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); return (void *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE) if (PDE)
{ {
if (PDE->Entries[Index.PDEIndex].Present) if (PDE->Entries[Index.PDEIndex].Present)
{ {
if (PDE->Entries[Index.PDEIndex].PageSize) if (PDE->Entries[Index.PDEIndex].PageSize)
return (void *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); return (void *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
if (PTE) if (PTE)
{ {
if (PTE->Entries[Index.PTEIndex].Present) if (PTE->Entries[Index.PTEIndex].Present)
return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12); return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12);
} }
} }
} }
} }
} }
} }
return nullptr; return nullptr;
} }
Virtual::MapType Virtual::GetMapType(void *VirtualAddress) Virtual::MapType Virtual::GetMapType(void *VirtualAddress)
{ {
// 0x1000 aligned // 0x1000 aligned
uintptr_t Address = (uintptr_t)VirtualAddress; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr; PageDirectoryEntryPtr *PDE = nullptr;
PageTableEntryPtr *PTE = nullptr; PageTableEntryPtr *PTE = nullptr;
if (PML4->Present) if (PML4->Present)
{ {
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12); PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12);
if (PDPTE) if (PDPTE)
{ {
if (PDPTE->Entries[Index.PDPTEIndex].Present) if (PDPTE->Entries[Index.PDPTEIndex].Present)
{ {
if (PDPTE->Entries[Index.PDPTEIndex].PageSize) if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
return MapType::OneGB; return MapType::OneGiB;
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12); PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE) if (PDE)
{ {
if (PDE->Entries[Index.PDEIndex].Present) if (PDE->Entries[Index.PDEIndex].Present)
{ {
if (PDE->Entries[Index.PDEIndex].PageSize) if (PDE->Entries[Index.PDEIndex].PageSize)
return MapType::TwoMB; return MapType::TwoMiB;
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12); PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
if (PTE) if (PTE)
{ {
if (PTE->Entries[Index.PTEIndex].Present) if (PTE->Entries[Index.PTEIndex].Present)
return MapType::FourKB; return MapType::FourKiB;
} }
} }
} }
} }
} }
} }
return MapType::NoMapType; return MapType::NoMapType;
} }
PageMapLevel5 *Virtual::GetPML5(void *VirtualAddress, MapType Type) PageMapLevel5 *Virtual::GetPML5(void *VirtualAddress, MapType Type)
{ {
stub; /* TODO */ UNUSED(VirtualAddress);
return nullptr; UNUSED(Type);
} stub; /* TODO */
return nullptr;
}
PageMapLevel4 *Virtual::GetPML4(void *VirtualAddress, MapType Type) PageMapLevel4 *Virtual::GetPML4(void *VirtualAddress, MapType Type)
{ {
uintptr_t Address = (uintptr_t)VirtualAddress; UNUSED(Type);
Address &= 0xFFFFFFFFFFFFF000; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (PML4->Present) if (PML4->Present)
return PML4; return PML4;
return nullptr; return nullptr;
} }
PageDirectoryPointerTableEntry *Virtual::GetPDPTE(void *VirtualAddress, MapType Type) PageDirectoryPointerTableEntry *Virtual::GetPDPTE(void *VirtualAddress, MapType Type)
{ {
uintptr_t Address = (uintptr_t)VirtualAddress; UNUSED(Type);
Address &= 0xFFFFFFFFFFFFF000; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
return nullptr; return nullptr;
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (PDPTE->Present) if (PDPTE->Present)
return PDPTE; return PDPTE;
return nullptr; return nullptr;
} }
PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type) PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type)
{ {
uintptr_t Address = (uintptr_t)VirtualAddress; UNUSED(Type);
Address &= 0xFFFFFFFFFFFFF000; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
return nullptr; return nullptr;
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE->Present) if (!PDPTE->Present)
return nullptr; return nullptr;
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (PDE->Present) if (PDE->Present)
return PDE; return PDE;
return nullptr; return nullptr;
} }
PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type) PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type)
{ {
uintptr_t Address = (uintptr_t)VirtualAddress; UNUSED(Type);
Address &= 0xFFFFFFFFFFFFF000; uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
return nullptr; return nullptr;
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE->Present) if (!PDPTE->Present)
return nullptr; return nullptr;
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (!PDE->Present) if (!PDE->Present)
return nullptr; return nullptr;
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
if (PTE->Present) if (PTE->Present)
return PTE; return PTE;
return nullptr; return nullptr;
} }
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
if (unlikely(!this->Table)) if (unlikely(!this->Table))
{ {
error("No page table"); error("No page table");
return; return;
} }
Flags |= PTFlag::P; Flags |= PTFlag::P;
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); 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 // 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; uint64_t DirectoryFlags = Flags & 0x3F;
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
if (!PML4->Present) if (!PML4->Present)
{ {
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1)); PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1));
memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr)); memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr));
PML4->Present = true; PML4->Present = true;
PML4->SetAddress((uintptr_t)PDPTEPtr >> 12); PML4->SetAddress((uintptr_t)PDPTEPtr >> 12);
} }
else else
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12); PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12);
PML4->raw |= DirectoryFlags; PML4->raw |= DirectoryFlags;
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (Type == MapType::OneGB) if (Type == MapType::OneGiB)
{ {
PDPTE->raw |= Flags; PDPTE->raw |= Flags;
PDPTE->PageSize = true; PDPTE->PageSize = true;
PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12); PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress); debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress);
return; return;
} }
PageDirectoryEntryPtr *PDEPtr = nullptr; PageDirectoryEntryPtr *PDEPtr = nullptr;
if (!PDPTE->Present) if (!PDPTE->Present)
{ {
PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1)); PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1));
memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr)); memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr));
PDPTE->Present = true; PDPTE->Present = true;
PDPTE->SetAddress((uintptr_t)PDEPtr >> 12); PDPTE->SetAddress((uintptr_t)PDEPtr >> 12);
} }
else else
PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PDPTE->raw |= DirectoryFlags; PDPTE->raw |= DirectoryFlags;
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (Type == MapType::TwoMB) if (Type == MapType::TwoMiB)
{ {
PDE->raw |= Flags; PDE->raw |= Flags;
PDE->PageSize = true; PDE->PageSize = true;
PDE->SetAddress((uintptr_t)PhysicalAddress >> 12); PDE->SetAddress((uintptr_t)PhysicalAddress >> 12);
debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress); debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress);
return; return;
} }
PageTableEntryPtr *PTEPtr = nullptr; PageTableEntryPtr *PTEPtr = nullptr;
if (!PDE->Present) if (!PDE->Present)
{ {
PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1)); PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1));
memset(PTEPtr, 0, sizeof(PageTableEntryPtr)); memset(PTEPtr, 0, sizeof(PageTableEntryPtr));
PDE->Present = true; PDE->Present = true;
PDE->SetAddress((uintptr_t)PTEPtr >> 12); PDE->SetAddress((uintptr_t)PTEPtr >> 12);
} }
else else
PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
PDE->raw |= DirectoryFlags; PDE->raw |= DirectoryFlags;
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
PTE->Present = true; PTE->Present = true;
PTE->raw |= Flags; PTE->raw |= Flags;
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
#if defined(a64) #if defined(a64)
CPU::x64::invlpg(VirtualAddress); CPU::x64::invlpg(VirtualAddress);
#elif defined(a32) #elif defined(a32)
CPU::x32::invlpg(VirtualAddress); CPU::x32::invlpg(VirtualAddress);
#elif defined(aa64) #elif defined(aa64)
asmv("dsb sy"); asmv("dsb sy");
asmv("tlbi vae1is, %0" asmv("tlbi vae1is, %0"
: :
: "r"(VirtualAddress) : "r"(VirtualAddress)
: "memory"); : "memory");
asmv("dsb sy"); asmv("dsb sy");
asmv("isb"); asmv("isb");
#endif #endif
#ifdef DEBUG #ifdef DEBUG
/* https://stackoverflow.com/a/3208376/9352057 */ /* https://stackoverflow.com/a/3208376/9352057 */
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte) \ #define BYTE_TO_BINARY(byte) \
(byte & 0x80 ? '1' : '0'), \ (byte & 0x80 ? '1' : '0'), \
(byte & 0x40 ? '1' : '0'), \ (byte & 0x40 ? '1' : '0'), \
(byte & 0x20 ? '1' : '0'), \ (byte & 0x20 ? '1' : '0'), \
(byte & 0x10 ? '1' : '0'), \ (byte & 0x10 ? '1' : '0'), \
(byte & 0x08 ? '1' : '0'), \ (byte & 0x08 ? '1' : '0'), \
(byte & 0x04 ? '1' : '0'), \ (byte & 0x04 ? '1' : '0'), \
(byte & 0x02 ? '1' : '0'), \ (byte & 0x02 ? '1' : '0'), \
(byte & 0x01 ? '1' : '0') (byte & 0x01 ? '1' : '0')
if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails
warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags)); warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags));
#endif #endif
} }
void Virtual::Unmap(void *VirtualAddress, MapType Type) void Virtual::Unmap(void *VirtualAddress, MapType Type)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
if (!this->Table) if (!this->Table)
{ {
error("No page table"); error("No page table");
return; return;
} }
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
{ {
warn("Page %#lx not present", PML4->GetAddress()); warn("Page %#lx not present", PML4->GetAddress());
return; return;
} }
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE->Present) if (!PDPTE->Present)
{ {
warn("Page %#lx not present", PDPTE->GetAddress()); warn("Page %#lx not present", PDPTE->GetAddress());
return; return;
} }
if (Type == MapType::OneGB && PDPTE->PageSize) if (Type == MapType::OneGiB && PDPTE->PageSize)
{ {
PDPTE->Present = false; PDPTE->Present = false;
return; return;
} }
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12); PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12);
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (!PDE->Present) if (!PDE->Present)
{ {
warn("Page %#lx not present", PDE->GetAddress()); warn("Page %#lx not present", PDE->GetAddress());
return; return;
} }
if (Type == MapType::TwoMB && PDE->PageSize) if (Type == MapType::TwoMiB && PDE->PageSize)
{ {
PDE->Present = false; PDE->Present = false;
return; return;
} }
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12); PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12);
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
if (!PTE.Present) if (!PTE.Present)
{ {
warn("Page %#lx not present", PTE.GetAddress()); warn("Page %#lx not present", PTE.GetAddress());
return; return;
} }
PTE.Present = false; PTE.Present = false;
PTEPtr->Entries[Index.PTEIndex] = PTE; PTEPtr->Entries[Index.PTEIndex] = PTE;
#if defined(a64) #if defined(a64)
CPU::x64::invlpg(VirtualAddress); CPU::x64::invlpg(VirtualAddress);
#elif defined(a32) #elif defined(a32)
CPU::x32::invlpg(VirtualAddress); CPU::x32::invlpg(VirtualAddress);
#elif defined(aa64) #elif defined(aa64)
asmv("dsb sy"); asmv("dsb sy");
asmv("tlbi vae1is, %0" asmv("tlbi vae1is, %0"
: :
: "r"(VirtualAddress) : "r"(VirtualAddress)
: "memory"); : "memory");
asmv("dsb sy"); asmv("dsb sy");
asmv("isb"); asmv("isb");
#endif #endif
} }
} }

View File

@ -31,11 +31,11 @@ extern "C" void SystemCallHandlerStub();
extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHandlerStub() extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHandlerStub()
{ {
asmv("swapgs\n"); /* Swap GS to get the TCB */ asmv("swapgs\n"); /* Swap GS to get the gsTCB */
asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to TCB->TempStack */ asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to gsTCB->TempStack */
asmv("mov %gs:0x0, %rsp\n"); /* Get TCB->SystemCallStack and set it as rsp */ asmv("mov %gs:0x0, %rsp\n"); /* Get gsTCB->SystemCallStack and set it as rsp */
asmv("push $0x1b\n"); /* Push user data segment for SyscallsFrame */ asmv("push $0x1b\n"); /* Push user data segment for SyscallsFrame */
asmv("push %gs:0x8\n"); /* Push TCB->TempStack (old rsp) for SyscallsFrame */ asmv("push %gs:0x8\n"); /* Push gsTCB->TempStack (old rsp) for SyscallsFrame */
asmv("push %r11\n"); /* Push the flags for SyscallsFrame */ asmv("push %r11\n"); /* Push the flags for SyscallsFrame */
asmv("push $0x23\n"); /* Push user code segment for SyscallsFrame */ asmv("push $0x23\n"); /* Push user code segment for SyscallsFrame */
asmv("push %rcx\n"); /* Push the return address for SyscallsFrame + sysretq (https://www.felixcloutier.com/x86/sysret) */ asmv("push %rcx\n"); /* Push the return address for SyscallsFrame + sysretq (https://www.felixcloutier.com/x86/sysret) */
@ -78,7 +78,7 @@ extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHand
"pop %rcx\n" "pop %rcx\n"
"pop %rbx\n"); "pop %rbx\n");
/* Restore rsp from TCB->TempStack */ /* Restore rsp from gsTCB->TempStack */
asmv("mov %gs:0x8, %rsp\n"); asmv("mov %gs:0x8, %rsp\n");
#ifdef DEBUG #ifdef DEBUG
/* Easier to debug stacks */ /* Easier to debug stacks */

View File

@ -24,249 +24,247 @@
namespace GlobalDescriptorTable namespace GlobalDescriptorTable
{ {
static GlobalDescriptorTableEntries GDTEntriesTemplate = { static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null = .Null = {
{ .Limit0 = 0x0,
.Limit0 = 0x0, .BaseLow = 0x0,
.BaseLow = 0x0, .BaseMiddle = 0x0,
.BaseMiddle = 0x0, .Access = {.Raw = 0x0},
.Access = {.Raw = 0x0}, // .Limit1 = 0x0,
// .Limit1 = 0x0, .Flags = {.Raw = 0x0},
.Flags = {.Raw = 0x0}, .BaseHigh = 0x0,
.BaseHigh = 0x0, },
},
.Code = .Code = {
{ .Limit0 = 0xFFFF,
.Limit0 = 0xFFFF, .BaseLow = 0x0,
.BaseLow = 0x0, .BaseMiddle = 0x0,
.BaseMiddle = 0x0, .Access = {
.Access = { .A = 0,
.A = 0, .RW = 1,
.RW = 1, .DC = 0,
.DC = 0, .E = 1,
.E = 1, .S = 1,
.S = 1, .DPL = 0,
.DPL = 0, .P = 1,
.P = 1, },
}, // .Limit1 = 0xF,
// .Limit1 = 0xF, .Flags = {
.Flags = { .Reserved = 0xF, /* Workaround for Limit1 */
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 1, .L = 1,
.DB = 0, .DB = 0,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.Data = { .Data = {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 0, .E = 0,
.S = 1, .S = 1,
.DPL = 0, .DPL = 0,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 0, .L = 0,
.DB = 1, .DB = 1,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.UserData = { .UserData = {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 0, .E = 0,
.S = 1, .S = 1,
.DPL = 3, .DPL = 3,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 0, .L = 0,
.DB = 1, .DB = 1,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.UserCode = { .UserCode = {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 1, .E = 1,
.S = 1, .S = 1,
.DPL = 3, .DPL = 3,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 1, .L = 1,
.DB = 0, .DB = 0,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.TaskStateSegment = {}, .TaskStateSegment = {},
}; };
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16); GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16); GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
TaskStateSegment tss[MAX_CPU] = { TaskStateSegment tss[MAX_CPU] = {
0, 0,
{0, 0, 0}, {0, 0, 0},
0, 0,
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
0, 0,
0, 0,
0, 0,
}; };
void *CPUStackPointer[MAX_CPU]; void *CPUStackPointer[MAX_CPU];
SafeFunction void Init(int Core) SafeFunction void Init(int Core)
{ {
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries)); memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]}; gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
debug("GDT: %#lx", &gdt[Core]); debug("GDT: %#lx", &gdt[Core]);
debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_KERNEL_CODE, GDT_KERNEL_CODE,
GDTEntries[Core].Code.Limit0, GDTEntries[Core].Code.Limit0,
GDTEntries[Core].Code.BaseLow, GDTEntries[Core].Code.BaseLow,
GDTEntries[Core].Code.BaseMiddle, GDTEntries[Core].Code.BaseMiddle,
GDTEntries[Core].Code.Access.Raw, GDTEntries[Core].Code.Access.Raw,
GDTEntries[Core].Code.Flags.Reserved, GDTEntries[Core].Code.Flags.Reserved,
GDTEntries[Core].Code.Flags.Raw & ~0xF, GDTEntries[Core].Code.Flags.Raw & ~0xF,
GDTEntries[Core].Code.BaseHigh); GDTEntries[Core].Code.BaseHigh);
debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_KERNEL_DATA, GDT_KERNEL_DATA,
GDTEntries[Core].Data.Limit0, GDTEntries[Core].Data.Limit0,
GDTEntries[Core].Data.BaseLow, GDTEntries[Core].Data.BaseLow,
GDTEntries[Core].Data.BaseMiddle, GDTEntries[Core].Data.BaseMiddle,
GDTEntries[Core].Data.Access.Raw, GDTEntries[Core].Data.Access.Raw,
GDTEntries[Core].Data.Flags.Reserved, GDTEntries[Core].Data.Flags.Reserved,
GDTEntries[Core].Data.Flags.Raw & ~0xF, GDTEntries[Core].Data.Flags.Raw & ~0xF,
GDTEntries[Core].Data.BaseHigh); GDTEntries[Core].Data.BaseHigh);
debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_USER_CODE, GDT_USER_CODE,
GDTEntries[Core].UserCode.Limit0, GDTEntries[Core].UserCode.Limit0,
GDTEntries[Core].UserCode.BaseLow, GDTEntries[Core].UserCode.BaseLow,
GDTEntries[Core].UserCode.BaseMiddle, GDTEntries[Core].UserCode.BaseMiddle,
GDTEntries[Core].UserCode.Access.Raw, GDTEntries[Core].UserCode.Access.Raw,
GDTEntries[Core].UserCode.Flags.Reserved, GDTEntries[Core].UserCode.Flags.Reserved,
GDTEntries[Core].UserCode.Flags.Raw & ~0xF, GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
GDTEntries[Core].UserCode.BaseHigh); GDTEntries[Core].UserCode.BaseHigh);
debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_USER_DATA, GDT_USER_DATA,
GDTEntries[Core].UserData.Limit0, GDTEntries[Core].UserData.Limit0,
GDTEntries[Core].UserData.BaseLow, GDTEntries[Core].UserData.BaseLow,
GDTEntries[Core].UserData.BaseMiddle, GDTEntries[Core].UserData.BaseMiddle,
GDTEntries[Core].UserData.Access.Raw, GDTEntries[Core].UserData.Access.Raw,
GDTEntries[Core].UserData.Flags.Reserved, GDTEntries[Core].UserData.Flags.Reserved,
GDTEntries[Core].UserData.Flags.Raw & ~0xF, GDTEntries[Core].UserData.Flags.Raw & ~0xF,
GDTEntries[Core].UserData.BaseHigh); GDTEntries[Core].UserData.BaseHigh);
CPU::x64::lgdt(&gdt[Core]); CPU::x64::lgdt(&gdt[Core]);
asmv("movq %%rsp, %%rax\n" asmv("movq %%rsp, %%rax\n"
"pushq $16\n" "pushq $16\n"
"pushq %%rax\n" "pushq %%rax\n"
"pushfq\n" "pushfq\n"
"pushq $8\n" "pushq $8\n"
"pushq $1f\n" "pushq $1f\n"
"iretq\n" "iretq\n"
"1:\n" "1:\n"
"movw $16, %%ax\n" "movw $16, %%ax\n"
"movw %%ax, %%ds\n" "movw %%ax, %%ds\n"
"movw %%ax, %%es\n" :: "movw %%ax, %%es\n" ::
: "memory", "rax"); : "memory", "rax");
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE); memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core, debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE, CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1)); TO_PAGES(STACK_SIZE + 1));
uintptr_t Base = (uintptr_t)&tss[Core]; uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment); size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF; gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF; gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 0xFF; gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 0xFF;
gdt[Core].Entries->TaskStateSegment.BaseHigh = (Base >> 24) & 0xFF; gdt[Core].Entries->TaskStateSegment.BaseHigh = (Base >> 24) & 0xFF;
gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF); gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1}; gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF); gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment); tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE; tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0; tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0; tss[Core].StackPointer[2] = 0x0;
for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++) for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
{ {
void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE; tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE;
memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE); memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE); debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
} }
CPU::x64::ltr(GDT_TSS); CPU::x64::ltr(GDT_TSS);
debug("Global Descriptor Table initialized"); debug("Global Descriptor Table initialized");
} }
SafeFunction void SetKernelStack(void *Stack) SafeFunction void SetKernelStack(void *Stack)
{ {
long CPUID = GetCurrentCPU()->ID; long CPUID = GetCurrentCPU()->ID;
if (Stack != nullptr) if (Stack != nullptr)
tss[CPUID].StackPointer[0] = (uint64_t)Stack; tss[CPUID].StackPointer[0] = (uint64_t)Stack;
else else
tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE; tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE;
/* /*
FIXME: There's a bug in kernel which if FIXME: There's a bug in kernel which if
we won't update "tss[CPUID].StackPointer[0]" we won't update "tss[CPUID].StackPointer[0]"
with the current stack pointer, the kernel with the current stack pointer, the kernel
will crash. will crash.
*/ */
asmv("mov %%rsp, %0" asmv("mov %%rsp, %0"
: "=r"(tss[CPUID].StackPointer[0])); : "=r"(tss[CPUID].StackPointer[0]));
} }
void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; } void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; }
} }

View File

@ -22,197 +22,299 @@
namespace GlobalDescriptorTable namespace GlobalDescriptorTable
{ {
struct TaskStateSegmentEntry struct TaskStateSegmentEntry
{ {
/* LOW */ /* LOW */
uint16_t Limit; uint16_t Limit;
uint16_t BaseLow; uint16_t BaseLow;
uint8_t BaseMiddle; uint8_t BaseMiddle;
union GlobalDescriptorTableAccess union GlobalDescriptorTableAccess
{ {
struct struct
{ {
/** @brief Access bit. /**
* @note The CPU sets this bit to 1 when the segment is accessed. * Access bit.
*/ *
uint8_t A : 1; * @note The CPU sets this bit to 1 when the segment
* is accessed.
*/
uint8_t A : 1;
/** @brief Readable bit for code segments, writable bit for data segments. /**
* @details For code segments, this bit must be 1 for the segment to be readable. * Readable bit for code segments, writable bit for data
* @details For data segments, this bit must be 1 for the segment to be writable. * segments.
*/ *
uint8_t RW : 1; * Code Segment:
* This bit must be 1 for the segment to be readable.
*
* Data Segment:
* This bit must be 1 for the segment to be writable.
*/
uint8_t RW : 1;
/** @brief Direction bit for data segments, conforming bit for code segments. /**
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses). * Direction bit for data segments, conforming bit for
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level. * code segments.
*/ *
uint8_t DC : 1; * Code Segment:
* This bit must be 1 for code in the segment to be
* able to be executed from an equal or lower privilege
* level.
*
* Data Segment:
* This bit must be 1 for the segment to grow up (higher
* addresses).
*/
uint8_t DC : 1;
/** @brief Executable bit. /**
* @details This bit must be 1 for code-segment descriptors. * Executable bit.
* @details This bit must be 0 for data-segment and system descriptors. *
*/ * This bit must be 1 for code-segment descriptors.
uint8_t E : 1; *
* This bit must be 0 for data-segment and system
* descriptors.
*/
uint8_t E : 1;
/** @brief Descriptor type. /**
* @details This bit must be 0 for system descriptors. * Descriptor type.
* @details This bit must be 1 for code or data segment descriptor. *
*/ * This bit must be 0 for system descriptors.
uint8_t S : 1; *
* This bit must be 1 for code or data segment
* descriptor.
*/
uint8_t S : 1;
/** @brief Descriptor privilege level. /**
* @details This field determines the privilege level of the segment. * Descriptor privilege level.
* @details 0 = kernel mode, 3 = user mode. *
*/ * This field determines the privilege level of the
uint8_t DPL : 2; * segment.
*
* 0 = kernel mode
* 3 = user mode
*/
uint8_t DPL : 2;
/** @brief Present bit. /**
* @details This bit must be 1 for all valid descriptors. * Present bit.
*/ *
uint8_t P : 1; * This bit must be 1 for all valid descriptors.
} __packed; */
uint8_t Raw : 8; uint8_t P : 1;
} Access; } __packed;
uint8_t Granularity; uint8_t Raw : 8;
uint8_t BaseHigh; } Access;
/* HIGH */ uint8_t Granularity;
uint32_t BaseUpper; uint8_t BaseHigh;
uint32_t Reserved; /* HIGH */
} __packed; uint32_t BaseUpper;
uint32_t Reserved;
} __packed;
struct TaskStateSegment struct TaskStateSegment
{ {
uint32_t Reserved0 __aligned(16); uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3]; uint64_t StackPointer[3];
uint64_t Reserved1; uint64_t Reserved1;
uint64_t InterruptStackTable[7]; uint64_t InterruptStackTable[7];
uint64_t Reserved2; uint64_t Reserved2;
uint16_t Reserved3; uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset; uint16_t IOMapBaseAddressOffset;
} __packed; } __packed;
struct GlobalDescriptorTableEntry struct GlobalDescriptorTableEntry
{ {
/** @brief Limit 0:15 */ /**
uint16_t Limit0 : 16; * Limit 0:15
*/
uint16_t Limit0 : 16;
/** @brief Low Base 0:15 */ /**
uint16_t BaseLow : 16; * Low Base 0:15
*/
uint16_t BaseLow : 16;
/** @brief Middle Base 16:23 */ /**
uint8_t BaseMiddle : 8; * Middle Base 16:23
*/
uint8_t BaseMiddle : 8;
/** @brief Access */ /**
union GlobalDescriptorTableAccess * Access
{ */
struct union GlobalDescriptorTableAccess
{ {
/** @brief Access bit. struct
* @note The CPU sets this bit to 1 when the segment is accessed. {
*/ /**
uint8_t A : 1; * Access bit.
*
* @note The CPU sets this bit to 1 when the segment
* is accessed.
*/
uint8_t A : 1;
/** @brief Readable bit for code segments, writable bit for data segments. /**
* @details For code segments, this bit must be 1 for the segment to be readable. * Readable bit for code segments, writable bit for
* @details For data segments, this bit must be 1 for the segment to be writable. * data segments.
*/ *
uint8_t RW : 1; * Code Segment:
* This bit must be 1 for the segment to be readable.
*
* Data Segment:
* This bit must be 1 for the segment to be writable.
*/
uint8_t RW : 1;
/** @brief Direction bit for data segments, conforming bit for code segments. /**
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses). * Direction bit for data segments, conforming bit for
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level. * code segments.
*/ *
uint8_t DC : 1; * Code Segment:
* This bit must be 1 for code in the segment to be able
* to be executed from an equal or lower privilege level.
*
* Data Segment:
* This bit must be 1 for the segment to grow up (higher
* addresses).
*/
uint8_t DC : 1;
/** @brief Executable bit. /**
* @details This bit must be 1 for code-segment descriptors. * Executable bit.
* @details This bit must be 0 for data-segment and system descriptors. *
*/ * This bit must be 1 for code-segment descriptors.
uint8_t E : 1; *
* This bit must be 0 for data-segment and
* system descriptors.
*/
uint8_t E : 1;
/** @brief Descriptor type. /**
* @details This bit must be 0 for system descriptors. * Descriptor type.
* @details This bit must be 1 for code or data segment descriptor. *
*/ * This bit must be 0 for system descriptors.
uint8_t S : 1; *
* This bit must be 1 for code or data segment
* descriptor.
*/
uint8_t S : 1;
/** @brief Descriptor privilege level. /**
* @details This field determines the privilege level of the segment. * Descriptor privilege level.
* @details 0 = kernel mode, 3 = user mode. *
*/ * This field determines the privilege level of the
uint8_t DPL : 2; * segment.
*
* 0 = kernel mode
* 3 = user mode
*/
uint8_t DPL : 2;
/** @brief Present bit. /**
* @details This bit must be 1 for all valid descriptors. * Present bit.
*/ *
uint8_t P : 1; * This bit must be 1 for all valid descriptors.
} __packed; */
uint8_t Raw : 8; uint8_t P : 1;
} Access; } __packed;
uint8_t Raw : 8;
} Access;
// /** @brief Limit 16:19 */ // /** Limit 16:19 */
// uint16_t Limit1 : 4;
/** @brief Flags */ // uint16_t Limit1 : 4;
union GlobalDescriptorTableFlags
{
struct
{
uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */
/** @brief Available bit.
* @details This bit is available for use by system software.
*/
uint8_t AVL : 1;
/** @brief Long mode. /**
* @details If the long mode bit is clear, the segment is in 32-bit protected mode. * Flags
* @details If the long mode bit is set, the segment is in 64-bit long mode. */
*/ union GlobalDescriptorTableFlags
uint8_t L : 1; {
struct
{
/* FIXME: Without this, the kernel crashes. */
uint8_t Reserved : 4;
/** @brief Size flag. /**
* @details If the size bit is clear, the segment is in 16-bit protected mode. * Available bit.
* @details If the size bit is set, the segment is in 32-bit protected mode. *
*/ * This bit is available for use by system software.
uint8_t DB : 1; */
uint8_t AVL : 1;
/** @brief Granularity bit. /**
* @details If the granularity bit is clear, the segment limit is in 1 B blocks. * Long mode.
* @details If the granularity bit is set, the segment limit is in 4 KiB blocks. *
*/ * If the long mode bit is clear, the segment is in
uint8_t G : 1; * 32-bit protected mode.
} __packed; *
uint8_t Raw : 8; * If the long mode bit is set, the segment is in
} Flags; * 64-bit long mode.
*/
uint8_t L : 1;
/** @brief High Base 24:31 */ /**
uint8_t BaseHigh : 8; * Size flag.
} __packed; *
* If the size bit is clear, the segment is in
* 16-bit protected mode.
*
* If the size bit is set, the segment is in
* 32-bit protected mode.
*/
uint8_t DB : 1;
struct GlobalDescriptorTableEntries /**
{ * Granularity bit.
GlobalDescriptorTableEntry Null; *
GlobalDescriptorTableEntry Code; * If the granularity bit is clear, the segment limit
GlobalDescriptorTableEntry Data; * is in 1 B blocks.
GlobalDescriptorTableEntry UserData; *
GlobalDescriptorTableEntry UserCode; * If the granularity bit is set, the segment limit is
TaskStateSegmentEntry TaskStateSegment; * in 4 KiB blocks.
} __packed; */
uint8_t G : 1;
} __packed;
uint8_t Raw : 8;
} Flags;
struct GlobalDescriptorTableDescriptor /**
{ * High Base 24:31
/** @brief GDT entries length */ */
uint16_t Length; uint8_t BaseHigh : 8;
/** @brief GDT entries address */ } __packed;
GlobalDescriptorTableEntries *Entries;
} __packed;
extern void *CPUStackPointer[]; struct GlobalDescriptorTableEntries
extern TaskStateSegment tss[]; {
void Init(int Core); GlobalDescriptorTableEntry Null;
void SetKernelStack(void *Stack); GlobalDescriptorTableEntry Code;
void *GetKernelStack(); GlobalDescriptorTableEntry Data;
GlobalDescriptorTableEntry UserData;
GlobalDescriptorTableEntry UserCode;
TaskStateSegmentEntry TaskStateSegment;
} __packed;
struct GlobalDescriptorTableDescriptor
{
/**
* GDT entries length
*/
uint16_t Length;
/**
* GDT entries address
*/
GlobalDescriptorTableEntries *Entries;
} __packed;
extern void *CPUStackPointer[];
extern TaskStateSegment tss[];
void Init(int Core);
void SetKernelStack(void *Stack);
void *GetKernelStack();
} }
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code) #define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)

View File

@ -34,7 +34,7 @@ namespace Memory
if ((PDE->raw & Flag) > 0) if ((PDE->raw & Flag) > 0)
{ {
if (Type == MapType::FourMB && PDE->PageSize) if (Type == MapType::FourMiB && PDE->PageSize)
return true; return true;
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
@ -86,13 +86,13 @@ namespace Memory
if (PDE->Present) if (PDE->Present)
{ {
if (PDE->PageSize) if (PDE->PageSize)
return MapType::FourMB; return MapType::FourMiB;
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
if (PTE) if (PTE)
{ {
if (PTE->Entries[Index.PTEIndex].Present) if (PTE->Entries[Index.PTEIndex].Present)
return MapType::FourKB; return MapType::FourKiB;
} }
} }
return MapType::NoMapType; return MapType::NoMapType;
@ -143,7 +143,7 @@ namespace Memory
uint64_t DirectoryFlags = Flags & 0x3F; uint64_t DirectoryFlags = Flags & 0x3F;
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
if (Type == MapType::FourMB) if (Type == MapType::FourMiB)
{ {
PDE->raw |= (uintptr_t)Flags; PDE->raw |= (uintptr_t)Flags;
PDE->PageSize = true; PDE->PageSize = true;
@ -218,7 +218,7 @@ namespace Memory
return; return;
} }
if (Type == MapType::FourMB && PDE->PageSize) if (Type == MapType::FourMiB && PDE->PageSize)
{ {
PDE->Present = false; PDE->Present = false;
return; return;

View File

@ -24,249 +24,236 @@
namespace GlobalDescriptorTable namespace GlobalDescriptorTable
{ {
static GlobalDescriptorTableEntries GDTEntriesTemplate = { static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null = .Null =
{ {
.Limit0 = 0x0, .Limit0 = 0x0,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = {.Raw = 0x0}, .Access = {.Raw = 0x0},
// .Limit1 = 0x0, // .Limit1 = 0x0,
.Flags = {.Raw = 0x0}, .Flags = {.Raw = 0x0},
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.Code = .Code =
{ {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 1, .E = 1,
.S = 1, .S = 1,
.DPL = 0, .DPL = 0,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 0, .L = 0,
.DB = 1, .DB = 1,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.Data = { .Data = {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 0, .E = 0,
.S = 1, .S = 1,
.DPL = 0, .DPL = 0,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 0, .L = 0,
.DB = 1, .DB = 1,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.UserData = { .UserData = {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 0, .E = 0,
.S = 1, .S = 1,
.DPL = 3, .DPL = 3,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 0, .L = 0,
.DB = 1, .DB = 1,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.UserCode = { .UserCode = {
.Limit0 = 0xFFFF, .Limit0 = 0xFFFF,
.BaseLow = 0x0, .BaseLow = 0x0,
.BaseMiddle = 0x0, .BaseMiddle = 0x0,
.Access = { .Access = {
.A = 0, .A = 0,
.RW = 1, .RW = 1,
.DC = 0, .DC = 0,
.E = 1, .E = 1,
.S = 1, .S = 1,
.DPL = 3, .DPL = 3,
.P = 1, .P = 1,
}, },
// .Limit1 = 0xF, // .Limit1 = 0xF,
.Flags = { .Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */ .Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0, .AVL = 0,
.L = 0, .L = 0,
.DB = 1, .DB = 1,
.G = 1, .G = 1,
}, },
.BaseHigh = 0x0, .BaseHigh = 0x0,
}, },
.TaskStateSegment = {}, .TaskStateSegment = {},
}; };
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16); GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16); GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
TaskStateSegment tss[MAX_CPU] = { TaskStateSegment tss[MAX_CPU] = {
0, 0,
{0, 0, 0}, {0, 0, 0},
0, 0,
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
0, 0,
0, 0,
0, 0,
}; };
void *CPUStackPointer[MAX_CPU]; void *CPUStackPointer[MAX_CPU];
SafeFunction void Init(int Core) SafeFunction void Init(int Core)
{ {
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries)); memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]}; gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
debug("GDT: %#lx", &gdt[Core]); debug("GDT: %#lx", &gdt[Core]);
debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_KERNEL_CODE, GDT_KERNEL_CODE,
GDTEntries[Core].Code.Limit0, GDTEntries[Core].Code.Limit0,
GDTEntries[Core].Code.BaseLow, GDTEntries[Core].Code.BaseLow,
GDTEntries[Core].Code.BaseMiddle, GDTEntries[Core].Code.BaseMiddle,
GDTEntries[Core].Code.Access.Raw, GDTEntries[Core].Code.Access.Raw,
GDTEntries[Core].Code.Flags.Reserved, GDTEntries[Core].Code.Flags.Reserved,
GDTEntries[Core].Code.Flags.Raw & ~0xF, GDTEntries[Core].Code.Flags.Raw & ~0xF,
GDTEntries[Core].Code.BaseHigh); GDTEntries[Core].Code.BaseHigh);
debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_KERNEL_DATA, GDT_KERNEL_DATA,
GDTEntries[Core].Data.Limit0, GDTEntries[Core].Data.Limit0,
GDTEntries[Core].Data.BaseLow, GDTEntries[Core].Data.BaseLow,
GDTEntries[Core].Data.BaseMiddle, GDTEntries[Core].Data.BaseMiddle,
GDTEntries[Core].Data.Access.Raw, GDTEntries[Core].Data.Access.Raw,
GDTEntries[Core].Data.Flags.Reserved, GDTEntries[Core].Data.Flags.Reserved,
GDTEntries[Core].Data.Flags.Raw & ~0xF, GDTEntries[Core].Data.Flags.Raw & ~0xF,
GDTEntries[Core].Data.BaseHigh); GDTEntries[Core].Data.BaseHigh);
debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_USER_CODE, GDT_USER_CODE,
GDTEntries[Core].UserCode.Limit0, GDTEntries[Core].UserCode.Limit0,
GDTEntries[Core].UserCode.BaseLow, GDTEntries[Core].UserCode.BaseLow,
GDTEntries[Core].UserCode.BaseMiddle, GDTEntries[Core].UserCode.BaseMiddle,
GDTEntries[Core].UserCode.Access.Raw, GDTEntries[Core].UserCode.Access.Raw,
GDTEntries[Core].UserCode.Flags.Reserved, GDTEntries[Core].UserCode.Flags.Reserved,
GDTEntries[Core].UserCode.Flags.Raw & ~0xF, GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
GDTEntries[Core].UserCode.BaseHigh); GDTEntries[Core].UserCode.BaseHigh);
debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X", debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
GDT_USER_DATA, GDT_USER_DATA,
GDTEntries[Core].UserData.Limit0, GDTEntries[Core].UserData.Limit0,
GDTEntries[Core].UserData.BaseLow, GDTEntries[Core].UserData.BaseLow,
GDTEntries[Core].UserData.BaseMiddle, GDTEntries[Core].UserData.BaseMiddle,
GDTEntries[Core].UserData.Access.Raw, GDTEntries[Core].UserData.Access.Raw,
GDTEntries[Core].UserData.Flags.Reserved, GDTEntries[Core].UserData.Flags.Reserved,
GDTEntries[Core].UserData.Flags.Raw & ~0xF, GDTEntries[Core].UserData.Flags.Raw & ~0xF,
GDTEntries[Core].UserData.BaseHigh); GDTEntries[Core].UserData.BaseHigh);
CPU::x32::lgdt(&gdt[Core]); CPU::x32::lgdt(&gdt[Core]);
asmv("mov %%esp, %%eax\n" asmv("mov %%esp, %%eax\n"
"push $16\n" "push $16\n"
"push %%eax\n" "push %%eax\n"
"pushf\n" "pushf\n"
"push $8\n" "push $8\n"
"push $1f\n" "push $1f\n"
"iret\n" "iret\n"
"1:\n" "1:\n"
"movw $16, %%ax\n" "movw $16, %%ax\n"
"movw %%ax, %%ds\n" "movw %%ax, %%ds\n"
"movw %%ax, %%es\n" :: "movw %%ax, %%es\n" ::
: "memory", "eax"); : "memory", "eax");
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE); memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core, debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE, CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1)); TO_PAGES(STACK_SIZE + 1));
uintptr_t Base = (uintptr_t)&tss[Core]; uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment); size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF; gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF; gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 0xFF; gdt[Core].Entries->TaskStateSegment.BaseMiddle = uint8_t((Base >> 16) & 0xFF);
gdt[Core].Entries->TaskStateSegment.BaseHigh = (Base >> 24) & 0xFF; gdt[Core].Entries->TaskStateSegment.BaseHigh = uint8_t((Base >> 24) & 0xFF);
gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF); gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1}; gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF); gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment); tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE; tss[Core].StackPointer[0] = (uint32_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0; tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0; tss[Core].StackPointer[2] = 0x0;
for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++) for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
{ {
void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE; tss[Core].InterruptStackTable[i] = (uint32_t)NewStack + STACK_SIZE;
memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE); memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE); debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
} }
CPU::x32::ltr(GDT_TSS); CPU::x32::ltr(GDT_TSS);
debug("Global Descriptor Table initialized"); debug("Global Descriptor Table initialized");
} }
SafeFunction void SetKernelStack(void *Stack) SafeFunction void SetKernelStack(void *Stack)
{ {
long CPUID = GetCurrentCPU()->ID; long CPUID = GetCurrentCPU()->ID;
if (Stack != nullptr) }
tss[CPUID].StackPointer[0] = (uint64_t)Stack;
else
tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE;
/* void *GetKernelStack() { return (void *)nullptr; }
FIXME: There's a bug in kernel which if
we won't update "tss[CPUID].StackPointer[0]"
with the current stack pointer, the kernel
will crash.
*/
asmv("mov %%esp, %0"
: "=r"(tss[CPUID].StackPointer[0]));
}
void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; }
} }

View File

@ -22,197 +22,197 @@
namespace GlobalDescriptorTable namespace GlobalDescriptorTable
{ {
struct TaskStateSegmentEntry struct TaskStateSegmentEntry
{ {
/* LOW */ /* LOW */
uint16_t Limit; uint16_t Limit;
uint16_t BaseLow; uint16_t BaseLow;
uint8_t BaseMiddle; uint8_t BaseMiddle;
union GlobalDescriptorTableAccess union GlobalDescriptorTableAccess
{ {
struct struct
{ {
/** @brief Access bit. /** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed. * @note The CPU sets this bit to 1 when the segment is accessed.
*/ */
uint8_t A : 1; uint8_t A : 1;
/** @brief Readable bit for code segments, writable bit for data segments. /** @brief Readable bit for code segments, writable bit for data segments.
* @details For code segments, this bit must be 1 for the segment to be readable. * @details For code segments, this bit must be 1 for the segment to be readable.
* @details For data segments, this bit must be 1 for the segment to be writable. * @details For data segments, this bit must be 1 for the segment to be writable.
*/ */
uint8_t RW : 1; uint8_t RW : 1;
/** @brief Direction bit for data segments, conforming bit for code segments. /** @brief Direction bit for data segments, conforming bit for code segments.
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses). * @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level. * @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
*/ */
uint8_t DC : 1; uint8_t DC : 1;
/** @brief Executable bit. /** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors. * @details This bit must be 1 for code-segment descriptors.
* @details This bit must be 0 for data-segment and system descriptors. * @details This bit must be 0 for data-segment and system descriptors.
*/ */
uint8_t E : 1; uint8_t E : 1;
/** @brief Descriptor type. /** @brief Descriptor type.
* @details This bit must be 0 for system descriptors. * @details This bit must be 0 for system descriptors.
* @details This bit must be 1 for code or data segment descriptor. * @details This bit must be 1 for code or data segment descriptor.
*/ */
uint8_t S : 1; uint8_t S : 1;
/** @brief Descriptor privilege level. /** @brief Descriptor privilege level.
* @details This field determines the privilege level of the segment. * @details This field determines the privilege level of the segment.
* @details 0 = kernel mode, 3 = user mode. * @details 0 = kernel mode, 3 = user mode.
*/ */
uint8_t DPL : 2; uint8_t DPL : 2;
/** @brief Present bit. /** @brief Present bit.
* @details This bit must be 1 for all valid descriptors. * @details This bit must be 1 for all valid descriptors.
*/ */
uint8_t P : 1; uint8_t P : 1;
} __packed; } __packed;
uint8_t Raw : 8; uint8_t Raw : 8;
} Access; } Access;
uint8_t Granularity; uint8_t Granularity;
uint8_t BaseHigh; uint8_t BaseHigh;
/* HIGH */ /* HIGH */
uint32_t BaseUpper; uint32_t BaseUpper;
uint32_t Reserved; uint32_t Reserved;
} __packed; } __packed;
struct TaskStateSegment struct TaskStateSegment
{ {
uint32_t Reserved0 __aligned(16); uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3]; uint64_t StackPointer[3];
uint64_t Reserved1; uint64_t Reserved1;
uint64_t InterruptStackTable[7]; uint64_t InterruptStackTable[7];
uint64_t Reserved2; uint64_t Reserved2;
uint16_t Reserved3; uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset; uint16_t IOMapBaseAddressOffset;
} __packed; } __packed;
struct GlobalDescriptorTableEntry struct GlobalDescriptorTableEntry
{ {
/** @brief Limit 0:15 */ /** @brief Limit 0:15 */
uint16_t Limit0 : 16; uint16_t Limit0 : 16;
/** @brief Low Base 0:15 */ /** @brief Low Base 0:15 */
uint16_t BaseLow : 16; uint16_t BaseLow : 16;
/** @brief Middle Base 16:23 */ /** @brief Middle Base 16:23 */
uint8_t BaseMiddle : 8; uint8_t BaseMiddle : 8;
/** @brief Access */ /** @brief Access */
union GlobalDescriptorTableAccess union GlobalDescriptorTableAccess
{ {
struct struct
{ {
/** @brief Access bit. /** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed. * @note The CPU sets this bit to 1 when the segment is accessed.
*/ */
uint8_t A : 1; uint8_t A : 1;
/** @brief Readable bit for code segments, writable bit for data segments. /** @brief Readable bit for code segments, writable bit for data segments.
* @details For code segments, this bit must be 1 for the segment to be readable. * @details For code segments, this bit must be 1 for the segment to be readable.
* @details For data segments, this bit must be 1 for the segment to be writable. * @details For data segments, this bit must be 1 for the segment to be writable.
*/ */
uint8_t RW : 1; uint8_t RW : 1;
/** @brief Direction bit for data segments, conforming bit for code segments. /** @brief Direction bit for data segments, conforming bit for code segments.
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses). * @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level. * @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
*/ */
uint8_t DC : 1; uint8_t DC : 1;
/** @brief Executable bit. /** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors. * @details This bit must be 1 for code-segment descriptors.
* @details This bit must be 0 for data-segment and system descriptors. * @details This bit must be 0 for data-segment and system descriptors.
*/ */
uint8_t E : 1; uint8_t E : 1;
/** @brief Descriptor type. /** @brief Descriptor type.
* @details This bit must be 0 for system descriptors. * @details This bit must be 0 for system descriptors.
* @details This bit must be 1 for code or data segment descriptor. * @details This bit must be 1 for code or data segment descriptor.
*/ */
uint8_t S : 1; uint8_t S : 1;
/** @brief Descriptor privilege level. /** @brief Descriptor privilege level.
* @details This field determines the privilege level of the segment. * @details This field determines the privilege level of the segment.
* @details 0 = kernel mode, 3 = user mode. * @details 0 = kernel mode, 3 = user mode.
*/ */
uint8_t DPL : 2; uint8_t DPL : 2;
/** @brief Present bit. /** @brief Present bit.
* @details This bit must be 1 for all valid descriptors. * @details This bit must be 1 for all valid descriptors.
*/ */
uint8_t P : 1; uint8_t P : 1;
} __packed; } __packed;
uint8_t Raw : 8; uint8_t Raw : 8;
} Access; } Access;
// /** @brief Limit 16:19 */ // /** @brief Limit 16:19 */
// uint16_t Limit1 : 4; // uint16_t Limit1 : 4;
/** @brief Flags */ /** @brief Flags */
union GlobalDescriptorTableFlags union GlobalDescriptorTableFlags
{ {
struct struct
{ {
uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */ uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */
/** @brief Available bit. /** @brief Available bit.
* @details This bit is available for use by system software. * @details This bit is available for use by system software.
*/ */
uint8_t AVL : 1; uint8_t AVL : 1;
/** @brief Long mode. /** @brief Long mode.
* @details If the long mode bit is clear, the segment is in 32-bit protected mode. * @details If the long mode bit is clear, the segment is in 32-bit protected mode.
* @details If the long mode bit is set, the segment is in 64-bit long mode. * @details If the long mode bit is set, the segment is in 64-bit long mode.
*/ */
uint8_t L : 1; uint8_t L : 1;
/** @brief Size flag. /** @brief Size flag.
* @details If the size bit is clear, the segment is in 16-bit protected mode. * @details If the size bit is clear, the segment is in 16-bit protected mode.
* @details If the size bit is set, the segment is in 32-bit protected mode. * @details If the size bit is set, the segment is in 32-bit protected mode.
*/ */
uint8_t DB : 1; uint8_t DB : 1;
/** @brief Granularity bit. /** @brief Granularity bit.
* @details If the granularity bit is clear, the segment limit is in 1 B blocks. * @details If the granularity bit is clear, the segment limit is in 1 B blocks.
* @details If the granularity bit is set, the segment limit is in 4 KiB blocks. * @details If the granularity bit is set, the segment limit is in 4 KiB blocks.
*/ */
uint8_t G : 1; uint8_t G : 1;
} __packed; } __packed;
uint8_t Raw : 8; uint8_t Raw : 8;
} Flags; } Flags;
/** @brief High Base 24:31 */ /** @brief High Base 24:31 */
uint8_t BaseHigh : 8; uint8_t BaseHigh : 8;
} __packed; } __packed;
struct GlobalDescriptorTableEntries struct GlobalDescriptorTableEntries
{ {
GlobalDescriptorTableEntry Null; GlobalDescriptorTableEntry Null;
GlobalDescriptorTableEntry Code; GlobalDescriptorTableEntry Code;
GlobalDescriptorTableEntry Data; GlobalDescriptorTableEntry Data;
GlobalDescriptorTableEntry UserData; GlobalDescriptorTableEntry UserData;
GlobalDescriptorTableEntry UserCode; GlobalDescriptorTableEntry UserCode;
TaskStateSegmentEntry TaskStateSegment; TaskStateSegmentEntry TaskStateSegment;
} __packed; } __packed;
struct GlobalDescriptorTableDescriptor struct GlobalDescriptorTableDescriptor
{ {
/** @brief GDT entries length */ /** @brief GDT entries length */
uint16_t Length; uint16_t Length;
/** @brief GDT entries address */ /** @brief GDT entries address */
GlobalDescriptorTableEntries *Entries; GlobalDescriptorTableEntries *Entries;
} __packed; } __packed;
extern void *CPUStackPointer[]; extern void *CPUStackPointer[];
extern TaskStateSegment tss[]; extern TaskStateSegment tss[];
void Init(int Core); void Init(int Core);
void SetKernelStack(void *Stack); void SetKernelStack(void *Stack);
void *GetKernelStack(); void *GetKernelStack();
} }
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code) #define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)

View File

@ -28,7 +28,7 @@ namespace CPU
{ {
static bool SSEEnabled = false; static bool SSEEnabled = false;
char *Vendor() const char *Vendor()
{ {
static char Vendor[13] = {0}; static char Vendor[13] = {0};
if (Vendor[0] != 0) if (Vendor[0] != 0)
@ -52,7 +52,7 @@ namespace CPU
return Vendor; return Vendor;
} }
char *Name() const char *Name()
{ {
static char Name[49] = {0}; static char Name[49] = {0};
if (Name[0] != 0) if (Name[0] != 0)
@ -98,7 +98,7 @@ namespace CPU
return Name; return Name;
} }
char *Hypervisor() const char *Hypervisor()
{ {
static char Hypervisor[13] = {0}; static char Hypervisor[13] = {0};
if (Hypervisor[0] != 0) if (Hypervisor[0] != 0)
@ -255,8 +255,7 @@ namespace CPU
bool SSEEnableAfter = false; bool SSEEnableAfter = false;
/* Not sure if my code is not working properly or something else is the issue. */ /* Not sure if my code is not working properly or something else is the issue. */
if ((strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) != 0 && if ((strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0) &&
strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0) &&
SSESupport) SSESupport)
{ {
debug("Enabling SSE support..."); debug("Enabling SSE support...");
@ -438,16 +437,16 @@ namespace CPU
#endif #endif
} }
uintptr_t Counter() uint64_t Counter()
{ {
// TODO: Get the counter from the x2APIC or any other timer that is available. (TSC is not available on all CPUs) // TODO: Get the counter from the x2APIC or any other timer that is available. (TSC is not available on all CPUs)
uintptr_t Counter; uint64_t Counter;
#if defined(a64) #if defined(a86)
uint32_t eax, edx;
asmv("rdtsc" asmv("rdtsc"
: "=A"(Counter)); : "=a"(eax),
#elif defined(a32) "=d"(edx));
asmv("rdtsc" Counter = ((uint64_t)eax) | (((uint64_t)edx) << 32);
: "=A"(Counter));
#elif defined(aa64) #elif defined(aa64)
asmv("mrs %0, cntvct_el0" asmv("mrs %0, cntvct_el0"
: "=r"(Counter)); : "=r"(Counter));

File diff suppressed because it is too large Load Diff

View File

@ -52,9 +52,11 @@ namespace CrashHandler
if (cpu) if (cpu)
{ {
EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu); EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu);
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n", cpu->Stack, cpu->ID, cpu->ErrorCode); EHPrint("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("Is Active: %s\n", cpu->IsActive ? "true" : "false");
EHPrint("Current Process: %#lx, Current Thread: %#lx\n", cpu->CurrentProcess, cpu->CurrentThread); EHPrint("Current Process: %#lx, Current Thread: %#lx\n",
cpu->CurrentProcess.load(), cpu->CurrentThread.load());
EHPrint("Arch Specific Data: %#lx\n", cpu->Data); EHPrint("Arch Specific Data: %#lx\n", cpu->Data);
EHPrint("Checksum: 0x%X\n", cpu->Checksum); EHPrint("Checksum: 0x%X\n", cpu->Checksum);
} }
@ -128,11 +130,11 @@ namespace CrashHandler
#endif #endif
#if defined(a86) #if defined(a86)
EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s BD:%s BS:%s BT:%s\n", EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s\n BD:%s BS:%s BT:%s\n",
data.dr6.B0 ? "True " : "False", data.dr6.B1 ? "True " : "False", data.dr6.B2 ? "True " : "False", data.dr6.B3 ? "True " : "False", data.dr6.B0 ? "True " : "False", data.dr6.B1 ? "True " : "False", data.dr6.B2 ? "True " : "False", data.dr6.B3 ? "True " : "False",
data.dr6.BD ? "True " : "False", data.dr6.BS ? "True " : "False", data.dr6.BT ? "True " : "False"); data.dr6.BD ? "True " : "False", data.dr6.BS ? "True " : "False", data.dr6.BT ? "True " : "False");
EHPrint("\eA0F0F0DR7: L0:%s G0:%s L1:%s G1:%s\n L2:%s G2:%s L3:%s G3:%s\n LE:%s GE:%s GD:%s\n R/W0:%s LEN0:%s R/W1:%s LEN1:%s\n R/W2:%s LEN2:%s R/W3:%s LEN3:%s\n", EHPrint("\eA0F0F0DR7: L0:%s G0:%s L1:%s G1:%s\n L2:%s G2:%s L3:%s G3:%s\n LE:%s GE:%s GD:%s\n R/W0:%s LEN0:%s R/W1:%s LEN1:%s\n R/W2:%s LEN2:%s R/W3:%s LEN3:%s\n",
data.dr7.L0 ? "True " : "False", data.dr7.G0 ? "True " : "False", data.dr7.L1 ? "True " : "False", data.dr7.G1 ? "True " : "False", data.dr7.L0 ? "True " : "False", data.dr7.G0 ? "True " : "False", data.dr7.L1 ? "True " : "False", data.dr7.G1 ? "True " : "False",
data.dr7.L2 ? "True " : "False", data.dr7.G2 ? "True " : "False", data.dr7.L3 ? "True " : "False", data.dr7.G3 ? "True " : "False", data.dr7.L2 ? "True " : "False", data.dr7.G2 ? "True " : "False", data.dr7.L3 ? "True " : "False", data.dr7.G3 ? "True " : "False",
data.dr7.LE ? "True " : "False", data.dr7.GE ? "True " : "False", data.dr7.GD ? "True " : "False", data.dr7.RW0 ? "True " : "False", data.dr7.LE ? "True " : "False", data.dr7.GE ? "True " : "False", data.dr7.GD ? "True " : "False", data.dr7.RW0 ? "True " : "False",

View File

@ -311,7 +311,7 @@ namespace CrashHandler
case CPU::x86::PageFault: case CPU::x86::PageFault:
{ {
EHPrint("Exception: Page Fault\n"); EHPrint("Exception: Page Fault\n");
EHPrint("The processor attempted to access a page that is not present.\n"); EHPrint("The processor attempted to access a page that is not present/accessible.\n");
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode}; CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
#if defined(a64) #if defined(a64)

View File

@ -41,8 +41,8 @@ namespace CrashHandler
"AAFF00", // Ready "AAFF00", // Ready
"00AA00", // Running "00AA00", // Running
"FFAA00", // Sleeping "FFAA00", // Sleeping
"FFAA00", // Waiting "FFAA00", // Blocked
"FF0088", // Stopped "FF0088", // Zombie
"FF0000", // Terminated "FF0000", // Terminated
}; };
@ -51,8 +51,8 @@ namespace CrashHandler
"Ready", // Ready "Ready", // Ready
"Running", // Running "Running", // Running
"Sleeping", // Sleeping "Sleeping", // Sleeping
"Waiting", // Waiting "Blocked", // Blocked
"Stopped", // Stopped "Zombie", // Zombie
"Terminated", // Terminated "Terminated", // Terminated
}; };
@ -62,9 +62,11 @@ namespace CrashHandler
if (data.Thread) if (data.Thread)
#if defined(a64) #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); 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) #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); 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) #elif defined(aa64)
#endif #endif
@ -72,12 +74,14 @@ namespace CrashHandler
foreach (auto Process in Plist) foreach (auto Process in Plist)
{ {
EHPrint("\e%s-> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA PT:\e00AAAA%#lx\n", EHPrint("\e%s-> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA PT:\e00AAAA%#lx\n",
StatusColor[Process->Status], Process->Name, Process->ID, StatusString[Process->Status], StatusColor[Process->Status.load()], Process->Name,
Process->ID, StatusString[Process->Status.load()],
Process->PageTable); Process->PageTable);
foreach (auto Thread in Process->Threads) foreach (auto Thread in Process->Threads)
EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n", EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n",
StatusColor[Thread->Status], Thread->Name, Thread->ID, StatusString[Thread->Status], StatusColor[Thread->Status.load()], Thread->Name,
Thread->ID, StatusString[Thread->Status.load()],
Thread->Stack); Thread->Stack);
} }
} }

View File

@ -47,7 +47,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
CriticalSection cs; CriticalSection cs;
debug("Interrupts? %s.", cs.IsInterruptsEnabled() ? "Yes" : "No"); debug("Interrupts? %s.", cs.IsInterruptsEnabled() ? "Yes" : "No");
fixme("Handling user mode exception"); fixme("Handling user mode exception");
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Stopped; thisThread->Status = Tasking::TaskStatus::Zombie;
CPUData *CurCPU = GetCurrentCPU(); CPUData *CurCPU = GetCurrentCPU();
{ {
@ -354,7 +354,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
if (CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress)) if (CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress))
{ {
debug("Stack expanded"); debug("Stack expanded");
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Ready; thisThread->Status = Tasking::TaskStatus::Ready;
return; return;
} }
break; break;
@ -389,7 +389,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
} }
} }
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated; thisThread->Status = Tasking::TaskStatus::Terminated;
__sync; __sync;
error("End of report."); error("End of report.");
CPU::Interrupts(CPU::Enable); CPU::Interrupts(CPU::Enable);

View File

@ -27,170 +27,170 @@ using namespace UniversalAsynchronousReceiverTransmitter;
static inline NIF void uart_wrapper(char c, void *unused) static inline NIF void uart_wrapper(char c, void *unused)
{ {
UART(COM1).Write(c); UART(COM1).Write(c);
UNUSED(unused); UNUSED(unused);
} }
static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args) static inline NIF bool WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, va_list args)
{ {
const char *DbgLvlString; const char *DbgLvlString;
switch (Level) switch (Level)
{ {
case DebugLevelError: case DebugLevelError:
DbgLvlString = "ERROR"; DbgLvlString = "ERROR";
break; break;
case DebugLevelWarning: case DebugLevelWarning:
DbgLvlString = "WARN "; DbgLvlString = "WARN ";
break; break;
case DebugLevelInfo: case DebugLevelInfo:
DbgLvlString = "INFO "; DbgLvlString = "INFO ";
break; break;
case DebugLevelDebug: case DebugLevelDebug:
DbgLvlString = "DEBUG"; DbgLvlString = "DEBUG";
break; break;
case DebugLevelTrace: case DebugLevelTrace:
DbgLvlString = "TRACE"; DbgLvlString = "TRACE";
break; break;
case DebugLevelFixme: case DebugLevelFixme:
DbgLvlString = "FIXME"; DbgLvlString = "FIXME";
break; break;
case DebugLevelStub: case DebugLevelStub:
fctprintf(uart_wrapper, nullptr, "STUB | %s>%s() is stub\n", File, Function); fctprintf(uart_wrapper, nullptr, "STUB | %s>%s() is stub\n", File, Function);
return false; return false;
case DebugLevelFunction: case DebugLevelFunction:
fctprintf(uart_wrapper, nullptr, "FUNC | %s>%s( ", File, Function); fctprintf(uart_wrapper, nullptr, "FUNC | %s>%s( ", File, Function);
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
fctprintf(uart_wrapper, nullptr, " )\n"); fctprintf(uart_wrapper, nullptr, " )\n");
return false; return false;
case DebugLevelUbsan: case DebugLevelUbsan:
{ {
DbgLvlString = "UBSAN"; DbgLvlString = "UBSAN";
fctprintf(uart_wrapper, nullptr, "%s| ", DbgLvlString); fctprintf(uart_wrapper, nullptr, "%s| ", DbgLvlString);
return true; return true;
} }
default: default:
DbgLvlString = "UNKNW"; DbgLvlString = "UNKNW";
break; break;
} }
fctprintf(uart_wrapper, nullptr, "%s| %s>%s:%d: ", DbgLvlString, File, Function, Line); fctprintf(uart_wrapper, nullptr, "%s| %s>%s:%d: ", DbgLvlString, File, Function, Line);
return true; return true;
} }
namespace SysDbg namespace SysDbg
{ {
NIF void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) NIF void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
} }
NIF void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) NIF void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
uart_wrapper('\n', nullptr); uart_wrapper('\n', nullptr);
} }
NIF void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) NIF void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
} }
NIF void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) NIF void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
uart_wrapper('\n', nullptr); uart_wrapper('\n', nullptr);
} }
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
uart_wrapper('\n', nullptr); uart_wrapper('\n', nullptr);
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
} }
// C compatibility // C compatibility
extern "C" NIF void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...) extern "C" NIF void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{ {
SmartTimeoutLock(DebuggerLock, 1000); SmartTimeoutLock(DebuggerLock, 1000);
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
if (!WritePrefix(Level, File, Line, Function, Format, args)) if (!WritePrefix(Level, File, Line, Function, Format, args))
{ {
va_end(args); va_end(args);
return; return;
} }
vfctprintf(uart_wrapper, nullptr, Format, args); vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args); va_end(args);
uart_wrapper('\n', nullptr); uart_wrapper('\n', nullptr);
} }

View File

@ -29,7 +29,7 @@ namespace Disk
void Manager::FetchDisks(unsigned long DriverUID) void Manager::FetchDisks(unsigned long DriverUID)
{ {
KernelCallback callback{}; KernelCallback callback{};
callback.Reason = FetchReason; callback.Reason = QueryReason;
DriverManager->IOCB(DriverUID, &callback); DriverManager->IOCB(DriverUID, &callback);
this->AvailablePorts = callback.DiskCallback.Fetch.Ports; this->AvailablePorts = callback.DiskCallback.Fetch.Ports;
this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector; this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector;

View File

@ -83,29 +83,29 @@ namespace Driver
{ {
debug("Searching for driver %ld", DUID); debug("Searching for driver %ld", DUID);
foreach (auto Drv in Drivers) forItr(Drv, Drivers)
{ {
if (Drv.DriverUID != DUID) if (Drv->DriverUID != DUID)
continue; continue;
KernelCallback callback{}; KernelCallback callback{};
callback.Reason = StopReason; callback.Reason = StopReason;
debug("Stopping & unloading driver %ld [%#lx]", Drv.DriverUID, Drv.Address); debug("Stopping & unloading driver %ld [%#lx]", Drv->DriverUID, Drv->Address);
this->IOCB(Drv.DriverUID, &callback); this->IOCB(Drv->DriverUID, &callback);
for (size_t j = 0; j < sizeof(Drv.InterruptHook) / sizeof(Drv.InterruptHook[0]); j++) for (size_t j = 0; j < sizeof(Drv->InterruptHook) / sizeof(Drv->InterruptHook[0]); j++)
{ {
if (!Drv.InterruptHook[j]) if (!Drv->InterruptHook[j])
continue; continue;
debug("Interrupt hook %#lx", Drv.InterruptHook[j]); debug("Interrupt hook %#lx", Drv->InterruptHook[j]);
delete Drv.InterruptHook[j], Drv.InterruptHook[j] = nullptr; delete Drv->InterruptHook[j], Drv->InterruptHook[j] = nullptr;
} }
if (Drv.MemTrk) if (Drv->MemTrk)
delete Drv.MemTrk, Drv.MemTrk = nullptr; delete Drv->MemTrk, Drv->MemTrk = nullptr;
Drivers.remove(Drv); Drivers.erase(Drv);
return true; return true;
} }
return false; return false;
@ -157,7 +157,7 @@ namespace Driver
return DriverCode::OK; return DriverCode::OK;
} }
DriverCode Driver::LoadDriver(uintptr_t DriverAddress, uintptr_t Size) DriverCode Driver::LoadDriver(uintptr_t DriverAddress, size_t Size)
{ {
Fex *DrvHdr = (Fex *)DriverAddress; Fex *DrvHdr = (Fex *)DriverAddress;
if (DrvHdr->Magic[0] != 'F' || DrvHdr->Magic[1] != 'E' || DrvHdr->Magic[2] != 'X' || DrvHdr->Magic[3] != '\0') if (DrvHdr->Magic[0] != 'F' || DrvHdr->Magic[1] != 'E' || DrvHdr->Magic[2] != 'X' || DrvHdr->Magic[3] != '\0')
@ -201,22 +201,23 @@ namespace Driver
StartAHCI(); StartAHCI();
StartVMwareMouse(); StartVMwareMouse();
StartPS2Mouse(); StartPS2Mouse();
StartPS2Keyboard();
StartATA(); StartATA();
StartAC97(); StartAC97();
StartRTL8139(); StartRTL8139();
StartPCNET(); StartPCNET();
StartGigabit(); StartGigabit();
VirtualFileSystem::File DriverDirectory = vfs->Open(Config.DriverDirectory); RefNode *DriverDirectory = vfs->Open(Config.DriverDirectory);
if (!DriverDirectory.IsOK()) if (!DriverDirectory)
{ {
KPrint("\eE85230Failed to open driver directory: %s! (Status: %#lx)", Config.DriverDirectory, DriverDirectory.Status); KPrint("\eE85230Failed to open %s: %d)",
vfs->Close(DriverDirectory); Config.DriverDirectory, errno);
return; return;
} }
debug("Loading drivers from %s", Config.DriverDirectory); debug("Loading drivers from %s", Config.DriverDirectory);
foreach (auto DrvFile in DriverDirectory.GetChildren()) foreach (auto DrvFile in DriverDirectory->GetNode()->Children)
{ {
if (DrvFile->Flags != VirtualFileSystem::NodeFlags::FILE) if (DrvFile->Flags != VirtualFileSystem::NodeFlags::FILE)
continue; continue;
@ -241,7 +242,7 @@ namespace Driver
} }
} }
} }
vfs->Close(DriverDirectory); delete DriverDirectory;
} }
Driver::Driver() {} Driver::Driver() {}

View File

@ -34,6 +34,9 @@ namespace Driver
DriverCode Driver::DriverLoadBindInput(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn) DriverCode Driver::DriverLoadBindInput(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn)
{ {
stub; stub;
UNUSED(DriverAddress);
UNUSED(Size);
UNUSED(IsBuiltIn);
return DriverCode::NOT_IMPLEMENTED; return DriverCode::NOT_IMPLEMENTED;
} }
} }

View File

@ -33,7 +33,7 @@ namespace Driver
{ {
DriverCode Driver::DriverLoadBindInterrupt(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn) DriverCode Driver::DriverLoadBindInterrupt(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn)
{ {
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory); Memory::MemMgr *mem = new Memory::MemMgr(nullptr, thisProcess->memDirectory);
BuiltInDriverInfo *bidi = (BuiltInDriverInfo *)DriverAddress; BuiltInDriverInfo *bidi = (BuiltInDriverInfo *)DriverAddress;
Fex *fex = nullptr; Fex *fex = nullptr;

View File

@ -61,7 +61,7 @@ namespace Driver
debug("[%ld] VendorID: %#x; DeviceID: %#x", debug("[%ld] VendorID: %#x; DeviceID: %#x",
devices.size(), PCIDevice->VendorID, PCIDevice->DeviceID); devices.size(), PCIDevice->VendorID, PCIDevice->DeviceID);
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory); Memory::MemMgr *mem = new Memory::MemMgr(nullptr, thisProcess->memDirectory);
BuiltInDriverInfo *bidi = (BuiltInDriverInfo *)DriverAddress; BuiltInDriverInfo *bidi = (BuiltInDriverInfo *)DriverAddress;
Fex *fex = nullptr; Fex *fex = nullptr;

View File

@ -34,6 +34,9 @@ namespace Driver
DriverCode Driver::DriverLoadBindProcess(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn) DriverCode Driver::DriverLoadBindProcess(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn)
{ {
stub; stub;
UNUSED(DriverAddress);
UNUSED(Size);
UNUSED(IsBuiltIn);
return DriverCode::NOT_IMPLEMENTED; return DriverCode::NOT_IMPLEMENTED;
} }
} }

View File

@ -40,209 +40,213 @@ extern "C" SafeFunction void ExceptionHandler(void *Data) { CrashHandler::Handle
namespace Interrupts namespace Interrupts
{ {
struct Event struct Event
{ {
int ID; int ID;
void *Data; void *Data;
}; };
std::vector<Event> RegisteredEvents; std::vector<Event> RegisteredEvents;
#if defined(a64) #if defined(a64)
/* APIC::APIC */ void *apic[MAX_CPU]; /* APIC::APIC */ void *apic[MAX_CPU];
/* APIC::Timer */ void *apicTimer[MAX_CPU]; /* APIC::Timer */ void *apicTimer[MAX_CPU];
#elif defined(a32) #elif defined(a32)
/* APIC::APIC */ void *apic[MAX_CPU]; /* APIC::APIC */ void *apic[MAX_CPU];
#elif defined(aa64) #elif defined(aa64)
#endif #endif
void *InterruptFrames[INT_FRAMES_MAX]; void *InterruptFrames[INT_FRAMES_MAX];
void Initialize(int Core) void Initialize(int Core)
{ {
#if defined(a64) #if defined(a64)
GlobalDescriptorTable::Init(Core); GlobalDescriptorTable::Init(Core);
InterruptDescriptorTable::Init(Core); InterruptDescriptorTable::Init(Core);
CPUData *CoreData = GetCPU(Core); CPUData *CoreData = GetCPU(Core);
CoreData->Checksum = CPU_DATA_CHECKSUM; CoreData->Checksum = CPU_DATA_CHECKSUM;
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, (uint64_t)CoreData); CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, (uint64_t)CoreData);
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, (uint64_t)CoreData); CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, (uint64_t)CoreData);
CoreData->ID = Core; CoreData->ID = Core;
CoreData->IsActive = true; CoreData->IsActive = true;
CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE; CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE;
if (CoreData->Checksum != CPU_DATA_CHECKSUM) if (CoreData->Checksum != CPU_DATA_CHECKSUM)
{ {
KPrint("CPU %d checksum mismatch! %x != %x", Core, CoreData->Checksum, CPU_DATA_CHECKSUM); KPrint("CPU %d checksum mismatch! %x != %x",
CPU::Stop(); Core, CoreData->Checksum, CPU_DATA_CHECKSUM);
} CPU::Stop();
debug("Stack for core %d is %#lx (Address: %#lx)", Core, CoreData->Stack, CoreData->Stack - STACK_SIZE); }
InitializeSystemCalls(); debug("Stack for core %d is %#lx (Address: %#lx)",
Core, CoreData->Stack, CoreData->Stack - STACK_SIZE);
InitializeSystemCalls();
#elif defined(a32) #elif defined(a32)
GlobalDescriptorTable::Init(Core); GlobalDescriptorTable::Init(Core);
InterruptDescriptorTable::Init(Core); InterruptDescriptorTable::Init(Core);
CPUData *CoreData = GetCPU(Core); CPUData *CoreData = GetCPU(Core);
CoreData->Checksum = CPU_DATA_CHECKSUM; CoreData->Checksum = CPU_DATA_CHECKSUM;
CPU::x32::wrmsr(CPU::x32::MSR_GS_BASE, (uint64_t)CoreData); CPU::x32::wrmsr(CPU::x32::MSR_GS_BASE, (uint64_t)CoreData);
CPU::x32::wrmsr(CPU::x32::MSR_SHADOW_GS_BASE, (uint64_t)CoreData); CPU::x32::wrmsr(CPU::x32::MSR_SHADOW_GS_BASE, (uint64_t)CoreData);
CoreData->ID = Core; CoreData->ID = Core;
CoreData->IsActive = true; CoreData->IsActive = true;
CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE; CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE;
if (CoreData->Checksum != CPU_DATA_CHECKSUM) if (CoreData->Checksum != CPU_DATA_CHECKSUM)
{ {
KPrint("CPU %d checksum mismatch! %x != %x", Core, CoreData->Checksum, CPU_DATA_CHECKSUM); KPrint("CPU %d checksum mismatch! %x != %x", Core, CoreData->Checksum, CPU_DATA_CHECKSUM);
CPU::Stop(); CPU::Stop();
} }
debug("Stack for core %d is %#lx (Address: %#lx)", Core, CoreData->Stack, CoreData->Stack - STACK_SIZE); debug("Stack for core %d is %#lx (Address: %#lx)", Core, CoreData->Stack, CoreData->Stack - STACK_SIZE);
#elif defined(aa64) #elif defined(aa64)
warn("aarch64 is not supported yet"); warn("aarch64 is not supported yet");
#endif #endif
} }
void Enable(int Core) void Enable(int Core)
{ {
#if defined(a64) #if defined(a64)
if (((ACPI::MADT *)PowerManager->GetMADT())->LAPICAddress != nullptr) 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. // TODO: This function is called by SMP too. Do not initialize timers that doesn't support multiple cores.
apic[Core] = new APIC::APIC(Core); apic[Core] = new APIC::APIC(Core);
if (Core == Config.IOAPICInterruptCore) // Redirect IRQs to the specified core. if (Core == Config.IOAPICInterruptCore) // Redirect IRQs to the specified core.
((APIC::APIC *)apic[Core])->RedirectIRQs(Core); ((APIC::APIC *)apic[Core])->RedirectIRQs(Core);
} }
else else
{ {
error("LAPIC not found"); error("LAPIC not found");
// TODO: PIC // TODO: PIC
} }
#elif defined(a32) #elif defined(a32)
warn("i386 is not supported yet"); warn("i386 is not supported yet");
#elif defined(aa64) #elif defined(aa64)
warn("aarch64 is not supported yet"); warn("aarch64 is not supported yet");
#endif #endif
} }
void InitializeTimer(int Core) void InitializeTimer(int Core)
{ {
// TODO: This function is called by SMP too. Do not initialize timers that doesn't support multiple cores. // TODO: This function is called by SMP too. Do not initialize timers that doesn't support multiple cores.
#if defined(a64) #if defined(a64)
if (apic[Core] != nullptr) if (apic[Core] != nullptr)
apicTimer[Core] = new APIC::Timer((APIC::APIC *)apic[Core]); apicTimer[Core] = new APIC::Timer((APIC::APIC *)apic[Core]);
else else
{ {
fixme("apic not found"); fixme("apic not found");
} }
#elif defined(a32) #elif defined(a32)
warn("i386 is not supported yet"); warn("i386 is not supported yet");
#elif defined(aa64) #elif defined(aa64)
warn("aarch64 is not supported yet"); warn("aarch64 is not supported yet");
#endif #endif
} }
SafeFunction void RemoveAll() SafeFunction void RemoveAll()
{ {
RegisteredEvents.clear(); RegisteredEvents.clear();
} }
extern "C" SafeFunction void MainInterruptHandler(void *Data) extern "C" SafeFunction void MainInterruptHandler(void *Data)
{ {
#if defined(a64) #if defined(a64)
CPU::x64::TrapFrame *Frame = (CPU::x64::TrapFrame *)Data; CPU::x64::TrapFrame *Frame = (CPU::x64::TrapFrame *)Data;
// debug("IRQ%ld", Frame->InterruptNumber - 32); // debug("IRQ%ld", Frame->InterruptNumber - 32);
memmove(InterruptFrames + 1, InterruptFrames, sizeof(InterruptFrames) - sizeof(InterruptFrames[0])); memmove(InterruptFrames + 1, InterruptFrames, sizeof(InterruptFrames) - sizeof(InterruptFrames[0]));
InterruptFrames[0] = (void *)Frame->rip; InterruptFrames[0] = (void *)Frame->rip;
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
int Core = 0; int Core = 0;
if (likely(CoreData != nullptr)) if (likely(CoreData != nullptr))
Core = CoreData->ID; Core = CoreData->ID;
/* If this is false, we have a big problem. */ /* If this is false, we have a big problem. */
if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 && Frame->InterruptNumber > CPU::x86::ISR0)) if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 && Frame->InterruptNumber > CPU::x86::ISR0))
{ {
/* Halt core interrupt */ /* Halt core interrupt */
if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ29)) if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ29))
CPU::Stop(); CPU::Stop();
bool InterruptHandled = false; bool InterruptHandled = false;
foreach (auto ev in RegisteredEvents) foreach (auto ev in RegisteredEvents)
{ {
#if defined(a86) #if defined(a86)
if ((ev.ID + CPU::x86::IRQ0) == static_cast<int>(Frame->InterruptNumber)) if ((ev.ID + CPU::x86::IRQ0) == s_cst(int, Frame->InterruptNumber))
#elif defined(aa64) #elif defined(aa64)
if (ev.ID == static_cast<int>(Frame->InterruptNumber)) if (ev.ID == s_cst(int, Frame->InterruptNumber))
#endif #endif
{ {
((Handler *)ev.Data)->OnInterruptReceived(Frame); Handler *hnd = (Handler *)ev.Data;
InterruptHandled = true; hnd->OnInterruptReceived(Frame);
} InterruptHandled = true;
} }
}
if (!InterruptHandled) if (!InterruptHandled)
{ {
error("IRQ%ld is unhandled on CPU %d.", Frame->InterruptNumber - 32, Core); error("IRQ%ld is unhandled on CPU %d.", Frame->InterruptNumber - 32, Core);
if (Frame->InterruptNumber == CPU::x86::IRQ1) if (Frame->InterruptNumber == CPU::x86::IRQ1)
{ {
uint8_t scancode = inb(0x60); uint8_t scancode = inb(0x60);
warn("IRQ1 is the keyboard interrupt. Scancode: %#x", scancode); warn("IRQ1 is the keyboard interrupt. Scancode: %#x", scancode);
} }
} }
if (likely(apic[Core])) if (likely(apic[Core]))
{ {
((APIC::APIC *)Interrupts::apic[Core])->EOI(); ((APIC::APIC *)Interrupts::apic[Core])->EOI();
// TODO: Handle PIC too // TODO: Handle PIC too
return; return;
} }
// TODO: PIC // TODO: PIC
} }
#elif defined(a32) #elif defined(a32)
void *Frame = Data; void *Frame = Data;
#elif defined(aa64) #elif defined(aa64)
CPU::aarch64::TrapFrame *Frame = (CPU::aarch64::TrapFrame *)Data; CPU::aarch64::TrapFrame *Frame = (CPU::aarch64::TrapFrame *)Data;
#endif #endif
error("HALT HALT HALT HALT HALT HALT HALT HALT HALT"); error("HALT HALT HALT HALT HALT HALT HALT HALT HALT");
CPU::Stop(); CPU::Stop();
} }
Handler::Handler(int InterruptNumber) Handler::Handler(int InterruptNumber)
{ {
foreach (auto ev in RegisteredEvents) foreach (auto ev in RegisteredEvents)
{ {
if (ev.ID == InterruptNumber) if (ev.ID == InterruptNumber)
{ {
warn("IRQ%d is already registered.", InterruptNumber); warn("IRQ%d is already registered.", InterruptNumber);
} }
} }
debug("Registering interrupt handler for IRQ%d.", InterruptNumber); debug("Registering interrupt handler for IRQ%d.", InterruptNumber);
this->InterruptNumber = InterruptNumber; this->InterruptNumber = InterruptNumber;
RegisteredEvents.push_back({InterruptNumber, this}); RegisteredEvents.push_back({InterruptNumber, this});
} }
Handler::~Handler() Handler::~Handler()
{ {
debug("Unregistering interrupt handler for IRQ%d.", this->InterruptNumber); debug("Unregistering interrupt handler for IRQ%d.", this->InterruptNumber);
for (size_t i = 0; i < RegisteredEvents.size(); i++)
{ forItr(itr, RegisteredEvents)
if (RegisteredEvents[i].ID == this->InterruptNumber) {
{ if (itr->ID == this->InterruptNumber)
RegisteredEvents.remove(i); {
return; RegisteredEvents.erase(itr);
} return;
} }
warn("Event %d not found.", this->InterruptNumber); }
} warn("Event %d not found.", this->InterruptNumber);
}
#if defined(a64) #if defined(a64)
void Handler::OnInterruptReceived(CPU::x64::TrapFrame *Frame) void Handler::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
{ {
trace("Unhandled interrupt IRQ%d", Frame->InterruptNumber - 32); trace("Unhandled interrupt IRQ%d", Frame->InterruptNumber - 32);
#elif defined(a32) #elif defined(a32)
void Handler::OnInterruptReceived(CPU::x32::TrapFrame *Frame) void Handler::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
{ {
trace("Unhandled interrupt received"); trace("Unhandled interrupt received");
#elif defined(aa64) #elif defined(aa64)
void Handler::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame) void Handler::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame)
{ {
trace("Unhandled interrupt received"); trace("Unhandled interrupt received");
#endif #endif
} }
} }

View File

@ -27,52 +27,67 @@
#endif #endif
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wframe-address" #pragma GCC diagnostic ignored "-Wframe-address"
void PrintStacktrace(LockClass::SpinLockData *Lock) void PrintStacktrace(LockClass::SpinLockData *Lock)
{ {
if (KernelSymbolTable) if (KernelSymbolTable)
{ {
struct StackFrame struct StackFrame
{ {
uintptr_t BasePointer; uintptr_t BasePointer;
uintptr_t ReturnAddress; uintptr_t ReturnAddress;
}; };
char DbgAttempt[1024] = "\0"; // char DbgAttempt[1024] = "\0";
char DbgHolder[1024] = "\0"; // char DbgHolder[1024] = "\0";
StackFrame *FrameAttempt = (StackFrame *)Lock->StackPointerAttempt.load(); std::string DbgAttempt = "\0";
StackFrame *FrameHolder = (StackFrame *)Lock->StackPointerHolder.load(); std::string DbgHolder = "\0";
while (Memory::Virtual().Check(FrameAttempt)) StackFrame *FrameAttempt = (StackFrame *)Lock->StackPointerAttempt.load();
{ StackFrame *FrameHolder = (StackFrame *)Lock->StackPointerHolder.load();
sprintf(DbgAttempt + strlen(DbgAttempt), "%s<-", KernelSymbolTable->GetSymbolFromAddress(FrameAttempt->ReturnAddress));
FrameAttempt = (StackFrame *)FrameAttempt->BasePointer;
}
while (Memory::Virtual().Check(FrameHolder)) while (Memory::Virtual().Check(FrameAttempt))
{ {
sprintf(DbgHolder + strlen(DbgHolder), "%s<-", KernelSymbolTable->GetSymbolFromAddress(FrameHolder->ReturnAddress)); DbgAttempt.concat(KernelSymbolTable->GetSymbolFromAddress(FrameAttempt->ReturnAddress));
FrameHolder = (StackFrame *)FrameHolder->BasePointer; DbgAttempt.concat("<-");
} FrameAttempt = (StackFrame *)FrameAttempt->BasePointer;
}
debug("Attempt: %s", DbgAttempt.c_str());
debug("Attempt: %s", DbgAttempt); while (Memory::Virtual().Check(FrameHolder))
debug("Holder: %s", DbgHolder); {
DbgHolder.concat(KernelSymbolTable->GetSymbolFromAddress(FrameHolder->ReturnAddress));
DbgHolder.concat("<-");
FrameHolder = (StackFrame *)FrameHolder->BasePointer;
}
// debug("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s", debug("Holder: %s", DbgHolder.c_str());
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(1)), // debug("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s",
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(2)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(3)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(1)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(4)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(2)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(5)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(3)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(6)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(4)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(7)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(5)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(8)), // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(6)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(9))); // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(7)),
} // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(8)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(9)));
}
} }
#pragma GCC diagnostic pop
#endif
#ifdef DEBUG
#define DEADLOCK_TIMEOUT 0x100000
#define DEADLOCK_TIMEOUT_DEBUGGER 0x1000
#else
#define DEADLOCK_TIMEOUT 0x10000000
#define DEADLOCK_TIMEOUT_DEBUGGER 0x100000
#endif #endif
bool ForceUnlock = false; bool ForceUnlock = false;
@ -80,161 +95,168 @@ std::atomic_size_t LocksCount = 0;
size_t GetLocksCount() { return LocksCount.load(); } size_t GetLocksCount() { return LocksCount.load(); }
void LockClass::DeadLock(SpinLockData Lock) void LockClass::Yield()
{ {
if (ForceUnlock) if (CPU::Interrupts(CPU::Check) &&
{ TaskManager &&
warn("Unlocking lock '%s' which it was held by '%s'...", Lock.AttemptingToGet, Lock.CurrentHolder); !TaskManager->IsPanic())
this->DeadLocks = 0; {
this->Unlock(); TaskManager->Yield();
return; }
}
CPUData *CoreData = GetCurrentCPU(); CPU::Pause();
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 held by %ld. (%ld times happened)", void LockClass::DeadLock(SpinLockData &Lock)
Lock.AttemptingToGet, Lock.CurrentHolder, {
Lock.Count, Lock.Count > 1 ? "locks" : "lock", if (ForceUnlock)
CPU::Interrupts(CPU::Check) ? "enabled" : "disabled", {
CCore, Lock.Core, this->DeadLocks); 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 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);
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
PrintStacktrace(&Lock); PrintStacktrace(&Lock);
#endif #endif
// TODO: Print on screen too. // TODO: Print on screen too.
this->DeadLocks++; this->DeadLocks++;
if (Config.UnlockDeadLock && this->DeadLocks.load() > 10) if (Config.UnlockDeadLock && this->DeadLocks.load() > 10)
{ {
warn("Unlocking lock '%s' to prevent deadlock. (this is enabled in the kernel config)", Lock.AttemptingToGet); warn("Unlocking lock '%s' to prevent deadlock. (this is enabled in the kernel config)", Lock.AttemptingToGet);
this->DeadLocks = 0; this->DeadLocks = 0;
this->Unlock(); this->Unlock();
} }
if (TaskManager && !TaskManager->IsPanic()) this->Yield();
TaskManager->Schedule();
} }
int LockClass::Lock(const char *FunctionName) int LockClass::Lock(const char *FunctionName)
{ {
LockData.AttemptingToGet = FunctionName; LockData.AttemptingToGet = FunctionName;
LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0);
Retry: Retry:
int i = 0; int i = 0;
while (IsLocked.exchange(true, std::memory_order_acquire) && ++i < (DebuggerIsAttached ? 0x100000 : 0x10000000)) while (IsLocked.exchange(true, std::memory_order_acquire) &&
{ ++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
/* FIXME */ {
// if (TaskManager && !TaskManager->IsPanic()) this->Yield();
// TaskManager->Schedule(); }
// else
CPU::Pause();
}
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000)) if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
{ {
DeadLock(LockData); DeadLock(LockData);
goto Retry; goto Retry;
} }
LockData.Count++; LockData.Count++;
LockData.CurrentHolder = FunctionName; LockData.CurrentHolder = FunctionName;
LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0);
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
if (CoreData != nullptr) if (CoreData != nullptr)
LockData.Core = CoreData->ID; LockData.Core = CoreData->ID;
LocksCount++; LocksCount++;
__sync; __sync;
return 0; return 0;
} }
int LockClass::Unlock() int LockClass::Unlock()
{ {
__sync; __sync;
IsLocked.store(false, std::memory_order_release); IsLocked.store(false, std::memory_order_release);
LockData.Count--; LockData.Count--;
LocksCount--; LocksCount--;
return 0; return 0;
} }
void LockClass::TimeoutDeadLock(SpinLockData Lock, uint64_t Timeout) void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout)
{ {
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
long CCore = 0xdead; long CCore = 0xdead;
if (CoreData != nullptr) if (CoreData != nullptr)
CCore = CoreData->ID; CCore = CoreData->ID;
uint64_t Counter = TimeManager->GetCounter(); uint64_t Counter = TimeManager->GetCounter();
warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).", warn("Potential deadlock in lock '%s' held by '%s'! %ld %s in queue. Interrupts are %s. Core %ld held by %ld. Timeout in %ld (%ld ticks remaining).",
Lock.AttemptingToGet, Lock.CurrentHolder, Lock.AttemptingToGet, Lock.CurrentHolder,
Lock.Count, Lock.Count > 1 ? "locks" : "lock", Lock.Count, Lock.Count > 1 ? "locks" : "lock",
CPU::Interrupts(CPU::Check) ? "enabled" : "disabled", CPU::Interrupts(CPU::Check) ? "enabled" : "disabled",
CCore, Lock.Core, Timeout, Timeout - Counter); CCore, Lock.Core, Timeout, Timeout - Counter);
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
PrintStacktrace(&Lock); PrintStacktrace(&Lock);
#endif #endif
if (Timeout < Counter) if (Timeout < Counter)
{ {
warn("Unlocking lock '%s' because of timeout. (%ld < %ld)", Lock.AttemptingToGet, Timeout, Counter); warn("Unlocking lock '%s' because of timeout. (%ld < %ld)",
this->Unlock(); Lock.AttemptingToGet, Timeout, Counter);
} this->Unlock();
}
if (TaskManager && !TaskManager->IsPanic()) this->Yield();
TaskManager->Schedule();
} }
int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout) int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout)
{ {
if (!TimeManager) if (!TimeManager)
return Lock(FunctionName); return Lock(FunctionName);
LockData.AttemptingToGet = FunctionName; LockData.AttemptingToGet = FunctionName;
LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0);
std::atomic_uint64_t Target = 0; std::atomic_uint64_t Target = 0;
Retry: Retry:
int i = 0; int i = 0;
while (IsLocked.exchange(true, std::memory_order_acquire) && ++i < (DebuggerIsAttached ? 0x100000 : 0x10000000)) while (IsLocked.exchange(true, std::memory_order_acquire) &&
{ ++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
/* FIXME */ {
// if (TaskManager && !TaskManager->IsPanic()) this->Yield();
// TaskManager->Schedule(); }
// else
CPU::Pause();
}
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000)) if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
{ {
if (Target.load() == 0) if (Target.load() == 0)
Target.store(TimeManager->CalculateTarget(Timeout, Time::Units::Milliseconds)); Target.store(TimeManager->CalculateTarget(Timeout,
TimeoutDeadLock(LockData, Target.load()); Time::Units::Milliseconds));
goto Retry; TimeoutDeadLock(LockData, Target.load());
} goto Retry;
}
LockData.Count++; LockData.Count++;
LockData.CurrentHolder = FunctionName; LockData.CurrentHolder = FunctionName;
LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0);
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
if (CoreData != nullptr) if (CoreData != nullptr)
LockData.Core = CoreData->ID; LockData.Core = CoreData->ID;
LocksCount++; LocksCount++;
__sync; __sync;
return 0; return 0;
} }

View File

@ -22,7 +22,7 @@ Xalloc_def;
#define XALLOC_CONCAT(x, y) x##y #define XALLOC_CONCAT(x, y) x##y
#define XStoP(d) (((d) + PAGE_SIZE - 1) / PAGE_SIZE) #define XStoP(d) (((d) + PAGE_SIZE - 1) / PAGE_SIZE)
#define XPtoS(d) ((d)*PAGE_SIZE) #define XPtoS(d) ((d)*PAGE_SIZE)
#define Xalloc_BlockChecksum 0xA110C #define Xalloc_BlockSanityKey 0xA110C
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages); extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages);
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages); extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages);
@ -55,7 +55,7 @@ namespace Xalloc
public: public:
void *Address = nullptr; void *Address = nullptr;
int Checksum = Xalloc_BlockChecksum; int Sanity = Xalloc_BlockSanityKey;
Xsize_t Size = 0; Xsize_t Size = 0;
Block *Next = nullptr; Block *Next = nullptr;
Block *Last = nullptr; Block *Last = nullptr;
@ -63,7 +63,7 @@ namespace Xalloc
bool Check() bool Check()
{ {
if (this->Checksum != Xalloc_BlockChecksum) if (this->Sanity != Xalloc_BlockSanityKey)
return false; return false;
return true; return true;
} }
@ -168,8 +168,8 @@ namespace Xalloc
{ {
if (!CurrentBlock->Check()) if (!CurrentBlock->Check())
{ {
Xalloc_err("Block %#lx has an invalid checksum! (%#x != %#x)", Xalloc_err("Block %#lx has an invalid sanity key! (%#x != %#x)",
(Xuint64_t)CurrentBlock, CurrentBlock->Checksum, Xalloc_BlockChecksum); (Xuint64_t)CurrentBlock, CurrentBlock->Sanity, Xalloc_BlockSanityKey);
while (Xalloc_StopOnFail) while (Xalloc_StopOnFail)
; ;
} }
@ -210,8 +210,8 @@ namespace Xalloc
{ {
if (!CurrentBlock->Check()) if (!CurrentBlock->Check())
{ {
Xalloc_err("Block %#lx has an invalid checksum! (%#x != %#x)", Xalloc_err("Block %#lx has an invalid sanity key! (%#x != %#x)",
(Xuint64_t)CurrentBlock, CurrentBlock->Checksum, Xalloc_BlockChecksum); (Xuint64_t)CurrentBlock, CurrentBlock->Sanity, Xalloc_BlockSanityKey);
while (Xalloc_StopOnFail) while (Xalloc_StopOnFail)
; ;
} }

File diff suppressed because it is too large Load Diff

View File

@ -22,250 +22,266 @@
namespace Memory namespace Memory
{ {
ReadFSFunction(MEM_Read) ReadFSFunction(MEM_Read)
{ {
if (!Size) if (!Size)
Size = node->Length; Size = node->Length;
if ((size_t)node->Offset > node->Length) if (RefOffset > node->Length)
return 0; return 0;
if (node->Offset + Size > node->Length) if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - node->Offset; Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + node->Offset), Size); memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size; return Size;
} }
WriteFSFunction(MEM_Write) WriteFSFunction(MEM_Write)
{ {
if (!Size) if (!Size)
Size = node->Length; Size = node->Length;
if ((size_t)node->Offset > node->Length) if (RefOffset > node->Length)
return 0; return 0;
if (node->Offset + Size > node->Length) if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - node->Offset; Size = node->Length - RefOffset;
memcpy((uint8_t *)(node->Address + node->Offset), Buffer, Size); memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
return Size; return Size;
} }
VirtualFileSystem::FileSystemOperations mem_op = { VirtualFileSystem::FileSystemOperations mem_op = {
.Name = "mem", .Name = "mem",
.Read = MEM_Read, .Read = MEM_Read,
.Write = MEM_Write, .Write = MEM_Write,
}; };
uint64_t MemMgr::GetAllocatedMemorySize() uint64_t MemMgr::GetAllocatedMemorySize()
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
uint64_t Size = 0; uint64_t Size = 0;
foreach (auto ap in AllocatedPagesList) foreach (auto ap in AllocatedPagesList)
Size += ap.PageCount; Size += ap.PageCount;
return FROM_PAGES(Size); return FROM_PAGES(Size);
} }
bool MemMgr::Add(void *Address, size_t Count) bool MemMgr::Add(void *Address, size_t Count)
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
if (Address == nullptr) if (Address == nullptr)
{ {
error("Address is null!"); error("Address is null!");
return false; return false;
} }
if (Count == 0) if (Count == 0)
{ {
error("Count is 0!"); error("Count is 0!");
return false; return false;
} }
for (size_t i = 0; i < AllocatedPagesList.size(); i++) for (size_t i = 0; i < AllocatedPagesList.size(); i++)
{ {
if (AllocatedPagesList[i].Address == Address) if (AllocatedPagesList[i].Address == Address)
{ {
error("Address already exists!"); error("Address already exists!");
return false; return false;
} }
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address) else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
{ {
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address) if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
{ {
error("Address intersects with an allocated page!"); error("Address intersects with an allocated page!");
return false; return false;
} }
} }
else else
{ {
if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address) if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address)
{ {
error("Address intersects with an allocated page!"); error("Address intersects with an allocated page!");
return false; return false;
} }
} }
} }
if (this->Directory) if (this->Directory)
{ {
char FileName[64]; char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count); #if defined(a64) || defined(aa64)
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory); sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
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)
{
SmartLock(MgrLock);
void *Address = KernelAllocator.RequestPages(Count);
for (size_t i = 0; i < Count; i++)
{
int Flags = Memory::PTFlag::RW;
if (User)
Flags |= Memory::PTFlag::US;
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
Memory::Virtual vmm = Memory::Virtual(this->Table);
vmm.Remap(AddressToMap, AddressToMap, 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 allocated page
if it's a user page. */
if (User)
memset(Address, 0, Count * PAGE_SIZE);
return Address;
}
void MemMgr::FreePages(void *Address, size_t Count)
{
SmartLock(MgrLock);
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);
Memory::Virtual vmm = Memory::Virtual(this->Table);
for (size_t i = 0; i < Count; i++)
{
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
vmm.Remap(AddressToMap, AddressToMap, Memory::PTFlag::RW);
// vmm.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)
{
SmartLock(MgrLock);
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(PageTable *Table, VirtualFileSystem::Node *Directory)
{
SmartLock(MgrLock);
if (Table)
this->Table = Table;
else
{
#if defined(a64)
this->Table = (PageTable *)CPU::x64::readcr3().raw;
#elif defined(a32) #elif defined(a32)
this->Table = (PageTable *)CPU::x32::readcr3().raw; sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#endif #endif
} 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;
}
}
this->Directory = Directory; AllocatedPagesList.push_back({Address, Count});
debug("+ %#lx", this); return true;
} }
MemMgr::~MemMgr() void *MemMgr::RequestPages(size_t Count, bool User)
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
foreach (auto ap in AllocatedPagesList) void *Address = KernelAllocator.RequestPages(Count);
{ for (size_t i = 0; i < Count; i++)
KernelAllocator.FreePages(ap.Address, ap.PageCount); {
Memory::Virtual vmm = Memory::Virtual(this->Table); int Flags = Memory::PTFlag::RW;
for (size_t i = 0; i < ap.PageCount; i++) if (User)
vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), Flags |= Memory::PTFlag::US;
(void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),
Memory::PTFlag::RW);
}
if (this->Directory) void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
{
foreach (auto Child in this->Directory->Children)
vfs->Delete(Child, true);
}
debug("- %#lx", this); Memory::Virtual vmm = Memory::Virtual(this->Table);
} vmm.Remap(AddressToMap, AddressToMap, Flags);
}
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#endif
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 allocated page
if it's a user page. */
if (User)
memset(Address, 0, Count * PAGE_SIZE);
return Address;
}
void MemMgr::FreePages(void *Address, size_t Count)
{
SmartLock(MgrLock);
forItr(itr, AllocatedPagesList)
{
if (itr->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 (itr->PageCount != Count)
{
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", itr->PageCount, Count);
return;
}
KernelAllocator.FreePages(Address, Count);
Memory::Virtual vmm = Memory::Virtual(this->Table);
for (size_t i = 0; i < Count; i++)
{
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
vmm.Remap(AddressToMap, AddressToMap, Memory::PTFlag::RW);
// vmm.Unmap((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
}
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#endif
if (!vfs->Delete(FileName, false, this->Directory))
error("Failed to delete file %s", FileName);
}
AllocatedPagesList.erase(itr);
return;
}
}
}
void MemMgr::DetachAddress(void *Address)
{
SmartLock(MgrLock);
forItr(itr, AllocatedPagesList)
{
if (itr->Address == Address)
{
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, itr->PageCount);
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, itr->PageCount);
#endif
if (!vfs->Delete(FileName, false, this->Directory))
error("Failed to delete file %s", FileName);
}
AllocatedPagesList.erase(itr);
return;
}
}
}
MemMgr::MemMgr(PageTable *Table, VirtualFileSystem::Node *Directory)
{
SmartLock(MgrLock);
if (Table)
this->Table = Table;
else
{
#if defined(a64)
this->Table = (PageTable *)CPU::x64::readcr3().raw;
#elif defined(a32)
this->Table = (PageTable *)CPU::x32::readcr3().raw;
#endif
}
this->Directory = Directory;
debug("+ %#lx %s", this,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "");
}
MemMgr::~MemMgr()
{
SmartLock(MgrLock);
foreach (auto ap in AllocatedPagesList)
{
KernelAllocator.FreePages(ap.Address, ap.PageCount);
Memory::Virtual vmm = Memory::Virtual(this->Table);
for (size_t i = 0; i < ap.PageCount; i++)
vmm.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 %s", this,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "");
}
} }

View File

@ -26,467 +26,477 @@
namespace Memory namespace Memory
{ {
uint64_t Physical::GetTotalMemory() uint64_t Physical::GetTotalMemory()
{ {
SmartLock(this->MemoryLock); return this->TotalMemory.load();
return this->TotalMemory; }
}
uint64_t Physical::GetFreeMemory() uint64_t Physical::GetFreeMemory()
{ {
SmartLock(this->MemoryLock); return this->FreeMemory.load();
return this->FreeMemory; }
}
uint64_t Physical::GetReservedMemory() uint64_t Physical::GetReservedMemory()
{ {
SmartLock(this->MemoryLock); return this->ReservedMemory.load();
return this->ReservedMemory; }
}
uint64_t Physical::GetUsedMemory() uint64_t Physical::GetUsedMemory()
{ {
SmartLock(this->MemoryLock); return this->UsedMemory.load();
return this->UsedMemory; }
}
bool Physical::SwapPage(void *Address) bool Physical::SwapPage(void *Address)
{ {
fixme("%p", Address); fixme("%p", Address);
return false; return false;
} }
bool Physical::SwapPages(void *Address, size_t PageCount) bool Physical::SwapPages(void *Address, size_t PageCount)
{ {
for (size_t i = 0; i < PageCount; i++) for (size_t i = 0; i < PageCount; i++)
{ {
if (!this->SwapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)))) if (!this->SwapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
return false; return false;
} }
return false; return false;
} }
bool Physical::UnswapPage(void *Address) bool Physical::UnswapPage(void *Address)
{ {
fixme("%p", Address); fixme("%p", Address);
return false; return false;
} }
bool Physical::UnswapPages(void *Address, size_t PageCount) bool Physical::UnswapPages(void *Address, size_t PageCount)
{ {
for (size_t i = 0; i < PageCount; i++) for (size_t i = 0; i < PageCount; i++)
{ {
if (!this->UnswapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)))) if (!this->UnswapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
return false; return false;
} }
return false; return false;
} }
void *Physical::RequestPage() void *Physical::RequestPage()
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++) for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{ {
if (PageBitmap[PageBitmapIndex] == true) if (PageBitmap[PageBitmapIndex] == true)
continue; continue;
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE)); this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
char LockTmpStr[64]; char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__); strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk"); strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000); mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "RequestPage( )=%p~%p\n\r", sprintf(mExtTrkLog, "RequestPage( )=%p~%p\n\r",
(void *)(PageBitmapIndex * PAGE_SIZE), __builtin_return_address(0)); (void *)(PageBitmapIndex * PAGE_SIZE), __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3); UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++) for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{ {
if (mExtTrkLog[i] == '\r') if (mExtTrkLog[i] == '\r')
break; break;
mTrkUART.Write(mExtTrkLog[i]); mTrkUART.Write(mExtTrkLog[i]);
} }
mExtTrkLock.Unlock(); mExtTrkLock.Unlock();
} }
#endif #endif
return (void *)(PageBitmapIndex * PAGE_SIZE); return (void *)(PageBitmapIndex * PAGE_SIZE);
} }
if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE))) if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE)))
{ {
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE)); this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE); return (void *)(PageBitmapIndex * PAGE_SIZE);
} }
if (TaskManager && !TaskManager->IsPanic()) if (TaskManager && !TaskManager->IsPanic())
{ {
error("Out of memory! Killing current process..."); error("Out of memory! Killing current process...");
TaskManager->KillProcess(TaskManager->GetCurrentProcess(), Tasking::KILL_OOM); TaskManager->KillProcess(thisProcess, Tasking::KILL_OOM);
TaskManager->Schedule(); TaskManager->Yield();
} }
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory)); error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
CPU::Stop(); TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
__builtin_unreachable(); KPrint("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
} TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
CPU::Stop();
__builtin_unreachable();
}
void *Physical::RequestPages(size_t Count) void *Physical::RequestPages(size_t Count)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++) for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{ {
if (PageBitmap[PageBitmapIndex] == true) if (PageBitmap[PageBitmapIndex] == true)
continue; continue;
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++) for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
{ {
if (PageBitmap[Index] == true) if (PageBitmap[Index] == true)
continue; continue;
for (size_t i = 0; i < Count; i++) for (size_t i = 0; i < Count; i++)
{ {
if (PageBitmap[Index + i] == true) if (PageBitmap[Index + i] == true)
goto NextPage; goto NextPage;
} }
this->LockPages((void *)(Index * PAGE_SIZE), Count); this->LockPages((void *)(Index * PAGE_SIZE), Count);
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
char LockTmpStr[64]; char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__); strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk"); strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000); mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "RequestPages( %ld )=%p~%p\n\r", sprintf(mExtTrkLog, "RequestPages( %ld )=%p~%p\n\r",
Count, Count,
(void *)(Index * PAGE_SIZE), __builtin_return_address(0)); (void *)(Index * PAGE_SIZE), __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3); UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++) for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{ {
if (mExtTrkLog[i] == '\r') if (mExtTrkLog[i] == '\r')
break; break;
mTrkUART.Write(mExtTrkLog[i]); mTrkUART.Write(mExtTrkLog[i]);
} }
mExtTrkLock.Unlock(); mExtTrkLock.Unlock();
} }
#endif #endif
return (void *)(Index * PAGE_SIZE); return (void *)(Index * PAGE_SIZE);
NextPage: NextPage:
Index += Count; Index += Count;
continue; continue;
} }
} }
if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count)) if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count))
{ {
this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count); this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count);
return (void *)(PageBitmapIndex * PAGE_SIZE); return (void *)(PageBitmapIndex * PAGE_SIZE);
} }
if (TaskManager && !TaskManager->IsPanic()) if (TaskManager && !TaskManager->IsPanic())
{ {
error("Out of memory! Killing current process..."); error("Out of memory! Killing current process...");
TaskManager->KillProcess(TaskManager->GetCurrentProcess(), Tasking::KILL_OOM); TaskManager->KillProcess(thisProcess, Tasking::KILL_OOM);
TaskManager->Schedule(); TaskManager->Yield();
} }
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory)); error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
CPU::Halt(true); TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
__builtin_unreachable(); KPrint("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
} TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
CPU::Halt(true);
__builtin_unreachable();
}
void Physical::FreePage(void *Address) void Physical::FreePage(void *Address)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
if (unlikely(Address == nullptr)) if (unlikely(Address == nullptr))
{ {
warn("Null pointer passed to FreePage."); warn("Null pointer passed to FreePage.");
return; return;
} }
size_t Index = (size_t)Address / PAGE_SIZE; size_t Index = (size_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false)) if (unlikely(PageBitmap[Index] == false))
{ {
warn("Tried to free an already free page. (%p)", Address); warn("Tried to free an already free page. (%p)",
return; Address);
} return;
}
if (PageBitmap.Set(Index, false)) if (PageBitmap.Set(Index, false))
{ {
FreeMemory += PAGE_SIZE; FreeMemory += PAGE_SIZE;
UsedMemory -= PAGE_SIZE; UsedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index) if (PageBitmapIndex > Index)
PageBitmapIndex = Index; PageBitmapIndex = Index;
} }
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
char LockTmpStr[64]; char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__); strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk"); strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000); mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "FreePage( %p )~%p\n\r", sprintf(mExtTrkLog, "FreePage( %p )~%p\n\r",
Address, Address,
__builtin_return_address(0)); __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3); UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++) for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{ {
if (mExtTrkLog[i] == '\r') if (mExtTrkLog[i] == '\r')
break; break;
mTrkUART.Write(mExtTrkLog[i]); mTrkUART.Write(mExtTrkLog[i]);
} }
mExtTrkLock.Unlock(); mExtTrkLock.Unlock();
} }
#endif #endif
} }
void Physical::FreePages(void *Address, size_t Count) void Physical::FreePages(void *Address, size_t Count)
{ {
if (unlikely(Address == nullptr || Count == 0)) 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" : ""); warn("%s%s%s passed to FreePages.", Address == nullptr ? "Null pointer " : "", Address == nullptr && Count == 0 ? "and " : "", Count == 0 ? "Zero count" : "");
return; return;
} }
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
char LockTmpStr[64]; char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__); strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk"); strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000); mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "!FreePages( %p %ld )~%p\n\r", sprintf(mExtTrkLog, "!FreePages( %p %ld )~%p\n\r",
Address, Count, Address, Count,
__builtin_return_address(0)); __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3); UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++) for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{ {
if (mExtTrkLog[i] == '\r') if (mExtTrkLog[i] == '\r')
break; break;
mTrkUART.Write(mExtTrkLog[i]); mTrkUART.Write(mExtTrkLog[i]);
} }
mExtTrkLock.Unlock(); mExtTrkLock.Unlock();
} }
#endif #endif
for (size_t t = 0; t < Count; t++) for (size_t t = 0; t < Count; t++)
this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE))); this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
} }
void Physical::LockPage(void *Address) void Physical::LockPage(void *Address)
{ {
if (unlikely(Address == nullptr)) if (unlikely(Address == nullptr))
warn("Trying to lock null address."); warn("Trying to lock null address.");
uintptr_t Index = (uintptr_t)Address / PAGE_SIZE; uintptr_t Index = (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true)) if (unlikely(PageBitmap[Index] == true))
return; return;
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
FreeMemory -= PAGE_SIZE; FreeMemory -= PAGE_SIZE;
UsedMemory += PAGE_SIZE; UsedMemory += PAGE_SIZE;
} }
} }
void Physical::LockPages(void *Address, size_t PageCount) void Physical::LockPages(void *Address, size_t PageCount)
{ {
if (unlikely(Address == nullptr || PageCount == 0)) if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : ""); warn("Trying to lock %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t i = 0; i < PageCount; i++) for (size_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))); this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
} }
void Physical::ReservePage(void *Address) void Physical::ReservePage(void *Address)
{ {
if (unlikely(Address == nullptr)) if (unlikely(Address == nullptr))
warn("Trying to reserve null address."); warn("Trying to reserve null address.");
uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE; uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true)) if (unlikely(PageBitmap[Index] == true))
return; return;
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
FreeMemory -= PAGE_SIZE; FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE; ReservedMemory += PAGE_SIZE;
} }
} }
void Physical::ReservePages(void *Address, size_t PageCount) void Physical::ReservePages(void *Address, size_t PageCount)
{ {
if (unlikely(Address == nullptr || PageCount == 0)) if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : ""); warn("Trying to reserve %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++) for (size_t t = 0; t < PageCount; t++)
{ {
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE; uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true)) if (unlikely(PageBitmap[Index] == true))
return; return;
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
FreeMemory -= PAGE_SIZE; FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE; ReservedMemory += PAGE_SIZE;
} }
} }
} }
void Physical::UnreservePage(void *Address) void Physical::UnreservePage(void *Address)
{ {
if (unlikely(Address == nullptr)) if (unlikely(Address == nullptr))
warn("Trying to unreserve null address."); warn("Trying to unreserve null address.");
uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE; uintptr_t Index = (Address == NULL) ? 0 : (uintptr_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false)) if (unlikely(PageBitmap[Index] == false))
return; return;
if (PageBitmap.Set(Index, false)) if (PageBitmap.Set(Index, false))
{ {
FreeMemory += PAGE_SIZE; FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE; ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index) if (PageBitmapIndex > Index)
PageBitmapIndex = Index; PageBitmapIndex = Index;
} }
} }
void Physical::UnreservePages(void *Address, size_t PageCount) void Physical::UnreservePages(void *Address, size_t PageCount)
{ {
if (unlikely(Address == nullptr || PageCount == 0)) if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : ""); warn("Trying to unreserve %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++) for (size_t t = 0; t < PageCount; t++)
{ {
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE; uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false)) if (unlikely(PageBitmap[Index] == false))
return; return;
if (PageBitmap.Set(Index, false)) if (PageBitmap.Set(Index, false))
{ {
FreeMemory += PAGE_SIZE; FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE; ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index) if (PageBitmapIndex > Index)
PageBitmapIndex = Index; PageBitmapIndex = Index;
} }
} }
} }
void Physical::Init() void Physical::Init()
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
uint64_t MemorySize = bInfo.Memory.Size; uint64_t MemorySize = bInfo.Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize)); debug("Memory size: %lld bytes (%ld pages)",
TotalMemory = MemorySize; MemorySize, TO_PAGES(MemorySize));
FreeMemory = MemorySize; TotalMemory = MemorySize;
FreeMemory = MemorySize;
size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1; size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1;
uintptr_t BitmapAddress = 0x0; uintptr_t BitmapAddress = 0x0;
size_t BitmapAddressSize = 0; size_t BitmapAddressSize = 0;
uintptr_t KernelStart = (uintptr_t)bInfo.Kernel.PhysicalBase; uintptr_t KernelStart = (uintptr_t)bInfo.Kernel.PhysicalBase;
uintptr_t KernelEnd = (uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size; uintptr_t KernelEnd = (uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size;
for (uint64_t i = 0; i < bInfo.Memory.Entries; i++) for (uint64_t i = 0; i < bInfo.Memory.Entries; i++)
{ {
if (bInfo.Memory.Entry[i].Type == Usable) if (bInfo.Memory.Entry[i].Type == Usable)
{ {
uintptr_t RegionAddress = (uintptr_t)bInfo.Memory.Entry[i].BaseAddress; uintptr_t RegionAddress = (uintptr_t)bInfo.Memory.Entry[i].BaseAddress;
uintptr_t RegionSize = bInfo.Memory.Entry[i].Length; uintptr_t RegionSize = bInfo.Memory.Entry[i].Length;
/* We don't want to use 0 as a memory address. */ /* We don't want to use the first 1MB of memory. */
if (RegionAddress == 0x0) if (RegionAddress <= 0xFFFFF)
continue; continue;
if ((BitmapSize + 0x100) > RegionSize) if ((BitmapSize + 0x100) > RegionSize)
{ {
debug("Region %p-%p (%dMB) is too small for bitmap.", debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)RegionAddress, (void *)RegionAddress,
(void *)(RegionAddress + RegionSize), (void *)(RegionAddress + RegionSize),
TO_MB(RegionSize)); TO_MiB(RegionSize));
continue; continue;
} }
BitmapAddress = RegionAddress; BitmapAddress = RegionAddress;
BitmapAddressSize = RegionSize; BitmapAddressSize = RegionSize;
if (RegionAddress >= KernelStart && KernelEnd <= (RegionAddress + RegionSize)) if (RegionAddress >= KernelStart && KernelEnd <= (RegionAddress + RegionSize))
{ {
BitmapAddress = KernelEnd; BitmapAddress = KernelEnd;
BitmapAddressSize = RegionSize - (KernelEnd - RegionAddress); BitmapAddressSize = RegionSize - (KernelEnd - RegionAddress);
} }
if ((BitmapSize + 0x100) > BitmapAddressSize) if ((BitmapSize + 0x100) > BitmapAddressSize)
{ {
debug("Region %p-%p (%dMB) is too small for bitmap.", debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)RegionAddress, (void *)RegionAddress,
(void *)(RegionAddress + BitmapAddressSize), (void *)(RegionAddress + BitmapAddressSize),
TO_MB(BitmapAddressSize)); TO_MiB(BitmapAddressSize));
continue; continue;
} }
for (size_t i = 0; i < MAX_MODULES; i++) for (size_t i = 0; i < MAX_MODULES; i++)
{ {
uintptr_t ModuleStart = (uintptr_t)bInfo.Modules[i].Address; uintptr_t ModuleStart = (uintptr_t)bInfo.Modules[i].Address;
uintptr_t ModuleEnd = (uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size; uintptr_t ModuleEnd = (uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size;
if (ModuleStart == 0x0) if (ModuleStart == 0x0)
break; break;
if (RegionAddress >= ModuleStart && ModuleEnd <= (RegionAddress + RegionSize)) if (RegionAddress >= ModuleStart && ModuleEnd <= (RegionAddress + RegionSize))
{ {
BitmapAddress = ModuleEnd; BitmapAddress = ModuleEnd;
BitmapAddressSize = RegionSize - (ModuleEnd - RegionAddress); BitmapAddressSize = RegionSize - (ModuleEnd - RegionAddress);
} }
} }
if ((BitmapSize + 0x100) > BitmapAddressSize) if ((BitmapSize + 0x100) > BitmapAddressSize)
{ {
debug("Region %p-%p (%dMB) is too small for bitmap.", debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)BitmapAddress, (void *)BitmapAddress,
(void *)(BitmapAddress + BitmapAddressSize), (void *)(BitmapAddress + BitmapAddressSize),
TO_MB(BitmapAddressSize)); TO_MiB(BitmapAddressSize));
continue; continue;
} }
debug("Found free memory for bitmap: %p (%dMB)", debug("Found free memory for bitmap: %p (%d MiB)",
(void *)BitmapAddress, (void *)BitmapAddress,
TO_MB(BitmapAddressSize)); TO_MiB(BitmapAddressSize));
break; break;
} }
} }
if (BitmapAddress == 0x0) if (BitmapAddress == 0x0)
{ {
error("No free memory found!"); error("No free memory found!");
CPU::Stop(); CPU::Stop();
} }
/* TODO: Read swap config and make the configure the bitmap size correctly */ /* TODO: Read swap config and make the configure the bitmap size correctly */
debug("Initializing Bitmap at %p-%p (%d Bytes)", debug("Initializing Bitmap at %p-%p (%d Bytes)",
BitmapAddress, BitmapAddress,
(void *)(BitmapAddress + BitmapSize), (void *)(BitmapAddress + BitmapSize),
BitmapSize); BitmapSize);
PageBitmap.Size = BitmapSize; PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)BitmapAddress; PageBitmap.Buffer = (uint8_t *)BitmapAddress;
for (size_t i = 0; i < BitmapSize; i++) for (size_t i = 0; i < BitmapSize; i++)
*(uint8_t *)(PageBitmap.Buffer + i) = 0; *(uint8_t *)(PageBitmap.Buffer + i) = 0;
ReserveEssentials(); ReserveEssentials();
} }
Physical::Physical() {} Physical::Physical() {}
Physical::~Physical() {} Physical::~Physical() {}
} }

View File

@ -18,6 +18,7 @@
#include <memory.hpp> #include <memory.hpp>
#include <debug.h> #include <debug.h>
#include <elf.h>
#ifdef DEBUG #ifdef DEBUG
#include <uart.hpp> #include <uart.hpp>
#endif #endif
@ -44,7 +45,13 @@ namespace Memory
for (uint64_t i = 0; i < bInfo.Memory.Entries; i++) for (uint64_t i = 0; i < bInfo.Memory.Entries; i++)
{ {
if (bInfo.Memory.Entry[i].Type == Usable) if (bInfo.Memory.Entry[i].Type == Usable)
this->UnreservePages(bInfo.Memory.Entry[i].BaseAddress, TO_PAGES(bInfo.Memory.Entry[i].Length)); {
if (uintptr_t(bInfo.Memory.Entry[i].BaseAddress) <= 0xFFFFF)
continue;
this->UnreservePages(bInfo.Memory.Entry[i].BaseAddress,
TO_PAGES(bInfo.Memory.Entry[i].Length));
}
} }
debug("Reserving 0x0-0xFFFFF range..."); debug("Reserving 0x0-0xFFFFF range...");
@ -57,18 +64,72 @@ namespace Memory
*/ */
this->ReservePages((void *)0x0, TO_PAGES(0xFFFFF)); this->ReservePages((void *)0x0, TO_PAGES(0xFFFFF));
debug("Reserving bitmap region %#lx-%#lx...", PageBitmap.Buffer, (void *)((uintptr_t)PageBitmap.Buffer + PageBitmap.Size)); debug("Reserving bitmap region %#lx-%#lx...",
PageBitmap.Buffer,
(void *)((uintptr_t)PageBitmap.Buffer + PageBitmap.Size));
this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size)); this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size));
debug("Reserving kernel physical region %#lx-%#lx...", bInfo.Kernel.PhysicalBase, (void *)((uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size)); debug("Reserving kernel physical region %#lx-%#lx...",
bInfo.Kernel.PhysicalBase,
(void *)((uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size));
this->ReservePages(bInfo.Kernel.PhysicalBase, TO_PAGES(bInfo.Kernel.Size)); this->ReservePages(bInfo.Kernel.PhysicalBase, TO_PAGES(bInfo.Kernel.Size));
debug("Reserving kernel file and symbols..."); debug("Reserving kernel file and symbols...");
if (bInfo.Kernel.FileBase) if (bInfo.Kernel.FileBase)
this->ReservePages(bInfo.Kernel.FileBase, TO_PAGES(bInfo.Kernel.Size)); this->ReservePages(bInfo.Kernel.FileBase, TO_PAGES(bInfo.Kernel.Size));
if (bInfo.Kernel.Symbols.Num && bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.Shndx) if (bInfo.Kernel.Symbols.Num &&
this->ReservePages((void *)bInfo.Kernel.Symbols.Sections, TO_PAGES(bInfo.Kernel.Symbols.Num * bInfo.Kernel.Symbols.EntSize)); bInfo.Kernel.Symbols.EntSize &&
bInfo.Kernel.Symbols.Shndx)
{
char *sections = reinterpret_cast<char *>(bInfo.Kernel.Symbols.Sections);
uint8_t *StringAddress = nullptr;
Elf_Sym *Symbols = nullptr;
#if defined(a64) || defined(aa64)
Elf64_Xword SymbolSize = 0;
Elf64_Xword StringSize = 0;
#elif defined(a32)
Elf32_Word SymbolSize = 0;
Elf32_Word StringSize = 0;
#endif
for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i)
{
Elf_Shdr *sym = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * i];
Elf_Shdr *str = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize *
sym->sh_link];
if (sym->sh_type == SHT_SYMTAB &&
str->sh_type == SHT_STRTAB)
{
Symbols = (Elf_Sym *)sym->sh_addr;
StringAddress = (uint8_t *)str->sh_addr;
SymbolSize = (int)sym->sh_size;
StringSize = (int)str->sh_size;
debug("Symbol table found, %d entries",
SymbolSize / sym->sh_entsize);
break;
}
}
if (Symbols)
{
debug("Reserving symbol table region %#lx-%#lx...",
Symbols, (void *)((uintptr_t)Symbols + SymbolSize));
this->ReservePages(Symbols, TO_PAGES(SymbolSize));
}
if (StringAddress)
{
debug("Reserving string table region %#lx-%#lx...",
StringAddress, (void *)((uintptr_t)StringAddress + StringSize));
this->ReservePages(StringAddress, TO_PAGES(StringSize));
}
}
debug("Reserving kernel modules..."); debug("Reserving kernel modules...");
@ -78,13 +139,17 @@ namespace Memory
continue; continue;
debug("Reserving module %s (%#lx-%#lx)...", bInfo.Modules[i].CommandLine, debug("Reserving module %s (%#lx-%#lx)...", bInfo.Modules[i].CommandLine,
bInfo.Modules[i].Address, (void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size)); bInfo.Modules[i].Address,
(void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size));
this->ReservePages((void *)bInfo.Modules[i].Address, TO_PAGES(bInfo.Modules[i].Size)); this->ReservePages((void *)bInfo.Modules[i].Address,
TO_PAGES(bInfo.Modules[i].Size));
} }
#if defined(a86) #if defined(a86)
debug("Reserving RSDT region %#lx-%#lx...", bInfo.RSDP, (void *)((uintptr_t)bInfo.RSDP + sizeof(BootInfo::RSDPInfo))); debug("Reserving RSDT region %#lx-%#lx...", bInfo.RSDP,
(void *)((uintptr_t)bInfo.RSDP + sizeof(BootInfo::RSDPInfo)));
this->ReservePages(bInfo.RSDP, TO_PAGES(sizeof(BootInfo::RSDPInfo))); this->ReservePages(bInfo.RSDP, TO_PAGES(sizeof(BootInfo::RSDPInfo)));
ACPI::ACPI::ACPIHeader *ACPIPtr = nullptr; ACPI::ACPI::ACPIHeader *ACPIPtr = nullptr;
@ -115,23 +180,27 @@ namespace Memory
} }
#endif #endif
size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / (XSDT ? 8 : 4)); size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) /
(XSDT ? 8 : 4));
debug("Reserving %d ACPI tables...", TableSize); debug("Reserving %d ACPI tables...", TableSize);
for (size_t t = 0; t < TableSize; t++) for (size_t t = 0; t < TableSize; t++)
{ {
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
// TODO: Should I be concerned about unaligned memory access? // TODO: Should I be concerned about unaligned memory access?
ACPI::ACPI::ACPIHeader *SDTHdr = nullptr; ACPI::ACPI::ACPIHeader *SDTHdr = nullptr;
if (XSDT) if (XSDT)
SDTHdr = (ACPI::ACPI::ACPIHeader *)(*(uint64_t *)((uint64_t)ACPIPtr + sizeof(ACPI::ACPI::ACPIHeader) + (t * 8))); SDTHdr =
(ACPI::ACPI::ACPIHeader *)(*(uint64_t *)((uint64_t)ACPIPtr +
sizeof(ACPI::ACPI::ACPIHeader) +
(t * 8)));
else else
SDTHdr = (ACPI::ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIPtr + sizeof(ACPI::ACPI::ACPIHeader) + (t * 4))); SDTHdr =
(ACPI::ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIPtr +
sizeof(ACPI::ACPI::ACPIHeader) +
(t * 4)));
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length)); this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length));
} }

15
Core/Memory/SmartHeap.cpp Normal file
View File

@ -0,0 +1,15 @@
#include <memory.hpp>
namespace Memory
{
SmartHeap::SmartHeap(size_t Size)
{
this->Object = kmalloc(Size);
this->ObjectSize = Size;
}
SmartHeap::~SmartHeap()
{
kfree(this->Object);
}
}

View File

@ -29,111 +29,102 @@
namespace Power namespace Power
{ {
void Power::Reboot() void Power::Reboot()
{ {
if (((ACPI::ACPI *)this->acpi)->FADT) if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Reboot(); ((ACPI::DSDT *)this->dsdt)->Reboot();
uint8_t val = 0x02; uint8_t val = 0x02;
while (val & 0x02) while (val & 0x02)
val = inb(0x64); val = inb(0x64);
outb(0x64, 0xFE); outb(0x64, 0xFE);
warn("Executing the second attempt to reboot..."); warn("Executing the second attempt to reboot...");
// second attempt to reboot // https://wiki.osdev.org/Reboot
// https://wiki.osdev.org/Reboot /* Second attempt to reboot */
uint8_t temp; asmv("cli");
asmv("cli"); uint8_t temp;
do do
{ {
temp = inb(0x64); temp = inb(0x64);
if (((temp) & (1 << (0))) != 0) if (((temp) & (1 << (0))) != 0)
inb(0x60); inb(0x60);
} while (((temp) & (1 << (1))) != 0); } while (((temp) & (1 << (1))) != 0);
outb(0x64, 0xFE); outb(0x64, 0xFE);
CPU::Stop(); CPU::Stop();
} }
void Power::Shutdown() void Power::Shutdown()
{ {
if (((ACPI::ACPI *)this->acpi)->FADT) if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Shutdown(); ((ACPI::DSDT *)this->dsdt)->Shutdown();
/* TODO: If no ACPI, display "It is now safe to turn off your computer" */
outl(0xB004, 0x2000); // for qemu /* FIXME: Detect emulators and use their shutdown methods */
outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu #ifdef DEBUG
outl(0x4004, 0x3400); // virtual box outl(0xB004, 0x2000); // for qemu
CPU::Stop(); outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu
} outl(0x4004, 0x3400); // virtual box
#endif
CPU::Stop();
}
void Power::InitDSDT() void Power::InitDSDT()
{ {
if (((ACPI::ACPI *)this->acpi)->FADT) if (((ACPI::ACPI *)this->acpi)->FADT)
this->dsdt = new ACPI::DSDT((ACPI::ACPI *)acpi); this->dsdt = new ACPI::DSDT((ACPI::ACPI *)acpi);
} }
Power::Power() Power::Power()
{ {
this->acpi = new ACPI::ACPI; this->acpi = new ACPI::ACPI;
this->madt = new ACPI::MADT(((ACPI::ACPI *)acpi)->MADT); this->madt = new ACPI::MADT(((ACPI::ACPI *)acpi)->MADT);
trace("Power manager initialized"); trace("Power manager initialized");
} }
Power::~Power()
{
debug("Destructor called");
}
} }
#elif defined(a32) #elif defined(a32)
namespace Power namespace Power
{ {
void Power::Reboot() void Power::Reboot()
{ {
warn("Reboot not implemented for i386"); warn("Reboot not implemented for i386");
} }
void Power::Shutdown() void Power::Shutdown()
{ {
warn("Shutdown not implemented for i386"); warn("Shutdown not implemented for i386");
} }
Power::Power() Power::Power()
{ {
error("Power not implemented for i386"); error("Power not implemented for i386");
} }
Power::~Power()
{
}
} }
#elif defined(aa64) #elif defined(aa64)
namespace Power namespace Power
{ {
void Power::Reboot() void Power::Reboot()
{ {
warn("Reboot not implemented for aarch64"); warn("Reboot not implemented for aarch64");
} }
void Power::Shutdown() void Power::Shutdown()
{ {
warn("Shutdown not implemented for aarch64"); warn("Shutdown not implemented for aarch64");
} }
Power::Power() Power::Power()
{ {
error("Power not implemented for aarch64"); error("Power not implemented for aarch64");
} }
Power::~Power()
{
}
} }
#endif #endif

View File

@ -25,220 +25,228 @@
namespace SymbolResolver namespace SymbolResolver
{ {
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address) const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address)
{ {
Symbols::SymbolTable Result{0, (char *)"<unknown>"}; SymbolTable Result{};
for (int64_t i = 0; i < this->TotalEntries; i++) foreach (auto tbl in this->SymTable)
if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address) {
Result = this->SymTable[i]; if (tbl.Address <= Address &&
return Result.FunctionName; tbl.Address > Result.Address)
} Result = tbl;
}
// debug("Address: %#lx, Function: %s",
// Address, Result.FunctionName);
return Result.FunctionName;
}
void Symbols::AddSymbol(uintptr_t Address, const char *Name) void Symbols::AddSymbol(uintptr_t Address, const char *Name)
{ {
if (this->TotalEntries >= 0x10000) SymbolTable tbl{};
{ tbl.Address = Address;
error("Symbol table is full"); tbl.FunctionName = (char *)Name;
return; this->SymTable.push_back(tbl);
} this->SymbolTableExists = true;
}
this->SymTable[this->TotalEntries].Address = Address; __no_sanitize("alignment") void Symbols::AddSymbolInfoFromGRUB(uint64_t Num,
strcpy(this->SymTable[this->TotalEntries].FunctionName, Name); uint64_t EntSize,
this->TotalEntries++; __unused uint64_t Shndx,
} uintptr_t Sections)
{
__no_sanitize("alignment") void Symbols::AddBySymbolInfo(uint64_t Num, uint64_t EntSize, uint64_t Shndx, uintptr_t Sections)
{
#ifdef a32 #ifdef a32
fixme("Function not working on 32-bit"); fixme("Function not working on 32-bit");
return; return;
#endif #endif
if (this->TotalEntries >= 0x10000) char *sections = reinterpret_cast<char *>(Sections);
{
error("Symbol table is full"); Elf_Sym *Symbols = nullptr;
return; uint8_t *StringAddress = nullptr;
}
#if defined(a64) || defined(aa64) #if defined(a64) || defined(aa64)
Elf64_Shdr *ElfSections = (Elf64_Shdr *)(Sections); Elf64_Xword SymbolSize = 0;
Elf64_Sym *ElfSymbols = nullptr; // Elf64_Xword StringSize = 0;
#elif defined(a32) #elif defined(a32)
Elf32_Shdr *ElfSections = (Elf32_Shdr *)(Sections); Elf32_Word SymbolSize = 0;
Elf32_Sym *ElfSymbols = nullptr; // Elf32_Word StringSize = 0;
#endif #endif
char *strtab = nullptr; int64_t TotalEntries = 0;
for (size_t i = 0; i < Num; ++i)
{
Elf_Shdr *sym = (Elf_Shdr *)&sections[EntSize * i];
Elf_Shdr *str = (Elf_Shdr *)&sections[EntSize * sym->sh_link];
if (sym->sh_type == SHT_SYMTAB &&
str->sh_type == SHT_STRTAB)
{
Symbols = (Elf_Sym *)sym->sh_addr;
StringAddress = (uint8_t *)str->sh_addr;
SymbolSize = (int)sym->sh_size;
// StringSize = (int)str->sh_size;
// TotalEntries = Section.sh_size / sizeof(Elf64_Sym)
TotalEntries = sym->sh_size / sym->sh_entsize;
debug("Symbol table found, %d entries",
SymbolSize / sym->sh_entsize);
UNUSED(SymbolSize);
break;
}
}
if (Symbols != nullptr && StringAddress != nullptr)
{
int64_t Index, MinimumIndex;
for (int64_t i = 0; i < TotalEntries - 1; i++)
{
MinimumIndex = i;
for (Index = i + 1; Index < TotalEntries; Index++)
if (Symbols[Index].st_value < Symbols[MinimumIndex].st_value)
MinimumIndex = Index;
Elf_Sym tmp = Symbols[MinimumIndex];
Symbols[MinimumIndex] = Symbols[i];
Symbols[i] = tmp;
}
while (Symbols[0].st_value == 0)
{
if (TotalEntries <= 0)
break;
Symbols++;
TotalEntries--;
}
if (TotalEntries <= 0)
{
error("Symbol table is empty");
return;
}
debug("Symbol table loaded, %d entries (%ld KiB)",
TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
Elf_Sym *sym = nullptr;
const char *name = nullptr;
for (int64_t i = 0, g = TotalEntries; i < g; i++)
{
sym = &Symbols[i];
name = (const char *)&StringAddress[Symbols[i].st_name];
if (strlen(name) == 0)
continue;
SymbolTable tbl{};
tbl.Address = sym->st_value;
tbl.FunctionName = (char *)name;
this->SymTable.push_back(tbl);
this->SymbolTableExists = true;
// debug("Symbol %d: %#lx %s(%#lx)",
// i, tbl.Address,
// tbl.FunctionName,
// name);
}
}
}
void Symbols::AppendSymbols(uintptr_t ImageAddress, uintptr_t BaseAddress)
{
/* FIXME: Get only the required headers instead of the whole file */
if (ImageAddress == 0 || Memory::Virtual().Check((void *)ImageAddress) == false)
{
error("Invalid image address %#lx", ImageAddress);
return;
}
debug("Solving symbols for address: %#llx", ImageAddress);
for (uint64_t i = 0; i < Num; i++)
switch (ElfSections[i].sh_type)
{
case SHT_SYMTAB:
#if defined(a64) || defined(aa64) #if defined(a64) || defined(aa64)
ElfSymbols = (Elf64_Sym *)(Sections + ElfSections[i].sh_offset); Elf64_Ehdr *Header = (Elf64_Ehdr *)ImageAddress;
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
#elif defined(a32) #elif defined(a32)
ElfSymbols = (Elf32_Sym *)(Sections + ElfSections[i].sh_offset); Elf32_Ehdr *Header = (Elf32_Ehdr *)ImageAddress;
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf32_Sym);
#endif #endif
if (this->TotalEntries >= 0x10000) if (Header->e_ident[0] != 0x7F &&
this->TotalEntries = 0x10000 - 1; Header->e_ident[1] != 'E' &&
Header->e_ident[2] != 'L' &&
Header->e_ident[3] != 'F')
{
error("Invalid ELF header");
return;
}
debug("Symbol table found, %d entries", this->TotalEntries); Elf_Shdr *ElfSections = (Elf_Shdr *)(ImageAddress + Header->e_shoff);
break; Elf_Sym *ElfSymbols = nullptr;
case SHT_STRTAB: char *strtab = nullptr;
if (Shndx == i) int64_t TotalEntries = 0;
{
debug("String table found, %d entries", ElfSections[i].sh_size);
}
else
{
strtab = (char *)(Sections + ElfSections[i].sh_offset);
debug("String table found, %d entries", ElfSections[i].sh_size);
}
break;
default:
break;
}
if (ElfSymbols != nullptr && strtab != nullptr) for (uint16_t i = 0; i < Header->e_shnum; i++)
{ {
int64_t Index, MinimumIndex; switch (ElfSections[i].sh_type)
for (int64_t i = 0; i < this->TotalEntries - 1; i++) {
{ case SHT_SYMTAB:
MinimumIndex = i; ElfSymbols = (Elf_Sym *)(ImageAddress + ElfSections[i].sh_offset);
for (Index = i + 1; Index < this->TotalEntries; Index++) TotalEntries = ElfSections[i].sh_size / sizeof(Elf_Sym);
if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value) debug("Symbol table found, %d entries", TotalEntries);
MinimumIndex = Index; break;
#if defined(a64) || defined(aa64) case SHT_STRTAB:
Elf64_Sym tmp = ElfSymbols[MinimumIndex]; if (Header->e_shstrndx == i)
#elif defined(a32) {
Elf32_Sym tmp = ElfSymbols[MinimumIndex]; debug("String table found, %d entries", ElfSections[i].sh_size);
#endif }
ElfSymbols[MinimumIndex] = ElfSymbols[i]; else
ElfSymbols[i] = tmp; {
} strtab = (char *)(ImageAddress + ElfSections[i].sh_offset);
debug("String table found, %d entries", ElfSections[i].sh_size);
}
break;
default:
break;
}
}
while (ElfSymbols[0].st_value == 0) if (ElfSymbols != nullptr && strtab != nullptr)
{ {
if (this->TotalEntries <= 0) int64_t Index, MinimumIndex;
break; for (int64_t i = 0; i < TotalEntries - 1; i++)
ElfSymbols++; {
this->TotalEntries--; MinimumIndex = i;
} for (Index = i + 1; Index < TotalEntries; Index++)
if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value)
MinimumIndex = Index;
Elf_Sym tmp = ElfSymbols[MinimumIndex];
ElfSymbols[MinimumIndex] = ElfSymbols[i];
ElfSymbols[i] = tmp;
}
if (this->TotalEntries <= 0) while (ElfSymbols[0].st_value == 0)
{ {
error("Symbol table is empty"); ElfSymbols++;
return; TotalEntries--;
} }
trace("Symbol table loaded, %d entries (%ldKB)", this->TotalEntries, TO_KB(this->TotalEntries * sizeof(SymbolTable))); trace("Symbol table loaded, %d entries (%ld KiB)",
for (int64_t i = 0, g = this->TotalEntries; i < g; i++) TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
{
this->SymTable[i].Address = ElfSymbols[i].st_value;
this->SymTable[i].FunctionName = &strtab[ElfSymbols[i].st_name];
// debug("Symbol %d: %#llx %s", i, this->SymTable[i].Address, this->SymTable[i].FunctionName); /* TODO: maybe a checker for duplicated addresses? */
} Elf_Sym *sym = nullptr;
} const char *name = nullptr;
} for (int64_t i = 0, g = TotalEntries; i < g; i++)
{
sym = &ElfSymbols[i];
name = &strtab[ElfSymbols[i].st_name];
SymbolTable tbl{};
tbl.Address = sym->st_value + BaseAddress;
tbl.FunctionName = (char *)name;
this->SymTable.push_back(tbl);
this->SymbolTableExists = true;
Symbols::Symbols(uintptr_t ImageAddress) // debug("Symbol %d: %#llx %s", i,
{ // this->SymTable[i].Address,
if (ImageAddress == 0 || Memory::Virtual().Check((void *)ImageAddress) == false) // this->SymTable[i].FunctionName);
{ }
error("Invalid image address %#lx", ImageAddress); }
return; }
}
this->Image = (void *)ImageAddress; Symbols::Symbols(uintptr_t ImageAddress)
debug("Solving symbols for address: %#llx", ImageAddress); {
#if defined(a64) || defined(aa64) this->Image = (void *)ImageAddress;
Elf64_Ehdr *Header = (Elf64_Ehdr *)ImageAddress; this->AppendSymbols(ImageAddress);
#elif defined(a32) }
Elf32_Ehdr *Header = (Elf32_Ehdr *)ImageAddress;
#endif
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;
}
#if defined(a64) || defined(aa64)
Elf64_Shdr *ElfSections = (Elf64_Shdr *)(ImageAddress + Header->e_shoff);
Elf64_Sym *ElfSymbols = nullptr;
#elif defined(a32)
Elf32_Shdr *ElfSections = (Elf32_Shdr *)(ImageAddress + Header->e_shoff);
Elf32_Sym *ElfSymbols = nullptr;
#endif
char *strtab = nullptr;
for (uint16_t i = 0; i < Header->e_shnum; i++) Symbols::~Symbols() {}
switch (ElfSections[i].sh_type)
{
case SHT_SYMTAB:
#if defined(a64) || defined(aa64)
ElfSymbols = (Elf64_Sym *)(ImageAddress + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
#elif defined(a32)
ElfSymbols = (Elf32_Sym *)(ImageAddress + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf32_Sym);
#endif
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;
default:
break;
}
if (ElfSymbols != nullptr && strtab != nullptr)
{
int64_t Index, MinimumIndex;
for (int64_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;
#if defined(a64) || defined(aa64)
Elf64_Sym tmp = ElfSymbols[MinimumIndex];
#elif defined(a32)
Elf32_Sym tmp = ElfSymbols[MinimumIndex];
#endif
ElfSymbols[MinimumIndex] = ElfSymbols[i];
ElfSymbols[i] = tmp;
}
while (ElfSymbols[0].st_value == 0)
{
ElfSymbols++;
this->TotalEntries--;
}
trace("Symbol table loaded, %d entries (%ldKB)", this->TotalEntries, TO_KB(this->TotalEntries * sizeof(SymbolTable)));
for (int64_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];
// debug("Symbol %d: %#llx %s", i, this->SymTable[i].Address, this->SymTable[i].FunctionName);
}
}
}
Symbols::~Symbols() {}
} }

View File

@ -32,52 +32,52 @@
namespace Time namespace Time
{ {
bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit) bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit)
{ {
#if defined(a64) #if defined(a64)
size_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
while (mminq(&((HPET *)hpet)->MainCounterValue) < Target) while (mminq(&((HPET *)hpet)->MainCounterValue) < Target)
CPU::Pause(); CPU::Pause();
return true; return true;
#elif defined(a32) #elif defined(a32)
size_t Target = mminl(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; uint64_t Target = mminl(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
while (mminl(&((HPET *)hpet)->MainCounterValue) < Target) while (mminl(&((HPET *)hpet)->MainCounterValue) < Target)
CPU::Pause(); CPU::Pause();
return true; return true;
#endif #endif
return false; return false;
} }
size_t HighPrecisionEventTimer::GetCounter() uint64_t HighPrecisionEventTimer::GetCounter()
{ {
#if defined(a64) #if defined(a64)
return mminq(&((HPET *)hpet)->MainCounterValue); return mminq(&((HPET *)hpet)->MainCounterValue);
#elif defined(a32) #elif defined(a32)
return mminl(&((HPET *)hpet)->MainCounterValue); return mminl(&((HPET *)hpet)->MainCounterValue);
#endif #endif
} }
size_t HighPrecisionEventTimer::CalculateTarget(size_t Target, Units Unit) uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit)
{ {
#if defined(a64) #if defined(a64)
return mminq(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; return mminq(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
#elif defined(a32) #elif defined(a32)
return mminl(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; return mminl(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
#endif #endif
} }
size_t HighPrecisionEventTimer::GetNanosecondsSinceClassCreation() uint64_t HighPrecisionEventTimer::GetNanosecondsSinceClassCreation()
{ {
#if defined(a86) #if defined(a86)
size_t Subtraction = this->GetCounter() - this->ClassCreationTime; uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime;
if (Subtraction <= 0 || this->clk <= 0) if (Subtraction <= 0 || this->clk <= 0)
return 0; return 0;
return Subtraction / (this->clk / ConvertUnit(Units::Nanoseconds)); return uint64_t(Subtraction / (this->clk / ConvertUnit(Units::Nanoseconds)));
#endif #endif
} }
HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet) HighPrecisionEventTimer::HighPrecisionEventTimer(void *hpet)
{ {
#if defined(a86) #if defined(a86)
ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet; ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet;
Memory::Virtual().Remap((void *)HPET_HDR->Address.Address, Memory::Virtual().Remap((void *)HPET_HDR->Address.Address,
@ -86,6 +86,7 @@ return false;
this->hpet = (HPET *)HPET_HDR->Address.Address; this->hpet = (HPET *)HPET_HDR->Address.Address;
trace("%s timer is at address %016p", HPET_HDR->Header.OEMID, (void *)HPET_HDR->Address.Address); trace("%s timer is at address %016p", HPET_HDR->Header.OEMID, (void *)HPET_HDR->Address.Address);
clk = s_cst(uint32_t, (uint64_t)this->hpet->GeneralCapabilities >> 32); clk = s_cst(uint32_t, (uint64_t)this->hpet->GeneralCapabilities >> 32);
debug("HPET clock is %u Hz", clk);
#ifdef a64 #ifdef a64
mmoutq(&this->hpet->GeneralConfiguration, 0); mmoutq(&this->hpet->GeneralConfiguration, 0);
mmoutq(&this->hpet->MainCounterValue, 0); mmoutq(&this->hpet->MainCounterValue, 0);
@ -97,9 +98,9 @@ return false;
#endif #endif
ClassCreationTime = this->GetCounter(); ClassCreationTime = this->GetCounter();
#endif #endif
} }
HighPrecisionEventTimer::~HighPrecisionEventTimer() HighPrecisionEventTimer::~HighPrecisionEventTimer()
{ {
} }
} }

View File

@ -34,31 +34,31 @@ namespace Time
bool TimeStampCounter::Sleep(size_t Duration, Units Unit) bool TimeStampCounter::Sleep(size_t Duration, Units Unit)
{ {
#if defined(a86) #if defined(a86)
size_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk; uint64_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk;
while (this->GetCounter() < Target) while (this->GetCounter() < Target)
CPU::Pause(); CPU::Pause();
return true; return true;
#endif #endif
} }
size_t TimeStampCounter::GetCounter() uint64_t TimeStampCounter::GetCounter()
{ {
#if defined(a86) #if defined(a86)
return CPU::Counter(); return CPU::Counter();
#endif #endif
} }
size_t TimeStampCounter::CalculateTarget(size_t Target, Units Unit) uint64_t TimeStampCounter::CalculateTarget(uint64_t Target, Units Unit)
{ {
#if defined(a86) #if defined(a86)
return this->GetCounter() + (Target * ConvertUnit(Unit)) / this->clk; return uint64_t((this->GetCounter() + (Target * ConvertUnit(Unit))) / this->clk);
#endif #endif
} }
size_t TimeStampCounter::GetNanosecondsSinceClassCreation() uint64_t TimeStampCounter::GetNanosecondsSinceClassCreation()
{ {
#if defined(a86) #if defined(a86)
return (this->GetCounter() - this->ClassCreationTime) / this->clk; return uint64_t((this->GetCounter() - this->ClassCreationTime) / this->clk);
#endif #endif
} }

View File

@ -61,90 +61,90 @@ namespace Time
} }
} }
size_t time::GetCounter() uint64_t time::GetCounter()
{ {
switch (ActiveTimer) switch (ActiveTimer)
{ {
case NONE: case NONE:
error("No timer is active"); error("No timer is active");
return false; return 0;
case RTC: case RTC:
fixme("RTC sleep not implemented"); fixme("RTC sleep not implemented");
return false; return 0;
case PIT: case PIT:
fixme("PIT sleep not implemented"); fixme("PIT sleep not implemented");
return false; return 0;
case HPET: case HPET:
return this->hpet->GetCounter(); return this->hpet->GetCounter();
case ACPI: case ACPI:
fixme("ACPI sleep not implemented"); fixme("ACPI sleep not implemented");
return false; return 0;
case APIC: case APIC:
fixme("APIC sleep not implemented"); fixme("APIC sleep not implemented");
return false; return 0;
case TSC: case TSC:
return this->tsc->GetCounter(); return this->tsc->GetCounter();
default: default:
error("Unknown timer"); error("Unknown timer");
return false; return 0;
} }
} }
size_t time::CalculateTarget(size_t Target, Units Unit) uint64_t time::CalculateTarget(uint64_t Target, Units Unit)
{ {
switch (ActiveTimer) switch (ActiveTimer)
{ {
case NONE: case NONE:
error("No timer is active"); error("No timer is active");
return false; return 0;
case RTC: case RTC:
fixme("RTC sleep not implemented"); fixme("RTC sleep not implemented");
return false; return 0;
case PIT: case PIT:
fixme("PIT sleep not implemented"); fixme("PIT sleep not implemented");
return false; return 0;
case HPET: case HPET:
return this->hpet->CalculateTarget(Target, Unit); return this->hpet->CalculateTarget(Target, Unit);
case ACPI: case ACPI:
fixme("ACPI sleep not implemented"); fixme("ACPI sleep not implemented");
return false; return 0;
case APIC: case APIC:
fixme("APIC sleep not implemented"); fixme("APIC sleep not implemented");
return false; return 0;
case TSC: case TSC:
return this->tsc->CalculateTarget(Target, Unit); return this->tsc->CalculateTarget(Target, Unit);
default: default:
error("Unknown timer"); error("Unknown timer");
return false; return 0;
} }
} }
size_t time::GetNanosecondsSinceClassCreation() uint64_t time::GetNanosecondsSinceClassCreation()
{ {
switch (ActiveTimer) switch (ActiveTimer)
{ {
case NONE: case NONE:
error("No timer is active"); error("No timer is active");
return false; return 0;
case RTC: case RTC:
fixme("RTC sleep not implemented"); fixme("RTC sleep not implemented");
return false; return 0;
case PIT: case PIT:
fixme("PIT sleep not implemented"); fixme("PIT sleep not implemented");
return false; return 0;
case HPET: case HPET:
return this->hpet->GetNanosecondsSinceClassCreation(); return this->hpet->GetNanosecondsSinceClassCreation();
case ACPI: case ACPI:
fixme("ACPI sleep not implemented"); fixme("ACPI sleep not implemented");
return false; return 0;
case APIC: case APIC:
fixme("APIC sleep not implemented"); fixme("APIC sleep not implemented");
return false; return 0;
case TSC: case TSC:
return this->tsc->GetNanosecondsSinceClassCreation(); return this->tsc->GetNanosecondsSinceClassCreation();
default: default:
error("Unknown timer"); error("Unknown timer");
return false; return 0;
} }
} }

View File

@ -20,6 +20,8 @@
#include <convert.h> #include <convert.h>
#include <debug.h> #include <debug.h>
#ifdef DEBUG
// TODO: implement: // TODO: implement:
/* /*
__ubsan_handle_type_mismatch_v1_abort __ubsan_handle_type_mismatch_v1_abort
@ -47,320 +49,320 @@ __ubsan_handle_pointer_overflow_abort
__ubsan_handle_cfi_check_fail __ubsan_handle_cfi_check_fail
*/ */
extern void __asan_report_load1(void *unknown) void __asan_report_load1(void *unknown)
{ {
ubsan("load1"); ubsan("load1");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load2(void *unknown) void __asan_report_load2(void *unknown)
{ {
ubsan("load2"); ubsan("load2");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load4(void *unknown) void __asan_report_load4(void *unknown)
{ {
ubsan("load4"); ubsan("load4");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load8(void *unknown) void __asan_report_load8(void *unknown)
{ {
ubsan("load8"); ubsan("load8");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load16(void *unknown) void __asan_report_load16(void *unknown)
{ {
ubsan("load16"); ubsan("load16");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load_n(void *unknown, uintptr_t size) void __asan_report_load_n(void *unknown, uintptr_t size)
{ {
ubsan("loadn"); ubsan("loadn");
UNUSED(unknown); UNUSED(unknown);
UNUSED(size); UNUSED(size);
} }
extern void __asan_report_store1(void *unknown) void __asan_report_store1(void *unknown)
{ {
ubsan("store1"); ubsan("store1");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store2(void *unknown) void __asan_report_store2(void *unknown)
{ {
ubsan("store2"); ubsan("store2");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store4(void *unknown) void __asan_report_store4(void *unknown)
{ {
ubsan("store4"); ubsan("store4");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store8(void *unknown) void __asan_report_store8(void *unknown)
{ {
ubsan("store8"); ubsan("store8");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store16(void *unknown) void __asan_report_store16(void *unknown)
{ {
ubsan("store16"); ubsan("store16");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store_n(void *unknown, uintptr_t size) void __asan_report_store_n(void *unknown, uintptr_t size)
{ {
ubsan("storen"); ubsan("storen");
UNUSED(unknown); UNUSED(unknown);
UNUSED(size); UNUSED(size);
} }
extern void __asan_report_load1_noabort(void *unknown) void __asan_report_load1_noabort(void *unknown)
{ {
ubsan("load1"); ubsan("load1");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load2_noabort(void *unknown) void __asan_report_load2_noabort(void *unknown)
{ {
ubsan("load2"); ubsan("load2");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load4_noabort(void *unknown) void __asan_report_load4_noabort(void *unknown)
{ {
ubsan("load4"); ubsan("load4");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load8_noabort(void *unknown) void __asan_report_load8_noabort(void *unknown)
{ {
ubsan("load8"); ubsan("load8");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load16_noabort(void *unknown) void __asan_report_load16_noabort(void *unknown)
{ {
ubsan("load16"); ubsan("load16");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_load_n_noabort(void *unknown, uintptr_t size) void __asan_report_load_n_noabort(void *unknown, uintptr_t size)
{ {
ubsan("loadn"); ubsan("loadn");
UNUSED(unknown); UNUSED(unknown);
UNUSED(size); UNUSED(size);
} }
extern void __asan_report_store1_noabort(void *unknown) void __asan_report_store1_noabort(void *unknown)
{ {
ubsan("store1"); ubsan("store1");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store2_noabort(void *unknown) void __asan_report_store2_noabort(void *unknown)
{ {
ubsan("store2"); ubsan("store2");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store4_noabort(void *unknown) void __asan_report_store4_noabort(void *unknown)
{ {
ubsan("store4"); ubsan("store4");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store8_noabort(void *unknown) void __asan_report_store8_noabort(void *unknown)
{ {
ubsan("store8"); ubsan("store8");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store16_noabort(void *unknown) void __asan_report_store16_noabort(void *unknown)
{ {
ubsan("store16"); ubsan("store16");
UNUSED(unknown); UNUSED(unknown);
} }
extern void __asan_report_store_n_noabort(void *unknown, uintptr_t size) void __asan_report_store_n_noabort(void *unknown, uintptr_t size)
{ {
ubsan("storen"); ubsan("storen");
UNUSED(unknown); UNUSED(unknown);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_0(uintptr_t size) void __asan_stack_malloc_0(uintptr_t size)
{ {
ubsan("stack malloc 0"); ubsan("stack malloc 0");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_1(uintptr_t size) void __asan_stack_malloc_1(uintptr_t size)
{ {
ubsan("stack malloc 1"); ubsan("stack malloc 1");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_2(uintptr_t size) void __asan_stack_malloc_2(uintptr_t size)
{ {
ubsan("stack malloc 2"); ubsan("stack malloc 2");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_3(uintptr_t size) void __asan_stack_malloc_3(uintptr_t size)
{ {
ubsan("stack malloc 3"); ubsan("stack malloc 3");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_4(uintptr_t size) void __asan_stack_malloc_4(uintptr_t size)
{ {
ubsan("stack malloc 4"); ubsan("stack malloc 4");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_5(uintptr_t size) void __asan_stack_malloc_5(uintptr_t size)
{ {
ubsan("stack malloc 5"); ubsan("stack malloc 5");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_6(uintptr_t size) void __asan_stack_malloc_6(uintptr_t size)
{ {
ubsan("stack malloc 6"); ubsan("stack malloc 6");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_7(uintptr_t size) void __asan_stack_malloc_7(uintptr_t size)
{ {
ubsan("stack malloc 7"); ubsan("stack malloc 7");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_8(uintptr_t size) void __asan_stack_malloc_8(uintptr_t size)
{ {
ubsan("stack malloc 8"); ubsan("stack malloc 8");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_malloc_9(uintptr_t size) void __asan_stack_malloc_9(uintptr_t size)
{ {
ubsan("stack malloc 9"); ubsan("stack malloc 9");
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_0(void *ptr, uintptr_t size) void __asan_stack_free_0(void *ptr, uintptr_t size)
{ {
ubsan("stack free 0"); ubsan("stack free 0");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_1(void *ptr, uintptr_t size) void __asan_stack_free_1(void *ptr, uintptr_t size)
{ {
ubsan("stack free 1"); ubsan("stack free 1");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_2(void *ptr, uintptr_t size) void __asan_stack_free_2(void *ptr, uintptr_t size)
{ {
ubsan("stack free 2"); ubsan("stack free 2");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_3(void *ptr, uintptr_t size) void __asan_stack_free_3(void *ptr, uintptr_t size)
{ {
ubsan("stack free 3"); ubsan("stack free 3");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_4(void *ptr, uintptr_t size) void __asan_stack_free_4(void *ptr, uintptr_t size)
{ {
ubsan("stack free 4"); ubsan("stack free 4");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_5(void *ptr, uintptr_t size) void __asan_stack_free_5(void *ptr, uintptr_t size)
{ {
ubsan("stack free 5"); ubsan("stack free 5");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_6(void *ptr, uintptr_t size) void __asan_stack_free_6(void *ptr, uintptr_t size)
{ {
ubsan("stack free 6"); ubsan("stack free 6");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_7(void *ptr, uintptr_t size) void __asan_stack_free_7(void *ptr, uintptr_t size)
{ {
ubsan("stack free 7"); ubsan("stack free 7");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_8(void *ptr, uintptr_t size) void __asan_stack_free_8(void *ptr, uintptr_t size)
{ {
ubsan("stack free 8"); ubsan("stack free 8");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_stack_free_9(void *ptr, uintptr_t size) void __asan_stack_free_9(void *ptr, uintptr_t size)
{ {
ubsan("stack free 9"); ubsan("stack free 9");
UNUSED(ptr); UNUSED(ptr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_poison_stack_memory(void *addr, uintptr_t size) void __asan_poison_stack_memory(void *addr, uintptr_t size)
{ {
ubsan("poison stack memory"); ubsan("poison stack memory");
UNUSED(addr); UNUSED(addr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_unpoison_stack_memory(void *addr, uintptr_t size) void __asan_unpoison_stack_memory(void *addr, uintptr_t size)
{ {
ubsan("unpoison stack memory"); ubsan("unpoison stack memory");
UNUSED(addr); UNUSED(addr);
UNUSED(size); UNUSED(size);
} }
extern void __asan_before_dynamic_init(const char *module_name) void __asan_before_dynamic_init(const char *module_name)
{ {
ubsan("before dynamic init"); ubsan("before dynamic init");
UNUSED(module_name); UNUSED(module_name);
} }
extern void __asan_after_dynamic_init(void) { ubsan("after dynamic init"); } void __asan_after_dynamic_init(void) { ubsan("after dynamic init"); }
extern void __asan_register_globals(void *unknown, size_t size) void __asan_register_globals(void *unknown, size_t size)
{ {
ubsan("register_globals"); ubsan("register_globals");
UNUSED(unknown); UNUSED(unknown);
UNUSED(size); UNUSED(size);
} }
extern void __asan_unregister_globals(void) { ubsan("unregister_globals"); } void __asan_unregister_globals(void) { ubsan("unregister_globals"); }
extern void __asan_init(void) { ubsan("init"); } void __asan_init(void) { ubsan("init"); }
extern void __asan_version_mismatch_check_v8(void) { ubsan("version_mismatch_check_v8"); } 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"); } void __asan_option_detect_stack_use_after_return(void) { ubsan("stack use after return"); }
extern __noreturn void __asan_handle_no_return(void) __noreturn void __asan_handle_no_return(void)
{ {
ubsan("no_return"); ubsan("no_return");
while (1) while (1)
@ -511,3 +513,5 @@ void __ubsan_handle_dynamic_type_cache_miss(struct dynamic_type_cache_miss_data
ubsan("Dynamic type cache miss."); ubsan("Dynamic type cache miss.");
UNUSED(ptr); UNUSED(ptr);
} }
#endif

View File

@ -26,18 +26,18 @@ std::vector<UniversalAsynchronousReceiverTransmitter::Events *> RegisteredEvents
#if defined(a86) #if defined(a86)
NIF __always_inline inline uint8_t NoProfiler_inportb(uint16_t Port) NIF __always_inline inline uint8_t NoProfiler_inportb(uint16_t Port)
{ {
uint8_t Result; uint8_t Result;
asm("in %%dx, %%al" asm("in %%dx, %%al"
: "=a"(Result) : "=a"(Result)
: "d"(Port)); : "d"(Port));
return Result; return Result;
} }
NIF __always_inline inline void NoProfiler_outportb(uint16_t Port, uint8_t Data) NIF __always_inline inline void NoProfiler_outportb(uint16_t Port, uint8_t Data)
{ {
asmv("out %%al, %%dx" asmv("out %%al, %%dx"
: :
: "a"(Data), "d"(Port)); : "a"(Data), "d"(Port));
} }
#endif #endif
@ -52,123 +52,125 @@ namespace UniversalAsynchronousReceiverTransmitter
#define SERIAL_RATE_38400_HI 0x00 #define SERIAL_RATE_38400_HI 0x00
#define SERIAL_BUFFER_EMPTY 0x20 #define SERIAL_BUFFER_EMPTY 0x20
/* TODO: Serial Port implementation needs reword. https://wiki.osdev.org/Serial_Ports */ /* TODO: Serial Port implementation needs reword. https://wiki.osdev.org/Serial_Ports */
SafeFunction NIF UART::UART(SerialPorts Port) SafeFunction NIF UART::UART(SerialPorts Port)
{ {
#if defined(a86) #if defined(a86)
if (Port == COMNULL) if (Port == COMNULL)
return; return;
this->Port = Port; this->Port = Port;
int PortNumber = 0; int PortNumber = 0;
switch (Port) switch (Port)
{ {
case COM1: case COM1:
PortNumber = 0; PortNumber = 0;
break; break;
case COM2: case COM2:
PortNumber = 1; PortNumber = 1;
break; break;
case COM3: case COM3:
PortNumber = 2; PortNumber = 2;
break; break;
case COM4: case COM4:
PortNumber = 3; PortNumber = 3;
break; break;
case COM5: case COM5:
PortNumber = 4; PortNumber = 4;
break; break;
case COM6: case COM6:
PortNumber = 5; PortNumber = 5;
break; break;
case COM7: case COM7:
PortNumber = 6; PortNumber = 6;
break; break;
case COM8: case COM8:
PortNumber = 7; PortNumber = 7;
break; break;
default: default:
return; return;
} }
if (serialports[PortNumber]) if (serialports[PortNumber])
return; return;
// Initialize the serial port // Initialize the serial port
NoProfiler_outportb(s_cst(uint16_t, Port + 1), 0x00); // Disable all interrupts NoProfiler_outportb(s_cst(uint16_t, Port + 1), 0x00); // Disable all interrupts
NoProfiler_outportb(s_cst(uint16_t, Port + 3), SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor) NoProfiler_outportb(s_cst(uint16_t, Port + 3), SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor)
NoProfiler_outportb(s_cst(uint16_t, Port + 0), SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud NoProfiler_outportb(s_cst(uint16_t, Port + 0), SERIAL_RATE_115200_LO); // Set divisor to 1 (lo byte) 115200 baud
NoProfiler_outportb(s_cst(uint16_t, Port + 1), SERIAL_RATE_115200_HI); // (hi byte) NoProfiler_outportb(s_cst(uint16_t, Port + 1), SERIAL_RATE_115200_HI); // (hi byte)
NoProfiler_outportb(s_cst(uint16_t, Port + 3), 0x03); // 8 bits, no parity, one stop bit NoProfiler_outportb(s_cst(uint16_t, Port + 3), 0x03); // 8 bits, no parity, one stop bit
NoProfiler_outportb(s_cst(uint16_t, Port + 2), 0xC7); // Enable FIFO, clear them, with 14-byte threshold NoProfiler_outportb(s_cst(uint16_t, Port + 2), 0xC7); // Enable FIFO, clear them, with 14-byte threshold
NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0B); // IRQs enabled, RTS/DSR set NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0B); // IRQs enabled, RTS/DSR set
/* FIXME https://wiki.osdev.org/Serial_Ports */ /* FIXME https://wiki.osdev.org/Serial_Ports */
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0x1E); // NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0x1E);
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0xAE); // NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0xAE);
// Check if the serial port is faulty. // Check if the serial port is faulty.
// if (NoProfiler_inportb(s_cst(uint16_t, Port + 0)) != 0xAE) // if (NoProfiler_inportb(s_cst(uint16_t, Port + 0)) != 0xAE)
// { // {
// static int once = 0; // static int once = 0;
// if (!once++) // if (!once++)
// warn("Serial port %#llx is faulty.", Port); // warn("Serial port %#llx is faulty.", Port);
// // serialports[Port] = false; // ignore for now // // serialports[Port] = false; // ignore for now
// // return; // // return;
// } // }
// Set to normal operation mode. // Set to normal operation mode.
NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0F); NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0F);
serialports[PortNumber] = true; serialports[PortNumber] = true;
#endif #endif
} }
SafeFunction NIF UART::~UART() {} SafeFunction NIF UART::~UART() {}
SafeFunction NIF void UART::Write(uint8_t Char) SafeFunction NIF void UART::Write(uint8_t Char)
{ {
#if defined(a86) #if defined(a86)
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & SERIAL_BUFFER_EMPTY) == 0) while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & SERIAL_BUFFER_EMPTY) == 0)
; ;
NoProfiler_outportb(Port, Char); NoProfiler_outportb(Port, Char);
#endif #endif
foreach (auto e in RegisteredEvents) foreach (auto e in RegisteredEvents)
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL) if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
e->OnSent(Char); e->OnSent(Char);
} }
SafeFunction NIF uint8_t UART::Read() SafeFunction NIF uint8_t UART::Read()
{ {
#if defined(a86) #if defined(a86)
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & 1) == 0) while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & 1) == 0)
; ;
return NoProfiler_inportb(Port); return NoProfiler_inportb(Port);
#endif #endif
foreach (auto e in RegisteredEvents) foreach (auto e in RegisteredEvents)
{ {
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL) if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
{ {
#if defined(a86) #if defined(a86)
e->OnReceived(NoProfiler_inportb(Port)); e->OnReceived(NoProfiler_inportb(Port));
#endif #endif
} }
} }
} }
SafeFunction NIF Events::Events(SerialPorts Port) SafeFunction NIF Events::Events(SerialPorts Port)
{ {
this->Port = Port; this->Port = Port;
RegisteredEvents.push_back(this); RegisteredEvents.push_back(this);
} }
SafeFunction NIF Events::~Events() SafeFunction NIF Events::~Events()
{ {
for (size_t i = 0; i < RegisteredEvents.size(); i++) forItr(itr, RegisteredEvents)
if (RegisteredEvents[i] == this) {
{ if (*itr == this)
RegisteredEvents.remove(i); {
return; RegisteredEvents.erase(itr);
} return;
} }
}
}
} }

View File

@ -28,418 +28,419 @@ NewLock(PrintLock);
namespace Video namespace Video
{ {
Font *Display::GetCurrentFont() { return CurrentFont; } Font *Display::GetCurrentFont() { return CurrentFont; }
void Display::SetCurrentFont(Font *Font) { CurrentFont = Font; } void Display::SetCurrentFont(Font *Font) { CurrentFont = Font; }
uint16_t Display::GetBitsPerPixel() { return this->framebuffer.BitsPerPixel; } uint16_t Display::GetBitsPerPixel() { return this->framebuffer.BitsPerPixel; }
size_t Display::GetPitch() { return this->framebuffer.Pitch; } size_t Display::GetPitch() { return this->framebuffer.Pitch; }
void Display::CreateBuffer(uint32_t Width, uint32_t Height, int Index) void Display::CreateBuffer(uint32_t Width, uint32_t Height, int Index)
{ {
if (Width == 0 || Height == 0) if (Width == 0 || Height == 0)
{ {
Width = this->framebuffer.Width; Width = this->framebuffer.Width;
Height = this->framebuffer.Height; Height = this->framebuffer.Height;
debug("Buffer %d created with default size (%d, %d)", Index, Width, Height); debug("Buffer %d created with default size (%d, %d)", Index, Width, Height);
} }
if (this->Buffers[Index].Checksum == 0xBBFFE515A117E) if (this->Buffers[Index].Checksum == 0xBBFFE515A117E)
{ {
warn("Buffer %d already exists, skipping creation", Index); warn("Buffer %d already exists, skipping creation", Index);
return; return;
} }
size_t Size = this->framebuffer.Pitch * Height; size_t Size = this->framebuffer.Pitch * Height;
this->Buffers[Index].Buffer = KernelAllocator.RequestPages(TO_PAGES(Size + 1)); this->Buffers[Index].Buffer = KernelAllocator.RequestPages(TO_PAGES(Size + 1));
memset(this->Buffers[Index].Buffer, 0, Size); memset(this->Buffers[Index].Buffer, 0, Size);
this->Buffers[Index].Width = Width; this->Buffers[Index].Width = Width;
this->Buffers[Index].Height = Height; this->Buffers[Index].Height = Height;
this->Buffers[Index].Size = Size; this->Buffers[Index].Size = Size;
this->Buffers[Index].Color = 0xFFFFFF; this->Buffers[Index].Color = 0xFFFFFF;
this->Buffers[Index].CursorX = 0; this->Buffers[Index].CursorX = 0;
this->Buffers[Index].CursorY = 0; this->Buffers[Index].CursorY = 0;
this->Buffers[Index].Brightness = 100; this->Buffers[Index].Brightness = 100;
this->Buffers[Index].Checksum = 0xBBFFE515A117E; this->Buffers[Index].Checksum = 0xBBFFE515A117E;
debug("Buffer %d created", Index); debug("Buffer %d created", Index);
} }
void Display::SetBuffer(int Index) void Display::SetBuffer(int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
if (this->Buffers[Index].Brightness != 100) if (this->Buffers[Index].Brightness != 100)
this->SetBrightness(this->Buffers[Index].Brightness, Index); this->SetBrightness(this->Buffers[Index].Brightness, Index);
if (this->Buffers[Index].Brightness == 0) /* Just clear the buffer */ if (this->Buffers[Index].Brightness == 0) /* Just clear the buffer */
memset(this->Buffers[Index].Buffer, 0, this->Buffers[Index].Size); memset(this->Buffers[Index].Buffer, 0, this->Buffers[Index].Size);
memcpy(this->framebuffer.BaseAddress, this->Buffers[Index].Buffer, 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]; } ScreenBuffer *Display::GetBuffer(int Index) { return &this->Buffers[Index]; }
void Display::ClearBuffer(int Index) void Display::ClearBuffer(int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
memset(this->Buffers[Index].Buffer, 0, this->Buffers[Index].Size); memset(this->Buffers[Index].Buffer, 0, this->Buffers[Index].Size);
} }
void Display::DeleteBuffer(int Index) void Display::DeleteBuffer(int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
KernelAllocator.FreePages(this->Buffers[Index].Buffer, TO_PAGES(this->Buffers[Index].Size + 1)); KernelAllocator.FreePages(this->Buffers[Index].Buffer, TO_PAGES(this->Buffers[Index].Size + 1));
this->Buffers[Index].Buffer = nullptr; this->Buffers[Index].Buffer = nullptr;
this->Buffers[Index].Checksum = 0; this->Buffers[Index].Checksum = 0;
debug("Buffer %d deleted", Index); debug("Buffer %d deleted", Index);
} }
void Display::SetBrightness(int Value, int Index) void Display::SetBrightness(int Value, int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
if (Value > 100) if (Value > 100)
Value = 100; Value = 100;
else if (Value < 0) else if (Value < 0)
Value = 0; Value = 0;
uint32_t *pixel = (uint32_t *)this->Buffers[Index].Buffer; uint32_t *pixel = (uint32_t *)this->Buffers[Index].Buffer;
for (uint32_t y = 0; y < this->Buffers[Index].Height; y++) for (uint32_t y = 0; y < this->Buffers[Index].Height; y++)
{ {
for (uint32_t x = 0; x < this->Buffers[Index].Width; x++) for (uint32_t x = 0; x < this->Buffers[Index].Width; x++)
{ {
uint32_t color = pixel[y * this->Buffers[Index].Width + x]; uint32_t color = pixel[y * this->Buffers[Index].Width + x];
uint8_t r = color & 0xff; uint8_t r = color & 0xff;
uint8_t g = (color >> 8) & 0xff; uint8_t g = (color >> 8) & 0xff;
uint8_t b = (color >> 16) & 0xff; uint8_t b = (color >> 16) & 0xff;
r = s_cst(uint8_t, (r * Value) / 100); r = s_cst(uint8_t, (r * Value) / 100);
g = s_cst(uint8_t, (g * Value) / 100); g = s_cst(uint8_t, (g * Value) / 100);
b = s_cst(uint8_t, (b * Value) / 100); b = s_cst(uint8_t, (b * Value) / 100);
pixel[y * this->Buffers[Index].Width + x] = (b << 16) | (g << 8) | r; pixel[y * this->Buffers[Index].Width + x] = (b << 16) | (g << 8) | r;
} }
} }
this->Buffers[Index].Brightness = s_cst(char, Value); this->Buffers[Index].Brightness = s_cst(char, Value);
} }
void Display::SetBufferCursor(int Index, uint32_t X, uint32_t Y) void Display::SetBufferCursor(int Index, uint32_t X, uint32_t Y)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
this->Buffers[Index].CursorX = X; this->Buffers[Index].CursorX = X;
this->Buffers[Index].CursorY = Y; this->Buffers[Index].CursorY = Y;
} }
void Display::GetBufferCursor(int Index, uint32_t *X, uint32_t *Y) void Display::GetBufferCursor(int Index, uint32_t *X, uint32_t *Y)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
*X = this->Buffers[Index].CursorX; *X = this->Buffers[Index].CursorX;
*Y = this->Buffers[Index].CursorY; *Y = this->Buffers[Index].CursorY;
} }
void Display::SetPixel(uint32_t X, uint32_t Y, uint32_t Color, int Index) void Display::SetPixel(uint32_t X, uint32_t Y, uint32_t Color, int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
if (unlikely(X >= this->Buffers[Index].Width)) if (unlikely(X >= this->Buffers[Index].Width))
X = this->Buffers[Index].Width - 1; X = this->Buffers[Index].Width - 1;
if (unlikely(Y >= this->Buffers[Index].Height)) if (unlikely(Y >= this->Buffers[Index].Height))
Y = this->Buffers[Index].Height - 1; 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)); uint32_t *Pixel = (uint32_t *)((uintptr_t)this->Buffers[Index].Buffer + (Y * this->Buffers[Index].Width + X) * (this->framebuffer.BitsPerPixel / 8));
*Pixel = Color; *Pixel = Color;
} }
uint32_t Display::GetPixel(uint32_t X, uint32_t Y, int Index) uint32_t Display::GetPixel(uint32_t X, uint32_t Y, int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
return 0; return 0;
if (unlikely(X >= this->Buffers[Index].Width || Y >= this->Buffers[Index].Height)) if (unlikely(X >= this->Buffers[Index].Width || Y >= this->Buffers[Index].Height))
return 0; return 0;
uint32_t *Pixel = (uint32_t *)((uintptr_t)this->Buffers[Index].Buffer + (Y * this->Buffers[Index].Width + X) * (this->framebuffer.BitsPerPixel / 8)); uint32_t *Pixel = (uint32_t *)((uintptr_t)this->Buffers[Index].Buffer + (Y * this->Buffers[Index].Width + X) * (this->framebuffer.BitsPerPixel / 8));
return *Pixel; return *Pixel;
} }
void Display::Scroll(int Index, int Lines) void Display::Scroll(int Index, int Lines)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
if (this->Buffers[Index].DoNotScroll) if (this->Buffers[Index].DoNotScroll)
return; return;
if (Lines == 0) if (Lines == 0)
return; return;
if (Lines > 0) if (Lines > 0)
{ {
uint32_t LineSize = this->Buffers[Index].Width * (this->framebuffer.BitsPerPixel / 8); uint32_t LineSize = this->Buffers[Index].Width * (this->framebuffer.BitsPerPixel / 8);
uint32_t BytesToMove = LineSize * Lines * this->CurrentFont->GetInfo().Height; uint32_t BytesToMove = LineSize * Lines * this->CurrentFont->GetInfo().Height;
size_t BytesToClear = this->Buffers[Index].Size - BytesToMove; size_t BytesToClear = this->Buffers[Index].Size - BytesToMove;
memmove(this->Buffers[Index].Buffer, (uint8_t *)this->Buffers[Index].Buffer + BytesToMove, BytesToClear); memmove(this->Buffers[Index].Buffer, (uint8_t *)this->Buffers[Index].Buffer + BytesToMove, BytesToClear);
memset((uint8_t *)this->Buffers[Index].Buffer + BytesToClear, 0, BytesToMove); memset((uint8_t *)this->Buffers[Index].Buffer + BytesToClear, 0, BytesToMove);
} }
} }
void Display::SetDoNotScroll(bool Value, int Index) void Display::SetDoNotScroll(bool Value, int Index)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
this->Buffers[Index].DoNotScroll = Value; this->Buffers[Index].DoNotScroll = Value;
} }
#if defined(a32) #if defined(a32)
__no_sanitize("undefined") __no_sanitize("undefined")
#endif #endif
char Display::Print(char Char, int Index, bool WriteToUART) char Display::Print(char Char, int Index, bool WriteToUART)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
return 0; return 0;
// SmartLock(PrintLock); // SmartLock(PrintLock);
if (this->ColorIteration) if (this->ColorIteration)
{ {
// RRGGBB // RRGGBB
if (Char >= '0' && Char <= '9') if (Char >= '0' && Char <= '9')
this->Buffers[Index].Color = (this->Buffers[Index].Color << 4) | (Char - '0'); this->Buffers[Index].Color = (this->Buffers[Index].Color << 4) | (Char - '0');
else if (Char >= 'a' && Char <= 'f') else if (Char >= 'a' && Char <= 'f')
this->Buffers[Index].Color = (this->Buffers[Index].Color << 4) | (Char - 'a' + 10); this->Buffers[Index].Color = (this->Buffers[Index].Color << 4) | (Char - 'a' + 10);
else if (Char >= 'A' && Char <= 'F') else if (Char >= 'A' && Char <= 'F')
this->Buffers[Index].Color = (this->Buffers[Index].Color << 4) | (Char - 'A' + 10); this->Buffers[Index].Color = (this->Buffers[Index].Color << 4) | (Char - 'A' + 10);
else else
this->Buffers[Index].Color = 0xFFFFFF; this->Buffers[Index].Color = 0xFFFFFF;
if (WriteToUART) if (WriteToUART)
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char); UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char);
this->ColorPickerIteration++; this->ColorPickerIteration++;
if (this->ColorPickerIteration == 6) if (this->ColorPickerIteration == 6)
{ {
this->ColorPickerIteration = 0; this->ColorPickerIteration = 0;
if (WriteToUART) if (WriteToUART)
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(']'); UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(']');
this->ColorIteration = false; this->ColorIteration = false;
} }
return Char; return Char;
} }
if (WriteToUART) if (WriteToUART)
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char); UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(Char);
switch (Char) switch (Char)
{ {
case '\e': case '\e':
{ {
if (WriteToUART) if (WriteToUART)
UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write('['); UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write('[');
this->ColorIteration = true; this->ColorIteration = true;
return Char; return Char;
} }
case '\b': case '\b':
{ {
switch (this->CurrentFont->GetInfo().Type) switch (this->CurrentFont->GetInfo().Type)
{ {
case FontType::PCScreenFont1: case FontType::PCScreenFont1:
{ {
fixme("PCScreenFont1"); fixme("PCScreenFont1");
break; break;
} }
case FontType::PCScreenFont2: case FontType::PCScreenFont2:
{ {
uint32_t fonthdrWidth = this->CurrentFont->GetInfo().PSF2Font->Header->width; uint32_t fonthdrWidth = this->CurrentFont->GetInfo().PSF2Font->Header->width;
uint32_t fonthdrHeight = this->CurrentFont->GetInfo().PSF2Font->Header->height; 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 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++) for (unsigned long X = this->Buffers[Index].CursorX - fonthdrWidth; X < this->Buffers[Index].CursorX; X++)
*(uint32_t *)((uintptr_t)this->Buffers[Index].Buffer + *(uint32_t *)((uintptr_t)this->Buffers[Index].Buffer +
(Y * this->Buffers[Index].Width + X) * (this->framebuffer.BitsPerPixel / 8)) = 0; (Y * this->Buffers[Index].Width + X) * (this->framebuffer.BitsPerPixel / 8)) = 0;
break; break;
} }
default: default:
warn("Unsupported font type"); warn("Unsupported font type");
break; break;
} }
if (this->Buffers[Index].CursorX > 0) if (this->Buffers[Index].CursorX > 0)
this->Buffers[Index].CursorX -= this->GetCurrentFont()->GetInfo().Width; this->Buffers[Index].CursorX -= this->GetCurrentFont()->GetInfo().Width;
return Char; return Char;
} }
case '\t': case '\t':
{ {
this->Buffers[Index].CursorX = (this->Buffers[Index].CursorX + 8) & ~(8 - 1); this->Buffers[Index].CursorX = (this->Buffers[Index].CursorX + 8) & ~(8 - 1);
return Char; return Char;
} }
case '\r': case '\r':
{ {
this->Buffers[Index].CursorX = 0; this->Buffers[Index].CursorX = 0;
return Char; return Char;
} }
case '\n': case '\n':
{ {
this->Buffers[Index].CursorX = 0; this->Buffers[Index].CursorX = 0;
this->Buffers[Index].CursorY += this->GetCurrentFont()->GetInfo().Height; this->Buffers[Index].CursorY += this->GetCurrentFont()->GetInfo().Height;
return Char; return Char;
} }
default: default:
break; break;
} }
uint32_t FontHeight = this->GetCurrentFont()->GetInfo().Height; uint32_t FontHeight = this->GetCurrentFont()->GetInfo().Height;
if (this->Buffers[Index].CursorX + this->GetCurrentFont()->GetInfo().Width >= this->Buffers[Index].Width) if (this->Buffers[Index].CursorX + this->GetCurrentFont()->GetInfo().Width >= this->Buffers[Index].Width)
{ {
this->Buffers[Index].CursorX = 0; this->Buffers[Index].CursorX = 0;
this->Buffers[Index].CursorY += FontHeight; this->Buffers[Index].CursorY += FontHeight;
} }
if (this->Buffers[Index].CursorY + FontHeight >= this->Buffers[Index].Height) if (this->Buffers[Index].CursorY + FontHeight >= this->Buffers[Index].Height)
{ {
if (!this->Buffers[Index].DoNotScroll) if (!this->Buffers[Index].DoNotScroll)
{ {
this->Buffers[Index].CursorY -= FontHeight; this->Buffers[Index].CursorY -= FontHeight;
this->Scroll(Index, 1); this->Scroll(Index, 1);
} }
} }
switch (this->CurrentFont->GetInfo().Type) switch (this->CurrentFont->GetInfo().Type)
{ {
case FontType::PCScreenFont1: case FontType::PCScreenFont1:
{ {
uint32_t *PixelPtr = (uint32_t *)this->Buffers[Index].Buffer; uint32_t *PixelPtr = (uint32_t *)this->Buffers[Index].Buffer;
char *FontPtr = (char *)this->CurrentFont->GetInfo().PSF1Font->GlyphBuffer + (Char * this->CurrentFont->GetInfo().PSF1Font->Header->charsize); 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 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++) for (uint64_t X = this->Buffers[Index].CursorX; X < this->Buffers[Index].CursorX + 8; X++)
if ((*FontPtr & (0b10000000 >> (X - this->Buffers[Index].CursorX))) > 0) if ((*FontPtr & (0b10000000 >> (X - this->Buffers[Index].CursorX))) > 0)
*(unsigned int *)(PixelPtr + X + (Y * this->Buffers[Index].Width)) = this->Buffers[Index].Color; *(unsigned int *)(PixelPtr + X + (Y * this->Buffers[Index].Width)) = this->Buffers[Index].Color;
FontPtr++; FontPtr++;
} }
this->Buffers[Index].CursorX += 8; this->Buffers[Index].CursorX += 8;
break; break;
} }
case FontType::PCScreenFont2: case FontType::PCScreenFont2:
{ {
// if (this->CurrentFont->PSF2Font->GlyphBuffer == (uint16_t *)0x01) // HAS UNICODE TABLE // if (this->CurrentFont->PSF2Font->GlyphBuffer == (uint16_t *)0x01) // HAS UNICODE TABLE
// Char = this->CurrentFont->PSF2Font->GlyphBuffer[Char]; // Char = this->CurrentFont->PSF2Font->GlyphBuffer[Char];
int BytesPerLine = (this->CurrentFont->GetInfo().PSF2Font->Header->width + 7) / 8; int BytesPerLine = (this->CurrentFont->GetInfo().PSF2Font->Header->width + 7) / 8;
char *FontAddress = (char *)this->CurrentFont->GetInfo().StartAddress; char *FontAddress = (char *)this->CurrentFont->GetInfo().StartAddress;
uint32_t FontHeaderSize = this->CurrentFont->GetInfo().PSF2Font->Header->headersize; uint32_t FontHeaderSize = this->CurrentFont->GetInfo().PSF2Font->Header->headersize;
uint32_t FontCharSize = this->CurrentFont->GetInfo().PSF2Font->Header->charsize; uint32_t FontCharSize = this->CurrentFont->GetInfo().PSF2Font->Header->charsize;
uint32_t FontLength = this->CurrentFont->GetInfo().PSF2Font->Header->length; uint32_t FontLength = this->CurrentFont->GetInfo().PSF2Font->Header->length;
char *FontPtr = FontAddress + FontHeaderSize + (Char > 0 && (uint32_t)Char < FontLength ? Char : 0) * FontCharSize; char *FontPtr = FontAddress + FontHeaderSize + (Char > 0 && (uint32_t)Char < FontLength ? Char : 0) * FontCharSize;
uint32_t FontHdrWidth = this->CurrentFont->GetInfo().PSF2Font->Header->width; uint32_t FontHdrWidth = this->CurrentFont->GetInfo().PSF2Font->Header->width;
uint32_t FontHdrHeight = this->CurrentFont->GetInfo().PSF2Font->Header->height; 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 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++) for (size_t X = this->Buffers[Index].CursorX; X < this->Buffers[Index].CursorX + FontHdrWidth; X++)
{ {
if ((*FontPtr & (0b10000000 >> (X - this->Buffers[Index].CursorX))) > 0) if ((*FontPtr & (0b10000000 >> (X - this->Buffers[Index].CursorX))) > 0)
{ {
void *FramebufferAddress = (void *)((uintptr_t)this->Buffers[Index].Buffer + void *FramebufferAddress = (void *)((uintptr_t)this->Buffers[Index].Buffer +
(Y * this->Buffers[Index].Width + X) * (Y * this->Buffers[Index].Width + X) *
(this->framebuffer.BitsPerPixel / 8)); (this->framebuffer.BitsPerPixel / 8));
*(uint32_t *)FramebufferAddress = this->Buffers[Index].Color; *(uint32_t *)FramebufferAddress = this->Buffers[Index].Color;
} }
} }
FontPtr += BytesPerLine; FontPtr += BytesPerLine;
} }
this->Buffers[Index].CursorX += FontHdrWidth; this->Buffers[Index].CursorX += FontHdrWidth;
break; break;
} }
default: default:
warn("Unsupported font type"); warn("Unsupported font type");
break; break;
} }
return Char; return Char;
} }
void Display::DrawString(const char *String, uint32_t X, uint32_t Y, int Index, bool WriteToUART) void Display::DrawString(const char *String, uint32_t X, uint32_t Y, int Index, bool WriteToUART)
{ {
if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E)) if (unlikely(this->Buffers[Index].Checksum != 0xBBFFE515A117E))
{ {
debug("Invalid buffer %d", Index); debug("Invalid buffer %d", Index);
return; return;
} }
this->Buffers[Index].CursorX = X; this->Buffers[Index].CursorX = X;
this->Buffers[Index].CursorY = Y; this->Buffers[Index].CursorY = Y;
for (int i = 0; String[i] != '\0'; i++) for (int i = 0; String[i] != '\0'; i++)
this->Print(String[i], Index, WriteToUART); this->Print(String[i], Index, WriteToUART);
} }
Display::Display(BootInfo::FramebufferInfo Info, bool LoadDefaultFont) Display::Display(BootInfo::FramebufferInfo Info, bool LoadDefaultFont)
{ {
this->framebuffer = Info; this->framebuffer = Info;
if (LoadDefaultFont) 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); this->CurrentFont = new Font(&_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, FontType::PCScreenFont2);
#ifdef DEBUG #ifdef DEBUG
FontInfo Info = this->CurrentFont->GetInfo(); FontInfo Info = this->CurrentFont->GetInfo();
debug("Font loaded: %dx%d %s", debug("Font loaded: %dx%d %s",
Info.Width, Info.Height, Info.Type == FontType::PCScreenFont1 ? "PSF1" : "PSF2"); Info.Width, Info.Height,
Info.Type == FontType::PCScreenFont1 ? "PSF1" : "PSF2");
#endif #endif
} }
this->CreateBuffer(Info.Width, Info.Height, 0); this->CreateBuffer(Info.Width, Info.Height, 0);
} }
Display::~Display() Display::~Display()
{ {
debug("Destructor called"); debug("Destructor called");
this->ClearBuffer(0); this->ClearBuffer(0);
this->SetBuffer(0); this->SetBuffer(0);
for (int i = 0; i < s_cst(int, sizeof(this->Buffers) / sizeof(this->Buffers[0])); i++) for (int i = 0; i < s_cst(int, sizeof(this->Buffers) / sizeof(this->Buffers[0])); i++)
{ {
if (this->Buffers[i].Checksum == 0xBBFFE515A117E) if (this->Buffers[i].Checksum == 0xBBFFE515A117E)
this->DeleteBuffer(i); this->DeleteBuffer(i);
} }
} }
} }

View File

@ -36,9 +36,11 @@ namespace Video
PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(TO_PAGES(FontDataLength + 1)); PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(TO_PAGES(FontDataLength + 1));
memcpy((void *)font2, Start, FontDataLength); memcpy((void *)font2, Start, FontDataLength);
Memory::Virtual().Map((void *)font2, (void *)font2, FontDataLength, Memory::PTFlag::RW); Memory::Virtual().Map((void *)font2, (void *)font2,
FontDataLength, Memory::PTFlag::RW);
if (font2->magic[0] != PSF2_MAGIC0 || font2->magic[1] != PSF2_MAGIC1 || font2->magic[2] != PSF2_MAGIC2 || font2->magic[3] != PSF2_MAGIC3) 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."); error("Font2 magic mismatch.");
KernelAllocator.FreePages((void *)font2, TO_PAGES(FontDataLength + 1)); KernelAllocator.FreePages((void *)font2, TO_PAGES(FontDataLength + 1));
@ -46,7 +48,8 @@ namespace Video
} }
this->Info.PSF2Font->Header = font2; this->Info.PSF2Font->Header = font2;
this->Info.PSF2Font->GlyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF2_HEADER)); this->Info.PSF2Font->GlyphBuffer =
r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF2_HEADER));
this->Info.Width = font2->width; this->Info.Width = font2->width;
this->Info.Height = font2->height; this->Info.Height = font2->height;
} }
@ -59,7 +62,8 @@ namespace Video
uint32_t glyphBufferSize = font1->charsize * 256; uint32_t glyphBufferSize = font1->charsize * 256;
if (font1->mode == 1) // 512 glyph mode if (font1->mode == 1) // 512 glyph mode
glyphBufferSize = font1->charsize * 512; glyphBufferSize = font1->charsize * 512;
void *glyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF1_HEADER)); void *glyphBuffer =
r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF1_HEADER));
this->Info.PSF1Font->Header = font1; this->Info.PSF1Font->Header = font1;
this->Info.PSF1Font->GlyphBuffer = glyphBuffer; this->Info.PSF1Font->GlyphBuffer = glyphBuffer;
UNUSED(glyphBufferSize); // TODO: Use this in the future? UNUSED(glyphBufferSize); // TODO: Use this in the future?

View File

@ -34,7 +34,7 @@
#define __FENNIX_DRIVER_API_H__ #define __FENNIX_DRIVER_API_H__
/** /**
* @brief The driver API is a set of functions that the kernel provides to the drivers. * The driver API is a set of functions that the kernel provides to the drivers.
* *
* - The driver is responsible for the memory management. * - The driver is responsible for the memory management.
* - The kernel will NOT free any memory allocated by the driver. On @see StopReason the driver must free all the memory it allocated and disable the hardware it uses. * - The kernel will NOT free any memory allocated by the driver. On @see StopReason the driver must free all the memory it allocated and disable the hardware it uses.
@ -115,14 +115,14 @@ struct KernelAPI
struct KAPIDriverTalk struct KAPIDriverTalk
{ {
/** @brief Connects to the network manager */ /** Connects to the network manager */
struct struct
{ {
void (*SendPacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size); void (*SendPacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size);
void (*ReceivePacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size); void (*ReceivePacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size);
} Network; } Network;
/** @brief Connects to the disk manager */ /** Connects to the disk manager */
struct struct
{ {
struct struct
@ -144,24 +144,24 @@ struct KernelAPI
enum CallbackReason enum CallbackReason
{ {
/** /**
* @brief This is used to detect memory corruption, not used. * This is used to detect memory corruption, not used.
*/ */
UnknownReason, UnknownReason,
/** /**
* @brief This is called once the kernel is ready to use the driver and call @see ConfigurationReason . * This is called once the kernel is ready to use the driver and call @see ConfigurationReason .
*/ */
AcknowledgeReason, AcknowledgeReason,
/** /**
* @brief This is used after the driver is loaded and the kernel is ready to use the driver. * This is used after the driver is loaded and the kernel is ready to use the driver.
* *
* For PCI drivers, @see RawPtr will be the PCI device address. * For PCI drivers, @see RawPtr will be the PCI device address.
*/ */
ConfigurationReason, ConfigurationReason,
/** /**
* @brief This is used when the kernel wants to stop the driver. * This is used when the kernel wants to stop the driver.
* *
* The memory allocated by the driver will be freed automatically. * The memory allocated by the driver will be freed automatically.
*/ */
@ -175,7 +175,7 @@ enum CallbackReason
/* Driver callbacks for basic usage. */ /* Driver callbacks for basic usage. */
/** /**
* @brief This is used when the kernel sends data. * This is used when the kernel sends data.
* *
* - Network * - Network
* - Packet * - Packet
@ -185,13 +185,13 @@ enum CallbackReason
SendReason, SendReason,
/** /**
* @brief This is used when the kernel wants to receive data. * This is used when the kernel wants to receive data.
* Currently not used. * Currently not used.
*/ */
ReceiveReason, ReceiveReason,
/** /**
* @brief This is used to adjust driver settings. * This is used to adjust driver settings.
* *
* - Audio * - Audio
* - Volume * - Volume
@ -200,7 +200,7 @@ enum CallbackReason
AdjustReason, AdjustReason,
/** /**
* @brief This is used when the kernel wants to fetch information about the driver. * This is used when the kernel wants to query information about the driver.
* *
* - Input * - Input
* - Mouse * - Mouse
@ -209,7 +209,19 @@ enum CallbackReason
* - Keyboard * - Keyboard
* - Key * - Key
*/ */
FetchReason, QueryReason,
/**
* This is used when the kernel wants to wait for an event.
*
* - Input
* - Mouse
* - Position
* - Buttons
* - Keyboard
* - Key
*/
PollWaitReason,
}; };
union KernelCallback union KernelCallback
@ -220,7 +232,7 @@ union KernelCallback
void *RawPtr; void *RawPtr;
unsigned long RawData; unsigned long RawData;
/** @brief When the kernel wants to send a packet. */ /** When the kernel wants to send a packet. */
struct struct
{ {
struct struct
@ -236,7 +248,7 @@ union KernelCallback
} Fetch; } Fetch;
} NetworkCallback; } NetworkCallback;
/** @brief When the kernel wants to write to disk. */ /** When the kernel wants to write to disk. */
struct struct
{ {
struct struct
@ -255,7 +267,7 @@ union KernelCallback
} Fetch; } Fetch;
} DiskCallback; } DiskCallback;
/** @brief When the kernel wants to get mouse position / keyboard key */ /** When the kernel wants to get mouse position / keyboard key */
struct struct
{ {
struct struct
@ -270,6 +282,16 @@ union KernelCallback
bool Middle; bool Middle;
} Buttons; } Buttons;
} Mouse; } Mouse;
struct
{
/**
* The key.
*
* @note This is a scancode, not a character.
*/
unsigned char Key;
} Keyboard;
} InputCallback; } InputCallback;
struct struct
@ -282,14 +304,14 @@ union KernelCallback
bool _Channels; bool _Channels;
/** /**
* @brief Adjust the volume. * Adjust the volume.
* *
* 0 - 100 * 0 - 100
*/ */
unsigned char Volume; unsigned char Volume;
/** /**
* @brief Adjust the encoding. * Adjust the encoding.
* *
* 0 - None, use default * 0 - None, use default
* *
@ -330,7 +352,7 @@ union KernelCallback
unsigned short Encoding; unsigned short Encoding;
/** /**
* @brief Adjust the sample rate. * Adjust the sample rate.
* *
* 0 - 8000 Hz * 0 - 8000 Hz
* 1 - 11025 Hz * 1 - 11025 Hz
@ -345,7 +367,7 @@ union KernelCallback
unsigned char SampleRate; unsigned char SampleRate;
/** /**
* @brief Adjust the channels. * Adjust the channels.
* *
* 0 - Mono * 0 - Mono
* 1 - Stereo * 1 - Stereo

View File

@ -1,171 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../kernel.h"
#include "../Fex.hpp"
namespace Execute
{
BinaryType GetBinaryType(void *Image)
{
Fex *FexHdr = (Fex *)Image;
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Image;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Image;
/* Check Fex magic */
if (FexHdr->Magic[0] == 'F' &&
FexHdr->Magic[1] == 'E' &&
FexHdr->Magic[2] == 'X' &&
FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
debug("Image - Fex");
return BinaryType::BinTypeFex;
}
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
{
debug("Fex Driver is not supposed to be executed.");
}
}
/* Check ELF magic. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
return BinaryType::BinTypeELF;
}
/* Every Windows executable starts with MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Image) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Image) + MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
return BinaryType::BinTypePE;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
return BinaryType::BinTypeNE;
}
else
{
debug("Image - MZ");
return BinaryType::BinTypeMZ;
}
}
/* ... */
return BinaryType::BinTypeUnknown;
}
BinaryType GetBinaryType(char *Path)
{
BinaryType Type = BinaryType::BinTypeInvalid;
VirtualFileSystem::File ExFile = vfs->Open(Path);
if (!ExFile.IsOK())
{
vfs->Close(ExFile);
return Type;
}
debug("File opened: %s", Path);
uint8_t *Buffer = new uint8_t[1024];
vfs->Read(ExFile, Buffer, 128);
Fex *FexHdr = (Fex *)Buffer;
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Buffer;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Buffer;
/* Check Fex header. */
if (FexHdr->Magic[0] == 'F' &&
FexHdr->Magic[1] == 'E' &&
FexHdr->Magic[2] == 'X' &&
FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
debug("Image - Fex");
Type = BinaryType::BinTypeFex;
goto Success;
}
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
{
fixme("Fex Driver is not supposed to be executed.");
/* TODO: Driver installation pop-up. */
}
}
/* Check ELF header. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
Type = BinaryType::BinTypeELF;
goto Success;
}
/* Check MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
vfs->Seek(ExFile, MZHeader->e_lfanew, SEEK_SET);
vfs->Read(ExFile, Buffer, 512);
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Buffer) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Buffer) + MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
Type = BinaryType::BinTypePE;
goto Success;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
Type = BinaryType::BinTypeNE;
goto Success;
}
else
{
debug("Image - MZ");
Type = BinaryType::BinTypeMZ;
goto Success;
}
}
/* ... */
Type = BinaryType::BinTypeUnknown;
Success:
delete[] Buffer;
vfs->Close(ExFile);
return Type;
}
}

View File

@ -1,187 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::NodeFlags;
namespace Execute
{
ELFBaseLoad ELFLoad(char *Path,
const char **argv, const char **envp,
TaskCompatibility Compatibility)
{
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
File ExFile = vfs->Open(Path);
if (ExFile.Status != FileStatus::OK)
{
vfs->Close(ExFile);
error("Failed to open file: %s", Path);
return {};
}
else if (ExFile.GetFlags() != NodeFlags::FILE)
{
vfs->Close(ExFile);
error("Invalid file path: %s", Path);
return {};
}
else if (GetBinaryType(Path) != BinaryType::BinTypeELF)
{
vfs->Close(ExFile);
error("Invalid file type: %s", Path);
return {};
}
size_t ExFileSize = ExFile.GetLength();
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize + 1));
vfs->Read(ExFile, (uint8_t *)ElfFile, ExFileSize);
debug("Loaded elf %s at %#lx with the length of %ld",
Path, ElfFile, ExFileSize);
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)ElfFile;
switch (ELFHeader->e_machine)
{
case EM_386:
Arch = TaskArchitecture::x32;
break;
case EM_X86_64:
Arch = TaskArchitecture::x64;
break;
case EM_ARM:
Arch = TaskArchitecture::ARM32;
break;
case EM_AARCH64:
Arch = TaskArchitecture::ARM64;
break;
default:
break;
}
// TODO: This shouldn't be ignored
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
fixme("32-bit ELF");
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
fixme("64-bit ELF");
else
fixme("Unknown class %d", ELFHeader->e_ident[EI_CLASS]);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if (ELFHeader->e_ident[EI_DATA] != ELFDATA2LSB)
{
fixme("ELF32 LSB expected, got %d", ELFHeader->e_ident[EI_DATA]);
}
#else
if (ELFHeader->e_ident[EI_DATA] != ELFDATA2MSB)
{
fixme("ELF32 MSB expected, got %d", ELFHeader->e_ident[EI_DATA]);
}
#endif
/* ------------------------------------------------------------------------------------------------------------------------------ */
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(),
BaseName, TaskTrustLevel::User, ElfFile);
Process->SetWorkingDirectory(vfs->GetNodeFromPath(Path)->Parent);
Process->Info.Compatibility = TaskCompatibility::Native;
Process->Info.Architecture = TaskArchitecture::x64;
ELFBaseLoad bl;
ELFObject *obj = new ELFObject(Path, Process);
if (!obj->IsValid())
{
error("Failed to load ELF object");
vfs->Close(ExFile);
TaskManager->RevertProcessCreation(Process);
return {};
}
bl = obj->GetBaseLoadInfo();
/* TODO: Keep only the necessary headers */
Memory::Virtual vmm = Memory::Virtual(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
{
void *AddressToMap = (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE));
vmm.Remap(AddressToMap, AddressToMap, Memory::RW | Memory::US);
}
if (bl.Interpreter)
{
debug("Keeping ElfFile at %p", ElfFile);
TCB *InterIPCThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(),
(IP)ELFInterpreterIPCThread,
nullptr,
nullptr,
std::vector<AuxiliaryVector>(),
TaskArchitecture::x64,
TaskCompatibility::Native,
true);
std::vector<const char *> *tmp_needed_libs =
new std::vector<const char *>(bl.NeededLibraries);
InterIPCThread->SYSV_ABI_Call((uintptr_t)Process,
(uintptr_t) new std::string(Path),
(uintptr_t)bl.VirtualMemoryImage,
(uintptr_t)tmp_needed_libs);
InterIPCThread->Rename("ELF Interpreter IPC Thread");
InterIPCThread->SetPriority(TaskPriority::Low);
InterIPCThread->Status = TaskStatus::Ready;
}
TCB *Thread = TaskManager->CreateThread(Process,
bl.InstructionPointer,
argv, envp, bl.auxv,
Arch,
Compatibility);
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
Thread->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
}
delete bl.TmpMem, bl.TmpMem = nullptr;
bl.sd.Process = Process;
bl.sd.Thread = Thread;
bl.sd.Status = ExStatus::OK;
vfs->Close(ExFile);
return bl;
}
}

View File

@ -1,155 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <debug.h>
#include "../../kernel.h"
using namespace Tasking;
namespace Execute
{
struct InterpreterIPCDataLibrary
{
char Name[64];
};
typedef struct
{
char Path[256];
void *MemoryImage;
struct InterpreterIPCDataLibrary Libraries[64];
} InterpreterIPCData;
void ELFInterpreterIPCThread(PCB *TargetProcess,
std::string *TargetPath,
void *MemoryImage,
std::vector<const char *> *_NeededLibraries)
{
std::vector<const char *> NeededLibraries = *_NeededLibraries;
delete _NeededLibraries;
debug("Interpreter thread started for %s", TargetPath->c_str());
// Interpreter will create an IPC with token "LOAD".
char UniqueToken[16] = {'L', 'O', 'A', 'D', '\0'};
InterProcessCommunication::IPCHandle *Handle = nullptr;
while (Handle == nullptr)
{
debug("Searching for IPC with token %s", UniqueToken);
Handle = TargetProcess->IPC->SearchByToken(UniqueToken);
if (Handle == nullptr)
debug("Failed");
TaskManager->Sleep(200);
if (Handle == nullptr)
debug("Retrying...");
}
debug("IPC found, sending data...");
InterpreterIPCData *TmpBuffer = new InterpreterIPCData;
strncpy(TmpBuffer->Path, TargetPath->c_str(), sizeof(TmpBuffer->Path) - 1);
TmpBuffer->MemoryImage = MemoryImage;
size_t NeededLibsSize = NeededLibraries.size();
for (size_t i = 0; i < NeededLibsSize; i++)
strncpy(TmpBuffer->Libraries[i].Name, NeededLibraries[i],
sizeof(TmpBuffer->Libraries[i].Name) - 1);
#ifdef DEBUG
debug("Input:");
debug("Path: %s", TargetPath->c_str());
debug("MemoryImage: %p", MemoryImage);
for (size_t i = 0; i < NeededLibsSize; i++)
debug("Library: %s", NeededLibraries[i]);
debug("Buffer:");
debug("Path: %s", TmpBuffer->Path);
debug("MemoryImage: %p", TmpBuffer->MemoryImage);
for (size_t i = 0; i < 64; i++)
{
if (TmpBuffer->Libraries[i].Name[0] != '\0')
break;
debug("Library: %s", TmpBuffer->Libraries[i].Name);
}
#endif
RetryIPCWrite:
InterProcessCommunication::IPCErrorCode ret =
TargetProcess->IPC->Write(Handle->ID, TmpBuffer, sizeof(InterpreterIPCData));
debug("Write returned %d", ret);
if (ret == InterProcessCommunication::IPCErrorCode::IPCNotListening)
{
debug("IPC not listening, retrying...");
TaskManager->Sleep(100);
goto RetryIPCWrite;
}
delete TmpBuffer;
while (!TargetProcess->IPC->SearchByToken(UniqueToken))
TaskManager->Schedule();
debug("Interpreter thread finished for %s", TargetPath->c_str());
for (size_t i = 0; i < NeededLibsSize; i++)
delete[] NeededLibraries[i];
delete TargetPath;
TEXIT(0);
}
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &vmm, const char *Interpreter)
{
if (GetBinaryType((char *)Interpreter) != BinaryType::BinTypeELF)
{
error("Interpreter \"%s\" is not an ELF file.", Interpreter);
return 0;
}
/* No need to check if it's valid because
the function that calls this already checks it. */
VirtualFileSystem::File ElfFile = vfs->Open(Interpreter);
Elf64_Ehdr ELFHeader;
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
debug("Interpreter type: %#x", ELFHeader.e_type);
uintptr_t BaseAddress;
size_t ElfPHDRsSize;
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
MmImage MemoryImage = ELFCreateMemoryImage(mem, vmm, ElfFile, ElfPHDRsSize);
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
vfs->Close(ElfFile);
bool IsPIC = ELFHeader.e_type == ET_DYN;
debug("Elf %s PIC", IsPIC ? "is" : "is not");
if (IsPIC)
{
debug("Interpreter entry point: %#lx (%#lx + %#lx)",
(uintptr_t)MemoryImage.Physical + ELFHeader.e_entry,
(uintptr_t)MemoryImage.Physical, ELFHeader.e_entry);
return (uintptr_t)MemoryImage.Physical + ELFHeader.e_entry;
}
else
{
debug("Interpreter entry point: %#lx", ELFHeader.e_entry);
return ELFHeader.e_entry;
}
}
}

View File

@ -1,480 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using namespace VirtualFileSystem;
namespace Execute
{
ELFBaseLoad ELFObject::LoadExec_x86_32(File &ElfFile, PCB *TargetProcess)
{
stub;
return {};
}
ELFBaseLoad ELFObject::LoadExec_x86_64(File &ElfFile, PCB *TargetProcess)
{
ELFBaseLoad ELFBase{};
uintptr_t BaseAddress;
size_t ElfPHDRsSize;
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
Elf64_Ehdr ELFHeader;
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("%s's entry point is %#lx", ElfFile.Name, EntryPoint);
ELFBase.TmpMem = new Memory::MemMgr(TargetProcess->PageTable); /* This should be deleted inside BaseLoad.cpp */
Memory::Virtual vmm(TargetProcess->PageTable);
/* If required, MemoryImage will be at virtual address. (unless is PIC)
tl;dr this is where the code is stored. */
MmImage MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, vmm, ElfFile, ElfPHDRsSize);
debug("Solving symbols for %s", ElfFile.Name);
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(ElfFile, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(ElfFile, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
/* Calculate entry point */
Elf64_Phdr FirstPhdr;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&FirstPhdr, sizeof(Elf64_Phdr));
/* FIXME: this is not the correct way to calculate entry point */
if (FirstPhdr.p_vaddr == 0)
{
debug("Entry point is null. Adding virtual address to entry point");
EntryPoint += (uintptr_t)MemoryImage.Virtual;
}
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
{
const char *ReqLib = new char[256];
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
debug("DT_NEEDED - %s", ReqLib);
ELFBase.NeededLibraries.push_back(ReqLib);
}
char InterpreterPath[256] = {'\0'};
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(ElfFile, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
const char *InterpPath = new char[256];
vfs->Seek(ElfFile, Interp.p_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)InterpPath, 256);
memcpy((void *)InterpreterPath, InterpPath,
(strlen(InterpPath) > 256) ? 256 : strlen(InterpPath));
debug("Interpreter: %s", InterpreterPath);
delete[] InterpPath;
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
if (!InterpreterFile.IsOK())
{
warn("Failed to open interpreter file: %s", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
else
{
if (GetBinaryType(InterpreterPath) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
vfs->Close(InterpreterFile);
break;
}
}
if (strlen(InterpreterPath) > 1)
{
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, InterpreterPath);
ELFBase.Interpreter = true;
}
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true); /* TODO: 4096 bytes is too much for this */
strcpy(aux_platform, "x86_64");
ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)0 /* FIXME */}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage.Virtual}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader.e_phoff}}});
ELFBase.InstructionPointer = EntryPoint;
ELFBase.MemoryImage = MemoryImage.Physical;
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
ELFBase.Success = true;
return ELFBase;
}
ELFBaseLoad ELFObject::LoadDyn_x86_32(File &ElfFile, PCB *TargetProcess, bool IsLibrary)
{
stub;
return {};
}
ELFBaseLoad ELFObject::LoadDyn_x86_64(File &ElfFile, PCB *TargetProcess, bool IsLibrary)
{
ELFBaseLoad ELFBase{};
uintptr_t BaseAddress;
size_t ElfPHDRsSize;
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
Elf64_Ehdr ELFHeader;
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("%s's entry point is %#lx", ElfFile.Name, EntryPoint);
ELFBase.TmpMem = new Memory::MemMgr(TargetProcess->PageTable); /* This should be deleted inside BaseLoad.cpp */
Memory::Virtual vmm(TargetProcess->PageTable);
/* If required, MemoryImage will be at virtual address. (unless is PIC)
tl;dr this is where the code is stored. */
MmImage MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, vmm, ElfFile, ElfPHDRsSize);
debug("Solving symbols for %s", ElfFile.Name);
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(ElfFile, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(ElfFile, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
/* Calculate entry point */
Elf64_Phdr FirstPhdr;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&FirstPhdr, sizeof(Elf64_Phdr));
/* FIXME: this is not the correct way to calculate entry point */
if (FirstPhdr.p_vaddr == 0)
{
debug("Entry point is null. Adding virtual address to entry point");
EntryPoint += (uintptr_t)MemoryImage.Virtual;
}
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
{
const char *ReqLib = new char[256];
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
debug("DT_NEEDED - %s", ReqLib);
ELFBase.NeededLibraries.push_back(ReqLib);
}
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(ElfFile, DT_JMPREL);
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(ElfFile, DT_SYMTAB);
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(ElfFile, DT_STRTAB);
if (JmpRel.size() < 1)
{
debug("No DT_JMPREL");
}
if (SymTab.size() < 1)
{
debug("No DT_SYMTAB");
}
if (StrTab.size() < 1)
{
debug("No DT_STRTAB");
}
if (JmpRel.size() > 1 &&
SymTab.size() > 1 &&
StrTab.size() > 1)
{
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, StrTab[0].d_un.d_ptr);
Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)MemoryImage.Physical + (JmpRel[0].d_un.d_ptr - BaseAddress));
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)MemoryImage.Physical + (SymTab[0].d_un.d_ptr - BaseAddress));
char *_DynStr = (char *)((uintptr_t)MemoryImage.Physical + (StrTab[0].d_un.d_ptr - BaseAddress));
Elf64_Shdr *gotSection = nullptr;
Elf64_Shdr shdr;
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
{
vfs->Seek(ElfFile, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
if (shdr.sh_type == SHT_PROGBITS &&
(shdr.sh_flags & SHF_WRITE) &&
(shdr.sh_flags & SHF_ALLOC))
{
gotSection = new Elf64_Shdr;
*gotSection = shdr;
break;
}
}
if (gotSection)
{
Elf64_Xword numEntries = gotSection->sh_size / sizeof(Elf64_Addr);
for (Elf64_Xword i = 0; i < numEntries - 3; i++)
{
Elf64_Rela *Rel = _JmpRel + i;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + (uintptr_t)MemoryImage.Physical);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
debug("r_offset: %#lx RelType: %d", Rel->r_offset, RelType);
switch (RelType)
{
case R_X86_64_NONE:
break;
case R_X86_64_JUMP_SLOT:
{
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = _DynStr + Sym->st_name;
debug("SymName: %s", SymName);
Elf64_Sym LibSym = ELFLookupSymbol(ElfFile, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)((uintptr_t)MemoryImage.Physical + LibSym.st_value);
debug("GOT[%ld]: %#lx + %#lx = %#lx",
i, (uintptr_t)MemoryImage.Physical, LibSym.st_value, *GOTEntry);
}
}
break;
}
default:
{
fixme("RelType %d not supported", RelType);
break;
}
}
debug("GOT[%ld](%#lx): %#lx", i, GOTEntry, *GOTEntry);
}
delete gotSection;
}
else
{
debug("GOT section not found");
}
}
/* ------------------------------------------------------------------------ */
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
{
const char *ReqLib = new char[256];
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
debug("DT_NEEDED - %s", ReqLib);
ELFBase.NeededLibraries.push_back(ReqLib);
}
char InterpreterPath[256] = {'\0'};
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(ElfFile, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
const char *InterpPath = new char[256];
vfs->Seek(ElfFile, Interp.p_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)InterpPath, 256);
memcpy((void *)InterpreterPath, InterpPath,
(strlen(InterpPath) > 256) ? 256 : strlen(InterpPath));
debug("Interpreter: %s", InterpreterPath);
delete[] InterpPath;
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
if (!InterpreterFile.IsOK())
{
warn("Failed to open interpreter file: %s", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
else
{
if (GetBinaryType(InterpreterPath) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
vfs->Close(InterpreterFile);
break;
}
}
if (strlen(InterpreterPath) > 1)
{
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, InterpreterPath);
ELFBase.Interpreter = true;
}
else if (IsLibrary)
{
/* FIXME: Detect interpreter from current running process. */
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, "/lib/ld.so");
ELFBase.Interpreter = true;
}
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true); /* TODO: 4096 bytes is too much for this */
strcpy(aux_platform, "x86_64");
ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)0 /* FIXME */}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage.Virtual}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader.e_phoff}}});
ELFBase.InstructionPointer = EntryPoint;
ELFBase.MemoryImage = MemoryImage.Physical;
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
ELFBase.Success = true;
return ELFBase;
}
ELFObject::ELFObject(char *AbsolutePath,
PCB *TargetProcess,
bool IsLibrary)
{
if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF)
{
error("%s is not an ELF file or is invalid.", AbsolutePath);
return;
}
VirtualFileSystem::File ExFile = vfs->Open(AbsolutePath);
Elf32_Ehdr ELFHeader;
vfs->Read(ExFile, (uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr));
ELFBaseLoad bl;
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->BaseLoadInfo = this->LoadExec_x86_32(ExFile,
TargetProcess);
break;
case EM_X86_64:
this->BaseLoadInfo = this->LoadExec_x86_64(ExFile,
TargetProcess);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_DYN:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->BaseLoadInfo = this->LoadDyn_x86_32(ExFile,
TargetProcess,
IsLibrary);
break;
case EM_X86_64:
this->BaseLoadInfo = this->LoadDyn_x86_64(ExFile,
TargetProcess,
IsLibrary);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
vfs->Close(ExFile);
}
ELFObject::~ELFObject()
{
}
}

View File

@ -1,340 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
bool ELFIs64(void *Header)
{
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
return true;
return false;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
break;
default:
{
break;
}
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return Symbol;
}
return nullptr;
}
Elf64_Sym ELFLookupSymbol(VirtualFileSystem::File &ElfFile, const char *Name)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
Elf64_Ehdr Header;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&Header, sizeof(Elf64_Ehdr));
Elf64_Shdr SymbolTable;
Elf64_Shdr StringTable;
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
{
Elf64_Shdr shdr;
vfs->Seek(ElfFile, Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
vfs->Seek(ElfFile, Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&StringTable, sizeof(Elf64_Shdr));
break;
default:
{
break;
}
}
}
if (SymbolTable.sh_name == 0 ||
StringTable.sh_name == 0)
{
error("Symbol table not found.");
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {};
}
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
{
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
Elf64_Sym Symbol;
vfs->Seek(ElfFile, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&Symbol, sizeof(Elf64_Sym));
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
char String[256];
vfs->Seek(ElfFile, StringTable.sh_offset + Symbol.st_name, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&String, 256);
if (strcmp(String, Name) == 0)
{
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return Symbol;
}
}
error("Symbol not found.");
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {};
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
{
#if defined(a64)
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = (void *)ELFLookupSymbol(Header, Name)->st_value;
if (Target == nullptr)
{
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
#endif
}
void CopyLOADSegments(VirtualFileSystem::File &ElfFile, uintptr_t HdrsBase, uintptr_t PhysicalBase)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
vfs->Seek(ElfFile, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
if (ProgramHeaders.p_type != PT_LOAD)
continue;
uintptr_t SegmentDestination = (ProgramHeaders.p_vaddr - HdrsBase) + PhysicalBase;
debug("Copying segment to %#lx (%ld file bytes, %ld mem bytes)",
SegmentDestination,
ProgramHeaders.p_filesz, ProgramHeaders.p_memsz);
if (ProgramHeaders.p_filesz > 0)
{
vfs->Seek(ElfFile, ProgramHeaders.p_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)SegmentDestination, ProgramHeaders.p_filesz);
}
if (ProgramHeaders.p_memsz - ProgramHeaders.p_filesz > 0)
memset((void *)(SegmentDestination + ProgramHeaders.p_filesz),
0,
ProgramHeaders.p_memsz - ProgramHeaders.p_filesz);
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
}
void GetBaseAndSize(VirtualFileSystem::File &ElfFile, uintptr_t &Base, size_t &Size)
{
Base = UINTPTR_MAX;
Size = 0;
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
Base = MIN(Base, ProgramHeaders.p_vaddr);
uintptr_t SegmentEnd = ProgramHeaders.p_vaddr - Base + ProgramHeaders.p_memsz;
Size = MAX(Size, SegmentEnd);
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
}
debug("Base: %#lx, Size: %#lx (%ld, %ld KB)", Base, Size, Size, TO_KB(Size));
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
}
MmImage ELFCreateMemoryImage(Memory::MemMgr *mem,
Memory::Virtual &vmm,
VirtualFileSystem::File &ElfFile,
size_t Length)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
void *MemoryImage = nullptr;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
bool IsPIC = ELFHeader.e_type == ET_DYN;
UNUSED(IsPIC);
debug("Elf %s PIC", IsPIC ? "is" : "is not");
bool FirstProgramHeader = false;
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
Elf64_Phdr ProgramHeaders;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
vfs->Seek(ElfFile, ELFHeader.e_phoff + i * sizeof(Elf64_Phdr), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
if (ProgramHeaders.p_type != PT_LOAD)
continue;
if (!FirstProgramHeader)
{
FirstProgramHeader = true;
FirstProgramHeaderVirtualAddress = ProgramHeaders.p_vaddr;
}
if (ProgramHeaders.p_vaddr == 0)
{
debug("p_vaddr is 0, allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
memset(MemoryImage, 0, Length);
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
}
}
debug("Allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
MemoryImage = mem->RequestPages(TO_PAGES(Length));
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
memset(MemoryImage, 0, Length);
uintptr_t FirstProgramHeaderVirtualAddressAligned = 0;
if (FirstProgramHeaderVirtualAddress != 0)
{
FirstProgramHeaderVirtualAddressAligned = ALIGN_DOWN(FirstProgramHeaderVirtualAddress, PAGE_SIZE);
debug("Aligning address %#lx to %#lx",
FirstProgramHeaderVirtualAddress,
FirstProgramHeaderVirtualAddressAligned);
}
else
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
for (size_t i = 0; i < TO_PAGES(Length); i++)
{
vmm.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddressAligned + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddressAligned + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
}
}

View File

@ -1,159 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#ifdef DEBUG
#include <dumper.hpp>
#endif
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
NewLock(ExecuteServiceLock);
namespace Execute
{
Memory::MemMgr *mem = nullptr;
std::vector<SharedLibrary> Libs;
void LibraryManagerService()
{
mem = new Memory::MemMgr;
while (true)
{
{
SmartLock(ExecuteServiceLock);
foreach (auto &Lib in Libs)
{
if (Lib.RefCount > 0)
{
Lib.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
debug("Reset timeout for %s", Lib.Identifier);
continue;
}
if (Lib.Timeout < TimeManager->GetCounter())
{
// TODO: Remove library from memory
fixme("Removed library %s because of timeout", Lib.Identifier);
}
else
{
debug("Timeout for %s is %ld", Lib.Identifier, Lib.Timeout);
}
}
debug("Waiting 10 seconds...");
}
TaskManager->Sleep(10000);
}
}
bool AddLibrary(char *Identifier,
VirtualFileSystem::File &ExFile,
const Memory::Virtual &vmm)
{
SmartLock(ExecuteServiceLock);
SharedLibrary sl;
foreach (auto lib in Libs)
{
if (strcmp(lib.Identifier, Identifier) == 0)
{
debug("Library %s already loaded", Identifier);
lib.RefCount++;
return true;
}
}
PCB *Process = TaskManager->GetCurrentProcess();
ELFObject *obj = new ELFObject(vfs->GetPathFromNode(ExFile.GetNode()).get(), Process, true);
if (!obj->IsValid())
{
error("Failed to load dynamic ELF");
return false;
}
ELFBaseLoad bl = obj->GetBaseLoadInfo();
strncpy(sl.Identifier, Identifier, sizeof(sl.Identifier) - 1);
char *AbsolutePath = vfs->GetPathFromNode(ExFile.GetNode()).get();
strncpy(sl.Path, AbsolutePath, sizeof(sl.Path) - 1);
sl.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
sl.RefCount = 0;
sl.MemoryImage = (uintptr_t)bl.MemoryImage;
sl.Length = ExFile.GetLength();
Libs.push_back(sl);
debug("Library %s loaded at %#lx", Identifier, sl.MemoryImage);
if (bl.InstructionPointer)
{
TCB *Thread = TaskManager->CreateThread(Process,
bl.InstructionPointer,
nullptr,
nullptr,
bl.auxv,
Process->Info.Architecture,
Process->Info.Compatibility,
true);
Thread->Rename(Identifier);
Thread->Status = TaskStatus::Ready;
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
Thread->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
}
}
else
{
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
/* FIXME: MEMORY LEAK */
// Process->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
fixme("Potential memory leak. (%#lx - %ld)",
p.Address, p.PageCount);
}
}
return true;
}
SharedLibrary GetLibrary(char *Identifier)
{
SmartLock(ExecuteServiceLock);
foreach (auto Lib in Libs)
{
if (strcmp(Lib.Identifier, Identifier) == 0)
{
Lib.RefCount++;
debug("Library %s found at %#lx", Identifier, Lib.MemoryImage);
return Lib;
}
}
error("Library %s not found", Identifier);
return SharedLibrary();
}
}

View File

@ -1,99 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../kernel.h"
#include "../Fex.hpp"
using namespace Tasking;
namespace Execute
{
SpawnData Spawn(char *Path, const char **argv, const char **envp)
{
SpawnData ret = {.Status = ExStatus::Unknown,
.Process = nullptr,
.Thread = nullptr};
VirtualFileSystem::File ExFile = vfs->Open(Path);
if (!ExFile.IsOK())
{
if (ExFile.Status == VirtualFileSystem::FileStatus::NotFound)
{
ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
else
{
ret.Status = ExStatus::InvalidFile;
goto Exit;
}
if (ExFile.GetFlags() != VirtualFileSystem::NodeFlags::FILE)
{
ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
}
switch (GetBinaryType(Path))
{
case BinaryType::BinTypeFex:
{
Fex FexHdr;
vfs->Read(ExFile, (uint8_t *)&FexHdr, sizeof(Fex));
if (FexHdr.Type == FexFormatType::FexFormatType_Executable)
{
stub;
assert(false);
}
ret.Status = ExStatus::InvalidFileHeader;
break;
}
case BinaryType::BinTypeELF:
{
ELFBaseLoad bl = ELFLoad(Path, argv, envp);
if (!bl.Success)
{
ret.Status = ExStatus::LoadingProcedureFailed;
break;
}
ret = bl.sd;
break;
}
default:
{
ret.Status = ExStatus::Unsupported;
break;
}
}
Exit:
vfs->Close(ExFile);
return ret;
}
}

View File

@ -0,0 +1,115 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../kernel.h"
#include "../Fex.hpp"
namespace Execute
{
BinaryType GetBinaryType(const char *Path)
{
BinaryType Type;
int fd = fopen(Path, "r");
if (fd < 0)
return (BinaryType)fd;
debug("File opened: %s, descriptor %d", Path, fd);
Memory::SmartHeap sh = Memory::SmartHeap(1024);
fread(fd, sh, 128);
Fex *FexHdr = (Fex *)sh.GetObject();
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.GetObject();
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)sh.GetObject();
/* Check Fex header. */
if (FexHdr->Magic[0] == 'F' &&
FexHdr->Magic[1] == 'E' &&
FexHdr->Magic[2] == 'X' &&
FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType_Executable)
{
debug("Image - Fex");
Type = BinaryType::BinTypeFex;
goto Success;
}
else if (FexHdr->Type == FexFormatType_Driver)
{
fixme("Fex Driver is not supposed to be executed.");
/* TODO: Driver installation pop-up. */
}
}
/* Check ELF header. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
Type = BinaryType::BinTypeELF;
goto Success;
}
/* Check MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
lseek(fd, MZHeader->e_lfanew, SEEK_SET);
fread(fd, sh, 512);
IMAGE_NT_HEADERS *PEHeader =
(IMAGE_NT_HEADERS *)(((char *)sh.GetObject()) +
MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader =
(IMAGE_OS2_HEADER *)(((char *)sh.GetObject()) +
MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
Type = BinaryType::BinTypePE;
goto Success;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
Type = BinaryType::BinTypeNE;
goto Success;
}
else
{
debug("Image - MZ");
Type = BinaryType::BinTypeMZ;
goto Success;
}
}
/* ... */
Type = BinaryType::BinTypeUnknown;
Success:
fclose(fd);
return Type;
}
}

View File

@ -0,0 +1,791 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using namespace VirtualFileSystem;
namespace Execute
{
void ELFObject::LoadExec_x86_32(int fd, PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(TargetProcess);
}
void ELFObject::LoadExec_x86_64(int fd, PCB *TargetProcess)
{
std::string InterpreterPath;
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
Memory::SmartHeap sh = Memory::SmartHeap(256);
lseek(fd, Interp.p_offset, SEEK_SET);
fread(fd, sh, 256);
InterpreterPath = sh;
int ifd = fopen(InterpreterPath.c_str(), "r");
if (ifd < 0)
{
warn("Failed to open interpreter file: %s",
InterpreterPath.c_str());
continue;
}
else
{
if (GetBinaryType(InterpreterPath.c_str()) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file",
InterpreterPath.c_str());
fclose(ifd);
continue;
}
if (LoadInterpreter(ifd, TargetProcess))
{
/* ba deci de aici trb sa fac
sa se incarce interperter-ul
argv[1] ar trb sa fie locatia pt intrep */
// modific argv-ul
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
debug("Interpreter loaded successfully");
fclose(ifd);
return;
}
}
}
Elf64_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint);
debug("Solving symbols");
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(fd, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(fd, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable);
Memory::MemMgr *mm = TargetProcess->Memory;
uint64_t BaseAddress = 0;
/* Copy segments into memory */
{
Elf64_Phdr ProgramHeader;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
{
if (ProgramHeader.p_memsz == 0)
continue;
void *pAddr = mm->RequestPages(TO_PAGES(ProgramHeader.p_memsz), true);
void *SegmentDestination = (void *)ProgramHeader.p_vaddr;
vmm.Map(SegmentDestination, pAddr,
ProgramHeader.p_memsz,
Memory::P | Memory::RW | Memory::US);
debug("Mapped %#lx to %#lx", SegmentDestination, pAddr);
if (BaseAddress == 0)
BaseAddress = (uintptr_t)SegmentDestination;
debug("Copying segment to p: %#lx-%#lx; v: %#lx-%#lx (%ld file bytes, %ld mem bytes)",
pAddr, uintptr_t(pAddr) + ProgramHeader.p_memsz,
SegmentDestination, uintptr_t(SegmentDestination) + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)pAddr, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(uintptr_t(pAddr) + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
default:
{
fixme("Unhandled program header type: %#lx",
ProgramHeader.p_type);
break;
}
}
}
}
struct stat statbuf;
fstat(fd, &statbuf);
Memory::SmartHeap sh = Memory::SmartHeap(statbuf.st_size);
lseek(fd, 0, SEEK_SET);
fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.GetObject()));
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)mm->RequestPages(1, true); /* TODO: 4KiB is too much for this */
strcpy(aux_platform, "x86_64");
std::string execfn = thisProcess->FileDescriptors->GetAbsolutePath(fd);
void *execfn_str = mm->RequestPages(TO_PAGES(execfn.size() + 1), true);
strcpy((char *)execfn_str, execfn.c_str());
// prep. for AT_PHDR
void *phdr_array = mm->RequestPages(TO_PAGES(ELFHeader.e_phnum * sizeof(Elf64_Phdr)), true);
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)phdr_array, ELFHeader.e_phnum * sizeof(Elf64_Phdr));
Elfauxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
Elfauxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)execfn_str}}});
// AT_HWCAP2 26
// AT_RANDOM 25
// AT_SECURE 23
Elfauxv.push_back({.archaux = {.a_type = AT_EGID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_GID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_EUID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_UID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
// AT_FLAGS 8
Elfauxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)BaseAddress}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)phdr_array}}});
// AT_CLKTCK 17
Elfauxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
// AT_HWCAP 16
// AT_MINSIGSTKSZ 51
// AT_SYSINFO_EHDR 33
this->ip = EntryPoint;
this->IsElfValid = true;
}
void ELFObject::LoadDyn_x86_32(int fd, PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(TargetProcess);
}
void ELFObject::LoadDyn_x86_64(int fd, PCB *TargetProcess)
{
std::string InterpreterPath;
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
Memory::SmartHeap sh = Memory::SmartHeap(256);
lseek(fd, Interp.p_offset, SEEK_SET);
fread(fd, sh, 256);
InterpreterPath = sh;
int ifd = fopen(InterpreterPath.c_str(), "r");
if (ifd < 0)
{
warn("Failed to open interpreter file: %s",
InterpreterPath.c_str());
continue;
}
else
{
if (GetBinaryType(InterpreterPath.c_str()) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file",
InterpreterPath.c_str());
fclose(ifd);
continue;
}
if (LoadInterpreter(ifd, TargetProcess))
{
/* ba deci de aici trb sa fac
sa se incarce interperter-ul
argv[1] ar trb sa fie locatia pt intrep */
// modific argv-ul
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
debug("Interpreter loaded successfully");
fclose(ifd);
return;
}
}
}
Elf64_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint);
debug("Solving symbols");
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(fd, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(fd, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable);
Memory::MemMgr *mm = TargetProcess->Memory;
uintptr_t BaseAddress = 0;
/* Copy segments into memory */
{
Elf64_Phdr ProgramHeader;
std::size_t SegmentsSize = 0;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
if (ProgramHeader.p_type == PT_LOAD ||
ProgramHeader.p_type == PT_DYNAMIC)
SegmentsSize += ProgramHeader.p_memsz;
}
/* TODO: Check if this is correct and/or it needs more
complex calculations & allocations */
void *SegmentsAddress = mm->RequestPages(TO_PAGES(SegmentsSize) + 1, true);
BaseAddress = (uintptr_t)SegmentsAddress;
debug("BaseAddress: %#lx, End: %#lx", BaseAddress,
BaseAddress + FROM_PAGES(TO_PAGES(SegmentsSize)));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
{
/* Because this is ET_DYN, we can load the segments
anywhere we want. */
uintptr_t SegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
if (ProgramHeader.p_memsz == 0)
continue;
debug("PIC: %#lx + %#lx",
BaseAddress,
ProgramHeader.p_vaddr);
debug("Copying segment to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
SegmentDestination, SegmentDestination + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)SegmentDestination, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(SegmentDestination + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
case PT_DYNAMIC:
{
/* PT_DYNAMIC contains the dynamic linking information for the
executable or shared library. */
uintptr_t DynamicSegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
if (ProgramHeader.p_memsz == 0)
continue;
debug("Copying PT_DYNAMIC segment to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
DynamicSegmentDestination, DynamicSegmentDestination + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(DynamicSegmentDestination + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
default:
{
fixme("Unhandled program header type: %#lx",
ProgramHeader.p_type);
break;
}
}
}
}
EntryPoint += BaseAddress;
debug("The new ep is %#lx", EntryPoint);
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL);
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB);
std::vector<Elf64_Dyn> RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA);
std::vector<Elf64_Dyn> RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ);
std::vector<Elf64_Dyn> PltGot = ELFGetDynamicTag_x86_64(fd, DT_PLTGOT);
std::size_t JmpRelSize = JmpRel.size();
std::size_t SymTabSize = SymTab.size();
std::size_t StrTabSize = StrTab.size();
std::size_t RelaDynSize_v = RelaDyn.size();
std::size_t PltGotSize = PltGot.size();
if (JmpRelSize < 1)
debug("No DT_JMPREL");
if (SymTabSize < 1)
debug("No DT_SYMTAB");
if (StrTabSize < 1)
debug("No DT_STRTAB");
if (RelaDynSize_v < 1)
debug("No DT_RELA");
if (RelaDynSize[0].d_un.d_val < 1)
debug("DT_RELASZ is < 1");
if (PltGotSize < 1)
debug("No DT_PLTGOT");
if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0)
{
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx",
JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, StrTab[0].d_un.d_ptr);
Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)BaseAddress + JmpRel[0].d_un.d_ptr);
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr);
char *_DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr);
Elf64_Rela *_RelaDyn = (Elf64_Rela *)((uintptr_t)BaseAddress + RelaDyn[0].d_un.d_ptr);
Elf64_Shdr *gotSection = nullptr;
Elf64_Shdr shdr;
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
{
lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
if (shdr.sh_type == SHT_PROGBITS &&
(shdr.sh_flags & SHF_WRITE) &&
(shdr.sh_flags & SHF_ALLOC))
{
gotSection = new Elf64_Shdr;
*gotSection = shdr;
debug("Found GOT section");
break;
}
}
if (gotSection)
{
// .rela.plt
// R_X86_64_JUMP_SLOT
Elf64_Xword numEntries = gotSection->sh_size / sizeof(Elf64_Addr);
for (Elf64_Xword i = 0; i < numEntries; i++)
{
Elf64_Addr *GOTEntry = (Elf64_Addr *)(gotSection->sh_addr + BaseAddress + i * sizeof(Elf64_Addr));
Elf64_Addr GOTEntryValue = *GOTEntry;
if (GOTEntryValue == 0)
continue;
Elf64_Rela *Rel = _JmpRel + i;
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_JUMP_SLOT:
{
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = _DynStr + Sym->st_name;
debug("SymName: %s", SymName);
Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
debug("GOT[%ld](%#lx): %#lx",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
continue;
}
default:
{
fixme("Unhandled relocation type: %#lx", RelType);
break;
}
}
}
// .rela.dyn
// R_X86_64_RELATIVE
// R_X86_64_GLOB_DAT
if (RelaDynSize_v > 0 && RelaDynSize[0].d_un.d_val > 0)
{
Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela);
for (Elf64_Xword i = 0; i < numRelaDynEntries; i++)
{
Elf64_Rela *Rel = _RelaDyn + i;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + BaseAddress);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_RELATIVE:
{
*GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend);
debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
break;
}
case R_X86_64_GLOB_DAT:
{
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = _DynStr + Sym->st_name;
debug("SymName: %s", SymName);
Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
break;
}
default:
{
fixme("Unhandled relocation type: %#lx", RelType);
break;
}
}
}
}
// _GLOBAL_OFFSET_TABLE_
if (PltGotSize > 0)
{
Elf64_Dyn got = PltGot[0];
Elf64_Addr *GOTEntry = (Elf64_Addr *)(got.d_un.d_ptr + BaseAddress);
// *GOTEntry = (Elf64_Addr)(BaseAddress + PltGot[0].d_un.d_val);
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC);
if (DYNAMICPhdrs.size() > 0)
*GOTEntry = (Elf64_Addr)(BaseAddress + DYNAMICPhdrs[0].p_vaddr);
}
delete gotSection;
}
else
{
debug("GOT section not found");
}
}
/* ------------------------------------------------------------------------ */
struct stat statbuf;
fstat(fd, &statbuf);
Memory::SmartHeap sh = Memory::SmartHeap(statbuf.st_size);
lseek(fd, 0, SEEK_SET);
fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.GetObject()), BaseAddress);
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)mm->RequestPages(1, true); /* TODO: 4KiB is too much for this */
strcpy(aux_platform, "x86_64");
std::string execfn = thisProcess->FileDescriptors->GetAbsolutePath(fd);
void *execfn_str = mm->RequestPages(TO_PAGES(execfn.size() + 1), true);
strcpy((char *)execfn_str, execfn.c_str());
// prep. for AT_PHDR
void *phdr_array = mm->RequestPages(TO_PAGES(ELFHeader.e_phnum * sizeof(Elf64_Phdr)), true);
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)phdr_array, ELFHeader.e_phnum * sizeof(Elf64_Phdr));
Elfauxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
Elfauxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)execfn_str}}});
// AT_HWCAP2 26
// AT_RANDOM 25
// AT_SECURE 23
Elfauxv.push_back({.archaux = {.a_type = AT_EGID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_GID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_EUID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_UID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
// AT_FLAGS 8
Elfauxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)BaseAddress}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)phdr_array}}});
// AT_CLKTCK 17
Elfauxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
// AT_HWCAP 16
// AT_MINSIGSTKSZ 51
// AT_SYSINFO_EHDR 33
this->ip = EntryPoint;
this->IsElfValid = true;
}
bool ELFObject::LoadInterpreter(int fd, PCB *TargetProcess)
{
Elf32_Ehdr ELFHeader;
fread(fd, &ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadExec_x86_32(fd, TargetProcess);
return true;
case EM_X86_64:
this->LoadExec_x86_64(fd, TargetProcess);
return true;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_DYN:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadDyn_x86_32(fd, TargetProcess);
return true;
case EM_X86_64:
this->LoadDyn_x86_64(fd, TargetProcess);
return true;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
return false;
}
ELFObject::ELFObject(char *AbsolutePath,
PCB *TargetProcess,
const char **argv,
const char **envp)
{
if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF)
{
error("%s is not an ELF file or is invalid.", AbsolutePath);
return;
}
int fd = fopen(AbsolutePath, "r");
if (fd < 0)
{
error("Failed to open %s, errno: %d", AbsolutePath, fd);
return;
}
int argc = 0;
int envc = 0;
while (argv[argc] != nullptr)
argc++;
while (envp[envc] != nullptr)
envc++;
// ELFargv = new const char *[argc + 2];
std::size_t argv_size = TO_PAGES(argc + 2 * sizeof(char *));
ELFargv = (const char **)TargetProcess->Memory->RequestPages(argv_size);
for (int i = 0; i < argc; i++)
ELFargv[i] = argv[i];
ELFargv[argc] = nullptr;
// ELFenvp = new const char *[envc + 1];
std::size_t envp_size = TO_PAGES(envc + 1 * sizeof(char *));
ELFenvp = (const char **)TargetProcess->Memory->RequestPages(envp_size);
for (int i = 0; i < envc; i++)
ELFenvp[i] = envp[i];
ELFenvp[envc] = nullptr;
Elf32_Ehdr ELFHeader;
fread(fd, &ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadExec_x86_32(fd, TargetProcess);
break;
case EM_X86_64:
this->LoadExec_x86_64(fd, TargetProcess);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_DYN:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadDyn_x86_32(fd, TargetProcess);
break;
case EM_X86_64:
this->LoadDyn_x86_64(fd, TargetProcess);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
fclose(fd);
}
ELFObject::~ELFObject()
{
}
}

View File

@ -0,0 +1,203 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
bool ELFIs64(void *Header)
{
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
return true;
return false;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
break;
default:
{
break;
}
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return Symbol;
}
return nullptr;
}
Elf64_Sym ELFLookupSymbol(int fd, const char *Name)
{
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
Elf64_Ehdr Header;
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&Header, sizeof(Elf64_Ehdr));
Elf64_Shdr SymbolTable;
Elf64_Shdr StringTable;
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
{
Elf64_Shdr shdr;
lseek(fd, Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET);
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
lseek(fd, Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET);
fread(fd, (uint8_t *)&StringTable, sizeof(Elf64_Shdr));
break;
default:
{
break;
}
}
}
if (SymbolTable.sh_name == 0 ||
StringTable.sh_name == 0)
{
error("Symbol table not found.");
lseek(fd, OldOffset, SEEK_SET);
return {};
}
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
{
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
Elf64_Sym Symbol;
lseek(fd, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET);
fread(fd, (uint8_t *)&Symbol, sizeof(Elf64_Sym));
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
char String[256];
lseek(fd, StringTable.sh_offset + Symbol.st_name, SEEK_SET);
fread(fd, (uint8_t *)&String, 256);
if (strcmp(String, Name) == 0)
{
lseek(fd, OldOffset, SEEK_SET);
return Symbol;
}
}
error("Symbol not found.");
lseek(fd, OldOffset, SEEK_SET);
return {};
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
{
#if defined(a64)
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = (void *)ELFLookupSymbol(Header, Name)->st_value;
if (Target == nullptr)
{
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
#endif
}
}

View File

@ -26,7 +26,7 @@ namespace Execute
{ {
/* Originally from https://wiki.osdev.org/ELF_Tutorial */ /* Originally from https://wiki.osdev.org/ELF_Tutorial */
ELFBaseLoad ELFLoadRel(void *BaseImage, void ELFLoadRel(void *BaseImage,
const char *Name, const char *Name,
Tasking::PCB *Process) Tasking::PCB *Process)
{ {
@ -35,11 +35,6 @@ namespace Execute
debug("Relocatable"); debug("Relocatable");
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */ /* TODO: I have to fully implement this, but for now I will leave it as it is now. */
warn("Relocatable ELF is not fully supported yet"); warn("Relocatable ELF is not fully supported yet");
/* This should be deleted after with kfree */
ELFBaseLoad ELFBase = {};
/* This should be deleted inside BaseLoad.cpp */
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage)); Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++) for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{ {
@ -78,10 +73,7 @@ namespace Execute
{ {
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info)); SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead) if (SymbolValue == 0xdead)
{ return;
delete ELFBase.TmpMem, ELFBase.TmpMem = nullptr;
return {};
}
} }
switch (ELF64_R_TYPE(RelTable->r_info)) switch (ELF64_R_TYPE(RelTable->r_info))
@ -97,17 +89,14 @@ namespace Execute
default: default:
{ {
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info)); error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
delete ELFBase.TmpMem, ELFBase.TmpMem = nullptr; return;
return {};
} }
} }
debug("Symbol value: %#lx", SymbolValue); debug("Symbol value: %#lx", SymbolValue);
} }
} }
} }
return ELFBase;
#elif defined(a32) #elif defined(a32)
return {};
#endif #endif
} }
} }

View File

@ -21,17 +21,18 @@
namespace Execute namespace Execute
{ {
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(VirtualFileSystem::File &ElfFile, std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(int fd,
DynamicArrayTags Tag) DynamicArrayTags Tag)
{ {
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR); #if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Dyn> Ret; std::vector<Elf64_Dyn> Ret;
Elf64_Ehdr ELFHeader; Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(ElfFile, PT_DYNAMIC); std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC);
if (DYNAMICPhdrs.size() < 1) if (DYNAMICPhdrs.size() < 1)
{ {
@ -44,19 +45,22 @@ namespace Execute
Elf64_Dyn Dynamic; Elf64_Dyn Dynamic;
for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++) for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
{ {
vfs->Seek(ElfFile, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET); lseek(fd, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn)); fread(fd, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn));
if (Dynamic.d_tag != Tag) if (Dynamic.d_tag != Tag)
continue; continue;
debug("Found dynamic tag %d at %#lx [d_val: %#lx].", debug("Found dynamic tag %d at %#lx [d_val: %#lx]",
Tag, &Dynamic, Dynamic.d_un.d_val); Tag, &Dynamic, Dynamic.d_un.d_val);
Ret.push_back(Dynamic); Ret.push_back(Dynamic);
} }
} }
vfs->Seek(ElfFile, OldOffset, SEEK_SET); lseek(fd, OldOffset, SEEK_SET);
return Ret; return Ret;
#elif defined(a32)
return {};
#endif
} }
} }

View File

@ -21,23 +21,24 @@
namespace Execute namespace Execute
{ {
std::vector<Elf64_Shdr> ELFGetSections_x86_64(VirtualFileSystem::File &ElfFile, std::vector<Elf64_Shdr> ELFGetSections_x86_64(int fd,
const char *SectionName) const char *SectionName)
{ {
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR); #if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Shdr> Ret; std::vector<Elf64_Shdr> Ret;
Elf64_Ehdr ELFHeader; Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum]; Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum];
vfs->Seek(ElfFile, ELFHeader.e_shoff, SEEK_SET); lseek(fd, ELFHeader.e_shoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum); fread(fd, (uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum);
char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size]; char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size];
vfs->Seek(ElfFile, SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET); lseek(fd, SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size); fread(fd, (uint8_t *)SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size);
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i) for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i)
{ {
@ -46,9 +47,12 @@ namespace Execute
Ret.push_back(SectionHeaders[i]); Ret.push_back(SectionHeaders[i]);
} }
vfs->Seek(ElfFile, OldOffset, SEEK_SET); lseek(fd, OldOffset, SEEK_SET);
delete[] SectionHeaders; delete[] SectionHeaders;
delete[] SectionNames; delete[] SectionNames;
return Ret; return Ret;
#elif defined(a32)
return {};
#endif
} }
} }

View File

@ -21,30 +21,34 @@
namespace Execute namespace Execute
{ {
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(VirtualFileSystem::File &ElfFile, std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(int fd,
SegmentTypes Tag) SegmentTypes Tag)
{ {
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR); #if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Phdr> Ret; std::vector<Elf64_Phdr> Ret;
Elf64_Ehdr ELFHeader; Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders; Elf64_Phdr ProgramHeaders;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET); lseek(fd, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr)); fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{ {
if (ProgramHeaders.p_type == Tag) if (ProgramHeaders.p_type == Tag)
Ret.push_back(ProgramHeaders); Ret.push_back(ProgramHeaders);
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR); lseek(fd, sizeof(Elf64_Phdr), SEEK_CUR);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr)); fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
} }
vfs->Seek(ElfFile, OldOffset, SEEK_SET); lseek(fd, OldOffset, SEEK_SET);
return Ret; return Ret;
#elif defined(a32)
return {};
#endif
} }
} }

161
ExecutionLayer/Spawn.cpp Normal file
View File

@ -0,0 +1,161 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../kernel.h"
#include "../Fex.hpp"
using namespace Tasking;
namespace Execute
{
int Spawn(char *Path, const char **argv, const char **envp,
Tasking::PCB *Parent,
Tasking::TaskCompatibility Compatibility)
{
int fd = fopen(Path, "r");
if (fd < 0)
return fd;
struct stat statbuf;
fstat(fd, &statbuf);
if (!S_ISREG(statbuf.st_mode))
{
fclose(fd);
return -EISDIR;
}
switch (GetBinaryType(Path))
{
case BinaryType::BinTypeFex:
{
Fex FexHdr;
fread(fd, (uint8_t *)&FexHdr, sizeof(Fex));
if (FexHdr.Type == FexFormatType::FexFormatType_Executable)
{
stub;
assert(false);
}
fclose(fd);
return -ENOEXEC;
}
case BinaryType::BinTypeELF:
{
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
Elf32_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_machine)
{
case EM_386:
Arch = TaskArchitecture::x32;
break;
case EM_X86_64:
Arch = TaskArchitecture::x64;
break;
case EM_ARM:
Arch = TaskArchitecture::ARM32;
break;
case EM_AARCH64:
Arch = TaskArchitecture::ARM64;
break;
default:
error("Unknown ELF architecture %d",
ELFHeader.e_machine);
break;
}
// TODO: This shouldn't be ignored
if (ELFHeader.e_ident[EI_CLASS] == ELFCLASS32)
fixme("32-bit ELF");
else if (ELFHeader.e_ident[EI_CLASS] == ELFCLASS64)
fixme("64-bit ELF");
else
fixme("Unknown class %d", ELFHeader.e_ident[EI_CLASS]);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if (ELFHeader.e_ident[EI_DATA] != ELFDATA2LSB)
{
fixme("ELF32 LSB expected, got %d", ELFHeader.e_ident[EI_DATA]);
}
#else
if (ELFHeader.e_ident[EI_DATA] != ELFDATA2MSB)
{
fixme("ELF32 MSB expected, got %d", ELFHeader.e_ident[EI_DATA]);
}
#endif
/* ------------------------------------------------------------------------------------------------------------------------------ */
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(statbuf.st_size + 1));
fread(fd, (uint8_t *)ElfFile, statbuf.st_size);
debug("Loaded elf %s at %#lx with the length of %ld",
Path, ElfFile, statbuf.st_size);
PCB *Process = TaskManager->CreateProcess(thisProcess,
BaseName,
TaskExecutionMode::User,
ElfFile, false,
0, 0);
KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1));
Process->SetWorkingDirectory(vfs->GetNodeFromPath(Path)->Parent);
Process->Info.Compatibility = TaskCompatibility::Native;
Process->Info.Architecture = TaskArchitecture::x64;
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
if (!obj->IsValid)
{
error("Failed to load ELF object");
fclose(fd);
delete Process;
return -ENOEXEC;
}
TCB *Thread = TaskManager->CreateThread(Process,
obj->InstructionPointer,
obj->argv, obj->envp, obj->auxv,
Arch,
Compatibility);
fclose(fd);
return Thread->ID;
}
default:
{
debug("Unknown binary type: %d",
GetBinaryType(Path));
fclose(fd);
return -ENOEXEC;
}
}
fclose(fd);
return -ENOEXEC;
}
}

View File

@ -29,13 +29,13 @@ namespace VirtualFileSystem
if (!Size) if (!Size)
Size = node->Length; Size = node->Length;
if ((size_t)node->Offset > node->Length) if (RefOffset > node->Length)
return 0; return 0;
if (node->Offset + Size > node->Length) if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - node->Offset; Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + node->Offset), Size); memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size; return Size;
} }
@ -113,7 +113,7 @@ namespace VirtualFileSystem
} }
else else
{ {
trace("%s %dKB Type:%c", header->name, TO_KB(size), header->typeflag[0]); debug("%s %d KiB, Type:%c", header->name, TO_KiB(size), header->typeflag[0]);
node->Mode = string2int(header->mode); node->Mode = string2int(header->mode);
node->Address = (Address + 512); node->Address = (Address + 512);
node->Length = size; node->Length = size;
@ -128,6 +128,8 @@ namespace VirtualFileSystem
break; break;
case SYMLINK: case SYMLINK:
node->Flags = NodeFlags::SYMLINK; node->Flags = NodeFlags::SYMLINK;
node->Symlink = new char[strlen(header->link) + 1];
strncpy((char *)node->Symlink, header->link, strlen(header->link));
break; break;
case DIRECTORY: case DIRECTORY:
node->Flags = NodeFlags::DIRECTORY; node->Flags = NodeFlags::DIRECTORY;

View File

@ -0,0 +1,434 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
#include <smart_ptr.hpp>
#include <convert.h>
#include <task.hpp>
#include <printf.h>
#include <lock.hpp>
#include <cwalk.h>
#include "../kernel.h"
namespace VirtualFileSystem
{
ReadFSFunction(fd_Read)
{
if (!Size)
Size = node->Length;
if (RefOffset > node->Length)
return 0;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size;
}
WriteFSFunction(fd_Write)
{
if (!Size)
Size = node->Length;
if (RefOffset > node->Length)
return 0;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
return Size;
}
VirtualFileSystem::FileSystemOperations fd_op = {
.Name = "fd",
// .Read = fd_Read,
// .Write = fd_Write,
};
FileDescriptorTable::FileDescriptor
FileDescriptorTable::GetFileDescriptor(int FileDescriptor)
{
foreach (auto fd in FileDescriptors)
{
if (fd.Descriptor == FileDescriptor)
return fd;
}
return {.Descriptor = -1};
}
int FileDescriptorTable::ProbeMode(mode_t Mode, int Flags)
{
if (Flags & O_RDONLY)
{
if (!(Mode & S_IRUSR))
return -EACCES;
}
if (Flags & O_WRONLY)
{
if (!(Mode & S_IWUSR))
return -EACCES;
}
if (Flags & O_RDWR)
{
if (!(Mode & S_IRUSR) ||
!(Mode & S_IWUSR))
return -EACCES;
}
return 0;
}
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
mode_t Mode, int Flags)
{
Tasking::PCB *pcb = thisProcess;
if (ProbeMode(Mode, Flags) < 0)
{
errno = EACCES;
return -1;
}
if (Flags & O_CREAT)
{
Node *n = vfs->Create(AbsolutePath,
NodeFlags::FILE,
pcb->CurrentWorkingDirectory);
if (!n)
{
error("Failed to create file %s: %d",
AbsolutePath, errno);
return -1;
}
}
if (Flags & O_EXCL)
{
RefNode *File = vfs->Open(AbsolutePath,
pcb->CurrentWorkingDirectory);
if (!File)
{
errno = EEXIST;
return -1;
}
}
if (Flags & O_TRUNC)
{
fixme("Implement O_TRUNC");
}
if (Flags & O_APPEND)
{
fixme("Implement O_APPEND");
}
if (Flags & O_CLOEXEC)
{
fixme("Implement O_CLOEXEC");
}
RefNode *File = vfs->Open(AbsolutePath,
pcb->CurrentWorkingDirectory);
if (!File)
{
error("Failed to open file %s: %d",
AbsolutePath, errno);
return -1;
}
FileDescriptorTable::FileDescriptor fd;
fd.Descriptor = GetFreeFileDescriptor();
if (fd.Descriptor < 0)
{
errno = EMFILE;
return -1;
}
fd.Mode = Mode;
fd.Flags = Flags;
fd.Handle = File;
FileDescriptors.push_back(fd);
char FileName[64];
sprintf(FileName, "%d", fd.Descriptor);
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->fdDir);
if (n)
{
/* FIXME: Implement proper file descriptors */
n->Address = (uintptr_t)0xdeadbeef;
n->Length = File->FileSize;
n->Operator = &fd_op;
}
return fd.Descriptor;
}
int FileDescriptorTable::RemoveFileDescriptor(int FileDescriptor)
{
forItr(itr, FileDescriptors)
{
if (itr->Descriptor == FileDescriptor)
{
FileDescriptors.erase(itr);
char FileName[64];
sprintf(FileName, "%d", FileDescriptor);
vfs->Delete(FileName, false, this->fdDir);
return 0;
}
}
errno = EBADF;
return -1;
}
int FileDescriptorTable::GetFreeFileDescriptor()
{
int i = 0;
while (true)
{
bool Found = false;
foreach (auto fd in FileDescriptors)
{
if (fd.Descriptor == i)
{
Found = true;
break;
}
}
if (!Found)
return i;
i++;
}
errno = EMFILE;
return -1;
}
std::string FileDescriptorTable::GetAbsolutePath(int FileDescriptor)
{
FileDescriptorTable::FileDescriptor fd =
this->GetFileDescriptor(FileDescriptor);
if (fd.Descriptor == -1)
return "";
Node *node = fd.Handle->node;
std::string absolutePath = vfs->GetPathFromNode(node);
std::string path = absolutePath.c_str();
return path;
}
int FileDescriptorTable::_open(const char *pathname, int flags,
mode_t mode)
{
if (pathname == nullptr)
{
errno = EFAULT;
return -1;
}
return AddFileDescriptor(pathname, mode, flags);
}
int FileDescriptorTable::_creat(const char *pathname, mode_t mode)
{
return _open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
}
ssize_t FileDescriptorTable::_read(int fd, void *buf, size_t count)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
return fdesc.Handle->Read((uint8_t *)buf, count);
}
ssize_t FileDescriptorTable::_write(int fd, const void *buf,
size_t count)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
return -1;
return fdesc.Handle->Write((uint8_t *)buf, count);
}
int FileDescriptorTable::_close(int fd)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
if (RemoveFileDescriptor(fd) < 0)
{
errno = EBADF;
return -1;
}
delete fdesc.Handle;
return 0;
}
off_t FileDescriptorTable::_lseek(int fd, off_t offset, int whence)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
return fdesc.Handle->Seek(offset, whence);
}
int FileDescriptorTable::_stat(const char *pathname,
struct stat *statbuf)
{
if (pathname == nullptr)
{
errno = EINVAL;
return -1;
}
RefNode *file = vfs->Open(pathname,
thisProcess->CurrentWorkingDirectory);
if (!file)
{
error("Failed to open file %s: %d",
pathname, errno);
return -1;
}
Node *node = file->node;
statbuf->st_dev = 0; /* FIXME: stub */
statbuf->st_ino = node->IndexNode;
statbuf->st_mode = node->Flags | node->Mode;
statbuf->st_nlink = 0; /* FIXME: stub */
statbuf->st_uid = node->UserIdentifier;
statbuf->st_gid = node->GroupIdentifier;
statbuf->st_rdev = 0; /* FIXME: stub */
statbuf->st_size = node->Length;
statbuf->st_blksize = 0; /* FIXME: stub */
statbuf->st_blocks = 0; /* FIXME: stub */
statbuf->st_attr = 0; /* FIXME: stub */
return 0;
}
int FileDescriptorTable::_fstat(int fd, struct stat *statbuf)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
Node *node = fdesc.Handle->node;
statbuf->st_dev = 0; /* FIXME: stub */
statbuf->st_ino = node->IndexNode;
statbuf->st_mode = node->Flags | node->Mode;
statbuf->st_nlink = 0; /* FIXME: stub */
statbuf->st_uid = node->UserIdentifier;
statbuf->st_gid = node->GroupIdentifier;
statbuf->st_rdev = 0; /* FIXME: stub */
statbuf->st_size = node->Length;
statbuf->st_blksize = 0; /* FIXME: stub */
statbuf->st_blocks = 0; /* FIXME: stub */
statbuf->st_attr = 0; /* FIXME: stub */
return 0;
}
int FileDescriptorTable::_lstat(const char *pathname,
struct stat *statbuf)
{
if (pathname == nullptr)
{
errno = EINVAL;
return -1;
}
RefNode *file = vfs->Open(pathname,
thisProcess->CurrentWorkingDirectory);
if (!file)
{
error("Failed to open file %s: %d",
pathname, errno);
return -1;
}
Node *node = file->node;
statbuf->st_dev = 0; /* FIXME: stub */
statbuf->st_ino = node->IndexNode;
statbuf->st_mode = node->Flags | node->Mode;
statbuf->st_nlink = 0; /* FIXME: stub */
statbuf->st_uid = node->UserIdentifier;
statbuf->st_gid = node->GroupIdentifier;
statbuf->st_rdev = 0; /* FIXME: stub */
statbuf->st_size = node->Length;
statbuf->st_blksize = 0; /* FIXME: stub */
statbuf->st_blocks = 0; /* FIXME: stub */
statbuf->st_attr = 0; /* FIXME: stub */
return 0;
}
FileDescriptorTable::FileDescriptorTable(void *Owner)
{
this->fdDir = vfs->Create("fd", VirtualFileSystem::NodeFlags::DIRECTORY,
((Tasking::PCB *)Owner)->ProcessDirectory);
}
FileDescriptorTable::~FileDescriptorTable()
{
foreach (auto var in FileDescriptors)
{
this->RemoveFileDescriptor(var.Descriptor);
delete var.Handle;
}
}
}

197
FileSystem/FileNode.cpp Normal file
View File

@ -0,0 +1,197 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
namespace VirtualFileSystem
{
ReferenceNode *Node::CreateReference()
{
SmartLock(NodeLock);
ReferenceNode *rn = new ReferenceNode(this);
References.push_back(rn);
debug("Created reference %p for node %p", rn, this);
return rn;
}
void Node::RemoveReference(ReferenceNode *Reference)
{
SmartLock(NodeLock);
debug("Removing reference %p for node %p", Reference, this);
References.erase(std::find(References.begin(), References.end(), Reference));
}
/**************************************************************/
size_t ReferenceNode::Read(uint8_t *Buffer, size_t Size)
{
if (this->SymlinkTo)
return this->SymlinkTo->Read(Buffer, Size);
if (!this->node->Operator)
{
errno = EFAULT;
return -1;
}
SmartLock(RefNodeLock);
if (this->node->Operator->Read)
{
off_t RefOffset = off_t(this->Offset.load());
return this->node->Operator->Read(this->node, Size, Buffer, RefOffset);
}
errno = ENOSYS;
return -1;
}
size_t ReferenceNode::Write(uint8_t *Buffer, size_t Size)
{
if (this->SymlinkTo)
return this->SymlinkTo->Write(Buffer, Size);
if (!this->node->Operator)
{
errno = EFAULT;
return -1;
}
SmartLock(RefNodeLock);
if (this->node->Operator->Write)
{
off_t RefOffset = off_t(this->Offset.load());
return this->node->Operator->Write(this->node, Size, Buffer, RefOffset);
}
errno = ENOSYS;
return -1;
}
off_t ReferenceNode::Seek(off_t Offset, int Whence)
{
if (this->SymlinkTo)
return this->SymlinkTo->Seek(Offset, Whence);
if (!this->node->Operator)
{
errno = EFAULT;
return -1;
}
SmartLock(RefNodeLock);
if (this->node->Operator->Seek)
{
off_t RefOffset = off_t(this->Offset.load());
return this->node->Operator->Seek(this->node, Offset, Whence, RefOffset);
}
switch (Whence)
{
case SEEK_SET:
{
if (Offset > this->node->Length)
{
errno = EINVAL;
return -1;
}
this->Offset.store(Offset);
break;
}
case SEEK_CUR:
{
off_t NewOffset = off_t(this->Offset.load()) + Offset;
if (NewOffset > this->node->Length ||
NewOffset < 0)
{
errno = EINVAL;
return -1;
}
this->Offset.store(NewOffset);
break;
}
case SEEK_END:
{
off_t NewOffset = this->node->Length + Offset;
if (NewOffset > this->node->Length ||
NewOffset < 0)
{
errno = EINVAL;
return -1;
}
this->Offset.store(NewOffset);
break;
}
default:
{
error("Invalid whence!");
errno = EINVAL;
return -1;
}
}
return (off_t)this->Offset.load();
}
ReferenceNode::ReferenceNode(Node *node)
{
SmartLock(RefNodeLock);
this->node = node;
this->FileSize = node->Length;
this->AbsolutePath += node->FileSystem->GetPathFromNode(node);
if (this->node->Flags == SYMLINK)
{
if (!this->node->SymlinkTarget)
{
this->node->SymlinkTarget =
node->FileSystem->GetNodeFromPath(this->node->Symlink);
/* not standard but useful in kernel-space */
this->node->Length = this->node->SymlinkTarget->Length;
}
if (!this->node->SymlinkTarget)
{
error("Symlink target %s not found!",
this->node->Symlink);
errno = ENOENT;
return;
}
this->SymlinkTo = this->node->SymlinkTarget->CreateReference();
}
debug("Created reference node for %s [%#lx]",
this->AbsolutePath.c_str(), (uintptr_t)this);
}
ReferenceNode::~ReferenceNode()
{
SmartLock(RefNodeLock);
if (this->SymlinkTo)
this->node->SymlinkTarget->RemoveReference(this);
this->node->RemoveReference(this);
debug("Destroyed reference node for %s [%#lx]",
this->AbsolutePath.c_str(), (uintptr_t)this);
}
}

File diff suppressed because it is too large Load Diff

157
FileSystem/Kernel_IO.cpp Normal file
View File

@ -0,0 +1,157 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
#include <errno.h>
#include "../kernel.h"
using Tasking::PCB;
using VirtualFileSystem::FileDescriptorTable;
static bool CheckForScheduler()
{
if (TaskManager == nullptr)
return false;
return true;
}
int fopen(const char *pathname, const char *mode)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int fd = fdt->_open(pathname, ConvertFileFlags(mode), 0666);
return fd;
}
int creat(const char *pathname, mode_t mode)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int fd = fdt->_creat(pathname, mode);
return fd;
}
ssize_t fread(int fd, void *buf, size_t count)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
ssize_t r = fdt->_read(fd, buf, count);
return r;
}
ssize_t fwrite(int fd, const void *buf, size_t count)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
ssize_t r = fdt->_write(fd, buf, count);
return r;
}
int fclose(int fd)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_close(fd);
return r;
}
off_t lseek(int fd, off_t offset, int whence)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
off_t r = fdt->_lseek(fd, offset, whence);
return r;
}
int stat(const char *pathname, struct stat *statbuf)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_stat(pathname, statbuf);
return r;
}
int fstat(int fd, struct stat *statbuf)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_fstat(fd, statbuf);
return r;
}
int lstat(const char *pathname, struct stat *statbuf)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_lstat(pathname, statbuf);
return r;
}

View File

@ -1,218 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include "../kernel.h"
namespace GraphicalUserInterface
{
Ofast inline void InlineSetPixel(ScreenBitmap *Bitmap, int64_t X, int64_t Y, uint32_t Color)
{
if (unlikely(X < 0 || Y < 0 || X >= (int64_t)Bitmap->Width || Y >= (int64_t)Bitmap->Height))
return;
uint32_t *Pixel = (uint32_t *)((uintptr_t)Bitmap->Data + (Y * Bitmap->Width + X) * (Bitmap->BitsPerPixel / 8));
*Pixel = Color;
// Bitmap->Data[Y * Bitmap->Width + X] = Color;
}
void SetPixel(ScreenBitmap *Bitmap, size_t X, size_t Y, uint32_t Color)
{
if (unlikely(!Bitmap))
return;
if (unlikely(!Bitmap->Data))
return;
InlineSetPixel(Bitmap, X, Y, Color);
}
uint32_t GetPixel(ScreenBitmap *Bitmap, int64_t X, int64_t Y)
{
if (unlikely(!Bitmap))
return 0;
if (unlikely(!Bitmap->Data))
return 0;
if (unlikely(X < 0 || Y < 0 || X >= (int64_t)Bitmap->Width || Y >= (int64_t)Bitmap->Height))
return 0;
uint32_t *Pixel = (uint32_t *)((uintptr_t)Bitmap->Data + (Y * Bitmap->Width + X) * (Bitmap->BitsPerPixel / 8));
return *Pixel;
}
Ofast void DrawOverBitmap(ScreenBitmap *DestinationBitmap,
ScreenBitmap *SourceBitmap,
int64_t Top,
int64_t Left, bool IgnoreZero)
{
if (unlikely(!SourceBitmap) || unlikely(!SourceBitmap->Data) ||
unlikely(!DestinationBitmap) || unlikely(!DestinationBitmap->Data))
return;
// for (uint32_t i = 0; i < SourceBitmap->Width; i++)
// for (uint32_t j = 0; j < SourceBitmap->Height; j++)
// {
// uint32_t *Pixel = (uint32_t *)((uintptr_t)SourceBitmap->Data + (j * SourceBitmap->Width + i) * (SourceBitmap->BitsPerPixel / 8));
// if (IgnoreZero && (*Pixel != 0x000000))
// InlineSetPixel(DestinationBitmap, Left + i, Top + j, *Pixel);
// }
for (uint32_t j = 0; j < SourceBitmap->Height; j++)
{
uint32_t *Pixel = (uint32_t *)((uintptr_t)SourceBitmap->Data + j * SourceBitmap->Width * (SourceBitmap->BitsPerPixel / 8));
if (IgnoreZero)
{
for (uint32_t i = 0; i < SourceBitmap->Width; i++)
{
if (Pixel[i] != 0x000000)
InlineSetPixel(DestinationBitmap, Left + i, Top + j, Pixel[i]);
}
}
else
{
memcpy((void *)((uintptr_t)DestinationBitmap->Data + (Top + j) * DestinationBitmap->Width * (DestinationBitmap->BitsPerPixel / 8) + Left * (DestinationBitmap->BitsPerPixel / 8)),
(void *)((uintptr_t)SourceBitmap->Data + j * SourceBitmap->Width * (SourceBitmap->BitsPerPixel / 8)),
(size_t)(SourceBitmap->Width * (SourceBitmap->BitsPerPixel / 8)));
}
}
}
Ofast void PutRect(ScreenBitmap *Bitmap, Rect rect, uint32_t Color)
{
if (unlikely(!Bitmap))
return;
if (unlikely(!Bitmap->Data))
return;
for (uint32_t i = 0; i < rect.Width; i++)
for (uint32_t j = 0; j < rect.Height; j++)
InlineSetPixel(Bitmap, rect.Left + i, rect.Top + j, Color);
}
void PutBorder(ScreenBitmap *Bitmap, Rect rect, uint32_t Color)
{
if (unlikely(!Bitmap))
return;
if (unlikely(!Bitmap->Data))
return;
for (uint32_t i = 0; i < rect.Width; i++)
{
InlineSetPixel(Bitmap, rect.Left + i, rect.Top, Color);
InlineSetPixel(Bitmap, rect.Left + i, rect.Top + rect.Height - 1, Color);
}
for (uint32_t i = 0; i < rect.Height; i++)
{
InlineSetPixel(Bitmap, rect.Left, rect.Top + i, Color);
InlineSetPixel(Bitmap, rect.Left + rect.Width - 1, rect.Top + i, Color);
}
}
uint32_t BlendColors(uint32_t c1, uint32_t c2, float t)
{
uint8_t r1 = (c1 >> 16) & 0xFF;
uint8_t g1 = (c1 >> 8) & 0xFF;
uint8_t b1 = c1 & 0xFF;
uint8_t r2 = (c2 >> 16) & 0xFF;
uint8_t g2 = (c2 >> 8) & 0xFF;
uint8_t b2 = c2 & 0xFF;
uint8_t r = (uint8_t)(r1 + t * (r2 - r1));
uint8_t g = (uint8_t)(g1 + t * (g2 - g1));
uint8_t b = (uint8_t)(b1 + t * (b2 - b1));
return (r << 16) | (g << 8) | b;
}
void PutBorderWithShadow(ScreenBitmap *Bitmap, Rect rect, uint32_t Color)
{
UNUSED(Bitmap);
UNUSED(rect);
UNUSED(Color);
}
#define SHADOW_SIZE 12
void DrawShadow(ScreenBitmap *Bitmap, Rect rect)
{
UNUSED(Bitmap);
UNUSED(rect);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-overflow"
void PaintChar(Video::Font *font, ScreenBitmap *Bitmap, char c, uint32_t Color, int64_t *CharCursorX, int64_t *CharCursorY)
{
switch (font->GetInfo().Type)
{
case Video::FontType::PCScreenFont1:
{
// uint32_t *PixelPtr = (uint32_t *)Bitmap->Data;
char *FontPtr = (char *)font->GetInfo().PSF1Font->GlyphBuffer + (c * font->GetInfo().PSF1Font->Header->charsize);
for (int64_t Y = *CharCursorY; Y < *CharCursorY + 16; Y++)
{
for (int64_t X = *CharCursorX; X < *CharCursorX + 8; X++)
if ((*FontPtr & (0b10000000 >> (X - *CharCursorX))) > 0)
InlineSetPixel(Bitmap, X, Y, Color);
FontPtr++;
}
*CharCursorX += 8;
break;
}
case Video::FontType::PCScreenFont2:
{
// if (font->PSF2Font->GlyphBuffer == (uint16_t *)0x01) // HAS UNICODE TABLE
// Char = font->PSF2Font->GlyphBuffer[Char];
int BytesPerLine = (font->GetInfo().PSF2Font->Header->width + 7) / 8;
char *FontPtr = (char *)font->GetInfo().StartAddress +
font->GetInfo().PSF2Font->Header->headersize +
(c > 0 && (unsigned char)c < font->GetInfo().PSF2Font->Header->length ? c : 0) *
font->GetInfo().PSF2Font->Header->charsize;
uint32_t fonthdrWidth = font->GetInfo().PSF2Font->Header->width;
uint32_t fonthdrHeight = font->GetInfo().PSF2Font->Header->height;
for (int64_t Y = *CharCursorY; Y < *CharCursorY + fonthdrHeight; Y++)
{
for (int64_t X = *CharCursorX; X < *CharCursorX + fonthdrWidth; X++)
if ((*FontPtr & (0b10000000 >> (X - *CharCursorX))) > 0)
InlineSetPixel(Bitmap, X, Y, Color);
FontPtr += BytesPerLine;
}
*CharCursorX += fonthdrWidth;
break;
}
default:
warn("Unsupported font type");
break;
}
}
#pragma GCC diagnostic pop
void DrawString(ScreenBitmap *Bitmap, Rect rect, const char *Text, uint32_t Color)
{
UNUSED(Bitmap);
UNUSED(rect);
UNUSED(Text);
UNUSED(Color);
}
}

View File

@ -1,667 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <debug.h>
#include "icons.hpp"
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
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;
#ifdef DEBUG
size_t FIi = 0, PDi = 0, PWi = 0, PWWi = 0, PCi = 0, mmi = 0;
#endif
namespace GraphicalUserInterface
{
void GUI::FetchInputs()
{
MouseData Mouse;
bool FoundMouseDriver = false;
if (likely(DriverManager->GetDrivers().size() > 0))
{
foreach (auto Driver in DriverManager->GetDrivers())
{
if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Input &&
((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.TypeFlags & FexDriverInputTypes::FexDriverInputTypes_Mouse)
{
#ifdef DEBUG
static int once = 0;
if (!once++)
debug("Found mouse driver %ld", Driver.DriverUID);
#endif
KernelCallback callback{};
callback.Reason = FetchReason;
DriverManager->IOCB(Driver.DriverUID, &callback);
Mouse.X = callback.InputCallback.Mouse.X;
Mouse.Y = callback.InputCallback.Mouse.Y;
Mouse.Z = callback.InputCallback.Mouse.Z;
Mouse.Left = callback.InputCallback.Mouse.Buttons.Left;
Mouse.Right = callback.InputCallback.Mouse.Buttons.Right;
Mouse.Middle = callback.InputCallback.Mouse.Buttons.Middle;
FoundMouseDriver = true;
break;
}
}
}
if (unlikely(!FoundMouseDriver))
{
static int once = 0;
if (!once++)
debug("No mouse driver found.");
Mouse.X = Display->GetBuffer(200)->Width / 2;
Mouse.Y = Display->GetBuffer(200)->Height / 2;
Mouse.Z = 0;
Mouse.Left = false;
Mouse.Right = false;
Mouse.Middle = false;
}
Event eTemplate;
memset(&eTemplate, 0, sizeof(Event));
foreach (auto wnd in this->Windows)
{
/* On mouse down event */
if (unlikely((!MouseArray[1].Left || !MouseArray[1].Right || !MouseArray[1].Middle) &&
(Mouse.Left || Mouse.Right || Mouse.Middle)))
{
eTemplate.MouseDown.X = Mouse.X;
eTemplate.MouseDown.Y = Mouse.Y;
eTemplate.MouseDown.Left = Mouse.Left;
eTemplate.MouseDown.Right = Mouse.Right;
eTemplate.MouseDown.Middle = Mouse.Middle;
wnd->OnMouseDown(&eTemplate);
}
/* On mouse up event */
if (unlikely((MouseArray[1].Left || MouseArray[1].Right || MouseArray[1].Middle) &&
(!Mouse.Left || !Mouse.Right || !Mouse.Middle)))
{
eTemplate.MouseUp.X = Mouse.X;
eTemplate.MouseUp.Y = Mouse.Y;
eTemplate.MouseUp.Left = Mouse.Left;
eTemplate.MouseUp.Right = Mouse.Right;
eTemplate.MouseUp.Middle = Mouse.Middle;
wnd->OnMouseUp(&eTemplate);
}
static int Idle = 0;
if (likely(Mouse.X != MouseArray[1].X || Mouse.Y != MouseArray[1].Y))
{
Idle = 0;
Rect TopBarPos = wnd->GetPosition();
TopBarPos.Top -= 20;
TopBarPos.Height = 20;
TopBarPos.Width -= 60; /* buttons */
if (unlikely((int64_t)TopBarPos.Top < 0))
{
TopBarPos.Top = 0;
wnd->GetPositionPtr()->Top = 20;
}
Rect ResizeHintPos = wnd->GetPosition();
ResizeHintPos.Left += ResizeHintPos.Width - 20;
ResizeHintPos.Top += ResizeHintPos.Height - 20;
ResizeHintPos.Width = 20;
ResizeHintPos.Height = 20;
if (unlikely(TopBarPos.Contains(Mouse.X, Mouse.Y) ||
TopBarPos.Contains(MouseArray[0].X, MouseArray[0].Y) ||
TopBarPos.Contains(MouseArray[1].X, MouseArray[1].Y)))
{
if (likely(Mouse.Left))
{
if (likely(MouseArray[1].Left))
{
wnd->GetPositionPtr()->Left += Mouse.X - MouseArray[0].X;
wnd->GetPositionPtr()->Top += Mouse.Y - MouseArray[0].Y;
OverlayBufferRepaint = true;
OverlayFullRepaint = true;
}
}
}
if (ResizeHintPos.Contains(Mouse.X, Mouse.Y) ||
ResizeHintPos.Contains(MouseArray[0].X, MouseArray[0].Y) ||
ResizeHintPos.Contains(MouseArray[1].X, MouseArray[1].Y))
{
if (Mouse.Left)
{
if (MouseArray[1].Left)
{
wnd->GetPositionPtr()->Width += (size_t)(Mouse.X - MouseArray[0].X);
wnd->GetPositionPtr()->Height += (size_t)(Mouse.Y - MouseArray[0].Y);
if (wnd->GetPositionPtr()->Width < 200)
{
wnd->GetPositionPtr()->Width = 200;
Mouse.X = MouseArray[0].X;
}
if (wnd->GetPositionPtr()->Height < 100)
{
wnd->GetPositionPtr()->Height = 100;
Mouse.Y = MouseArray[0].Y;
}
OverlayBufferRepaint = true;
OverlayFullRepaint = true;
eTemplate.Resize.Width = wnd->GetPosition().Width;
eTemplate.Resize.Height = wnd->GetPosition().Height;
wnd->OnResize(&eTemplate);
}
}
if (unlikely(Cursor != CursorType::ResizeAll))
{
Cursor = CursorType::ResizeAll;
CursorBufferRepaint = true;
}
}
else
{
if (unlikely(Cursor != CursorType::Arrow))
{
Cursor = CursorType::Arrow;
CursorBufferRepaint = true;
}
}
eTemplate.MouseMove.X = Mouse.X;
eTemplate.MouseMove.Y = Mouse.Y;
eTemplate.MouseMove.Left = Mouse.Left;
eTemplate.MouseMove.Right = Mouse.Right;
eTemplate.MouseMove.Middle = Mouse.Middle;
wnd->OnMouseMove(&eTemplate);
}
else
{
if (unlikely(Idle > 1000))
CPU::Pause();
else
Idle++;
}
}
foreach (auto wdg in this->Widgets)
{
// TODO: Implement mouse events for widgets
UNUSED(wdg);
}
memmove(MouseArray + 1, MouseArray, sizeof(MouseArray) - sizeof(MouseArray[1]));
MouseArray[0] = Mouse;
LastCursor = Cursor;
}
void GUI::PaintDesktop()
{
if (DesktopBufferRepaint)
{
// PutRect(this->DesktopBuffer, this->Desktop, 0x404040);
memset(this->DesktopBuffer->Data, 0x404040, this->DesktopBuffer->Size);
DesktopBufferRepaint = false;
}
// Well... I have to do some code optimization on DrawOverBitmap. It's too slow and it's not even using SIMD
memcpy(this->BackBuffer->Data, this->DesktopBuffer->Data, this->DesktopBuffer->Size);
}
void GUI::PaintWidgets()
{
Event eTemplate;
memset(&eTemplate, 0, sizeof(Event));
foreach (auto wdg in this->Widgets)
wdg->OnPaint(nullptr);
}
void GUI::PaintWindows()
{
foreach (auto wnd in this->Windows)
{
ScreenBitmap *wndBuffer = wnd->GetBuffer();
if (unlikely(wndBuffer == nullptr)) // I think "unlikely" is not needed here
continue;
Rect WndPos = wnd->GetPosition();
// Draw window content
DrawOverBitmap(this->BackBuffer,
wndBuffer,
WndPos.Top,
WndPos.Left);
/* We can't use memcpy because the window buffer
is not the same size as the screen buffer
https://i.imgur.com/OHfaYnS.png */
// memcpy(this->BackBuffer->Data + wnd->GetPositionPtr()->Top * this->BackBuffer->Width + wnd->GetPositionPtr()->Left, wndBuffer->Data, wndBuffer->Size);
Rect TopBarPos = WndPos;
TopBarPos.Top -= 20;
TopBarPos.Height = 20;
if ((int64_t)TopBarPos.Top < 0)
{
TopBarPos.Top = 0;
wnd->GetPositionPtr()->Top = 20;
}
Rect CloseButtonPos;
Rect MinimizeButtonPos;
CloseButtonPos.Left = TopBarPos.Left + TopBarPos.Width - 20;
CloseButtonPos.Top = TopBarPos.Top;
CloseButtonPos.Width = 20;
CloseButtonPos.Height = 20;
MinimizeButtonPos.Left = TopBarPos.Left + TopBarPos.Width - 60;
if (unlikely(MouseArray[0].X >= (size_t)MinimizeButtonPos.Left &&
MouseArray[0].X <= (size_t)CloseButtonPos.Left + CloseButtonPos.Width &&
MouseArray[0].Y >= (size_t)CloseButtonPos.Top &&
MouseArray[0].Y <= (size_t)CloseButtonPos.Top + CloseButtonPos.Height))
{
OverlayBufferRepaint = true;
}
// Title bar
if (unlikely(OverlayBufferRepaint))
{
if (OverlayFullRepaint)
{
memset(this->OverlayBuffer->Data, 0, this->OverlayBuffer->Size);
OverlayFullRepaint = false;
}
static bool RepaintNeeded = false;
DrawShadow(this->OverlayBuffer, wnd->GetPosition());
Rect MaximizeButtonPos;
MaximizeButtonPos.Left = TopBarPos.Left + TopBarPos.Width - 40;
MaximizeButtonPos.Top = TopBarPos.Top;
MaximizeButtonPos.Width = 20;
MaximizeButtonPos.Height = 20;
MinimizeButtonPos.Top = TopBarPos.Top;
MinimizeButtonPos.Width = 20;
MinimizeButtonPos.Height = 20;
PutRect(this->OverlayBuffer, TopBarPos, 0x282828);
// Title bar buttons (close, minimize, maximize) on the right
if (MouseArray[0].X >= (size_t)CloseButtonPos.Left &&
MouseArray[0].X <= (size_t)CloseButtonPos.Left + CloseButtonPos.Width &&
MouseArray[0].Y >= (size_t)CloseButtonPos.Top &&
MouseArray[0].Y <= (size_t)CloseButtonPos.Top + CloseButtonPos.Height)
{
PutRect(this->OverlayBuffer, CloseButtonPos, MouseArray[0].Left ? 0xFF5500 : 0xFF0000);
RepaintNeeded = true;
}
else
{
PutRect(this->OverlayBuffer, MaximizeButtonPos, 0x282828);
}
if (MouseArray[0].X >= (size_t)MaximizeButtonPos.Left &&
MouseArray[0].X <= (size_t)MaximizeButtonPos.Left + MaximizeButtonPos.Width &&
MouseArray[0].Y >= (size_t)MaximizeButtonPos.Top &&
MouseArray[0].Y <= (size_t)MaximizeButtonPos.Top + MaximizeButtonPos.Height)
{
PutRect(this->OverlayBuffer, MaximizeButtonPos, MouseArray[0].Left ? 0x454545 : 0x404040);
RepaintNeeded = true;
}
else
{
PutRect(this->OverlayBuffer, MaximizeButtonPos, 0x282828);
}
if (MouseArray[0].X >= (size_t)MinimizeButtonPos.Left &&
MouseArray[0].X <= (size_t)MinimizeButtonPos.Left + MinimizeButtonPos.Width &&
MouseArray[0].Y >= (size_t)MinimizeButtonPos.Top &&
MouseArray[0].Y <= (size_t)MinimizeButtonPos.Top + MinimizeButtonPos.Height)
{
PutRect(this->OverlayBuffer, MinimizeButtonPos, MouseArray[0].Left ? 0x454545 : 0x404040);
RepaintNeeded = true;
}
else
{
PutRect(this->OverlayBuffer, MinimizeButtonPos, 0x282828);
}
// Title bar icons (close, minimize, maximize) on the right
for (short i = 0; i < 20; i++)
{
for (short j = 0; j < 20; j++)
{
if (CloseButton[i * 20 + j] == 1)
SetPixel(this->OverlayBuffer,
CloseButtonPos.Left + j,
CloseButtonPos.Top + i,
0xFFFFFF);
if ((MaximizeButtonMaximized[i * 20 + j] == 1) && !wnd->IsMaximized())
SetPixel(this->OverlayBuffer,
MaximizeButtonPos.Left + j,
MaximizeButtonPos.Top + i,
0xFFFFFF);
else if ((MaximizeButtonNormal[i * 20 + j] == 1) && wnd->IsMaximized())
SetPixel(this->OverlayBuffer,
MaximizeButtonPos.Left + j,
MaximizeButtonPos.Top + i,
0xFFFFFF);
if (MinimizeButton[i * 20 + j] == 1)
SetPixel(this->OverlayBuffer,
MinimizeButtonPos.Left + j,
MinimizeButtonPos.Top + i,
0xFFFFFF);
}
}
Rect wndPos = wnd->GetPosition();
// Resize hint
for (short i = 0; i < 20; i++)
for (short j = 0; j < 20; j++)
if (ResizeHint[i * 20 + j] == 1)
SetPixel(this->OverlayBuffer, wndPos.Left + wndPos.Width - 20 + j, wndPos.Top + wndPos.Height - 20 + i, 0xFFFFFF);
// Title bar border
PutBorder(this->OverlayBuffer, TopBarPos, 0xFF000000);
// Window border
PutBorder(this->OverlayBuffer, wndPos, 0xFF000000);
Rect TopBarTextPos = TopBarPos;
TopBarTextPos.Left += 4;
TopBarTextPos.Top += 4;
// Title bar text
int64_t CharCursorX = TopBarTextPos.Left;
int64_t CharCursorY = TopBarTextPos.Top;
for (uint64_t i = 0; i < strlen(wnd->GetTitle()); i++)
PaintChar(this->CurrentFont, this->OverlayBuffer, wnd->GetTitle()[i], 0xFFFFFF, &CharCursorX, &CharCursorY);
if (!RepaintNeeded)
{
OverlayBufferRepaint = false;
RepaintNeeded = false;
}
}
wnd->OnPaint(nullptr);
}
DrawOverBitmap(this->BackBuffer, this->OverlayBuffer, 0, 0);
}
/*
"* 2" to increase the size of the cursor
"/ 2" to decrease the size of the cursor
*/
#define ICON_SIZE
void GUI::PaintCursor()
{
uint32_t CursorColorInner = 0xFFFFFFFF;
uint32_t CursorColorOuter = 0xFF000000;
if (MouseArray[0].X != MouseArray[1].X ||
MouseArray[0].Y != MouseArray[1].Y ||
MouseArray[0].Z != MouseArray[1].Z ||
Cursor != LastCursor)
CursorBufferRepaint = true;
if (CursorBufferRepaint)
{
memset(this->CursorBuffer->Data, 0, this->CursorBuffer->Size);
switch (this->Cursor)
{
case CursorType::Visible:
{
CursorVisible = true;
break;
}
case CursorType::Hidden:
{
CursorVisible = false;
break;
}
default:
fixme("Unknown cursor type %d", this->Cursor);
[[fallthrough]];
case CursorType::Arrow:
{
if (CursorVisible)
for (int i = 0; i < 19; i++)
{
for (int j = 0; j < 12; j++)
{
if (CursorArrow[i * 12 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorArrow[i * 12 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::Hand:
{
if (CursorVisible)
for (int i = 0; i < 24; i++)
{
for (int j = 0; j < 17; j++)
{
if (CursorHand[i * 17 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorHand[i * 17 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::Wait:
{
if (CursorVisible)
for (int i = 0; i < 22; i++)
{
for (int j = 0; j < 13; j++)
{
if (CursorWait[i * 13 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorWait[i * 13 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::IBeam:
{
if (CursorVisible)
for (int i = 0; i < 22; i++)
{
for (int j = 0; j < 13; j++)
{
if (CursorIBeam[i * 13 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorIBeam[i * 13 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::ResizeAll:
{
if (CursorVisible)
for (int i = 0; i < 23; i++)
{
for (int j = 0; j < 23; j++)
{
if (CursorResizeAll[i * 23 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorResizeAll[i * 23 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
}
CursorBufferRepaint = false;
}
DrawOverBitmap(this->BackBuffer, this->CursorBuffer, MouseArray[0].Y, MouseArray[0].X);
}
void GUI::Loop()
{
/*
Because we do not use a gpu to do the rendering, we need to do it manually.
This is why the mouse is slow when we have to draw a bunch of things.
*/
while (IsRunning)
{
#ifdef DEBUG
FIi = CPU::Counter();
#endif
FetchInputs();
#ifdef DEBUG
FIi = CPU::Counter() - FIi;
PDi = CPU::Counter();
#endif
PaintDesktop();
#ifdef DEBUG
PDi = CPU::Counter() - PDi;
PWi = CPU::Counter();
#endif
PaintWidgets();
#ifdef DEBUG
PWi = CPU::Counter() - PWi;
PWWi = CPU::Counter();
#endif
PaintWindows();
#ifdef DEBUG
PWWi = CPU::Counter() - PWWi;
PCi = CPU::Counter();
#endif
PaintCursor();
#ifdef DEBUG
PCi = CPU::Counter() - PCi;
mmi = CPU::Counter();
#endif
memcpy(Display->GetBuffer(200)->Buffer, this->BackBuffer->Data, this->BackBuffer->Size);
Display->SetBuffer(200);
#ifdef DEBUG
mmi = CPU::Counter() - mmi;
#endif
}
}
void GUI::AddWindow(Window *window)
{
this->Windows.push_back(window);
}
void GUI::AddWidget(WidgetCollection *widget)
{
this->Widgets.push_back(widget);
}
GUI::GUI()
{
Display->CreateBuffer(0, 0, 200);
this->CurrentFont = new Video::Font(&_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, Video::FontType::PCScreenFont2);
this->mem = new Memory::MemMgr;
this->Desktop.Top = 0;
this->Desktop.Left = 0;
this->Desktop.Width = Display->GetBuffer(200)->Width;
this->Desktop.Height = Display->GetBuffer(200)->Height;
this->BackBuffer = new ScreenBitmap;
this->BackBuffer->Width = this->Desktop.Width;
this->BackBuffer->Height = this->Desktop.Height;
this->BackBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->BackBuffer->Pitch = Display->GetPitch();
this->BackBuffer->Size = Display->GetBuffer(200)->Size;
this->BackBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->BackBuffer->Size + 1));
memset(this->BackBuffer->Data, 0, this->BackBuffer->Size);
this->DesktopBuffer = new ScreenBitmap;
this->DesktopBuffer->Width = this->Desktop.Width;
this->DesktopBuffer->Height = this->Desktop.Height;
this->DesktopBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->DesktopBuffer->Pitch = Display->GetPitch();
this->DesktopBuffer->Size = Display->GetBuffer(200)->Size;
this->DesktopBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->DesktopBuffer->Size + 1));
memset(this->DesktopBuffer->Data, 0, this->DesktopBuffer->Size);
this->OverlayBuffer = new ScreenBitmap;
this->OverlayBuffer->Width = this->Desktop.Width;
this->OverlayBuffer->Height = this->Desktop.Height;
this->OverlayBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->OverlayBuffer->Pitch = Display->GetPitch();
this->OverlayBuffer->Size = Display->GetBuffer(200)->Size;
this->OverlayBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->OverlayBuffer->Size + 1));
memset(this->OverlayBuffer->Data, 0, this->OverlayBuffer->Size);
this->CursorBuffer = new ScreenBitmap;
this->CursorBuffer->Width = 25;
this->CursorBuffer->Height = 25;
this->CursorBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->CursorBuffer->Pitch = Display->GetPitch();
this->CursorBuffer->Size = (size_t)(this->CursorBuffer->Width * this->CursorBuffer->Height * (this->CursorBuffer->BitsPerPixel / 8));
this->CursorBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->CursorBuffer->Size + 1));
memset(this->CursorBuffer->Data, 0, this->CursorBuffer->Size);
this->IsRunning = true;
}
GUI::~GUI()
{
debug("Destructor called");
delete this->mem, this->mem = nullptr;
delete this->BackBuffer, this->BackBuffer = nullptr;
delete this->DesktopBuffer, this->DesktopBuffer = nullptr;
delete this->OverlayBuffer, this->OverlayBuffer = nullptr;
delete this->CursorBuffer, this->CursorBuffer = nullptr;
Display->DeleteBuffer(200);
this->Windows.clear();
}
}

View File

@ -1,253 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "icons.hpp"
char CursorArrow[] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12x19
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, //
1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0, //
1, 2, 2, 1, 0, 1, 2, 2, 1, 0, 0, 0, //
1, 2, 1, 0, 0, 1, 2, 2, 1, 0, 0, 0, //
1, 1, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, //
1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, //
};
char CursorHand[] = {
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x24
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, //
1, 1, 1, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, //
1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, //
1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, //
0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, //
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};
char CursorWait[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 13x22
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, //
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 0, //
0, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 0, //
0, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 0, //
0, 0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0, 0, //
0, 0, 0, 1, 1, 2, 1, 2, 1, 1, 0, 0, 0, //
0, 0, 0, 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 1, 1, 2, 2, 2, 1, 1, 0, 0, 0, //
0, 0, 1, 1, 2, 2, 1, 2, 2, 1, 1, 0, 0, //
0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, //
0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 0, //
0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, //
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, //
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //
};
char CursorIBeam[] = {
1, 1, 1, 0, 1, 1, 1, // 7x17
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
1, 1, 1, 0, 1, 1, 1, //
};
char CursorResizeAll[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x23
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, //
0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, //
0, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, //
0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, //
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, //
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};
char CloseButton[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};
char MinimizeButton[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};
char MaximizeButtonNormal[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};
char MaximizeButtonMaximized[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};
char ResizeHint[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
};

View File

@ -1,159 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
namespace GraphicalUserInterface
{
void WidgetCollection::OnPaintBackground(Event *e)
{
UNUSED(e);
}
void WidgetCollection::OnPaintForeground(Event *e)
{
UNUSED(e);
foreach (auto Panel in this->Panels)
{
PutRect(this->Buffer, Panel->rect, Panel->Color);
}
foreach (auto Label in this->Labels)
{
Label->CharCursorX = Label->rect.Left;
Label->CharCursorY = Label->rect.Top;
for (uint64_t i = 0; i < strlen(Label->Text); i++)
PaintChar(this->CurrentFont, this->Buffer, Label->Text[i], 0xFFFFFF, &Label->CharCursorX, &Label->CharCursorY);
}
foreach (auto Button in this->Buttons)
{
if (Button->Pressed)
PutRect(this->Buffer, Button->rect, Button->PressedColor);
else if (Button->Hover)
PutRect(this->Buffer, Button->rect, Button->HoverColor);
else
PutRect(this->Buffer, Button->rect, Button->Color);
Button->CharCursorX = Button->rect.Left + (((Button->rect.Width / 2) - (this->CurrentFont->GetInfo().Width * strlen(Button->Text) / 2)));
Button->CharCursorY = Button->rect.Top + (((Button->rect.Height / 2) - (this->CurrentFont->GetInfo().Height / 2)));
for (uint64_t i = 0; i < strlen(Button->Text); i++)
PaintChar(this->CurrentFont, this->Buffer, Button->Text[i], 0xFFFFFF, &Button->CharCursorX, &Button->CharCursorY);
}
}
void WidgetCollection::OnPaint(Event *e)
{
static size_t LastWidth = 0;
static size_t LastHeight = 0;
if (LastWidth != ((Window *)this->ParentWindow)->GetPosition().Width ||
LastHeight != ((Window *)this->ParentWindow)->GetPosition().Height)
{
LastWidth = ((Window *)this->ParentWindow)->GetPosition().Width;
LastHeight = ((Window *)this->ParentWindow)->GetPosition().Height;
this->mem->FreePages(this->Buffer->Data, TO_PAGES(this->Buffer->Size + 1));
this->Buffer->Data = nullptr;
delete this->Buffer, this->Buffer = nullptr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = LastWidth;
this->Buffer->Height = LastHeight;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = this->Buffer->Pitch * (size_t)LastHeight;
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->NeedRedraw = true;
}
if (this->NeedRedraw)
{
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->OnPaintBackground(e);
this->OnPaintForeground(e);
this->NeedRedraw = false;
}
DrawOverBitmap(((Window *)this->ParentWindow)->GetBuffer(), this->Buffer, 0, 0);
}
void WidgetCollection::OnMouseDown(Event *e)
{
foreach (auto Button in this->Buttons)
{
if (Button->rect.Contains(e->MouseDown.X, e->MouseDown.Y))
{
if (e->MouseDown.Left)
{
debug("Button Hold");
Button->Pressed = true;
this->NeedRedraw = true;
}
}
}
}
void WidgetCollection::OnMouseUp(Event *e)
{
foreach (auto Button in this->Buttons)
{
if (Button->rect.Contains(e->MouseUp.X, e->MouseUp.Y))
{
if (e->MouseUp.Left)
{
debug("Button Release");
if (Button->Pressed)
{
debug("Button Clicked");
if (Button->OnClick != (uintptr_t) nullptr)
((void (*)(void))Button->OnClick)();
Button->Pressed = false;
this->NeedRedraw = true;
}
}
}
}
}
void WidgetCollection::OnMouseMove(Event *e)
{
foreach (auto Button in this->Buttons)
{
if (Button->rect.Contains(e->MouseMove.X, e->MouseMove.Y))
{
Button->Hover = true;
this->NeedRedraw = true;
}
else
{
Button->Hover = false;
this->NeedRedraw = true;
}
}
}
}

View File

@ -1,141 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_start;
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_end;
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_size;
namespace GraphicalUserInterface
{
Handle WidgetCollection::CreatePanel(Rect rect, uint32_t Color)
{
PanelObject *panel = (PanelObject *)this->mem->RequestPages(TO_PAGES(sizeof(PanelObject) + 1));
panel->Handle.Type[0] = 'P';
panel->Handle.Type[1] = 'N';
panel->Handle.Type[2] = 'L';
panel->Handle.Type[3] = '\0';
panel->rect = rect;
panel->Color = Color;
panel->BorderColor = 0xFF000000;
panel->ShadowColor = 0xFF000000;
panel->Shadow = false;
Panels.push_back(panel);
this->NeedRedraw = true;
return (Handle)panel;
}
Handle WidgetCollection::CreateLabel(Rect rect, const char *Text)
{
LabelObject *label = (LabelObject *)this->mem->RequestPages(TO_PAGES(sizeof(LabelObject) + 1));
label->Handle.Type[0] = 'L';
label->Handle.Type[1] = 'B';
label->Handle.Type[2] = 'L';
label->Handle.Type[3] = '\0';
label->rect = rect;
strcpy(label->Text, Text);
label->Color = 0xFFFFFF;
label->CharCursorX = rect.Left;
label->CharCursorY = rect.Top;
Labels.push_back(label);
NeedRedraw = true;
return (Handle)label;
}
Handle WidgetCollection::CreateButton(Rect rect, const char *Text, uintptr_t OnClick)
{
ButtonObject *button = (ButtonObject *)this->mem->RequestPages(TO_PAGES(sizeof(ButtonObject) + 1));
button->Handle.Type[0] = 'B';
button->Handle.Type[1] = 'T';
button->Handle.Type[2] = 'N';
button->Handle.Type[3] = '\0';
button->rect = rect;
strcpy(button->Text, Text);
button->Color = 0x252525;
button->HoverColor = 0x353535;
button->PressedColor = 0x555555;
button->BorderColor = 0xFF000000;
button->ShadowColor = 0xFF000000;
button->Shadow = false;
button->Hover = false;
button->Pressed = false;
button->OnClick = OnClick;
Buttons.push_back(button);
this->NeedRedraw = true;
return (Handle)button;
}
void WidgetCollection::SetText(Handle handle, const char *Text)
{
HandleMeta *meta = (HandleMeta *)handle;
if (meta->Type[0] == 'L' && meta->Type[1] == 'B' && meta->Type[2] == 'L')
{
LabelObject *label = (LabelObject *)handle;
strcpy(label->Text, Text);
this->NeedRedraw = true;
}
}
WidgetCollection::WidgetCollection(void *ParentWindow)
{
if (!ParentWindow)
{
error("ParentWindow is null");
return;
}
this->ParentWindow = ParentWindow;
this->mem = new Memory::MemMgr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = ((Window *)this->ParentWindow)->GetPosition().Width;
this->Buffer->Height = ((Window *)this->ParentWindow)->GetPosition().Height;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = (size_t)(this->Buffer->Pitch * ((Window *)this->ParentWindow)->GetPosition().Height);
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->CurrentFont = new Video::Font(&_binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_end, Video::FontType::PCScreenFont2);
}
WidgetCollection::~WidgetCollection()
{
delete this->mem, this->mem = nullptr;
delete this->Buffer, this->Buffer = nullptr;
delete this->CurrentFont, this->CurrentFont = nullptr;
}
}

View File

@ -1,82 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
namespace GraphicalUserInterface
{
#define TASKBAR_HEIGHT 25
// if (!Maximized)
// {
// this->LastPosition.Left = this->Position.Left;
// this->LastPosition.Top = this->Position.Top;
// this->LastPosition.Width = this->Position.Width;
// this->LastPosition.Height = this->Position.Height;
// this->Position.Left = 0;
// this->Position.Top = 0;
// this->Position.Width = Display->GetBuffer(200)->Width;
// this->Position.Height = Display->GetBuffer(200)->Height - 20 - TASKBAR_HEIGHT;
// Maximized = true;
// }
// else
// {
// this->Position.Left = this->LastPosition.Left;
// this->Position.Top = this->LastPosition.Top;
// this->Position.Width = this->LastPosition.Width;
// this->Position.Height = this->LastPosition.Height;
// Maximized = false;
// }
void Window::AddWidget(WidgetCollection *widget)
{
this->Widgets.push_back(widget);
}
Window::Window(void *ParentGUI, Rect rect, const char *Title)
{
this->mem = new Memory::MemMgr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = rect.Width;
this->Buffer->Height = rect.Height;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = this->Buffer->Pitch * rect.Height;
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->ParentGUI = ParentGUI;
this->Position = rect;
strcpy(this->Title, Title);
this->Maximized = false;
this->Minimized = false;
}
Window::~Window()
{
delete this->mem, this->mem = nullptr;
}
}

View File

@ -1,137 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
namespace GraphicalUserInterface
{
void Window::OnResize(Event *e)
{
// TODO: Optimize this
this->mem->FreePages(this->Buffer->Data, TO_PAGES(this->Buffer->Size + 1));
this->Buffer->Data = nullptr;
delete this->Buffer, this->Buffer = nullptr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = e->Resize.Width;
this->Buffer->Height = e->Resize.Height;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = this->Buffer->Pitch * e->Resize.Height;
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->OnPaint(e);
}
void Window::OnMinimize(Event *e)
{
UNUSED(e);
fixme("Window::OnMinimize() not implemented");
}
void Window::OnMaximize(Event *e)
{
UNUSED(e);
fixme("Window::OnMaximize() not implemented");
}
void Window::OnClose(Event *e)
{
UNUSED(e);
fixme("Window::OnClose() not implemented");
}
void Window::OnPaintBackground(Event *e)
{
UNUSED(e);
Rect PaintPosition = this->Position;
PaintPosition.Left = 0;
PaintPosition.Top = 0;
PutRect(this->Buffer, PaintPosition, 0x121212);
}
void Window::OnPaintForeground(Event *e)
{
// Window content
if (!this->Maximized)
{
char buf[256];
sprintf(buf, "Left:\eAA11FF%ld\eFFFFFF Top:\eAA11FF%ld\eFFFFFF W:\eAA11FF%ld\eFFFFFF H:\eAA11FF%ld\eFFFFFF", this->Position.Left, this->Position.Top, this->Position.Width, this->Position.Height);
// Display->DrawString(buf, this->Position.Left + 20, this->Position.Top + 25, 200);
}
foreach (auto var in this->Widgets)
{
var->OnPaint(e);
}
}
void Window::OnPaint(Event *e)
{
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->OnPaintBackground(e);
this->OnPaintForeground(e);
}
void Window::OnMouseDown(Event *e)
{
Event WindowPos = *e;
WindowPos.MouseDown.X -= this->Position.Left;
WindowPos.MouseDown.Y -= this->Position.Top;
foreach (auto var in this->Widgets)
{
var->OnMouseDown(&WindowPos);
}
}
void Window::OnMouseUp(Event *e)
{
Event WindowPos = *e;
WindowPos.MouseUp.X -= this->Position.Left;
WindowPos.MouseUp.Y -= this->Position.Top;
foreach (auto var in this->Widgets)
{
var->OnMouseUp(&WindowPos);
}
}
void Window::OnMouseMove(Event *e)
{
Event WindowPos = *e;
WindowPos.MouseMove.X -= this->Position.Left;
WindowPos.MouseMove.Y -= this->Position.Top;
foreach (auto var in this->Widgets)
{
var->OnMouseMove(&WindowPos);
}
}
}

View File

@ -67,12 +67,11 @@ LockClass mExtTrkLock;
* - [x] The cleanup should be done by a thread (tasking). This is done to avoid a deadlock. * - [x] The cleanup should be done by a thread (tasking). This is done to avoid a deadlock.
* - [ ] Implement a better Display::SetBrightness() function. * - [ ] Implement a better Display::SetBrightness() function.
* - [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD). * - [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD).
* - [ ] Support Aarch64.
* - [ ] Fully support i386. * - [ ] Fully support i386.
* - [ ] Support Aarch64.
* - [ ] SMP trampoline shouldn't be hardcoded at 0x2000. * - [ ] SMP trampoline shouldn't be hardcoded at 0x2000.
* - [ ] Rework the stack guard. * - [ ] Rework the stack guard.
* - [ ] Mutex implementation. * - [x] Mutex implementation.
* - [ ] Vector should have a mutex.
* - [ ] Update SMBIOS functions to support newer versions and actually use it. * - [ ] Update SMBIOS functions to support newer versions and actually use it.
* - [ ] COW (Copy On Write) for the virtual memory. (https://en.wikipedia.org/wiki/Copy-on-write) * - [ ] COW (Copy On Write) for the virtual memory. (https://en.wikipedia.org/wiki/Copy-on-write)
* - [ ] Bootstrap should have a separate bss section + PHDR. * - [ ] Bootstrap should have a separate bss section + PHDR.
@ -183,6 +182,10 @@ LockClass mExtTrkLock;
* https://github.com/gcc-mirror/gcc/tree/master/libstdc%2B%2B-v3 * https://github.com/gcc-mirror/gcc/tree/master/libstdc%2B%2B-v3
* https://itanium-cxx-abi.github.io/cxx-abi/abi.html * https://itanium-cxx-abi.github.io/cxx-abi/abi.html
* *
* - Keyboard:
* https://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html
* https://wiki.osdev.org/PS/2_Keyboard
*
*/ */
#ifdef a64 #ifdef a64
@ -207,8 +210,6 @@ NewLock(KernelLock);
#include <intrin.hpp> #include <intrin.hpp>
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node; using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags; using VirtualFileSystem::NodeFlags;
@ -223,9 +224,10 @@ VirtualFileSystem::Virtual *vfs = nullptr;
KernelConfig Config = { KernelConfig Config = {
.AllocatorType = Memory::MemoryAllocatorType::XallocV1, .AllocatorType = Memory::MemoryAllocatorType::XallocV1,
.SchedulerType = 1, .SchedulerType = Multi,
.DriverDirectory = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\0'}, .DriverDirectory = {'/', 'm', 'o', 'd', 'u', 'l', 'e', 's', '\0'},
.InitPath = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'i', 'n', 'i', 't', '\0'}, .InitPath = {'/', 'b', 'i', 'n', '/', 'i', 'n', 'i', 't', '\0'},
.UseLinuxSyscalls = false,
.InterruptsOnCrash = true, .InterruptsOnCrash = true,
.Cores = 0, .Cores = 0,
.IOAPICInterruptCore = 0, .IOAPICInterruptCore = 0,
@ -280,6 +282,9 @@ EXTERNC NIF void Main()
KPrint("CPU: \e058C19%s \e8822AA%s \e8888FF%s", KPrint("CPU: \e058C19%s \e8822AA%s \e8888FF%s",
CPU::Hypervisor(), CPU::Vendor(), CPU::Name()); CPU::Hypervisor(), CPU::Vendor(), CPU::Name());
debug("CPU: %s %s %s",
CPU::Hypervisor(), CPU::Vendor(), CPU::Name());
if (DebuggerIsAttached) if (DebuggerIsAttached)
KPrint("\eFFA500Kernel debugger detected."); KPrint("\eFFA500Kernel debugger detected.");
@ -291,14 +296,11 @@ EXTERNC NIF void Main()
KPrint("Loading Kernel Symbols"); KPrint("Loading Kernel Symbols");
KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)bInfo.Kernel.FileBase); KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)bInfo.Kernel.FileBase);
if (KernelSymbolTable->GetTotalEntries() == 0 && if (!KernelSymbolTable->SymTableExists)
bInfo.Kernel.Symbols.Num && KernelSymbolTable->AddSymbolInfoFromGRUB(bInfo.Kernel.Symbols.Num,
bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.EntSize,
bInfo.Kernel.Symbols.Shndx) bInfo.Kernel.Symbols.Shndx,
KernelSymbolTable->AddBySymbolInfo(bInfo.Kernel.Symbols.Num, bInfo.Kernel.Symbols.Sections);
bInfo.Kernel.Symbols.EntSize,
bInfo.Kernel.Symbols.Shndx,
bInfo.Kernel.Symbols.Sections);
KPrint("Reading Kernel Parameters"); KPrint("Reading Kernel Parameters");
ParseConfig((char *)bInfo.Kernel.CommandLine, &Config); ParseConfig((char *)bInfo.Kernel.CommandLine, &Config);
@ -453,74 +455,74 @@ EXTERNC NIF void Main()
DevFS = vfs->Create("/dev", NodeFlags::DIRECTORY); DevFS = vfs->Create("/dev", NodeFlags::DIRECTORY);
else else
{ {
File dev = vfs->Open("/dev"); RefNode *dev = vfs->Open("/dev");
if (dev.GetFlags() != NodeFlags::DIRECTORY) if (dev->GetNode()->Flags != NodeFlags::DIRECTORY)
{ {
KPrint("\eE85230/dev is not a directory! Halting..."); KPrint("\eE85230/dev is not a directory! Halting...");
CPU::Stop(); CPU::Stop();
} }
vfs->Close(dev); DevFS = dev->GetNode();
DevFS = dev.GetNode(); delete dev;
} }
if (!vfs->PathExists("/mnt")) if (!vfs->PathExists("/mnt"))
MntFS = vfs->Create("/mnt", NodeFlags::DIRECTORY); MntFS = vfs->Create("/mnt", NodeFlags::DIRECTORY);
else else
{ {
File mnt = vfs->Open("/mnt"); RefNode *mnt = vfs->Open("/mnt");
if (mnt.GetFlags() != NodeFlags::DIRECTORY) if (mnt->GetNode()->Flags != NodeFlags::DIRECTORY)
{ {
KPrint("\eE85230/mnt is not a directory! Halting..."); KPrint("\eE85230/mnt is not a directory! Halting...");
CPU::Stop(); CPU::Stop();
} }
vfs->Close(mnt); MntFS = mnt->GetNode();
MntFS = mnt.GetNode(); delete mnt;
} }
if (!vfs->PathExists("/proc")) if (!vfs->PathExists("/proc"))
ProcFS = vfs->Create("/proc", NodeFlags::DIRECTORY); ProcFS = vfs->Create("/proc", NodeFlags::DIRECTORY);
else else
{ {
File proc = vfs->Open("/proc", nullptr); RefNode *proc = vfs->Open("/proc", nullptr);
if (proc.GetFlags() != NodeFlags::DIRECTORY) if (proc->GetNode()->Flags != NodeFlags::DIRECTORY)
{ {
KPrint("\eE85230/proc is not a directory! Halting..."); KPrint("\eE85230/proc is not a directory! Halting...");
CPU::Stop(); CPU::Stop();
} }
vfs->Close(proc); ProcFS = proc->GetNode();
ProcFS = proc.GetNode(); delete proc;
} }
if (!vfs->PathExists("/var")) if (!vfs->PathExists("/var"))
VarLogFS = vfs->Create("/var", NodeFlags::DIRECTORY); VarLogFS = vfs->Create("/var", NodeFlags::DIRECTORY);
else else
{ {
File var = vfs->Open("/var", nullptr); RefNode *var = vfs->Open("/var", nullptr);
if (var.GetFlags() != NodeFlags::DIRECTORY) if (var->GetNode()->Flags != NodeFlags::DIRECTORY)
{ {
KPrint("\eE85230/var is not a directory! Halting..."); KPrint("\eE85230/var is not a directory! Halting...");
CPU::Stop(); CPU::Stop();
} }
vfs->Close(var); VarLogFS = var->GetNode();
VarLogFS = var.GetNode(); delete var;
if (!vfs->PathExists("/var/log")) if (!vfs->PathExists("/var/log"))
VarLogFS = vfs->Create("/var/log", NodeFlags::DIRECTORY); VarLogFS = vfs->Create("/var/log", NodeFlags::DIRECTORY);
else else
{ {
File var_log = vfs->Open("/var/log", nullptr); RefNode *var_log = vfs->Open("/var/log", nullptr);
if (var_log.GetFlags() != NodeFlags::DIRECTORY) if (var_log->GetNode()->Flags != NodeFlags::DIRECTORY)
{ {
KPrint("\eE85230/var/log is not a directory! Halting..."); KPrint("\eE85230/var/log is not a directory! Halting...");
CPU::Stop(); CPU::Stop();
} }
vfs->Close(var_log); VarLogFS = var_log->GetNode();
VarLogFS = var_log.GetNode(); delete var_log;
} }
} }
KPrint("\e058C19################################"); KPrint("\e058C19################################");
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread); TaskManager = new Tasking::Task(Tasking::IP(KernelMainThread));
CPU::Halt(true); CPU::Halt(true);
} }
@ -573,14 +575,16 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info)
* memory management to be initialized first. * memory management to be initialized first.
*/ */
TestString(); TestString();
Test_std();
TestMemoryAllocation(); TestMemoryAllocation();
#endif #endif
EnableProfiler = true; EnableProfiler = true;
Main(); Main();
} }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
extern "C" void __cxa_finalize(void *);
EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot) EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
{ {
UNUSED(Reboot); UNUSED(Reboot);
@ -588,9 +592,6 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
trace("\n\n\n#################### SYSTEM SHUTTING DOWN ####################\n\n"); trace("\n\n\n#################### SYSTEM SHUTTING DOWN ####################\n\n");
if (RecoveryScreen)
delete RecoveryScreen, RecoveryScreen = nullptr;
if (NIManager) if (NIManager)
delete NIManager, NIManager = nullptr; delete NIManager, NIManager = nullptr;
@ -620,8 +621,10 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
debug("Calling destructors..."); debug("Calling destructors...");
for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++) for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++)
(*func)(); (*func)();
__cxa_finalize(nullptr);
debug("Done."); debug("Done.");
} }
#pragma GCC diagnostic pop
EXTERNC void TaskingPanic() EXTERNC void TaskingPanic()
{ {

View File

@ -27,245 +27,249 @@
// TODO: Implement proper fprintf // TODO: Implement proper fprintf
EXTERNC void fprintf(FILE *stream, const char *Format, ...) EXTERNC void fprintf(FILE *stream, const char *Format, ...)
{ {
va_list args; va_list args;
va_start(args, Format); va_start(args, Format);
vprintf(Format, args); vprintf(Format, args);
va_end(args); va_end(args);
UNUSED(stream); UNUSED(stream);
} }
// TODO: Implement proper fputs // TODO: Implement proper fputs
EXTERNC void fputs(const char *s, FILE *stream) EXTERNC void fputs(const char *s, FILE *stream)
{ {
printf("%s", s); printf("%s", s);
UNUSED(stream); UNUSED(stream);
} }
static struct cag_option ConfigOptions[] = { static struct cag_option ConfigOptions[] = {
{.identifier = 'a', {.identifier = 'a',
.access_letters = "aA", .access_letters = "aA",
.access_name = "alloc", .access_name = "alloc",
.value_name = "TYPE", .value_name = "TYPE",
.description = "Memory allocator to use"}, .description = "Memory allocator to use"},
{.identifier = 'c', {.identifier = 'c',
.access_letters = "cC", .access_letters = "cC",
.access_name = "cores", .access_name = "cores",
.value_name = "VALUE", .value_name = "VALUE",
.description = "Number of cores to use (0 = all; 1 is the first code, not 0)"}, .description = "Number of cores to use (0 = all; 1 is the first code, not 0)"},
{.identifier = 'p', {.identifier = 'p',
.access_letters = "pP", .access_letters = "pP",
.access_name = "ioapicirq", .access_name = "ioapicirq",
.value_name = "VALUE", .value_name = "VALUE",
.description = "Which core will be used for I/O APIC interrupts"}, .description = "Which core will be used for I/O APIC interrupts"},
{.identifier = 't', {.identifier = 't',
.access_letters = "tT", .access_letters = "tT",
.access_name = "tasking", .access_name = "tasking",
.value_name = "MODE", .value_name = "MODE",
.description = "Tasking mode (multi, single)"}, .description = "Tasking mode (multi, single)"},
{.identifier = 'd', {.identifier = 'd',
.access_letters = "dD", .access_letters = "dD",
.access_name = "drvdir", .access_name = "drvdir",
.value_name = "PATH", .value_name = "PATH",
.description = "Directory to load drivers from"}, .description = "Directory to load drivers from"},
{.identifier = 'i', {.identifier = 'i',
.access_letters = "iI", .access_letters = "iI",
.access_name = "init", .access_name = "init",
.value_name = "PATH", .value_name = "PATH",
.description = "Path to init program"}, .description = "Path to init program"},
{.identifier = 'l', {.identifier = 'y',
.access_letters = NULL, .access_letters = "yY",
.access_name = "udl", .access_name = "linux",
.value_name = "BOOL", .value_name = "BOOL",
.description = "Unlock the deadlock after 10 retries"}, .description = "Use Linux syscalls by default"},
{.identifier = 'o', {.identifier = 'l',
.access_letters = NULL, .access_letters = NULL,
.access_name = "ioc", .access_name = "udl",
.value_name = "BOOL", .value_name = "BOOL",
.description = "Enable Interrupts On Crash. If enabled, the navigation keys will be enabled on crash"}, .description = "Unlock the deadlock after 10 retries"},
{.identifier = 's', {.identifier = 'o',
.access_letters = NULL, .access_letters = NULL,
.access_name = "simd", .access_name = "ioc",
.value_name = "BOOL", .value_name = "BOOL",
.description = "Enable SIMD instructions"}, .description = "Enable Interrupts On Crash. If enabled, the navigation keys will be enabled on crash"},
{.identifier = 'b', {.identifier = 's',
.access_letters = NULL, .access_letters = NULL,
.access_name = "bootanim", .access_name = "simd",
.value_name = "BOOL", .value_name = "BOOL",
.description = "Enable boot animation"}, .description = "Enable SIMD instructions"},
{.identifier = 'h', {.identifier = 'b',
.access_letters = "h", .access_letters = NULL,
.access_name = "help", .access_name = "bootanim",
.value_name = NULL, .value_name = "BOOL",
.description = "Show help on screen and halt"}}; .description = "Enable boot animation"},
{.identifier = 'h',
.access_letters = "h",
.access_name = "help",
.value_name = NULL,
.description = "Show help on screen and halt"}};
void ParseConfig(char *ConfigString, KernelConfig *ModConfig) void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
{ {
if (ConfigString == NULL) if (ConfigString == NULL ||
{ strlen(ConfigString) == 0)
KPrint("Empty kernel parameters!"); {
return; KPrint("Empty kernel parameters!");
} return;
else if (strlen(ConfigString) == 0) }
{
KPrint("Empty kernel parameters!");
return;
}
if (ModConfig == NULL) if (ModConfig == NULL)
{ {
KPrint("ModConfig is NULL!"); KPrint("ModConfig is NULL!");
return; return;
} }
KPrint("Kernel parameters: %s", ConfigString); KPrint("Kernel parameters: %s", ConfigString);
debug("Kernel parameters: %s", ConfigString); debug("Kernel parameters: %s", ConfigString);
char *argv[32]; char *argv[32];
int argc = 0; int argc = 0;
/* Not sure if the quotes are being parsed correctly. */ /* Not sure if the quotes are being parsed correctly. */
targp_parse(ConfigString, argv, &argc); targp_parse(ConfigString, argv, &argc);
#ifdef DEBUG #ifdef DEBUG
for (int i = 0; i < argc; i++) for (int i = 0; i < argc; i++)
debug("argv[%d] = %s", i, argv[i]); debug("argv[%d] = %s", i, argv[i]);
debug("argc = %d", argc); debug("argc = %d", argc);
#endif #endif
char identifier; char identifier;
const char *value; const char *value;
cag_option_context context; cag_option_context context;
cag_option_prepare(&context, ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), argc, argv); cag_option_prepare(&context, ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), argc, argv);
while (cag_option_fetch(&context)) while (cag_option_fetch(&context))
{ {
identifier = cag_option_get(&context); identifier = cag_option_get(&context);
switch (identifier) switch (identifier)
{ {
case 'a': case 'a':
{ {
value = cag_option_get_value(&context); value = cag_option_get_value(&context);
if (strcmp(value, "xallocv1") == 0) if (strcmp(value, "xallocv1") == 0)
{ {
KPrint("\eAAFFAAUsing XallocV1 as memory allocator"); KPrint("\eAAFFAAUsing XallocV1 as memory allocator");
ModConfig->AllocatorType = Memory::MemoryAllocatorType::XallocV1; ModConfig->AllocatorType = Memory::MemoryAllocatorType::XallocV1;
} }
else if (strcmp(value, "liballoc11") == 0) else if (strcmp(value, "liballoc11") == 0)
{ {
KPrint("\eAAFFAAUsing Liballoc11 as memory allocator"); KPrint("\eAAFFAAUsing Liballoc11 as memory allocator");
ModConfig->AllocatorType = Memory::MemoryAllocatorType::liballoc11; ModConfig->AllocatorType = Memory::MemoryAllocatorType::liballoc11;
} }
else if (strcmp(value, "pages") == 0) else if (strcmp(value, "pages") == 0)
{ {
KPrint("\eAAFFAAUsing Pages as memory allocator"); KPrint("\eAAFFAAUsing Pages as memory allocator");
ModConfig->AllocatorType = Memory::MemoryAllocatorType::Pages; ModConfig->AllocatorType = Memory::MemoryAllocatorType::Pages;
} }
else break;
{ }
KPrint("\eAAFFAAUnknown memory allocator: %s", value); case 'c':
ModConfig->AllocatorType = Memory::MemoryAllocatorType::None; {
} value = cag_option_get_value(&context);
break; KPrint("\eAAFFAAUsing %s cores", atoi(value) ? value : "all");
} ModConfig->Cores = atoi(value);
case 'c': break;
{ }
value = cag_option_get_value(&context); case 'p':
KPrint("\eAAFFAAUsing %s cores", atoi(value) ? value : "all"); {
ModConfig->Cores = atoi(value); value = cag_option_get_value(&context);
break; KPrint("\eAAFFAARedirecting I/O APIC interrupts to %s%s", atoi(value) ? "core " : "", atoi(value) ? value : "BSP");
} ModConfig->IOAPICInterruptCore = atoi(value);
case 'p': break;
{ }
value = cag_option_get_value(&context); case 't':
KPrint("\eAAFFAARedirecting I/O APIC interrupts to %s%s", atoi(value) ? "core " : "", atoi(value) ? value : "BSP"); {
ModConfig->IOAPICInterruptCore = atoi(value); value = cag_option_get_value(&context);
break; if (strcmp(value, "multi") == 0)
} {
case 't': KPrint("\eAAFFAAUsing Multi-Tasking Scheduler");
{ ModConfig->SchedulerType = Multi;
value = cag_option_get_value(&context); }
if (strcmp(value, "multi") == 0) else if (strcmp(value, "single") == 0)
{ {
KPrint("\eAAFFAAUsing Multi-Tasking Scheduler"); KPrint("\eAAFFAAUsing Single-Tasking Scheduler");
ModConfig->SchedulerType = 1; ModConfig->SchedulerType = Mono;
} }
else if (strcmp(value, "single") == 0) else
{ {
KPrint("\eAAFFAAUsing Single-Tasking Scheduler"); KPrint("\eAAFFAAUnknown scheduler: %s", value);
ModConfig->SchedulerType = 0; ModConfig->SchedulerType = Multi;
} }
else break;
{ }
KPrint("\eAAFFAAUnknown scheduler: %s", value); case 'd':
ModConfig->SchedulerType = 1; {
} value = cag_option_get_value(&context);
break; strncpy(ModConfig->DriverDirectory, value, strlen(value));
} KPrint("\eAAFFAAUsing %s as driver directory", value);
case 'd': break;
{ }
value = cag_option_get_value(&context); case 'i':
strncpy(ModConfig->DriverDirectory, value, strlen(value)); {
KPrint("\eAAFFAAUsing %s as driver directory", value); value = cag_option_get_value(&context);
break; strncpy(ModConfig->InitPath, value, strlen(value));
} KPrint("\eAAFFAAUsing %s as init program", value);
case 'i': break;
{ }
value = cag_option_get_value(&context); case 'y':
strncpy(ModConfig->InitPath, value, strlen(value)); {
KPrint("\eAAFFAAUsing %s as init program", value); value = cag_option_get_value(&context);
break; strcmp(value, "true") == 0 ? ModConfig->UseLinuxSyscalls = true : ModConfig->UseLinuxSyscalls = false;
} KPrint("\eAAFFAAUse Linux syscalls by default: %s", value);
case 'o': break;
{ }
value = cag_option_get_value(&context); case 'o':
strcmp(value, "true") == 0 ? ModConfig->InterruptsOnCrash = true : ModConfig->InterruptsOnCrash = false; {
KPrint("\eAAFFAAInterrupts on crash: %s", value); value = cag_option_get_value(&context);
break; strcmp(value, "true") == 0 ? ModConfig->InterruptsOnCrash = true : ModConfig->InterruptsOnCrash = false;
} KPrint("\eAAFFAAInterrupts on crash: %s", value);
case 'l': break;
{ }
value = cag_option_get_value(&context); case 'l':
strcmp(value, "true") == 0 ? ModConfig->UnlockDeadLock = true : ModConfig->UnlockDeadLock = false; {
KPrint("\eAAFFAAUnlocking the deadlock after 10 retries"); value = cag_option_get_value(&context);
break; strcmp(value, "true") == 0 ? ModConfig->UnlockDeadLock = true : ModConfig->UnlockDeadLock = false;
} KPrint("\eAAFFAAUnlocking the deadlock after 10 retries");
case 's': break;
{ }
value = cag_option_get_value(&context); case 's':
strcmp(value, "true") == 0 ? ModConfig->SIMD = true : ModConfig->SIMD = false; {
KPrint("\eAAFFAASingle Instruction, Multiple Data (SIMD): %s", value); value = cag_option_get_value(&context);
break; strcmp(value, "true") == 0 ? ModConfig->SIMD = true : ModConfig->SIMD = false;
} KPrint("\eAAFFAASingle Instruction, Multiple Data (SIMD): %s", value);
case 'b': break;
{ }
value = cag_option_get_value(&context); case 'b':
strcmp(value, "true") == 0 ? ModConfig->BootAnimation = true : ModConfig->BootAnimation = false; {
KPrint("\eAAFFAABoot animation: %s", value); value = cag_option_get_value(&context);
break; strcmp(value, "true") == 0 ? ModConfig->BootAnimation = true : ModConfig->BootAnimation = false;
} KPrint("\eAAFFAABoot animation: %s", value);
case 'h': break;
{ }
KPrint("\n---------------------------------------------------------------------------\nUsage: kernel.fsys [OPTION]...\nKernel configuration."); case 'h':
cag_option_print(ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), nullptr); {
KPrint("\eFF2200System Halted."); KPrint("\n---------------------------------------------------------------------------\nUsage: kernel.fsys [OPTION]...\nKernel configuration.");
CPU::Stop(); cag_option_print(ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), nullptr);
} KPrint("\eFF2200System Halted.");
default: CPU::Stop();
{ }
KPrint("\eFF2200Unknown option: %c", identifier); default:
break; {
} KPrint("\eFF2200Unknown option: %c", identifier);
} break;
} }
debug("Config loaded"); }
}
debug("Config loaded");
} }

View File

@ -0,0 +1,55 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_cat(const char *args)
{
if (args[0] == '\0')
return;
Node *thisNode = vfs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory);
if (thisNode == nullptr)
{
printf("cat: %s: No such file or directory\n", args);
return;
}
if (thisNode->Flags != NodeFlags::FILE &&
thisNode->Flags != NodeFlags::CHARDEVICE)
{
printf("cat: %s: Not a file\n", args);
return;
}
std::string path = vfs->GetPathFromNode(thisNode);
int fd = fopen(path.c_str(), "r");
struct stat st;
fstat(fd, &st);
char *buffer = new char[st.st_size + 1];
fread(fd, buffer, st.st_size);
printf("%s\n", buffer);
delete[] buffer;
fclose(fd);
}

View File

@ -0,0 +1,46 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_cd(const char *args)
{
if (args[0] == '\0')
return;
Node *thisNode = vfs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory);
if (thisNode == nullptr)
{
printf("cd: %s: No such file or directory\n", args);
return;
}
if (thisNode->Flags != NodeFlags::DIRECTORY)
{
printf("cd: %s: Not a directory\n", args);
return;
}
thisProcess->CurrentWorkingDirectory = thisNode;
}

View File

@ -15,10 +15,11 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <kshell.hpp> #include "../cmds.hpp"
#include <debug.h>
void StartKernelShell() #include "../../kernel.h"
void cmd_echo(const char *args)
{ {
stub; printf("%s\n", args);
} }

View File

@ -15,27 +15,19 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __FENNIX_KERNEL_RECOVERY_H__ #include "../cmds.hpp"
#define __FENNIX_KERNEL_RECOVERY_H__
#include <types.h> #include <filesystem.hpp>
#include <memory.hpp>
#include <task.hpp> #include <task.hpp>
namespace Recovery #include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_exit(const char *)
{ {
class KernelRecovery KernelShutdownThread(false);
{ // TaskManager->KillThread(thisThread, KILL_SUCCESS);
private: CPU::Halt(true);
Memory::MemMgr *mem;
Tasking::TCB *guiThread;
Tasking::TCB *recoveryThread;
public:
void RecoveryThread();
KernelRecovery();
~KernelRecovery();
};
} }
#endif // !__FENNIX_KERNEL_RECOVERY_H__

View File

@ -15,20 +15,25 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __FENNIX_KERNEL_ICONS_AND_FONTS_H__ #include "../cmds.hpp"
#define __FENNIX_KERNEL_ICONS_AND_FONTS_H__
#include <types.h> #include <filesystem.hpp>
#include <task.hpp>
extern char CursorArrow[]; #include "../../kernel.h"
extern char CursorHand[];
extern char CursorWait[];
extern char CursorIBeam[];
extern char CursorResizeAll[];
extern char CloseButton[];
extern char MinimizeButton[];
extern char MaximizeButtonNormal[];
extern char MaximizeButtonMaximized[];
extern char ResizeHint[];
#endif // !__FENNIX_KERNEL_ICONS_AND_FONTS_H__ using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_kill(const char *args)
{
PID pid = atoi(args);
PCB *pcb = TaskManager->GetProcessByID(pid);
if (pcb == nullptr)
{
printf("No process with PID %d\n", pid);
return;
}
TaskManager->KillProcess(pcb, KILL_BY_OTHER_PROCESS);
}

View File

@ -0,0 +1,37 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_killall(const char *args)
{
foreach (auto Proc in TaskManager->GetProcessList())
{
if (strcmp(Proc->Name, args) == 0)
{
TaskManager->KillProcess(Proc, KILL_BY_OTHER_PROCESS);
}
}
}

View File

@ -0,0 +1,57 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_ls(const char *args)
{
if (args[0] == '\0')
{
Node *rootNode = thisProcess->CurrentWorkingDirectory;
if (rootNode == nullptr)
rootNode = vfs->GetRootNode()->Children[0];
foreach (auto var in rootNode->Children)
printf("%s\n", var->Name);
}
else
{
Node *thisNode = vfs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory);
if (thisNode == nullptr)
{
printf("ls: %s: No such file or directory\n", args);
return;
}
if (thisNode->Flags != NodeFlags::DIRECTORY)
{
printf("%s\n", thisNode->Name);
return;
}
foreach (auto var in thisNode->Children)
printf("%s\n", var->Name);
}
}

View File

@ -0,0 +1,35 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include "../../kernel.h"
void cmd_lsof(const char *)
{
printf("PROCESS FD NAME\n");
foreach (auto Proc in TaskManager->GetProcessList())
{
if (!Proc)
continue;
std::vector<VirtualFileSystem::FileDescriptorTable::FileDescriptor> fds_array = Proc->FileDescriptors->GetFileDescriptors();
foreach (auto fd in fds_array)
printf("%s %d: %s\n", Proc->Name, fd.Descriptor,
fd.Handle->AbsolutePath.c_str());
}
}

View File

@ -0,0 +1,41 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_lspci(const char *)
{
foreach (auto Device in PCIManager->GetDevices())
{
printf("%02x:%02x.%d: %s: %s %s %s\n",
// Device->Bus,
// Device->Device,
// Device->Function,
// FIXME
0, 0, 0,
PCI::Descriptors::BridgeDeviceSubclassName(Device->Subclass),
PCI::Descriptors::GetVendorName(Device->VendorID),
PCI::Descriptors::GetDeviceName(Device->VendorID, Device->DeviceID),
PCI::Descriptors::GetSubclassName(Device->Class, Device->Subclass));
}
}

View File

@ -0,0 +1,64 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_mem(const char *)
{
uint64_t total = KernelAllocator.GetTotalMemory();
uint64_t used = KernelAllocator.GetUsedMemory();
uint64_t free = KernelAllocator.GetFreeMemory();
uint64_t reserved = KernelAllocator.GetReservedMemory();
int usedPercent = (int)((used * 100) / total);
int usedBar = (int)(usedPercent / 2);
int reservedPercent = (int)((reserved * 100) / total);
int reservedBar = (int)(reservedPercent / 2);
printf("[");
for (int i = 0; i < usedBar; i++)
printf("=");
for (int i = 0; i < 50 - usedBar; i++)
printf(" ");
printf("] %d%% Used\n", usedPercent);
printf("[");
for (int i = 0; i < reservedBar; i++)
printf("=");
for (int i = 0; i < 50 - reservedBar; i++)
printf(" ");
printf("] %d%% Reserved\n", reservedPercent);
// printf("Total: %d MiB\n", (int)(TO_MiB(total)));
// printf("Used: %d MiB\n", (int)(TO_MiB(used)));
// printf("Free: %d MiB\n", (int)(TO_MiB(free)));
// printf("Reserved: %d MiB\n", (int)(TO_MiB(reserved)));
printf("TOTAL USED FREE RESERVED\n");
printf("%d MiB %d MiB %d MiB %d MiB\n",
(int)(TO_MiB(total)), (int)(TO_MiB(used)),
(int)(TO_MiB(free)), (int)(TO_MiB(reserved)));
}

View File

@ -0,0 +1,33 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_ps(const char *)
{
printf("PID Name\n");
foreach (auto p in TaskManager->GetProcessList())
printf("%d %s\n", p->ID, p->Name);
}

View File

@ -0,0 +1,32 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_reboot(const char *)
{
KernelShutdownThread(true);
CPU::Halt(true);
}

View File

@ -0,0 +1,32 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_shutdown(const char *)
{
KernelShutdownThread(false);
CPU::Halt(true);
}

View File

@ -0,0 +1,46 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_top(const char *)
{
printf("\e9400A1PID \e9CA100Name \e00A15BState \eCCCCCCPriority Memory Usage CPU Usage\n");
foreach (auto Proc in TaskManager->GetProcessList())
{
printf("\e9400A1%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld %ld\n",
Proc->ID, Proc->Name, Proc->Status == Running ? "Running" : "Stopped",
Proc->Info.Priority, Proc->Memory->GetAllocatedMemorySize(),
Proc->Info.UserTime + Proc->Info.KernelTime);
foreach (auto Thrd in Proc->Threads)
{
printf(" \eA80011%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld %ld\n",
Thrd->ID, Thrd->Name, Thrd->Status == Running ? "Running" : "Stopped",
Thrd->Info.Priority, Thrd->Memory->GetAllocatedMemorySize(),
Thrd->Info.UserTime + Thrd->Info.KernelTime);
}
}
}

View File

@ -0,0 +1,65 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_uname(const char *args)
{
if (args)
{
if (strcmp(args, "-a") == 0)
{
printf("Fennix Kernel %s %s %s %s\n",
KERNEL_VERSION, KERNEL_NAME, __DATE__,
KERNEL_ARCH);
}
else if (strcmp(args, "-s") == 0)
{
printf("%s\n", KERNEL_NAME);
}
else if (strcmp(args, "-v") == 0)
{
printf("%s\n", KERNEL_VERSION);
}
else if (strcmp(args, "-n") == 0)
{
printf("unknown\n");
}
else if (strcmp(args, "-r") == 0)
{
printf("%s\n", KERNEL_NAME);
}
else if (strcmp(args, "-m") == 0)
{
printf("%s\n", KERNEL_ARCH);
}
else
{
printf("uname: invalid option: %s\n", args);
}
}
else
{
printf("Fennix Kernel\n");
}
}

View File

@ -0,0 +1,51 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_uptime(const char *)
{
if (TimeManager)
{
size_t Nanoseconds =
TimeManager->GetNanosecondsSinceClassCreation();
size_t Seconds = Nanoseconds / 10000000;
size_t Minutes = Seconds / 60;
size_t Hours = Minutes / 60;
size_t Days = Hours / 24;
debug("Nanoseconds: %ld", Nanoseconds);
Seconds %= 60;
Minutes %= 60;
Hours %= 24;
printf("%ld days, %ld hours, %ld minutes, %ld %s\n",
Days, Hours, Minutes, Seconds,
Seconds == 1 ? "second" : "seconds");
}
else
{
printf("Could not get uptime\n");
}
}

View File

@ -0,0 +1,29 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_whoami(const char *)
{
printf("kernel\n");
}

422
KernelShell/Shell.cpp Normal file
View File

@ -0,0 +1,422 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <kshell.hpp>
#include <filesystem.hpp>
#include <driver.hpp>
#include <lock.hpp>
#include <debug.h>
#include "../Modules/PersonalSystem2/keyboard.hpp"
#include "../kernel.h"
#include "../Fex.hpp"
#include "../DAPI.hpp"
#include "cmds.hpp"
using namespace PS2Keyboard;
NewLock(ShellLock);
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;
char GetLetterFromScanCode(uint8_t ScanCode)
{
if (ScanCode & 0x80)
{
switch (ScanCode)
{
case KEY_U_LSHIFT:
LowerCase = true;
return 0;
case KEY_U_RSHIFT:
LowerCase = true;
return 0;
default:
return 0;
}
}
else
{
switch (ScanCode)
{
case KEY_D_RETURN:
return '\n';
case KEY_D_LSHIFT:
LowerCase = false;
return 0;
case KEY_D_RSHIFT:
LowerCase = false;
return 0;
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 0;
}
int GetChar()
{
return 0;
}
struct Command
{
const char *Name;
void (*Function)(const char *);
};
static Command commands[] = {
{"lsof", cmd_lsof},
{"ls", cmd_ls},
{"cd", cmd_cd},
{"cat", cmd_cat},
{"echo", cmd_echo},
{"mkdir", nullptr},
{"touch", nullptr},
{"rm", nullptr},
{"rmdir", nullptr},
{"mv", nullptr},
{"cp", nullptr},
{"clear", nullptr},
{"help", nullptr},
{"exit", cmd_exit},
{"reboot", cmd_reboot},
{"shutdown", cmd_shutdown},
{"ps", cmd_ps},
{"kill", cmd_kill},
{"killall", cmd_killall},
{"top", cmd_top},
{"mem", cmd_mem},
{"mount", nullptr},
{"umount", nullptr},
{"uname", cmd_uname},
{"whoami", cmd_whoami},
{"passwd", nullptr},
{"su", nullptr},
{"login", nullptr},
{"logout", nullptr},
{"uptime", cmd_uptime},
{"chown", nullptr},
{"chgrp", nullptr},
{"chmod", nullptr},
{"chroot", nullptr},
{"lspci", cmd_lspci}};
void StartKernelShell()
{
SmartLock(ShellLock);
debug("Starting kernel shell...");
printf("Starting kernel shell...\n");
thisThread->SetPriority(Tasking::TaskPriority::High);
Display->SetBuffer(0);
Driver::DriverFile KeyboardModule;
if (likely(DriverManager->GetDrivers().size() > 0))
{
foreach (auto Driver in DriverManager->GetDrivers())
{
if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Input &&
((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.TypeFlags & FexDriverInputTypes::FexDriverInputTypes_Keyboard)
{
KeyboardModule = Driver;
printf("Using driver \eCA21F6%s\eCCCCCC for keyboard input.\n",
((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Name);
break;
}
}
}
Display->SetBuffer(0);
std::string Buffer;
std::vector<std::string *> History;
size_t HistoryIndex = 0;
bool CtrlDown = false;
bool TabDoublePress = false;
while (true)
{
size_t BackspaceCount = 0;
Buffer.clear();
VirtualFileSystem::Node *cwd = thisProcess->CurrentWorkingDirectory;
if (!cwd)
cwd = vfs->GetNodeFromPath("/");
printf("\e34C6EB%s@%s:%s$ \eCCCCCC",
"kernel",
"fennix",
cwd->FileSystem->GetPathFromNode(cwd).c_str());
Display->SetBuffer(0);
while (true)
{
KernelCallback callback{};
callback.Reason = PollWaitReason;
DriverManager->IOCB(KeyboardModule.DriverUID, &callback);
char c = GetLetterFromScanCode(callback.InputCallback.Keyboard.Key);
switch (callback.InputCallback.Keyboard.Key)
{
case KEY_D_LCTRL:
{
CtrlDown = true;
continue;
}
case KEY_U_LCTRL:
{
CtrlDown = false;
continue;
}
case KEY_D_BACKSPACE:
{
if (BackspaceCount == 0)
continue;
Display->Print('\b', 0);
Buffer.pop_back();
BackspaceCount--;
Display->SetBuffer(0);
continue;
}
case KEY_D_UP:
{
if (History.size() == 0 ||
HistoryIndex == 0)
continue;
HistoryIndex--;
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
Display->SetBuffer(0);
Buffer = History[HistoryIndex]->c_str();
for (size_t i = 0; i < strlen(Buffer.c_str()); i++)
Display->Print(Buffer[i], 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
continue;
}
case KEY_D_DOWN:
{
if (History.size() == 0 ||
HistoryIndex == History.size())
continue;
if (HistoryIndex == History.size() - 1)
{
HistoryIndex++;
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
continue;
}
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
Display->SetBuffer(0);
HistoryIndex++;
Buffer = History[HistoryIndex]->c_str();
for (size_t i = 0; i < strlen(Buffer.c_str()); i++)
Display->Print(Buffer[i], 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
continue;
}
case KEY_D_TAB:
{
if (!TabDoublePress)
{
TabDoublePress = true;
continue;
}
TabDoublePress = false;
if (Buffer.size() == 0)
{
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
{
printf("%s ", commands[i].Name);
Display->SetBuffer(0);
}
Display->Print('\n', 0);
Display->SetBuffer(0);
goto SecLoopEnd;
}
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
Display->SetBuffer(0);
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
{
if (strncmp(Buffer.c_str(), commands[i].Name, Buffer.size()) == 0)
{
Buffer = commands[i].Name;
for (size_t i = 0; i < strlen(Buffer.c_str()); i++)
Display->Print(Buffer[i], 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
break;
}
}
continue;
}
default:
break;
}
if (c == 0)
continue;
if (CtrlDown)
{
switch (std::toupper((char)c))
{
case 'C':
{
Display->Print('^', 0);
Display->Print('C', 0);
Display->Print('\n', 0);
fixme("No SIGINT handler yet.");
Display->SetBuffer(0);
goto SecLoopEnd;
}
case 'D':
{
Display->Print('^', 0);
Display->Print('D', 0);
Display->Print('\n', 0);
fixme("No SIGKILL handler yet.");
Display->SetBuffer(0);
goto SecLoopEnd;
}
default:
continue;
}
}
Display->Print(c, 0);
if (c == '\n')
{
if (Buffer.length() > 0)
{
std::string *hBuff = new std::string(Buffer.c_str());
History.push_back(hBuff);
HistoryIndex = History.size();
}
break;
}
Buffer += c;
BackspaceCount++;
Display->SetBuffer(0);
}
SecLoopEnd:
if (Buffer.length() == 0)
continue;
bool Found = false;
for (size_t i = 0; i < sizeof(commands) / sizeof(Command); i++)
{
std::string cmd_extracted;
for (size_t i = 0; i < Buffer.length(); i++)
{
if (Buffer[i] == ' ')
break;
cmd_extracted += Buffer[i];
}
debug("cmd: %s, array[%d]: %s", cmd_extracted.c_str(), i, commands[i].Name);
if (strncmp(commands[i].Name, cmd_extracted.c_str(), cmd_extracted.size()) == 0)
{
if (strlen(commands[i].Name) != cmd_extracted.size())
continue;
Found = true;
std::string arg_only;
const char *cmd_name = commands[i].Name;
for (size_t i = strlen(cmd_name) + 1; i < Buffer.length(); i++)
arg_only += Buffer[i];
if (commands[i].Function)
commands[i].Function(arg_only.c_str());
else
{
std::string cmd_only;
for (size_t i = 0; i < Buffer.length(); i++)
{
if (Buffer[i] == ' ')
break;
cmd_only += Buffer[i];
}
printf("%s: command not implemented\n",
cmd_only.c_str());
}
break;
}
}
if (!Found)
{
std::string cmd_only;
for (size_t i = 0; i < Buffer.length(); i++)
{
if (Buffer[i] == ' ')
break;
cmd_only += Buffer[i];
}
printf("%s: command not found\n",
cmd_only.c_str());
}
}
}
void KShellThread()
{
StartKernelShell();
inf_loop;
}

View File

@ -15,36 +15,27 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __FENNIX_KERNEL_SHELL_CMDS_H__
#define __FENNIX_KERNEL_SHELL_CMDS_H__
#include <types.h> #include <types.h>
#include "../syscalls.h" void cmd_lsof(const char *args);
void cmd_echo(const char *args);
void cmd_ls(const char *args);
void cmd_cd(const char *args);
void cmd_cat(const char *args);
void cmd_ps(const char *args);
void cmd_uptime(const char *args);
void cmd_whoami(const char *args);
void cmd_uname(const char *args);
void cmd_mem(const char *args);
void cmd_kill(const char *args);
void cmd_killall(const char *args);
void cmd_top(const char *args);
void cmd_exit(const char *args);
void cmd_shutdown(const char *args);
void cmd_reboot(const char *args);
void cmd_lspci(const char *args);
#ifdef DEBUG #endif // !__FENNIX_KERNEL_SHELL_CMDS_H__
__aligned(0x1000) __no_stack_protector void TestSyscalls()
{
#if defined(a64)
__asm__ __volatile__("syscall"
:
: "a"(_Print), "D"('H'), "S"(0)
: "rcx", "r11", "memory");
int fork_id = -0xda;
__asm__ __volatile__("syscall"
: "=a"(fork_id)
: "a"(_Fork)
: "rcx", "r11", "memory");
__asm__ __volatile__("syscall"
:
: "a"(_Exit), "D"(fork_id)
: "rcx", "r11", "memory");
#elif defined(a32)
#elif defined(aa64)
#endif
while (1)
;
}
#endif

View File

@ -21,13 +21,14 @@
#endif #endif
#include <filesystem/ustar.hpp> #include <filesystem/ustar.hpp>
#include <kshell.hpp>
#include <power.hpp> #include <power.hpp>
#include <lock.hpp> #include <lock.hpp>
#include <printf.h> #include <printf.h>
#include <exec.hpp> #include <exec.hpp>
#include <cwalk.h> #include <cwalk.h>
#include <vm.hpp>
#include <vector> #include <vector>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_STDIO #define STBI_NO_STDIO
#define STBI_NO_LINEAR #define STBI_NO_LINEAR
@ -39,22 +40,17 @@
#include "DAPI.hpp" #include "DAPI.hpp"
#include "Fex.hpp" #include "Fex.hpp"
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node; using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags; using VirtualFileSystem::NodeFlags;
Driver::Driver *DriverManager = nullptr; Driver::Driver *DriverManager = nullptr;
Disk::Manager *DiskManager = nullptr; Disk::Manager *DiskManager = nullptr;
NetworkInterfaceManager::NetworkInterface *NIManager = nullptr; NetworkInterfaceManager::NetworkInterface *NIManager = nullptr;
Recovery::KernelRecovery *RecoveryScreen = nullptr;
VirtualFileSystem::Node *DevFS = nullptr; VirtualFileSystem::Node *DevFS = nullptr;
VirtualFileSystem::Node *MntFS = nullptr; VirtualFileSystem::Node *MntFS = nullptr;
VirtualFileSystem::Node *ProcFS = nullptr; VirtualFileSystem::Node *ProcFS = nullptr;
VirtualFileSystem::Node *VarLogFS = nullptr; VirtualFileSystem::Node *VarLogFS = nullptr;
NewLock(ShutdownLock);
#ifdef DEBUG #ifdef DEBUG
void TreeFS(Node *node, int Depth) void TreeFS(Node *node, int Depth)
{ {
@ -62,6 +58,7 @@ void TreeFS(Node *node, int Depth)
foreach (auto Chld in node->Children) foreach (auto Chld in node->Children)
{ {
printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name); printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name);
if (!Config.BootAnimation) if (!Config.BootAnimation)
Display->SetBuffer(0); Display->SetBuffer(0);
TaskManager->Sleep(100); TaskManager->Sleep(100);
@ -74,8 +71,8 @@ const char *Statuses[] = {
"AAFF00", /* Ready */ "AAFF00", /* Ready */
"00AA00", /* Running */ "00AA00", /* Running */
"FFAA00", /* Sleeping */ "FFAA00", /* Sleeping */
"FFAA00", /* Waiting */ "FFAA00", /* Blocked */
"FF0088", /* Stopped */ "FF0088", /* Zombie */
"FF0000", /* Terminated */ "FF0000", /* Terminated */
}; };
@ -135,14 +132,16 @@ static int ShowTaskManager = 0;
void TaskMgr() void TaskMgr()
{ {
TaskManager->GetCurrentThread()->Rename("Debug Task Manager"); thisThread->Rename("Debug Task Manager");
TaskManager->GetCurrentThread()->SetPriority(Tasking::Low); thisThread->SetPriority(Tasking::Idle);
while (ShowTaskManager == 0) while (ShowTaskManager == 0)
CPU::Pause(); CPU::Pause();
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy100Usage)->Rename("Dummy 100% Usage"); thisThread->SetPriority(Tasking::Idle);
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy0Usage)->Rename("Dummy 0% Usage");
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr_Dummy100Usage))->Rename("Dummy 100% Usage");
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr_Dummy0Usage))->Rename("Dummy 0% Usage");
while (true) while (true)
{ {
@ -169,7 +168,7 @@ void TaskMgr()
{ {
if (!Proc) if (!Proc)
continue; continue;
int Status = Proc->Status; int Status = Proc->Status.load();
uint64_t ProcessCpuUsage = GetUsage(OldSystemTime, &Proc->Info); uint64_t ProcessCpuUsage = GetUsage(OldSystemTime, &Proc->Info);
printf("\e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld)\n", printf("\e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld)\n",
Statuses[Status], Proc->Name, StatusesSign[Status], ProcessCpuUsage, Proc->Info.KernelTime, Proc->Info.UserTime); Statuses[Status], Proc->Name, StatusesSign[Status], ProcessCpuUsage, Proc->Info.KernelTime, Proc->Info.UserTime);
@ -178,7 +177,7 @@ void TaskMgr()
{ {
if (!Thd) if (!Thd)
continue; continue;
Status = Thd->Status; Status = Thd->Status.load();
uint64_t ThreadCpuUsage = GetUsage(OldSystemTime, &Thd->Info); uint64_t ThreadCpuUsage = GetUsage(OldSystemTime, &Thd->Info);
#if defined(a64) #if defined(a64)
printf(" \e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld, IP: \e24FF2B%#lx \eEDFF24%s\e00AAAA)\n\eAABBCC", printf(" \e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld, IP: \e24FF2B%#lx \eEDFF24%s\e00AAAA)\n\eAABBCC",
@ -213,49 +212,87 @@ void TaskMgr()
} }
} }
void TestSyscallsKernel() static int ShowOpenFiles = 0;
void lsof()
{ {
return; thisThread->Rename("Debug File List");
KPrint("Testing syscalls..."); thisThread->SetPriority(Tasking::Idle);
Tasking::PCB *SyscallsTestProcess = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(),
"Syscalls Test",
Tasking::TaskTrustLevel::User,
KernelSymbolTable);
Tasking::TCB *SyscallsTestThread = TaskManager->CreateThread(SyscallsTestProcess, while (ShowOpenFiles == 0)
(Tasking::IP)TestSyscalls, CPU::Pause();
nullptr,
nullptr,
std::vector<AuxiliaryVector>(),
Tasking::TaskArchitecture::x64,
Tasking::TaskCompatibility::Native,
true);
SyscallsTestThread->SetCritical(true);
TaskManager->GetSecurityManager()->TrustToken(SyscallsTestThread->Security.UniqueToken, Tasking::TTL::FullTrust);
Memory::Virtual vmm = Memory::Virtual(SyscallsTestProcess->PageTable); thisThread->SetPriority(Tasking::High);
// vmm.Remap((void *)TestSyscalls, vmm.GetPhysical((void *)TestSyscalls), Memory::P | Memory::RW | Memory::US); vfs->Create("/dummy_lsof_file", NodeFlags::FILE);
fopen("/dummy_lsof_file", "r");
// for (uintptr_t k = (uintptr_t)&_kernel_start; k < (uintptr_t)&_kernel_end; k += PAGE_SIZE) while (true)
// {
// vmm.Remap((void *)k, (void *)vmm.GetPhysical((void *)k), Memory::P | Memory::RW | Memory::US);
// debug("Remapped %#lx %#lx", k, vmm.GetPhysical((void *)k));
// }
for (uintptr_t k = (uintptr_t)TestSyscalls - PAGE_SIZE; k < (uintptr_t)TestSyscalls + FROM_PAGES(5); k += PAGE_SIZE)
{ {
vmm.Remap((void *)k, (void *)vmm.GetPhysical((void *)k), Memory::P | Memory::RW | Memory::US); while (ShowOpenFiles == 0)
debug("Remapped %#lx %#lx", k, vmm.GetPhysical((void *)k)); CPU::Pause();
}
SyscallsTestThread->Status = Tasking::TaskStatus::Ready; Video::ScreenBuffer *sb = Display->GetBuffer(0);
TaskManager->WaitForThread(SyscallsTestThread); for (short i = 0; i < 500; i++)
KPrint("Test complete"); {
for (short j = 0; j < 500; j++)
{
uint32_t *Pixel = (uint32_t *)((uintptr_t)sb->Buffer + (j * sb->Width + i) * (bInfo.Framebuffer[0].BitsPerPixel / 8));
*Pixel = 0x222222;
}
}
uint32_t tmpX, tmpY;
Display->GetBufferCursor(0, &tmpX, &tmpY);
Display->SetBufferCursor(0, 0, 0);
printf("\eF02C21Open Files (%ld):\e00AAAA\n",
TaskManager->GetProcessList().size());
foreach (auto Proc in TaskManager->GetProcessList())
{
if (!Proc)
continue;
printf("%s:\n", Proc->Name);
std::vector<VirtualFileSystem::FileDescriptorTable::FileDescriptor> fds_array = Proc->FileDescriptors->GetFileDescriptors();
foreach (auto fd in fds_array)
printf(" %d: %s\n", fd.Descriptor, fd.Handle->AbsolutePath.c_str());
}
Display->SetBufferCursor(0, tmpX, tmpY);
if (!Config.BootAnimation)
Display->SetBuffer(0);
}
}
#include <mutex>
std::mutex test_mutex;
void mutex_test_long()
{
while (true)
{
test_mutex.lock();
debug("Long Thread %d got mutex",
thisThread->ID);
// TaskManager->Sleep(2000);
test_mutex.unlock();
}
}
void mutex_test()
{
while (true)
{
test_mutex.lock();
debug("Thread %d got mutex",
thisThread->ID);
// TaskManager->Sleep(200);
test_mutex.unlock();
}
} }
#endif #endif
Execute::SpawnData SpawnInit() int SpawnInit()
{ {
const char *envp[5] = { const char *envp[5] = {
"PATH=/bin:/usr/bin", "PATH=/bin:/usr/bin",
@ -284,18 +321,17 @@ void BootLogoAnimationThread()
while (FrameCount < 27) while (FrameCount < 27)
{ {
sprintf(BootAnimPath, "/etc/boot/%ld.tga", FrameCount); sprintf(BootAnimPath, "/etc/boot/%ld.tga", FrameCount);
File ba = vfs->Open(BootAnimPath); RefNode *frame = vfs->Open(BootAnimPath);
if (!ba.IsOK()) if (!frame)
{ {
vfs->Close(ba);
debug("Failed to load boot animation frame %s", BootAnimPath); debug("Failed to load boot animation frame %s", BootAnimPath);
break; break;
} }
FrameSizes[FrameCount] = s_cst(uint32_t, ba.GetLength()); FrameSizes[FrameCount] = s_cst(uint32_t, frame->Length);
Frames[FrameCount] = new uint8_t[ba.GetLength()]; Frames[FrameCount] = new uint8_t[frame->Length];
vfs->Read(ba, Frames[FrameCount], ba.GetLength()); frame->Read(Frames[FrameCount], frame->Length);
vfs->Close(ba); delete frame;
FrameCount++; FrameCount++;
} }
@ -306,10 +342,13 @@ void BootLogoAnimationThread()
{ {
int x, y, channels; int x, y, channels;
if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels)) if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i],
&x, &y, &channels))
continue; continue;
uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, STBI_rgb_alpha); uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i],
FrameSizes[i], &x, &y,
&channels, STBI_rgb_alpha);
if (img == NULL) if (img == NULL)
continue; continue;
@ -332,7 +371,8 @@ void BootLogoAnimationThread()
b = (b * a) / 0xFF; b = (b * a) / 0xFF;
} }
Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1); Display->SetPixel((i % x) + offsetX, (i / x) + offsetY,
(r << 16) | (g << 8) | (b << 0), 1);
} }
free(img); free(img);
@ -359,14 +399,17 @@ void ExitLogoAnimationThread()
uint32_t DispX = Display->GetBuffer(1)->Width; uint32_t DispX = Display->GetBuffer(1)->Width;
uint32_t DispY = Display->GetBuffer(1)->Height; uint32_t DispY = Display->GetBuffer(1)->Height;
for (size_t i = 40; i > 25; i--) for (size_t i = FrameCount - 1; i > 0; i--)
{ {
int x, y, channels; int x, y, channels;
if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels)) if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i],
&x, &y, &channels))
continue; continue;
uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, STBI_rgb_alpha); uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i],
FrameSizes[i], &x, &y,
&channels, STBI_rgb_alpha);
if (img == NULL) if (img == NULL)
continue; continue;
@ -389,7 +432,8 @@ void ExitLogoAnimationThread()
b = (b * a) / 0xFF; b = (b * a) / 0xFF;
} }
Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1); Display->SetPixel((i % x) + offsetX, (i / x) + offsetY,
(r << 16) | (g << 8) | (b << 0), 1);
} }
free(img); free(img);
@ -411,28 +455,49 @@ void CleanupProcessesThreadWrapper() { TaskManager->CleanupProcessesThread(); }
void KernelMainThread() void KernelMainThread()
{ {
Tasking::TCB *clnThd = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)CleanupProcessesThreadWrapper); // TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test_long));
// TaskManager->Yield();
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// ilp;
Tasking::TCB *clnThd =
TaskManager->CreateThread(thisProcess,
Tasking::IP(CleanupProcessesThreadWrapper));
clnThd->SetPriority(Tasking::Idle); clnThd->SetPriority(Tasking::Idle);
TaskManager->SetCleanupThread(clnThd); TaskManager->SetCleanupThread(clnThd);
TaskManager->GetCurrentThread()->SetPriority(Tasking::Critical); thisThread->SetPriority(Tasking::Critical);
Tasking::TCB *blaThread = nullptr; Tasking::TCB *blaThread = nullptr;
if (Config.BootAnimation) if (Config.BootAnimation)
{ {
blaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)BootLogoAnimationThread); blaThread =
TaskManager->CreateThread(thisProcess,
Tasking::IP(BootLogoAnimationThread));
blaThread->Rename("Logo Animation"); blaThread->Rename("Logo Animation");
} }
#ifdef DEBUG #ifdef DEBUG
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr); TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr));
TaskManager->CreateThread(thisProcess, Tasking::IP(lsof));
TreeFS(vfs->GetRootNode(), 0); TreeFS(vfs->GetRootNode(), 0);
TestSyscallsKernel();
#endif #endif
KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD); KPrint("Kernel Compiled at: %s %s with C++ Standard: %d",
__DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
KPrint("C++ Language Version (__cplusplus): %ld", __cplusplus); KPrint("C++ Language Version (__cplusplus): %ld", __cplusplus);
if (IsVirtualizedEnvironment())
KPrint("Running in Virtualized Environment");
KPrint("Initializing Disk Manager..."); KPrint("Initializing Disk Manager...");
DiskManager = new Disk::Manager; DiskManager = new Disk::Manager;
@ -455,47 +520,23 @@ void KernelMainThread()
KPrint("Starting Network Interface Manager..."); KPrint("Starting Network Interface Manager...");
NIManager->StartService(); NIManager->StartService();
printf("\eCCCCCC[\e00AEFFKernel Thread\eCCCCCC] Setting up userspace"); KPrint("Setting up userspace");
if (!Config.BootAnimation)
Display->SetBuffer(0);
Execute::SpawnData ret = {Execute::ExStatus::Unknown, nullptr, nullptr};
Tasking::TCB *ExecuteThread = nullptr;
int ExitCode = -1; int ExitCode = -1;
ExecuteThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)Execute::LibraryManagerService); Tasking::TCB *initThread = nullptr;
ExecuteThread->Rename("Library Manager"); int tid = SpawnInit();
ExecuteThread->SetCritical(true); if (tid < 0)
ExecuteThread->SetPriority(Tasking::Idle);
Display->Print('.', 0);
if (!Config.BootAnimation)
Display->SetBuffer(0);
ret = SpawnInit();
Display->Print('.', 0);
if (!Config.BootAnimation)
Display->SetBuffer(0);
if (ret.Status != Execute::ExStatus::OK)
{ {
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, ret.Status); KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, tid);
goto Exit; goto Exit;
} }
ret.Thread->SetCritical(true);
TaskManager->GetSecurityManager()->TrustToken(ret.Process->Security.UniqueToken, Tasking::TTL::FullTrust);
TaskManager->GetSecurityManager()->TrustToken(ret.Thread->Security.UniqueToken, Tasking::TTL::FullTrust);
Display->Print('.', 0);
Display->Print('\n', 0);
if (!Config.BootAnimation)
Display->SetBuffer(0);
initThread = TaskManager->GetThreadByID(tid);
initThread->SetCritical(true);
KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath); KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath);
TaskManager->GetCurrentThread()->SetPriority(Tasking::Idle); thisThread->SetPriority(Tasking::Idle);
TaskManager->WaitForThread(ret.Thread); TaskManager->WaitForThread(initThread);
ExitCode = ret.Thread->GetExitCode(); ExitCode = initThread->GetExitCode();
Exit: Exit:
if (ExitCode == 0) if (ExitCode == 0)
{ {
@ -505,25 +546,27 @@ Exit:
CPU::Halt(true); CPU::Halt(true);
} }
KPrint("\eE85230Userspace process exited with code %d (%#x)", ExitCode, KPrint("\eE85230Userspace process exited with code %d (%#x)",
ExitCode < 0 ? -ExitCode : ExitCode); ExitCode, ExitCode < 0 ? -ExitCode : ExitCode);
KPrint("Dropping to recovery screen..."); KPrint("Dropping to kernel shell...");
TaskManager->Sleep(2500); TaskManager->Sleep(1000);
TaskManager->WaitForThread(blaThread); TaskManager->WaitForThread(blaThread);
RecoveryScreen = new Recovery::KernelRecovery; TaskManager->CreateThread(thisProcess,
Tasking::IP(KShellThread))
->Rename("Kernel Shell");
CPU::Halt(true); CPU::Halt(true);
} }
NewLock(ShutdownLock);
void __no_stack_protector KernelShutdownThread(bool Reboot) void __no_stack_protector KernelShutdownThread(bool Reboot)
{ {
SmartLock(ShutdownLock); SmartLock(ShutdownLock);
debug("KernelShutdownThread(%s)", Reboot ? "true" : "false"); debug("KernelShutdownThread(%s)", Reboot ? "true" : "false");
if (Config.BootAnimation && TaskManager) if (Config.BootAnimation && TaskManager)
{ {
if (RecoveryScreen) Tasking::TCB *elaThread =
delete RecoveryScreen, RecoveryScreen = nullptr; TaskManager->CreateThread(thisProcess,
Tasking::IP(ExitLogoAnimationThread));
Tasking::TCB *elaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)ExitLogoAnimationThread);
elaThread->Rename("Logo Animation"); elaThread->Rename("Logo Animation");
TaskManager->WaitForThread(elaThread); TaskManager->WaitForThread(elaThread);
} }

10
LICENSE
View File

@ -631,10 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
A kernel that serves as the core of an operating system, managing <one line to give the program's name and a brief idea of what it does.>
hardware resources and providing essential services to user-level Copyright (C) <year> <name of author>
applications.
Copyright (C) 2023 EnderIce2
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -643,7 +641,7 @@ the "copyright" line and a pointer to where the full notice is found.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
@ -654,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode: notice like this when it starts in an interactive mode:
Fennix Kernel Copyright (C) 2023 EnderIce2 <program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.

View File

@ -17,29 +17,35 @@
#include <bitmap.hpp> #include <bitmap.hpp>
bool Bitmap::operator[](uint64_t index) { return Get(index); }
bool Bitmap::Get(uint64_t index) bool Bitmap::Get(uint64_t index)
{ {
if (index > Size * 8) if (index > Size * 8)
return false; return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8; uint64_t byteIndex = index / 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex; uint8_t bitIndex = index % 8;
if ((Buffer[byteIndex] & bitIndexer) > 0) uint8_t bitIndexer = 0b10000000 >> bitIndex;
return true;
return false; if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
} }
bool Bitmap::Set(uint64_t index, bool value) bool Bitmap::Set(uint64_t index, bool value)
{ {
if (index > Size * 8) if (index > Size * 8)
return false; return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8; uint64_t byteIndex = index / 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex; uint8_t bitIndex = index % 8;
Buffer[byteIndex] &= ~bitIndexer; uint8_t bitIndexer = 0b10000000 >> bitIndex;
if (value)
Buffer[byteIndex] |= bitIndexer; Buffer[byteIndex] &= ~bitIndexer;
return true; if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
} }
bool Bitmap::operator[](uint64_t index) { return this->Get(index); }

View File

@ -474,6 +474,7 @@ size_t wcslen(const wchar_t *s)
size_t wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps) size_t wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps)
{ {
UNUSED(ps);
size_t count = 0; size_t count = 0;
while (len > 0) while (len > 0)
@ -792,21 +793,31 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz
__chk_fail(); __chk_fail();
void *ret = nullptr; void *ret = nullptr;
uint64_t simd = CPU::CheckSIMD(); if (0) /* FIXME */
if (simd & CPU::x86SIMDType::SIMD_SSE42) {
ret = memcpy_sse4_2(dest, src, len); uint64_t simd = CPU::CheckSIMD();
else if (simd & CPU::x86SIMDType::SIMD_SSE41) if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memcpy_sse4_1(dest, src, len); ret = memcpy_sse4_2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3) else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memcpy_ssse3(dest, src, len); ret = memcpy_sse4_1(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3) else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memcpy_sse3(dest, src, len); ret = memcpy_ssse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2) else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memcpy_sse2(dest, src, len); ret = memcpy_sse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE) else if (simd & CPU::x86SIMDType::SIMD_SSE2)
ret = memcpy_sse(dest, src, len); ret = memcpy_sse2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE)
ret = memcpy_sse(dest, src, len);
else
ret = memcpy_unsafe(dest, src, len);
}
else else
{
static int once = 0;
if (!once++)
fixme("SIMD memcpy disabled");
ret = memcpy_unsafe(dest, src, len); ret = memcpy_unsafe(dest, src, len);
}
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
@ -857,21 +868,31 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len,
__chk_fail(); __chk_fail();
void *ret = nullptr; void *ret = nullptr;
uint64_t simd = CPU::CheckSIMD(); if (0) /* FIXME */
if (simd & CPU::x86SIMDType::SIMD_SSE42) {
ret = memset_sse4_2(dest, val, len); uint64_t simd = CPU::CheckSIMD();
else if (simd & CPU::x86SIMDType::SIMD_SSE41) if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memset_sse4_1(dest, val, len); ret = memset_sse4_2(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3) else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memset_ssse3(dest, val, len); ret = memset_sse4_1(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3) else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memset_sse3(dest, val, len); ret = memset_ssse3(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2) else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memset_sse2(dest, val, len); ret = memset_sse3(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE) else if (simd & CPU::x86SIMDType::SIMD_SSE2)
ret = memset_sse(dest, val, len); ret = memset_sse2(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE)
ret = memset_sse(dest, val, len);
else
ret = memset_unsafe(dest, val, len);
}
else else
{
static int once = 0;
if (!once++)
fixme("SIMD memset disabled");
ret = memset_unsafe(dest, val, len); ret = memset_unsafe(dest, val, len);
}
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {
@ -928,21 +949,31 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si
__chk_fail(); __chk_fail();
void *ret = nullptr; void *ret = nullptr;
uint64_t simd = CPU::CheckSIMD(); if (0) /* FIXME */
if (simd & CPU::x86SIMDType::SIMD_SSE42) {
ret = memmove_sse4_2(dest, src, len); uint64_t simd = CPU::CheckSIMD();
else if (simd & CPU::x86SIMDType::SIMD_SSE41) if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memmove_sse4_1(dest, src, len); ret = memmove_sse4_2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3) else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memmove_ssse3(dest, src, len); ret = memmove_sse4_1(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3) else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memmove_sse3(dest, src, len); ret = memmove_ssse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2) else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memmove_sse2(dest, src, len); ret = memmove_sse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE) else if (simd & CPU::x86SIMDType::SIMD_SSE2)
ret = memmove_sse(dest, src, len); ret = memmove_sse2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE)
ret = memmove_sse(dest, src, len);
else
ret = memmove_unsafe(dest, src, len);
}
else else
{
static int once = 0;
if (!once++)
fixme("SIMD memmove disabled");
ret = memmove_unsafe(dest, src, len); ret = memmove_unsafe(dest, src, len);
}
#ifdef DEBUG #ifdef DEBUG
if (EnableExternalMemoryTracer) if (EnableExternalMemoryTracer)
{ {

View File

@ -37,10 +37,25 @@ namespace __cxxabiv1
return &GetCurrentCPU()->EHGlobals; return &GetCurrentCPU()->EHGlobals;
} }
/**
* @param f The destructor
* @param objptr The object to be destructed
* @param dso The DSO from which the object was obtained (unused in our case)
* @return Zero on success, non-zero on failure
*/
extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso) extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso)
{ {
debug("Registering atexit function %p( %p, %p )", if (KernelSymbolTable)
f, objptr, dso); {
debug("Registering atexit function for \"%s\" with destructor \"%s\"",
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)objptr),
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)f));
}
else
{
debug("Registering atexit function for %p with destructor %p",
objptr, f);
}
if (__atexit_func_count >= ATEXIT_MAX_FUNCS) if (__atexit_func_count >= ATEXIT_MAX_FUNCS)
return -1; return -1;
@ -53,23 +68,38 @@ namespace __cxxabiv1
extern "C" void __cxa_finalize(void *f) extern "C" void __cxa_finalize(void *f)
{ {
fixme("__cxa_finalize( %p ) called.", f); function("%p", f);
uarch_t i = __atexit_func_count; uarch_t i = __atexit_func_count;
if (!f) if (f == nullptr)
{ {
while (i--) while (i--)
{
if (__atexit_funcs[i].destructor_func) if (__atexit_funcs[i].destructor_func)
{
if (KernelSymbolTable)
{
debug("Calling atexit function \"%s\"",
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__atexit_funcs[i].destructor_func));
}
else
{
debug("Calling atexit function %p",
__atexit_funcs[i].destructor_func);
}
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
}
}
return; return;
} }
while (i--) while (i--)
{
if (__atexit_funcs[i].destructor_func == f) if (__atexit_funcs[i].destructor_func == f)
{ {
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr); (*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__atexit_funcs[i].destructor_func = 0; __atexit_funcs[i].destructor_func = 0;
} }
}
} }
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context) extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context)
@ -122,8 +152,8 @@ namespace __cxxabiv1
{ {
if (TaskManager && !TaskManager->IsPanic()) if (TaskManager && !TaskManager->IsPanic())
{ {
TaskManager->KillThread(TaskManager->GetCurrentThread(), Tasking::KILL_CXXABI_EXCEPTION); TaskManager->KillThread(thisThread, Tasking::KILL_CXXABI_EXCEPTION);
TaskManager->Schedule(); TaskManager->Yield();
} }
error("No task manager to kill thread!"); error("No task manager to kill thread!");

View File

@ -26,6 +26,9 @@ namespace __cxxabiv1
unsigned outer) const unsigned outer) const
{ {
#ifndef __GXX_RTTI #ifndef __GXX_RTTI
UNUSED(ThrowType);
UNUSED(ThrowObject);
UNUSED(outer);
return false; return false;
#else #else
if (*this == *ThrowType) if (*this == *ThrowType)

View File

@ -28,6 +28,9 @@ namespace __cxxabiv1
unsigned Outer) const unsigned Outer) const
{ {
#ifndef __GXX_RTTI #ifndef __GXX_RTTI
UNUSED(ThrownType);
UNUSED(ThrowObject);
UNUSED(Outer);
return false; return false;
#else #else
if (Outer < 2 && *this->Pointee == typeid(void)) if (Outer < 2 && *this->Pointee == typeid(void))

View File

@ -19,9 +19,15 @@
#include <types.h> #include <types.h>
#include <debug.h> #include <debug.h>
#include <atomic>
#include "../../kernel.h"
__aligned(16) static int errno_value = 0;
int *__errno_location(void) int *__errno_location(void)
{ {
fixme("errno_location() is not implemented yet!"); if (unlikely(!TaskManager || !thisThread))
return nullptr; return &errno_value;
return &thisThread->ErrorNumber;
} }

81
Library/std/mutex.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <mutex>
#include <algorithm>
#include <assert.h>
#include <cpu.hpp>
#include "../../kernel.h"
using namespace Tasking;
namespace std
{
void mutex::lock()
{
bool Result = this->Locked.exchange(true, std::memory_order_acquire);
__sync;
if (Result)
{
this->Waiting.push_back(thisThread);
thisThread->Block();
TaskManager->Yield();
return;
}
this->Holder = thisThread;
this->Waiting.erase(std::find(this->Waiting.begin(),
this->Waiting.end(),
thisThread));
}
bool mutex::try_lock()
{
bool Result = this->Locked.exchange(true, std::memory_order_acquire);
__sync;
if (!Result)
{
this->Holder = thisThread;
this->Waiting.erase(std::find(this->Waiting.begin(),
this->Waiting.end(),
thisThread));
}
return !Result;
}
void mutex::unlock()
{
__sync;
this->Locked.store(false, std::memory_order_release);
if (!this->Waiting.empty())
{
this->Holder = this->Waiting[0];
this->Holder = this->Waiting.front();
this->Waiting.erase(this->Waiting.begin());
this->Holder->Unblock();
TaskManager->Yield();
}
else
this->Holder = nullptr;
}
}

Some files were not shown because too many files have changed in this diff Show More