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."
},
"For Iteratoion": {
"prefix": [
"foritr",
],
"body": [
"forItr(${1:itr}, ${2:container})",
"{",
"\t$0",
"}"
],
"description": "Create for loop with iterator."
},
"License": {
"prefix": [
"license",
@ -66,4 +78,4 @@
],
"description": "Create kernel license."
}
}
}

View File

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

78
.vscode/launch.json vendored
View File

@ -74,8 +74,82 @@
"description": "Load /bin/init."
},
{
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/lib/ld.so",
"description": "Load /lib/ld.so."
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom",
"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",

View File

@ -18,6 +18,7 @@
#include <types.h>
#include <memory.hpp>
#include <elf.h>
#include <io.h>
#include "multiboot2.h"
@ -50,7 +51,6 @@ EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info)
if (tmp != (tmp | 3))
outb(0x61, tmp | 3);
int pos = 0;
auto InfoAddress = Info;
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.EntSize = elf->entsize;
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;
}
case MULTIBOOT_TAG_TYPE_APM:

View File

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

View File

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

View File

@ -31,11 +31,11 @@ extern "C" void SystemCallHandlerStub();
extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHandlerStub()
{
asmv("swapgs\n"); /* Swap GS to get the TCB */
asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to TCB->TempStack */
asmv("mov %gs:0x0, %rsp\n"); /* Get TCB->SystemCallStack and set it as rsp */
asmv("swapgs\n"); /* Swap GS to get the gsTCB */
asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to gsTCB->TempStack */
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 %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 $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) */
@ -78,7 +78,7 @@ extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHand
"pop %rcx\n"
"pop %rbx\n");
/* Restore rsp from TCB->TempStack */
/* Restore rsp from gsTCB->TempStack */
asmv("mov %gs:0x8, %rsp\n");
#ifdef DEBUG
/* Easier to debug stacks */

View File

@ -24,249 +24,247 @@
namespace GlobalDescriptorTable
{
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null =
{
.Limit0 = 0x0,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {.Raw = 0x0},
// .Limit1 = 0x0,
.Flags = {.Raw = 0x0},
.BaseHigh = 0x0,
},
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null = {
.Limit0 = 0x0,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {.Raw = 0x0},
// .Limit1 = 0x0,
.Flags = {.Raw = 0x0},
.BaseHigh = 0x0,
},
.Code =
{
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.Code = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 1,
.DB = 0,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 1,
.DB = 0,
.G = 1,
},
.BaseHigh = 0x0,
},
.Data = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.Data = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.UserData = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.UserData = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.UserCode = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.UserCode = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 1,
.DB = 0,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 1,
.DB = 0,
.G = 1,
},
.BaseHigh = 0x0,
},
.TaskStateSegment = {},
};
.TaskStateSegment = {},
};
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
TaskStateSegment tss[MAX_CPU] = {
0,
{0, 0, 0},
0,
{0, 0, 0, 0, 0, 0, 0},
0,
0,
0,
};
TaskStateSegment tss[MAX_CPU] = {
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)
{
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
SafeFunction void Init(int Core)
{
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[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",
GDT_KERNEL_CODE,
GDTEntries[Core].Code.Limit0,
GDTEntries[Core].Code.BaseLow,
GDTEntries[Core].Code.BaseMiddle,
GDTEntries[Core].Code.Access.Raw,
GDTEntries[Core].Code.Flags.Reserved,
GDTEntries[Core].Code.Flags.Raw & ~0xF,
GDTEntries[Core].Code.BaseHigh);
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",
GDT_KERNEL_CODE,
GDTEntries[Core].Code.Limit0,
GDTEntries[Core].Code.BaseLow,
GDTEntries[Core].Code.BaseMiddle,
GDTEntries[Core].Code.Access.Raw,
GDTEntries[Core].Code.Flags.Reserved,
GDTEntries[Core].Code.Flags.Raw & ~0xF,
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",
GDT_KERNEL_DATA,
GDTEntries[Core].Data.Limit0,
GDTEntries[Core].Data.BaseLow,
GDTEntries[Core].Data.BaseMiddle,
GDTEntries[Core].Data.Access.Raw,
GDTEntries[Core].Data.Flags.Reserved,
GDTEntries[Core].Data.Flags.Raw & ~0xF,
GDTEntries[Core].Data.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",
GDT_KERNEL_DATA,
GDTEntries[Core].Data.Limit0,
GDTEntries[Core].Data.BaseLow,
GDTEntries[Core].Data.BaseMiddle,
GDTEntries[Core].Data.Access.Raw,
GDTEntries[Core].Data.Flags.Reserved,
GDTEntries[Core].Data.Flags.Raw & ~0xF,
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",
GDT_USER_CODE,
GDTEntries[Core].UserCode.Limit0,
GDTEntries[Core].UserCode.BaseLow,
GDTEntries[Core].UserCode.BaseMiddle,
GDTEntries[Core].UserCode.Access.Raw,
GDTEntries[Core].UserCode.Flags.Reserved,
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
GDTEntries[Core].UserCode.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",
GDT_USER_CODE,
GDTEntries[Core].UserCode.Limit0,
GDTEntries[Core].UserCode.BaseLow,
GDTEntries[Core].UserCode.BaseMiddle,
GDTEntries[Core].UserCode.Access.Raw,
GDTEntries[Core].UserCode.Flags.Reserved,
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
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",
GDT_USER_DATA,
GDTEntries[Core].UserData.Limit0,
GDTEntries[Core].UserData.BaseLow,
GDTEntries[Core].UserData.BaseMiddle,
GDTEntries[Core].UserData.Access.Raw,
GDTEntries[Core].UserData.Flags.Reserved,
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
GDTEntries[Core].UserData.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",
GDT_USER_DATA,
GDTEntries[Core].UserData.Limit0,
GDTEntries[Core].UserData.BaseLow,
GDTEntries[Core].UserData.BaseMiddle,
GDTEntries[Core].UserData.Access.Raw,
GDTEntries[Core].UserData.Flags.Reserved,
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
GDTEntries[Core].UserData.BaseHigh);
CPU::x64::lgdt(&gdt[Core]);
CPU::x64::lgdt(&gdt[Core]);
asmv("movq %%rsp, %%rax\n"
"pushq $16\n"
"pushq %%rax\n"
"pushfq\n"
"pushq $8\n"
"pushq $1f\n"
"iretq\n"
"1:\n"
"movw $16, %%ax\n"
"movw %%ax, %%ds\n"
"movw %%ax, %%es\n" ::
: "memory", "rax");
asmv("movq %%rsp, %%rax\n"
"pushq $16\n"
"pushq %%rax\n"
"pushfq\n"
"pushq $8\n"
"pushq $1f\n"
"iretq\n"
"1:\n"
"movw $16, %%ax\n"
"movw %%ax, %%ds\n"
"movw %%ax, %%es\n" ::
: "memory", "rax");
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1));
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1));
uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 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.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);
uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 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.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);
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0;
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0;
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));
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));
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + 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);
}
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + 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);
}
CPU::x64::ltr(GDT_TSS);
debug("Global Descriptor Table initialized");
}
CPU::x64::ltr(GDT_TSS);
debug("Global Descriptor Table initialized");
}
SafeFunction void SetKernelStack(void *Stack)
{
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;
SafeFunction void SetKernelStack(void *Stack)
{
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;
/*
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 %%rsp, %0"
: "=r"(tss[CPUID].StackPointer[0]));
}
/*
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 %%rsp, %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
{
struct TaskStateSegmentEntry
{
/* LOW */
uint16_t Limit;
uint16_t BaseLow;
uint8_t BaseMiddle;
union GlobalDescriptorTableAccess
{
struct
{
/** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed.
*/
uint8_t A : 1;
struct TaskStateSegmentEntry
{
/* LOW */
uint16_t Limit;
uint16_t BaseLow;
uint8_t BaseMiddle;
union GlobalDescriptorTableAccess
{
struct
{
/**
* 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.
* @details For data segments, this bit must be 1 for the segment to be writable.
*/
uint8_t RW : 1;
/**
* Readable bit for code segments, writable bit for data
* segments.
*
* 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).
* @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;
/**
* Direction bit for data segments, conforming bit for
* code segments.
*
* 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.
* @details This bit must be 0 for data-segment and system descriptors.
*/
uint8_t E : 1;
/**
* Executable bit.
*
* This bit must be 1 for code-segment descriptors.
*
* 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.
* @details This bit must be 1 for code or data segment descriptor.
*/
uint8_t S : 1;
/**
* Descriptor type.
*
* This bit must be 0 for system descriptors.
*
* 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.
* @details 0 = kernel mode, 3 = user mode.
*/
uint8_t DPL : 2;
/**
* Descriptor privilege level.
*
* This field determines the privilege level of the
* segment.
*
* 0 = kernel mode
* 3 = user mode
*/
uint8_t DPL : 2;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
uint8_t Granularity;
uint8_t BaseHigh;
/* HIGH */
uint32_t BaseUpper;
uint32_t Reserved;
} __packed;
/**
* Present bit.
*
* This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
uint8_t Granularity;
uint8_t BaseHigh;
/* HIGH */
uint32_t BaseUpper;
uint32_t Reserved;
} __packed;
struct TaskStateSegment
{
uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3];
uint64_t Reserved1;
uint64_t InterruptStackTable[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset;
} __packed;
struct TaskStateSegment
{
uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3];
uint64_t Reserved1;
uint64_t InterruptStackTable[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset;
} __packed;
struct GlobalDescriptorTableEntry
{
/** @brief Limit 0:15 */
uint16_t Limit0 : 16;
struct GlobalDescriptorTableEntry
{
/**
* 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
{
struct
{
/** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed.
*/
uint8_t A : 1;
/**
* Access
*/
union GlobalDescriptorTableAccess
{
struct
{
/**
* 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.
* @details For data segments, this bit must be 1 for the segment to be writable.
*/
uint8_t RW : 1;
/**
* Readable bit for code segments, writable bit for
* data segments.
*
* 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).
* @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;
/**
* Direction bit for data segments, conforming bit for
* code segments.
*
* 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.
* @details This bit must be 0 for data-segment and system descriptors.
*/
uint8_t E : 1;
/**
* Executable bit.
*
* This bit must be 1 for code-segment descriptors.
*
* 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.
* @details This bit must be 1 for code or data segment descriptor.
*/
uint8_t S : 1;
/**
* Descriptor type.
*
* This bit must be 0 for system descriptors.
*
* 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.
* @details 0 = kernel mode, 3 = user mode.
*/
uint8_t DPL : 2;
/**
* Descriptor privilege level.
*
* This field determines the privilege level of the
* segment.
*
* 0 = kernel mode
* 3 = user mode
*/
uint8_t DPL : 2;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
/**
* Present bit.
*
* This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
// /** @brief Limit 16:19 */
// uint16_t Limit1 : 4;
// /** Limit 16:19 */
/** @brief Flags */
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;
// uint16_t Limit1 : 4;
/** @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 set, the segment is in 64-bit long mode.
*/
uint8_t L : 1;
/**
* Flags
*/
union GlobalDescriptorTableFlags
{
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.
* @details If the size bit is set, the segment is in 32-bit protected mode.
*/
uint8_t DB : 1;
/**
* Available bit.
*
* This bit is available for use by system software.
*/
uint8_t AVL : 1;
/** @brief Granularity bit.
* @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.
*/
uint8_t G : 1;
} __packed;
uint8_t Raw : 8;
} Flags;
/**
* Long mode.
*
* If the long mode bit is clear, the segment is in
* 32-bit protected mode.
*
* If the long mode bit is set, the segment is in
* 64-bit long mode.
*/
uint8_t L : 1;
/** @brief High Base 24:31 */
uint8_t BaseHigh : 8;
} __packed;
/**
* Size flag.
*
* 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
{
GlobalDescriptorTableEntry Null;
GlobalDescriptorTableEntry Code;
GlobalDescriptorTableEntry Data;
GlobalDescriptorTableEntry UserData;
GlobalDescriptorTableEntry UserCode;
TaskStateSegmentEntry TaskStateSegment;
} __packed;
/**
* Granularity bit.
*
* If the granularity bit is clear, the segment limit
* is in 1 B blocks.
*
* If the granularity bit is set, the segment limit is
* in 4 KiB blocks.
*/
uint8_t G : 1;
} __packed;
uint8_t Raw : 8;
} Flags;
struct GlobalDescriptorTableDescriptor
{
/** @brief GDT entries length */
uint16_t Length;
/** @brief GDT entries address */
GlobalDescriptorTableEntries *Entries;
} __packed;
/**
* High Base 24:31
*/
uint8_t BaseHigh : 8;
} __packed;
extern void *CPUStackPointer[];
extern TaskStateSegment tss[];
void Init(int Core);
void SetKernelStack(void *Stack);
void *GetKernelStack();
struct GlobalDescriptorTableEntries
{
GlobalDescriptorTableEntry Null;
GlobalDescriptorTableEntry Code;
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)

View File

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

View File

@ -24,249 +24,236 @@
namespace GlobalDescriptorTable
{
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null =
{
.Limit0 = 0x0,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {.Raw = 0x0},
// .Limit1 = 0x0,
.Flags = {.Raw = 0x0},
.BaseHigh = 0x0,
},
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null =
{
.Limit0 = 0x0,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {.Raw = 0x0},
// .Limit1 = 0x0,
.Flags = {.Raw = 0x0},
.BaseHigh = 0x0,
},
.Code =
{
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.Code =
{
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.Data = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.Data = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 0,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.UserData = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.UserData = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 0,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.UserCode = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.UserCode = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
.Access = {
.A = 0,
.RW = 1,
.DC = 0,
.E = 1,
.S = 1,
.DPL = 3,
.P = 1,
},
// .Limit1 = 0xF,
.Flags = {
.Reserved = 0xF, /* Workaround for Limit1 */
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.AVL = 0,
.L = 0,
.DB = 1,
.G = 1,
},
.BaseHigh = 0x0,
},
.TaskStateSegment = {},
};
.TaskStateSegment = {},
};
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
TaskStateSegment tss[MAX_CPU] = {
0,
{0, 0, 0},
0,
{0, 0, 0, 0, 0, 0, 0},
0,
0,
0,
};
TaskStateSegment tss[MAX_CPU] = {
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)
{
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
SafeFunction void Init(int Core)
{
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[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",
GDT_KERNEL_CODE,
GDTEntries[Core].Code.Limit0,
GDTEntries[Core].Code.BaseLow,
GDTEntries[Core].Code.BaseMiddle,
GDTEntries[Core].Code.Access.Raw,
GDTEntries[Core].Code.Flags.Reserved,
GDTEntries[Core].Code.Flags.Raw & ~0xF,
GDTEntries[Core].Code.BaseHigh);
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",
GDT_KERNEL_CODE,
GDTEntries[Core].Code.Limit0,
GDTEntries[Core].Code.BaseLow,
GDTEntries[Core].Code.BaseMiddle,
GDTEntries[Core].Code.Access.Raw,
GDTEntries[Core].Code.Flags.Reserved,
GDTEntries[Core].Code.Flags.Raw & ~0xF,
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",
GDT_KERNEL_DATA,
GDTEntries[Core].Data.Limit0,
GDTEntries[Core].Data.BaseLow,
GDTEntries[Core].Data.BaseMiddle,
GDTEntries[Core].Data.Access.Raw,
GDTEntries[Core].Data.Flags.Reserved,
GDTEntries[Core].Data.Flags.Raw & ~0xF,
GDTEntries[Core].Data.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",
GDT_KERNEL_DATA,
GDTEntries[Core].Data.Limit0,
GDTEntries[Core].Data.BaseLow,
GDTEntries[Core].Data.BaseMiddle,
GDTEntries[Core].Data.Access.Raw,
GDTEntries[Core].Data.Flags.Reserved,
GDTEntries[Core].Data.Flags.Raw & ~0xF,
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",
GDT_USER_CODE,
GDTEntries[Core].UserCode.Limit0,
GDTEntries[Core].UserCode.BaseLow,
GDTEntries[Core].UserCode.BaseMiddle,
GDTEntries[Core].UserCode.Access.Raw,
GDTEntries[Core].UserCode.Flags.Reserved,
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
GDTEntries[Core].UserCode.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",
GDT_USER_CODE,
GDTEntries[Core].UserCode.Limit0,
GDTEntries[Core].UserCode.BaseLow,
GDTEntries[Core].UserCode.BaseMiddle,
GDTEntries[Core].UserCode.Access.Raw,
GDTEntries[Core].UserCode.Flags.Reserved,
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
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",
GDT_USER_DATA,
GDTEntries[Core].UserData.Limit0,
GDTEntries[Core].UserData.BaseLow,
GDTEntries[Core].UserData.BaseMiddle,
GDTEntries[Core].UserData.Access.Raw,
GDTEntries[Core].UserData.Flags.Reserved,
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
GDTEntries[Core].UserData.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",
GDT_USER_DATA,
GDTEntries[Core].UserData.Limit0,
GDTEntries[Core].UserData.BaseLow,
GDTEntries[Core].UserData.BaseMiddle,
GDTEntries[Core].UserData.Access.Raw,
GDTEntries[Core].UserData.Flags.Reserved,
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
GDTEntries[Core].UserData.BaseHigh);
CPU::x32::lgdt(&gdt[Core]);
CPU::x32::lgdt(&gdt[Core]);
asmv("mov %%esp, %%eax\n"
"push $16\n"
"push %%eax\n"
"pushf\n"
"push $8\n"
"push $1f\n"
"iret\n"
"1:\n"
"movw $16, %%ax\n"
"movw %%ax, %%ds\n"
"movw %%ax, %%es\n" ::
: "memory", "eax");
asmv("mov %%esp, %%eax\n"
"push $16\n"
"push %%eax\n"
"pushf\n"
"push $8\n"
"push $1f\n"
"iret\n"
"1:\n"
"movw $16, %%ax\n"
"movw %%ax, %%ds\n"
"movw %%ax, %%es\n" ::
: "memory", "eax");
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1));
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1));
uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 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.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);
uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = uint8_t((Base >> 16) & 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.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);
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0;
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint32_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0;
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));
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));
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + 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);
}
tss[Core].InterruptStackTable[i] = (uint32_t)NewStack + 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);
}
CPU::x32::ltr(GDT_TSS);
debug("Global Descriptor Table initialized");
}
CPU::x32::ltr(GDT_TSS);
debug("Global Descriptor Table initialized");
}
SafeFunction void SetKernelStack(void *Stack)
{
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;
SafeFunction void SetKernelStack(void *Stack)
{
long CPUID = GetCurrentCPU()->ID;
}
/*
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]; }
void *GetKernelStack() { return (void *)nullptr; }
}

View File

@ -22,197 +22,197 @@
namespace GlobalDescriptorTable
{
struct TaskStateSegmentEntry
{
/* LOW */
uint16_t Limit;
uint16_t BaseLow;
uint8_t BaseMiddle;
union GlobalDescriptorTableAccess
{
struct
{
/** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed.
*/
uint8_t A : 1;
struct TaskStateSegmentEntry
{
/* LOW */
uint16_t Limit;
uint16_t BaseLow;
uint8_t BaseMiddle;
union GlobalDescriptorTableAccess
{
struct
{
/** @brief 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.
* @details For data segments, this bit must be 1 for the segment to be writable.
*/
uint8_t RW : 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.
* @details For data segments, 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).
* @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;
/** @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 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;
/** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors.
* @details This bit must be 0 for data-segment and system descriptors.
*/
uint8_t E : 1;
/** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors.
* @details 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.
* @details This bit must be 1 for code or data segment descriptor.
*/
uint8_t S : 1;
/** @brief Descriptor type.
* @details This bit must be 0 for system descriptors.
* @details 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.
* @details 0 = kernel mode, 3 = user mode.
*/
uint8_t DPL : 2;
/** @brief Descriptor privilege level.
* @details This field determines the privilege level of the segment.
* @details 0 = kernel mode, 3 = user mode.
*/
uint8_t DPL : 2;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
uint8_t Granularity;
uint8_t BaseHigh;
/* HIGH */
uint32_t BaseUpper;
uint32_t Reserved;
} __packed;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
uint8_t Granularity;
uint8_t BaseHigh;
/* HIGH */
uint32_t BaseUpper;
uint32_t Reserved;
} __packed;
struct TaskStateSegment
{
uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3];
uint64_t Reserved1;
uint64_t InterruptStackTable[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset;
} __packed;
struct TaskStateSegment
{
uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3];
uint64_t Reserved1;
uint64_t InterruptStackTable[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset;
} __packed;
struct GlobalDescriptorTableEntry
{
/** @brief Limit 0:15 */
uint16_t Limit0 : 16;
struct GlobalDescriptorTableEntry
{
/** @brief Limit 0:15 */
uint16_t Limit0 : 16;
/** @brief Low Base 0:15 */
uint16_t BaseLow : 16;
/** @brief Low Base 0:15 */
uint16_t BaseLow : 16;
/** @brief Middle Base 16:23 */
uint8_t BaseMiddle : 8;
/** @brief Middle Base 16:23 */
uint8_t BaseMiddle : 8;
/** @brief Access */
union GlobalDescriptorTableAccess
{
struct
{
/** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed.
*/
uint8_t A : 1;
/** @brief Access */
union GlobalDescriptorTableAccess
{
struct
{
/** @brief 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.
* @details For data segments, this bit must be 1 for the segment to be writable.
*/
uint8_t RW : 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.
* @details For data segments, 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).
* @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;
/** @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 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;
/** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors.
* @details This bit must be 0 for data-segment and system descriptors.
*/
uint8_t E : 1;
/** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors.
* @details 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.
* @details This bit must be 1 for code or data segment descriptor.
*/
uint8_t S : 1;
/** @brief Descriptor type.
* @details This bit must be 0 for system descriptors.
* @details 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.
* @details 0 = kernel mode, 3 = user mode.
*/
uint8_t DPL : 2;
/** @brief Descriptor privilege level.
* @details This field determines the privilege level of the segment.
* @details 0 = kernel mode, 3 = user mode.
*/
uint8_t DPL : 2;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
// /** @brief Limit 16:19 */
// uint16_t Limit1 : 4;
// /** @brief Limit 16:19 */
// uint16_t Limit1 : 4;
/** @brief Flags */
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 Flags */
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.
* @details If the long mode bit is set, the segment is in 64-bit long mode.
*/
uint8_t L : 1;
/** @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 set, the segment is in 64-bit long mode.
*/
uint8_t L : 1;
/** @brief Size flag.
* @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.
*/
uint8_t DB : 1;
/** @brief Size flag.
* @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.
*/
uint8_t DB : 1;
/** @brief Granularity bit.
* @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.
*/
uint8_t G : 1;
} __packed;
uint8_t Raw : 8;
} Flags;
/** @brief Granularity bit.
* @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.
*/
uint8_t G : 1;
} __packed;
uint8_t Raw : 8;
} Flags;
/** @brief High Base 24:31 */
uint8_t BaseHigh : 8;
} __packed;
/** @brief High Base 24:31 */
uint8_t BaseHigh : 8;
} __packed;
struct GlobalDescriptorTableEntries
{
GlobalDescriptorTableEntry Null;
GlobalDescriptorTableEntry Code;
GlobalDescriptorTableEntry Data;
GlobalDescriptorTableEntry UserData;
GlobalDescriptorTableEntry UserCode;
TaskStateSegmentEntry TaskStateSegment;
} __packed;
struct GlobalDescriptorTableEntries
{
GlobalDescriptorTableEntry Null;
GlobalDescriptorTableEntry Code;
GlobalDescriptorTableEntry Data;
GlobalDescriptorTableEntry UserData;
GlobalDescriptorTableEntry UserCode;
TaskStateSegmentEntry TaskStateSegment;
} __packed;
struct GlobalDescriptorTableDescriptor
{
/** @brief GDT entries length */
uint16_t Length;
/** @brief GDT entries address */
GlobalDescriptorTableEntries *Entries;
} __packed;
struct GlobalDescriptorTableDescriptor
{
/** @brief GDT entries length */
uint16_t Length;
/** @brief GDT entries address */
GlobalDescriptorTableEntries *Entries;
} __packed;
extern void *CPUStackPointer[];
extern TaskStateSegment tss[];
void Init(int Core);
void SetKernelStack(void *Stack);
void *GetKernelStack();
extern void *CPUStackPointer[];
extern TaskStateSegment tss[];
void Init(int Core);
void SetKernelStack(void *Stack);
void *GetKernelStack();
}
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -52,9 +52,11 @@ namespace CrashHandler
if (cpu)
{
EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu);
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n", cpu->Stack, cpu->ID, cpu->ErrorCode);
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n",
cpu->Stack, cpu->ID, cpu->ErrorCode);
EHPrint("Is Active: %s\n", cpu->IsActive ? "true" : "false");
EHPrint("Current Process: %#lx, Current Thread: %#lx\n", cpu->CurrentProcess, cpu->CurrentThread);
EHPrint("Current Process: %#lx, Current Thread: %#lx\n",
cpu->CurrentProcess.load(), cpu->CurrentThread.load());
EHPrint("Arch Specific Data: %#lx\n", cpu->Data);
EHPrint("Checksum: 0x%X\n", cpu->Checksum);
}
@ -128,11 +130,11 @@ namespace CrashHandler
#endif
#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.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.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",

View File

@ -311,7 +311,7 @@ namespace CrashHandler
case CPU::x86::PageFault:
{
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};
#if defined(a64)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,7 +33,7 @@ namespace Driver
{
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;
Fex *fex = nullptr;

View File

@ -61,7 +61,7 @@ namespace Driver
debug("[%ld] VendorID: %#x; DeviceID: %#x",
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;
Fex *fex = nullptr;

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -22,250 +22,266 @@
namespace Memory
{
ReadFSFunction(MEM_Read)
{
if (!Size)
Size = node->Length;
ReadFSFunction(MEM_Read)
{
if (!Size)
Size = node->Length;
if ((size_t)node->Offset > node->Length)
return 0;
if (RefOffset > node->Length)
return 0;
if (node->Offset + Size > node->Length)
Size = node->Length - node->Offset;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + node->Offset), Size);
return Size;
}
memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size;
}
WriteFSFunction(MEM_Write)
{
if (!Size)
Size = node->Length;
WriteFSFunction(MEM_Write)
{
if (!Size)
Size = node->Length;
if ((size_t)node->Offset > node->Length)
return 0;
if (RefOffset > node->Length)
return 0;
if (node->Offset + Size > node->Length)
Size = node->Length - node->Offset;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy((uint8_t *)(node->Address + node->Offset), Buffer, Size);
return Size;
}
memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
return Size;
}
VirtualFileSystem::FileSystemOperations mem_op = {
.Name = "mem",
.Read = MEM_Read,
.Write = MEM_Write,
};
VirtualFileSystem::FileSystemOperations mem_op = {
.Name = "mem",
.Read = MEM_Read,
.Write = MEM_Write,
};
uint64_t MemMgr::GetAllocatedMemorySize()
{
SmartLock(MgrLock);
uint64_t Size = 0;
foreach (auto ap in AllocatedPagesList)
Size += ap.PageCount;
return FROM_PAGES(Size);
}
uint64_t MemMgr::GetAllocatedMemorySize()
{
SmartLock(MgrLock);
uint64_t Size = 0;
foreach (auto ap in AllocatedPagesList)
Size += ap.PageCount;
return FROM_PAGES(Size);
}
bool MemMgr::Add(void *Address, size_t Count)
{
SmartLock(MgrLock);
if (Address == nullptr)
{
error("Address is null!");
return false;
}
bool MemMgr::Add(void *Address, size_t Count)
{
SmartLock(MgrLock);
if (Address == nullptr)
{
error("Address is null!");
return false;
}
if (Count == 0)
{
error("Count is 0!");
return false;
}
if (Count == 0)
{
error("Count is 0!");
return false;
}
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
{
if (AllocatedPagesList[i].Address == Address)
{
error("Address already exists!");
return false;
}
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
{
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
{
error("Address intersects with an allocated page!");
return false;
}
}
else
{
if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address)
{
error("Address intersects with an allocated page!");
return false;
}
}
}
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
{
if (AllocatedPagesList[i].Address == Address)
{
error("Address already exists!");
return false;
}
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
{
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
{
error("Address intersects with an allocated page!");
return false;
}
}
else
{
if ((uintptr_t)AllocatedPagesList[i].Address + (AllocatedPagesList[i].PageCount * PAGE_SIZE) > (uintptr_t)Address)
{
error("Address intersects with an allocated page!");
return false;
}
}
}
if (this->Directory)
{
char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
if (n)
{
n->Address = (uintptr_t)Address;
n->Length = Count * PAGE_SIZE;
n->Operator = &mem_op;
}
}
AllocatedPagesList.push_back({Address, Count});
return true;
}
void *MemMgr::RequestPages(size_t Count, bool User)
{
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;
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
#elif defined(a32)
this->Table = (PageTable *)CPU::x32::readcr3().raw;
sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#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;
debug("+ %#lx", this);
}
AllocatedPagesList.push_back({Address, Count});
return true;
}
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);
}
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;
if (this->Directory)
{
foreach (auto Child in this->Directory->Children)
vfs->Delete(Child, true);
}
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
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
{
uint64_t Physical::GetTotalMemory()
{
SmartLock(this->MemoryLock);
return this->TotalMemory;
}
uint64_t Physical::GetTotalMemory()
{
return this->TotalMemory.load();
}
uint64_t Physical::GetFreeMemory()
{
SmartLock(this->MemoryLock);
return this->FreeMemory;
}
uint64_t Physical::GetFreeMemory()
{
return this->FreeMemory.load();
}
uint64_t Physical::GetReservedMemory()
{
SmartLock(this->MemoryLock);
return this->ReservedMemory;
}
uint64_t Physical::GetReservedMemory()
{
return this->ReservedMemory.load();
}
uint64_t Physical::GetUsedMemory()
{
SmartLock(this->MemoryLock);
return this->UsedMemory;
}
uint64_t Physical::GetUsedMemory()
{
return this->UsedMemory.load();
}
bool Physical::SwapPage(void *Address)
{
fixme("%p", Address);
return false;
}
bool Physical::SwapPage(void *Address)
{
fixme("%p", Address);
return false;
}
bool Physical::SwapPages(void *Address, size_t PageCount)
{
for (size_t i = 0; i < PageCount; i++)
{
if (!this->SwapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
return false;
}
return false;
}
bool Physical::SwapPages(void *Address, size_t PageCount)
{
for (size_t i = 0; i < PageCount; i++)
{
if (!this->SwapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
return false;
}
return false;
}
bool Physical::UnswapPage(void *Address)
{
fixme("%p", Address);
return false;
}
bool Physical::UnswapPage(void *Address)
{
fixme("%p", Address);
return false;
}
bool Physical::UnswapPages(void *Address, size_t PageCount)
{
for (size_t i = 0; i < PageCount; i++)
{
if (!this->UnswapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
return false;
}
return false;
}
bool Physical::UnswapPages(void *Address, size_t PageCount)
{
for (size_t i = 0; i < PageCount; i++)
{
if (!this->UnswapPage((void *)((uintptr_t)Address + (i * PAGE_SIZE))))
return false;
}
return false;
}
void *Physical::RequestPage()
{
SmartLock(this->MemoryLock);
void *Physical::RequestPage()
{
SmartLock(this->MemoryLock);
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "RequestPage( )=%p~%p\n\r",
(void *)(PageBitmapIndex * PAGE_SIZE), __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "RequestPage( )=%p~%p\n\r",
(void *)(PageBitmapIndex * PAGE_SIZE), __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
#endif
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE)))
{
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE)))
{
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
if (TaskManager && !TaskManager->IsPanic())
{
error("Out of memory! Killing current process...");
TaskManager->KillProcess(TaskManager->GetCurrentProcess(), Tasking::KILL_OOM);
TaskManager->Schedule();
}
if (TaskManager && !TaskManager->IsPanic())
{
error("Out of memory! Killing current process...");
TaskManager->KillProcess(thisProcess, Tasking::KILL_OOM);
TaskManager->Yield();
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
CPU::Stop();
__builtin_unreachable();
}
error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
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)
{
SmartLock(this->MemoryLock);
void *Physical::RequestPages(size_t Count)
{
SmartLock(this->MemoryLock);
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
{
if (PageBitmap[Index] == true)
continue;
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
{
if (PageBitmap[Index] == true)
continue;
for (size_t i = 0; i < Count; i++)
{
if (PageBitmap[Index + i] == true)
goto NextPage;
}
for (size_t i = 0; i < Count; i++)
{
if (PageBitmap[Index + i] == true)
goto NextPage;
}
this->LockPages((void *)(Index * PAGE_SIZE), Count);
this->LockPages((void *)(Index * PAGE_SIZE), Count);
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "RequestPages( %ld )=%p~%p\n\r",
Count,
(void *)(Index * PAGE_SIZE), __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "RequestPages( %ld )=%p~%p\n\r",
Count,
(void *)(Index * PAGE_SIZE), __builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
#endif
return (void *)(Index * PAGE_SIZE);
return (void *)(Index * PAGE_SIZE);
NextPage:
Index += Count;
continue;
}
}
NextPage:
Index += Count;
continue;
}
}
if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count))
{
this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count);
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count))
{
this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count);
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
if (TaskManager && !TaskManager->IsPanic())
{
error("Out of memory! Killing current process...");
TaskManager->KillProcess(TaskManager->GetCurrentProcess(), Tasking::KILL_OOM);
TaskManager->Schedule();
}
if (TaskManager && !TaskManager->IsPanic())
{
error("Out of memory! Killing current process...");
TaskManager->KillProcess(thisProcess, Tasking::KILL_OOM);
TaskManager->Yield();
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
CPU::Halt(true);
__builtin_unreachable();
}
error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
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)
{
SmartLock(this->MemoryLock);
void Physical::FreePage(void *Address)
{
SmartLock(this->MemoryLock);
if (unlikely(Address == nullptr))
{
warn("Null pointer passed to FreePage.");
return;
}
if (unlikely(Address == nullptr))
{
warn("Null pointer passed to FreePage.");
return;
}
size_t Index = (size_t)Address / PAGE_SIZE;
size_t Index = (size_t)Address / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
{
warn("Tried to free an already free page. (%p)", Address);
return;
}
if (unlikely(PageBitmap[Index] == false))
{
warn("Tried to free an already free page. (%p)",
Address);
return;
}
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
UsedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
UsedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "FreePage( %p )~%p\n\r",
Address,
__builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "FreePage( %p )~%p\n\r",
Address,
__builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
#endif
}
}
void Physical::FreePages(void *Address, size_t Count)
{
if (unlikely(Address == nullptr || Count == 0))
{
warn("%s%s%s passed to FreePages.", Address == nullptr ? "Null pointer " : "", Address == nullptr && Count == 0 ? "and " : "", Count == 0 ? "Zero count" : "");
return;
}
void Physical::FreePages(void *Address, size_t Count)
{
if (unlikely(Address == nullptr || Count == 0))
{
warn("%s%s%s passed to FreePages.", Address == nullptr ? "Null pointer " : "", Address == nullptr && Count == 0 ? "and " : "", Count == 0 ? "Zero count" : "");
return;
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "!FreePages( %p %ld )~%p\n\r",
Address, Count,
__builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
if (EnableExternalMemoryTracer)
{
char LockTmpStr[64];
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
sprintf(mExtTrkLog, "!FreePages( %p %ld )~%p\n\r",
Address, Count,
__builtin_return_address(0));
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
if (mExtTrkLog[i] == '\r')
break;
mTrkUART.Write(mExtTrkLog[i]);
}
mExtTrkLock.Unlock();
}
#endif
for (size_t t = 0; t < Count; t++)
this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
}
for (size_t t = 0; t < Count; t++)
this->FreePage((void *)((uintptr_t)Address + (t * PAGE_SIZE)));
}
void Physical::LockPage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to lock null address.");
void Physical::LockPage(void *Address)
{
if (unlikely(Address == nullptr))
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))
return;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
UsedMemory += PAGE_SIZE;
}
}
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
UsedMemory += PAGE_SIZE;
}
}
void Physical::LockPages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
void Physical::LockPages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to lock %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
}
for (size_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
}
void Physical::ReservePage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to reserve null address.");
void Physical::ReservePage(void *Address)
{
if (unlikely(Address == nullptr))
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))
return;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
void Physical::ReservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
void Physical::ReservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to reserve %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == true))
return;
if (unlikely(PageBitmap[Index] == true))
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
}
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
}
void Physical::UnreservePage(void *Address)
{
if (unlikely(Address == nullptr))
warn("Trying to unreserve null address.");
void Physical::UnreservePage(void *Address)
{
if (unlikely(Address == nullptr))
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))
return;
if (unlikely(PageBitmap[Index] == false))
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::UnreservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
void Physical::UnreservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to unreserve %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
for (size_t t = 0; t < PageCount; t++)
{
uintptr_t Index = ((uintptr_t)Address + (t * PAGE_SIZE)) / PAGE_SIZE;
if (unlikely(PageBitmap[Index] == false))
return;
if (unlikely(PageBitmap[Index] == false))
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
}
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
}
void Physical::Init()
{
SmartLock(this->MemoryLock);
void Physical::Init()
{
SmartLock(this->MemoryLock);
uint64_t MemorySize = bInfo.Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize));
TotalMemory = MemorySize;
FreeMemory = MemorySize;
uint64_t MemorySize = bInfo.Memory.Size;
debug("Memory size: %lld bytes (%ld pages)",
MemorySize, TO_PAGES(MemorySize));
TotalMemory = MemorySize;
FreeMemory = MemorySize;
size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1;
uintptr_t BitmapAddress = 0x0;
size_t BitmapAddressSize = 0;
size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1;
uintptr_t BitmapAddress = 0x0;
size_t BitmapAddressSize = 0;
uintptr_t KernelStart = (uintptr_t)bInfo.Kernel.PhysicalBase;
uintptr_t KernelEnd = (uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size;
uintptr_t KernelStart = (uintptr_t)bInfo.Kernel.PhysicalBase;
uintptr_t KernelEnd = (uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size;
for (uint64_t i = 0; i < bInfo.Memory.Entries; i++)
{
if (bInfo.Memory.Entry[i].Type == Usable)
{
uintptr_t RegionAddress = (uintptr_t)bInfo.Memory.Entry[i].BaseAddress;
uintptr_t RegionSize = bInfo.Memory.Entry[i].Length;
for (uint64_t i = 0; i < bInfo.Memory.Entries; i++)
{
if (bInfo.Memory.Entry[i].Type == Usable)
{
uintptr_t RegionAddress = (uintptr_t)bInfo.Memory.Entry[i].BaseAddress;
uintptr_t RegionSize = bInfo.Memory.Entry[i].Length;
/* We don't want to use 0 as a memory address. */
if (RegionAddress == 0x0)
continue;
/* We don't want to use the first 1MB of memory. */
if (RegionAddress <= 0xFFFFF)
continue;
if ((BitmapSize + 0x100) > RegionSize)
{
debug("Region %p-%p (%dMB) is too small for bitmap.",
(void *)RegionAddress,
(void *)(RegionAddress + RegionSize),
TO_MB(RegionSize));
continue;
}
if ((BitmapSize + 0x100) > RegionSize)
{
debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)RegionAddress,
(void *)(RegionAddress + RegionSize),
TO_MiB(RegionSize));
continue;
}
BitmapAddress = RegionAddress;
BitmapAddressSize = RegionSize;
BitmapAddress = RegionAddress;
BitmapAddressSize = RegionSize;
if (RegionAddress >= KernelStart && KernelEnd <= (RegionAddress + RegionSize))
{
BitmapAddress = KernelEnd;
BitmapAddressSize = RegionSize - (KernelEnd - RegionAddress);
}
if (RegionAddress >= KernelStart && KernelEnd <= (RegionAddress + RegionSize))
{
BitmapAddress = KernelEnd;
BitmapAddressSize = RegionSize - (KernelEnd - RegionAddress);
}
if ((BitmapSize + 0x100) > BitmapAddressSize)
{
debug("Region %p-%p (%dMB) is too small for bitmap.",
(void *)RegionAddress,
(void *)(RegionAddress + BitmapAddressSize),
TO_MB(BitmapAddressSize));
continue;
}
if ((BitmapSize + 0x100) > BitmapAddressSize)
{
debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)RegionAddress,
(void *)(RegionAddress + BitmapAddressSize),
TO_MiB(BitmapAddressSize));
continue;
}
for (size_t i = 0; i < MAX_MODULES; i++)
{
uintptr_t ModuleStart = (uintptr_t)bInfo.Modules[i].Address;
uintptr_t ModuleEnd = (uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size;
for (size_t i = 0; i < MAX_MODULES; i++)
{
uintptr_t ModuleStart = (uintptr_t)bInfo.Modules[i].Address;
uintptr_t ModuleEnd = (uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size;
if (ModuleStart == 0x0)
break;
if (ModuleStart == 0x0)
break;
if (RegionAddress >= ModuleStart && ModuleEnd <= (RegionAddress + RegionSize))
{
BitmapAddress = ModuleEnd;
BitmapAddressSize = RegionSize - (ModuleEnd - RegionAddress);
}
}
if (RegionAddress >= ModuleStart && ModuleEnd <= (RegionAddress + RegionSize))
{
BitmapAddress = ModuleEnd;
BitmapAddressSize = RegionSize - (ModuleEnd - RegionAddress);
}
}
if ((BitmapSize + 0x100) > BitmapAddressSize)
{
debug("Region %p-%p (%dMB) is too small for bitmap.",
(void *)BitmapAddress,
(void *)(BitmapAddress + BitmapAddressSize),
TO_MB(BitmapAddressSize));
continue;
}
if ((BitmapSize + 0x100) > BitmapAddressSize)
{
debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)BitmapAddress,
(void *)(BitmapAddress + BitmapAddressSize),
TO_MiB(BitmapAddressSize));
continue;
}
debug("Found free memory for bitmap: %p (%dMB)",
(void *)BitmapAddress,
TO_MB(BitmapAddressSize));
break;
}
}
debug("Found free memory for bitmap: %p (%d MiB)",
(void *)BitmapAddress,
TO_MiB(BitmapAddressSize));
break;
}
}
if (BitmapAddress == 0x0)
{
error("No free memory found!");
CPU::Stop();
}
if (BitmapAddress == 0x0)
{
error("No free memory found!");
CPU::Stop();
}
/* TODO: Read swap config and make the configure the bitmap size correctly */
debug("Initializing Bitmap at %p-%p (%d Bytes)",
BitmapAddress,
(void *)(BitmapAddress + BitmapSize),
BitmapSize);
/* TODO: Read swap config and make the configure the bitmap size correctly */
debug("Initializing Bitmap at %p-%p (%d Bytes)",
BitmapAddress,
(void *)(BitmapAddress + BitmapSize),
BitmapSize);
PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)BitmapAddress;
for (size_t i = 0; i < BitmapSize; i++)
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)BitmapAddress;
for (size_t i = 0; i < BitmapSize; i++)
*(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 <debug.h>
#include <elf.h>
#ifdef DEBUG
#include <uart.hpp>
#endif
@ -44,7 +45,13 @@ namespace Memory
for (uint64_t i = 0; i < bInfo.Memory.Entries; i++)
{
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...");
@ -57,18 +64,72 @@ namespace Memory
*/
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));
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));
debug("Reserving kernel file and symbols...");
if (bInfo.Kernel.FileBase)
this->ReservePages(bInfo.Kernel.FileBase, TO_PAGES(bInfo.Kernel.Size));
if (bInfo.Kernel.Symbols.Num && bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.Shndx)
this->ReservePages((void *)bInfo.Kernel.Symbols.Sections, TO_PAGES(bInfo.Kernel.Symbols.Num * bInfo.Kernel.Symbols.EntSize));
if (bInfo.Kernel.Symbols.Num &&
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...");
@ -78,13 +139,17 @@ namespace Memory
continue;
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)
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)));
ACPI::ACPI::ACPIHeader *ACPIPtr = nullptr;
@ -115,23 +180,27 @@ namespace Memory
}
#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);
for (size_t t = 0; t < TableSize; t++)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
// TODO: Should I be concerned about unaligned memory access?
ACPI::ACPI::ACPIHeader *SDTHdr = nullptr;
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
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
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
{
void Power::Reboot()
{
if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Reboot();
void Power::Reboot()
{
if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Reboot();
uint8_t val = 0x02;
while (val & 0x02)
val = inb(0x64);
outb(0x64, 0xFE);
uint8_t val = 0x02;
while (val & 0x02)
val = inb(0x64);
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
uint8_t temp;
asmv("cli");
do
{
temp = inb(0x64);
if (((temp) & (1 << (0))) != 0)
inb(0x60);
} while (((temp) & (1 << (1))) != 0);
outb(0x64, 0xFE);
// https://wiki.osdev.org/Reboot
/* Second attempt to reboot */
asmv("cli");
uint8_t temp;
do
{
temp = inb(0x64);
if (((temp) & (1 << (0))) != 0)
inb(0x60);
} while (((temp) & (1 << (1))) != 0);
outb(0x64, 0xFE);
CPU::Stop();
}
CPU::Stop();
}
void Power::Shutdown()
{
if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Shutdown();
void Power::Shutdown()
{
if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Shutdown();
/* TODO: If no ACPI, display "It is now safe to turn off your computer" */
outl(0xB004, 0x2000); // for qemu
outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu
outl(0x4004, 0x3400); // virtual box
CPU::Stop();
}
/* FIXME: Detect emulators and use their shutdown methods */
#ifdef DEBUG
outl(0xB004, 0x2000); // for qemu
outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu
outl(0x4004, 0x3400); // virtual box
#endif
CPU::Stop();
}
void Power::InitDSDT()
{
if (((ACPI::ACPI *)this->acpi)->FADT)
this->dsdt = new ACPI::DSDT((ACPI::ACPI *)acpi);
}
void Power::InitDSDT()
{
if (((ACPI::ACPI *)this->acpi)->FADT)
this->dsdt = new ACPI::DSDT((ACPI::ACPI *)acpi);
}
Power::Power()
{
this->acpi = new ACPI::ACPI;
this->madt = new ACPI::MADT(((ACPI::ACPI *)acpi)->MADT);
trace("Power manager initialized");
}
Power::~Power()
{
debug("Destructor called");
}
Power::Power()
{
this->acpi = new ACPI::ACPI;
this->madt = new ACPI::MADT(((ACPI::ACPI *)acpi)->MADT);
trace("Power manager initialized");
}
}
#elif defined(a32)
namespace Power
{
void Power::Reboot()
{
warn("Reboot not implemented for i386");
}
void Power::Reboot()
{
warn("Reboot not implemented for i386");
}
void Power::Shutdown()
{
warn("Shutdown not implemented for i386");
}
void Power::Shutdown()
{
warn("Shutdown not implemented for i386");
}
Power::Power()
{
error("Power not implemented for i386");
}
Power::~Power()
{
}
Power::Power()
{
error("Power not implemented for i386");
}
}
#elif defined(aa64)
namespace Power
{
void Power::Reboot()
{
warn("Reboot not implemented for aarch64");
}
void Power::Reboot()
{
warn("Reboot not implemented for aarch64");
}
void Power::Shutdown()
{
warn("Shutdown not implemented for aarch64");
}
void Power::Shutdown()
{
warn("Shutdown not implemented for aarch64");
}
Power::Power()
{
error("Power not implemented for aarch64");
}
Power::~Power()
{
}
Power::Power()
{
error("Power not implemented for aarch64");
}
}
#endif

View File

@ -25,220 +25,228 @@
namespace SymbolResolver
{
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address)
{
Symbols::SymbolTable Result{0, (char *)"<unknown>"};
for (int64_t i = 0; i < this->TotalEntries; i++)
if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address)
Result = this->SymTable[i];
return Result.FunctionName;
}
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address)
{
SymbolTable Result{};
foreach (auto tbl in this->SymTable)
{
if (tbl.Address <= Address &&
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)
{
if (this->TotalEntries >= 0x10000)
{
error("Symbol table is full");
return;
}
void Symbols::AddSymbol(uintptr_t Address, const char *Name)
{
SymbolTable tbl{};
tbl.Address = Address;
tbl.FunctionName = (char *)Name;
this->SymTable.push_back(tbl);
this->SymbolTableExists = true;
}
this->SymTable[this->TotalEntries].Address = Address;
strcpy(this->SymTable[this->TotalEntries].FunctionName, Name);
this->TotalEntries++;
}
__no_sanitize("alignment") void Symbols::AddBySymbolInfo(uint64_t Num, uint64_t EntSize, uint64_t Shndx, uintptr_t Sections)
{
__no_sanitize("alignment") void Symbols::AddSymbolInfoFromGRUB(uint64_t Num,
uint64_t EntSize,
__unused uint64_t Shndx,
uintptr_t Sections)
{
#ifdef a32
fixme("Function not working on 32-bit");
return;
fixme("Function not working on 32-bit");
return;
#endif
if (this->TotalEntries >= 0x10000)
{
error("Symbol table is full");
return;
}
char *sections = reinterpret_cast<char *>(Sections);
Elf_Sym *Symbols = nullptr;
uint8_t *StringAddress = nullptr;
#if defined(a64) || defined(aa64)
Elf64_Shdr *ElfSections = (Elf64_Shdr *)(Sections);
Elf64_Sym *ElfSymbols = nullptr;
Elf64_Xword SymbolSize = 0;
// Elf64_Xword StringSize = 0;
#elif defined(a32)
Elf32_Shdr *ElfSections = (Elf32_Shdr *)(Sections);
Elf32_Sym *ElfSymbols = nullptr;
Elf32_Word SymbolSize = 0;
// Elf32_Word StringSize = 0;
#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)
ElfSymbols = (Elf64_Sym *)(Sections + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
Elf64_Ehdr *Header = (Elf64_Ehdr *)ImageAddress;
#elif defined(a32)
ElfSymbols = (Elf32_Sym *)(Sections + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf32_Sym);
Elf32_Ehdr *Header = (Elf32_Ehdr *)ImageAddress;
#endif
if (this->TotalEntries >= 0x10000)
this->TotalEntries = 0x10000 - 1;
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;
}
debug("Symbol table found, %d entries", this->TotalEntries);
break;
case SHT_STRTAB:
if (Shndx == i)
{
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;
}
Elf_Shdr *ElfSections = (Elf_Shdr *)(ImageAddress + Header->e_shoff);
Elf_Sym *ElfSymbols = nullptr;
char *strtab = nullptr;
int64_t TotalEntries = 0;
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;
}
for (uint16_t i = 0; i < Header->e_shnum; i++)
{
switch (ElfSections[i].sh_type)
{
case SHT_SYMTAB:
ElfSymbols = (Elf_Sym *)(ImageAddress + ElfSections[i].sh_offset);
TotalEntries = ElfSections[i].sh_size / sizeof(Elf_Sym);
debug("Symbol table found, %d entries", 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;
}
}
while (ElfSymbols[0].st_value == 0)
{
if (this->TotalEntries <= 0)
break;
ElfSymbols++;
this->TotalEntries--;
}
if (ElfSymbols != nullptr && strtab != nullptr)
{
int64_t Index, MinimumIndex;
for (int64_t i = 0; i < TotalEntries - 1; i++)
{
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)
{
error("Symbol table is empty");
return;
}
while (ElfSymbols[0].st_value == 0)
{
ElfSymbols++;
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];
trace("Symbol table loaded, %d entries (%ld KiB)",
TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
// 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)
{
if (ImageAddress == 0 || Memory::Virtual().Check((void *)ImageAddress) == false)
{
error("Invalid image address %#lx", ImageAddress);
return;
}
// debug("Symbol %d: %#llx %s", i,
// this->SymTable[i].Address,
// this->SymTable[i].FunctionName);
}
}
}
this->Image = (void *)ImageAddress;
debug("Solving symbols for address: %#llx", ImageAddress);
#if defined(a64) || defined(aa64)
Elf64_Ehdr *Header = (Elf64_Ehdr *)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;
Symbols::Symbols(uintptr_t ImageAddress)
{
this->Image = (void *)ImageAddress;
this->AppendSymbols(ImageAddress);
}
for (uint16_t i = 0; i < Header->e_shnum; i++)
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() {}
Symbols::~Symbols() {}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -26,18 +26,18 @@ std::vector<UniversalAsynchronousReceiverTransmitter::Events *> RegisteredEvents
#if defined(a86)
NIF __always_inline inline uint8_t NoProfiler_inportb(uint16_t Port)
{
uint8_t Result;
asm("in %%dx, %%al"
: "=a"(Result)
: "d"(Port));
return Result;
uint8_t Result;
asm("in %%dx, %%al"
: "=a"(Result)
: "d"(Port));
return Result;
}
NIF __always_inline inline void NoProfiler_outportb(uint16_t Port, uint8_t Data)
{
asmv("out %%al, %%dx"
:
: "a"(Data), "d"(Port));
asmv("out %%al, %%dx"
:
: "a"(Data), "d"(Port));
}
#endif
@ -52,123 +52,125 @@ namespace UniversalAsynchronousReceiverTransmitter
#define SERIAL_RATE_38400_HI 0x00
#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 (Port == COMNULL)
return;
if (Port == COMNULL)
return;
this->Port = Port;
int PortNumber = 0;
this->Port = Port;
int PortNumber = 0;
switch (Port)
{
case COM1:
PortNumber = 0;
break;
case COM2:
PortNumber = 1;
break;
case COM3:
PortNumber = 2;
break;
case COM4:
PortNumber = 3;
break;
case COM5:
PortNumber = 4;
break;
case COM6:
PortNumber = 5;
break;
case COM7:
PortNumber = 6;
break;
case COM8:
PortNumber = 7;
break;
default:
return;
}
switch (Port)
{
case COM1:
PortNumber = 0;
break;
case COM2:
PortNumber = 1;
break;
case COM3:
PortNumber = 2;
break;
case COM4:
PortNumber = 3;
break;
case COM5:
PortNumber = 4;
break;
case COM6:
PortNumber = 5;
break;
case COM7:
PortNumber = 6;
break;
case COM8:
PortNumber = 7;
break;
default:
return;
}
if (serialports[PortNumber])
return;
if (serialports[PortNumber])
return;
// Initialize the serial port
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 + 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 + 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 + 4), 0x0B); // IRQs enabled, RTS/DSR set
// Initialize the serial port
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 + 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 + 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 + 4), 0x0B); // IRQs enabled, RTS/DSR set
/* FIXME https://wiki.osdev.org/Serial_Ports */
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0x1E);
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0xAE);
// Check if the serial port is faulty.
// if (NoProfiler_inportb(s_cst(uint16_t, Port + 0)) != 0xAE)
// {
// static int once = 0;
// if (!once++)
// warn("Serial port %#llx is faulty.", Port);
// // serialports[Port] = false; // ignore for now
// // return;
// }
/* FIXME https://wiki.osdev.org/Serial_Ports */
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0x1E);
// NoProfiler_outportb(s_cst(uint16_t, Port + 0), 0xAE);
// Check if the serial port is faulty.
// if (NoProfiler_inportb(s_cst(uint16_t, Port + 0)) != 0xAE)
// {
// static int once = 0;
// if (!once++)
// warn("Serial port %#llx is faulty.", Port);
// // serialports[Port] = false; // ignore for now
// // return;
// }
// Set to normal operation mode.
NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0F);
serialports[PortNumber] = true;
// Set to normal operation mode.
NoProfiler_outportb(s_cst(uint16_t, Port + 4), 0x0F);
serialports[PortNumber] = true;
#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)
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & SERIAL_BUFFER_EMPTY) == 0)
;
NoProfiler_outportb(Port, Char);
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & SERIAL_BUFFER_EMPTY) == 0)
;
NoProfiler_outportb(Port, Char);
#endif
foreach (auto e in RegisteredEvents)
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
e->OnSent(Char);
}
foreach (auto e in RegisteredEvents)
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
e->OnSent(Char);
}
SafeFunction NIF uint8_t UART::Read()
{
SafeFunction NIF uint8_t UART::Read()
{
#if defined(a86)
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & 1) == 0)
;
return NoProfiler_inportb(Port);
while ((NoProfiler_inportb(s_cst(uint16_t, Port + 5)) & 1) == 0)
;
return NoProfiler_inportb(Port);
#endif
foreach (auto e in RegisteredEvents)
{
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
{
foreach (auto e in RegisteredEvents)
{
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
{
#if defined(a86)
e->OnReceived(NoProfiler_inportb(Port));
e->OnReceived(NoProfiler_inportb(Port));
#endif
}
}
}
}
}
}
SafeFunction NIF Events::Events(SerialPorts Port)
{
this->Port = Port;
RegisteredEvents.push_back(this);
}
SafeFunction NIF Events::Events(SerialPorts Port)
{
this->Port = Port;
RegisteredEvents.push_back(this);
}
SafeFunction NIF Events::~Events()
{
for (size_t i = 0; i < RegisteredEvents.size(); i++)
if (RegisteredEvents[i] == this)
{
RegisteredEvents.remove(i);
return;
}
}
SafeFunction NIF Events::~Events()
{
forItr(itr, RegisteredEvents)
{
if (*itr == this)
{
RegisteredEvents.erase(itr);
return;
}
}
}
}

View File

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

View File

@ -36,9 +36,11 @@ namespace Video
PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(TO_PAGES(FontDataLength + 1));
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.");
KernelAllocator.FreePages((void *)font2, TO_PAGES(FontDataLength + 1));
@ -46,7 +48,8 @@ namespace Video
}
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.Height = font2->height;
}
@ -59,7 +62,8 @@ namespace Video
uint32_t glyphBufferSize = font1->charsize * 256;
if (font1->mode == 1) // 512 glyph mode
glyphBufferSize = font1->charsize * 512;
void *glyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF1_HEADER));
void *glyphBuffer =
r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF1_HEADER));
this->Info.PSF1Font->Header = font1;
this->Info.PSF1Font->GlyphBuffer = glyphBuffer;
UNUSED(glyphBufferSize); // TODO: Use this in the future?

View File

@ -34,7 +34,7 @@
#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 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
{
/** @brief Connects to the network manager */
/** Connects to the network manager */
struct
{
void (*SendPacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size);
void (*ReceivePacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size);
} Network;
/** @brief Connects to the disk manager */
/** Connects to the disk manager */
struct
{
struct
@ -144,24 +144,24 @@ struct KernelAPI
enum CallbackReason
{
/**
* @brief This is used to detect memory corruption, not used.
* This is used to detect memory corruption, not used.
*/
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,
/**
* @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.
*/
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.
*/
@ -175,7 +175,7 @@ enum CallbackReason
/* Driver callbacks for basic usage. */
/**
* @brief This is used when the kernel sends data.
* This is used when the kernel sends data.
*
* - Network
* - Packet
@ -185,13 +185,13 @@ enum CallbackReason
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.
*/
ReceiveReason,
/**
* @brief This is used to adjust driver settings.
* This is used to adjust driver settings.
*
* - Audio
* - Volume
@ -200,7 +200,7 @@ enum CallbackReason
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
* - Mouse
@ -209,7 +209,19 @@ enum CallbackReason
* - Keyboard
* - Key
*/
FetchReason,
QueryReason,
/**
* This is used when the kernel wants to wait for an event.
*
* - Input
* - Mouse
* - Position
* - Buttons
* - Keyboard
* - Key
*/
PollWaitReason,
};
union KernelCallback
@ -220,7 +232,7 @@ union KernelCallback
void *RawPtr;
unsigned long RawData;
/** @brief When the kernel wants to send a packet. */
/** When the kernel wants to send a packet. */
struct
{
struct
@ -236,7 +248,7 @@ union KernelCallback
} Fetch;
} NetworkCallback;
/** @brief When the kernel wants to write to disk. */
/** When the kernel wants to write to disk. */
struct
{
struct
@ -255,7 +267,7 @@ union KernelCallback
} Fetch;
} DiskCallback;
/** @brief When the kernel wants to get mouse position / keyboard key */
/** When the kernel wants to get mouse position / keyboard key */
struct
{
struct
@ -270,6 +282,16 @@ union KernelCallback
bool Middle;
} Buttons;
} Mouse;
struct
{
/**
* The key.
*
* @note This is a scancode, not a character.
*/
unsigned char Key;
} Keyboard;
} InputCallback;
struct
@ -282,14 +304,14 @@ union KernelCallback
bool _Channels;
/**
* @brief Adjust the volume.
* Adjust the volume.
*
* 0 - 100
*/
unsigned char Volume;
/**
* @brief Adjust the encoding.
* Adjust the encoding.
*
* 0 - None, use default
*
@ -330,7 +352,7 @@ union KernelCallback
unsigned short Encoding;
/**
* @brief Adjust the sample rate.
* Adjust the sample rate.
*
* 0 - 8000 Hz
* 1 - 11025 Hz
@ -345,7 +367,7 @@ union KernelCallback
unsigned char SampleRate;
/**
* @brief Adjust the channels.
* Adjust the channels.
*
* 0 - Mono
* 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 */
ELFBaseLoad ELFLoadRel(void *BaseImage,
void ELFLoadRel(void *BaseImage,
const char *Name,
Tasking::PCB *Process)
{
@ -35,11 +35,6 @@ namespace Execute
debug("Relocatable");
/* 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");
/* 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));
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));
if (SymbolValue == 0xdead)
{
delete ELFBase.TmpMem, ELFBase.TmpMem = nullptr;
return {};
}
return;
}
switch (ELF64_R_TYPE(RelTable->r_info))
@ -97,17 +89,14 @@ namespace Execute
default:
{
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
delete ELFBase.TmpMem, ELFBase.TmpMem = nullptr;
return {};
return;
}
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
return ELFBase;
#elif defined(a32)
return {};
#endif
}
}

View File

@ -21,17 +21,18 @@
namespace Execute
{
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(VirtualFileSystem::File &ElfFile,
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(int fd,
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;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
lseek(fd, 0, SEEK_SET);
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)
{
@ -44,19 +45,22 @@ namespace Execute
Elf64_Dyn Dynamic;
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);
vfs->Read(ElfFile, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn));
lseek(fd, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET);
fread(fd, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn));
if (Dynamic.d_tag != Tag)
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);
Ret.push_back(Dynamic);
}
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
lseek(fd, OldOffset, SEEK_SET);
return Ret;
#elif defined(a32)
return {};
#endif
}
}

View File

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

View File

@ -21,30 +21,34 @@
namespace Execute
{
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(VirtualFileSystem::File &ElfFile,
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(int fd,
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;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
lseek(fd, 0, SEEK_SET);
fread(fd, (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));
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
if (ProgramHeaders.p_type == Tag)
Ret.push_back(ProgramHeaders);
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
lseek(fd, sizeof(Elf64_Phdr), SEEK_CUR);
fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
lseek(fd, OldOffset, SEEK_SET);
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)
Size = node->Length;
if ((size_t)node->Offset > node->Length)
if (RefOffset > node->Length)
return 0;
if (node->Offset + Size > node->Length)
Size = node->Length - node->Offset;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + node->Offset), Size);
memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size;
}
@ -113,7 +113,7 @@ namespace VirtualFileSystem
}
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->Address = (Address + 512);
node->Length = size;
@ -128,6 +128,8 @@ namespace VirtualFileSystem
break;
case SYMLINK:
node->Flags = NodeFlags::SYMLINK;
node->Symlink = new char[strlen(header->link) + 1];
strncpy((char *)node->Symlink, header->link, strlen(header->link));
break;
case 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.
* - [ ] Implement a better Display::SetBrightness() function.
* - [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD).
* - [ ] Support Aarch64.
* - [ ] Fully support i386.
* - [ ] Support Aarch64.
* - [ ] SMP trampoline shouldn't be hardcoded at 0x2000.
* - [ ] Rework the stack guard.
* - [ ] Mutex implementation.
* - [ ] Vector should have a mutex.
* - [x] Mutex implementation.
* - [ ] 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)
* - [ ] 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://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
@ -207,8 +210,6 @@ NewLock(KernelLock);
#include <intrin.hpp>
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
@ -223,9 +224,10 @@ VirtualFileSystem::Virtual *vfs = nullptr;
KernelConfig Config = {
.AllocatorType = Memory::MemoryAllocatorType::XallocV1,
.SchedulerType = 1,
.DriverDirectory = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\0'},
.InitPath = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'i', 'n', 'i', 't', '\0'},
.SchedulerType = Multi,
.DriverDirectory = {'/', 'm', 'o', 'd', 'u', 'l', 'e', 's', '\0'},
.InitPath = {'/', 'b', 'i', 'n', '/', 'i', 'n', 'i', 't', '\0'},
.UseLinuxSyscalls = false,
.InterruptsOnCrash = true,
.Cores = 0,
.IOAPICInterruptCore = 0,
@ -280,6 +282,9 @@ EXTERNC NIF void Main()
KPrint("CPU: \e058C19%s \e8822AA%s \e8888FF%s",
CPU::Hypervisor(), CPU::Vendor(), CPU::Name());
debug("CPU: %s %s %s",
CPU::Hypervisor(), CPU::Vendor(), CPU::Name());
if (DebuggerIsAttached)
KPrint("\eFFA500Kernel debugger detected.");
@ -291,14 +296,11 @@ EXTERNC NIF void Main()
KPrint("Loading Kernel Symbols");
KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)bInfo.Kernel.FileBase);
if (KernelSymbolTable->GetTotalEntries() == 0 &&
bInfo.Kernel.Symbols.Num &&
bInfo.Kernel.Symbols.EntSize &&
bInfo.Kernel.Symbols.Shndx)
KernelSymbolTable->AddBySymbolInfo(bInfo.Kernel.Symbols.Num,
bInfo.Kernel.Symbols.EntSize,
bInfo.Kernel.Symbols.Shndx,
bInfo.Kernel.Symbols.Sections);
if (!KernelSymbolTable->SymTableExists)
KernelSymbolTable->AddSymbolInfoFromGRUB(bInfo.Kernel.Symbols.Num,
bInfo.Kernel.Symbols.EntSize,
bInfo.Kernel.Symbols.Shndx,
bInfo.Kernel.Symbols.Sections);
KPrint("Reading Kernel Parameters");
ParseConfig((char *)bInfo.Kernel.CommandLine, &Config);
@ -453,74 +455,74 @@ EXTERNC NIF void Main()
DevFS = vfs->Create("/dev", NodeFlags::DIRECTORY);
else
{
File dev = vfs->Open("/dev");
if (dev.GetFlags() != NodeFlags::DIRECTORY)
RefNode *dev = vfs->Open("/dev");
if (dev->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/dev is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(dev);
DevFS = dev.GetNode();
DevFS = dev->GetNode();
delete dev;
}
if (!vfs->PathExists("/mnt"))
MntFS = vfs->Create("/mnt", NodeFlags::DIRECTORY);
else
{
File mnt = vfs->Open("/mnt");
if (mnt.GetFlags() != NodeFlags::DIRECTORY)
RefNode *mnt = vfs->Open("/mnt");
if (mnt->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/mnt is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(mnt);
MntFS = mnt.GetNode();
MntFS = mnt->GetNode();
delete mnt;
}
if (!vfs->PathExists("/proc"))
ProcFS = vfs->Create("/proc", NodeFlags::DIRECTORY);
else
{
File proc = vfs->Open("/proc", nullptr);
if (proc.GetFlags() != NodeFlags::DIRECTORY)
RefNode *proc = vfs->Open("/proc", nullptr);
if (proc->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/proc is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(proc);
ProcFS = proc.GetNode();
ProcFS = proc->GetNode();
delete proc;
}
if (!vfs->PathExists("/var"))
VarLogFS = vfs->Create("/var", NodeFlags::DIRECTORY);
else
{
File var = vfs->Open("/var", nullptr);
if (var.GetFlags() != NodeFlags::DIRECTORY)
RefNode *var = vfs->Open("/var", nullptr);
if (var->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/var is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(var);
VarLogFS = var.GetNode();
VarLogFS = var->GetNode();
delete var;
if (!vfs->PathExists("/var/log"))
VarLogFS = vfs->Create("/var/log", NodeFlags::DIRECTORY);
else
{
File var_log = vfs->Open("/var/log", nullptr);
if (var_log.GetFlags() != NodeFlags::DIRECTORY)
RefNode *var_log = vfs->Open("/var/log", nullptr);
if (var_log->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/var/log is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(var_log);
VarLogFS = var_log.GetNode();
VarLogFS = var_log->GetNode();
delete var_log;
}
}
KPrint("\e058C19################################");
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
TaskManager = new Tasking::Task(Tasking::IP(KernelMainThread));
CPU::Halt(true);
}
@ -573,14 +575,16 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info)
* memory management to be initialized first.
*/
TestString();
Test_std();
TestMemoryAllocation();
#endif
EnableProfiler = true;
Main();
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
extern "C" void __cxa_finalize(void *);
EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
{
UNUSED(Reboot);
@ -588,9 +592,6 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
trace("\n\n\n#################### SYSTEM SHUTTING DOWN ####################\n\n");
if (RecoveryScreen)
delete RecoveryScreen, RecoveryScreen = nullptr;
if (NIManager)
delete NIManager, NIManager = nullptr;
@ -620,8 +621,10 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
debug("Calling destructors...");
for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++)
(*func)();
__cxa_finalize(nullptr);
debug("Done.");
}
#pragma GCC diagnostic pop
EXTERNC void TaskingPanic()
{

View File

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

View File

@ -15,20 +15,25 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_ICONS_AND_FONTS_H__
#define __FENNIX_KERNEL_ICONS_AND_FONTS_H__
#include "../cmds.hpp"
#include <types.h>
#include <filesystem.hpp>
#include <task.hpp>
extern char CursorArrow[];
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[];
#include "../../kernel.h"
#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/>.
*/
#ifndef __FENNIX_KERNEL_SHELL_CMDS_H__
#define __FENNIX_KERNEL_SHELL_CMDS_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
__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
#endif // !__FENNIX_KERNEL_SHELL_CMDS_H__

View File

@ -21,13 +21,14 @@
#endif
#include <filesystem/ustar.hpp>
#include <kshell.hpp>
#include <power.hpp>
#include <lock.hpp>
#include <printf.h>
#include <exec.hpp>
#include <cwalk.h>
#include <vm.hpp>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_STDIO
#define STBI_NO_LINEAR
@ -39,22 +40,17 @@
#include "DAPI.hpp"
#include "Fex.hpp"
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
Driver::Driver *DriverManager = nullptr;
Disk::Manager *DiskManager = nullptr;
NetworkInterfaceManager::NetworkInterface *NIManager = nullptr;
Recovery::KernelRecovery *RecoveryScreen = nullptr;
VirtualFileSystem::Node *DevFS = nullptr;
VirtualFileSystem::Node *MntFS = nullptr;
VirtualFileSystem::Node *ProcFS = nullptr;
VirtualFileSystem::Node *VarLogFS = nullptr;
NewLock(ShutdownLock);
#ifdef DEBUG
void TreeFS(Node *node, int Depth)
{
@ -62,6 +58,7 @@ void TreeFS(Node *node, int Depth)
foreach (auto Chld in node->Children)
{
printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name);
if (!Config.BootAnimation)
Display->SetBuffer(0);
TaskManager->Sleep(100);
@ -74,8 +71,8 @@ const char *Statuses[] = {
"AAFF00", /* Ready */
"00AA00", /* Running */
"FFAA00", /* Sleeping */
"FFAA00", /* Waiting */
"FF0088", /* Stopped */
"FFAA00", /* Blocked */
"FF0088", /* Zombie */
"FF0000", /* Terminated */
};
@ -135,14 +132,16 @@ static int ShowTaskManager = 0;
void TaskMgr()
{
TaskManager->GetCurrentThread()->Rename("Debug Task Manager");
TaskManager->GetCurrentThread()->SetPriority(Tasking::Low);
thisThread->Rename("Debug Task Manager");
thisThread->SetPriority(Tasking::Idle);
while (ShowTaskManager == 0)
CPU::Pause();
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy100Usage)->Rename("Dummy 100% Usage");
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy0Usage)->Rename("Dummy 0% Usage");
thisThread->SetPriority(Tasking::Idle);
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr_Dummy100Usage))->Rename("Dummy 100% Usage");
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr_Dummy0Usage))->Rename("Dummy 0% Usage");
while (true)
{
@ -169,7 +168,7 @@ void TaskMgr()
{
if (!Proc)
continue;
int Status = Proc->Status;
int Status = Proc->Status.load();
uint64_t ProcessCpuUsage = GetUsage(OldSystemTime, &Proc->Info);
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);
@ -178,7 +177,7 @@ void TaskMgr()
{
if (!Thd)
continue;
Status = Thd->Status;
Status = Thd->Status.load();
uint64_t ThreadCpuUsage = GetUsage(OldSystemTime, &Thd->Info);
#if defined(a64)
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;
KPrint("Testing syscalls...");
Tasking::PCB *SyscallsTestProcess = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(),
"Syscalls Test",
Tasking::TaskTrustLevel::User,
KernelSymbolTable);
thisThread->Rename("Debug File List");
thisThread->SetPriority(Tasking::Idle);
Tasking::TCB *SyscallsTestThread = TaskManager->CreateThread(SyscallsTestProcess,
(Tasking::IP)TestSyscalls,
nullptr,
nullptr,
std::vector<AuxiliaryVector>(),
Tasking::TaskArchitecture::x64,
Tasking::TaskCompatibility::Native,
true);
SyscallsTestThread->SetCritical(true);
TaskManager->GetSecurityManager()->TrustToken(SyscallsTestThread->Security.UniqueToken, Tasking::TTL::FullTrust);
while (ShowOpenFiles == 0)
CPU::Pause();
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)
// {
// 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)
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));
}
while (ShowOpenFiles == 0)
CPU::Pause();
SyscallsTestThread->Status = Tasking::TaskStatus::Ready;
TaskManager->WaitForThread(SyscallsTestThread);
KPrint("Test complete");
Video::ScreenBuffer *sb = Display->GetBuffer(0);
for (short i = 0; i < 500; i++)
{
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
Execute::SpawnData SpawnInit()
int SpawnInit()
{
const char *envp[5] = {
"PATH=/bin:/usr/bin",
@ -284,18 +321,17 @@ void BootLogoAnimationThread()
while (FrameCount < 27)
{
sprintf(BootAnimPath, "/etc/boot/%ld.tga", FrameCount);
File ba = vfs->Open(BootAnimPath);
if (!ba.IsOK())
RefNode *frame = vfs->Open(BootAnimPath);
if (!frame)
{
vfs->Close(ba);
debug("Failed to load boot animation frame %s", BootAnimPath);
break;
}
FrameSizes[FrameCount] = s_cst(uint32_t, ba.GetLength());
Frames[FrameCount] = new uint8_t[ba.GetLength()];
vfs->Read(ba, Frames[FrameCount], ba.GetLength());
vfs->Close(ba);
FrameSizes[FrameCount] = s_cst(uint32_t, frame->Length);
Frames[FrameCount] = new uint8_t[frame->Length];
frame->Read(Frames[FrameCount], frame->Length);
delete frame;
FrameCount++;
}
@ -306,10 +342,13 @@ void BootLogoAnimationThread()
{
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;
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)
continue;
@ -332,7 +371,8 @@ void BootLogoAnimationThread()
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);
@ -359,14 +399,17 @@ void ExitLogoAnimationThread()
uint32_t DispX = Display->GetBuffer(1)->Width;
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;
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;
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)
continue;
@ -389,7 +432,8 @@ void ExitLogoAnimationThread()
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);
@ -411,28 +455,49 @@ void CleanupProcessesThreadWrapper() { TaskManager->CleanupProcessesThread(); }
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);
TaskManager->SetCleanupThread(clnThd);
TaskManager->GetCurrentThread()->SetPriority(Tasking::Critical);
thisThread->SetPriority(Tasking::Critical);
Tasking::TCB *blaThread = nullptr;
if (Config.BootAnimation)
{
blaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)BootLogoAnimationThread);
blaThread =
TaskManager->CreateThread(thisProcess,
Tasking::IP(BootLogoAnimationThread));
blaThread->Rename("Logo Animation");
}
#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);
TestSyscallsKernel();
#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);
if (IsVirtualizedEnvironment())
KPrint("Running in Virtualized Environment");
KPrint("Initializing Disk Manager...");
DiskManager = new Disk::Manager;
@ -455,47 +520,23 @@ void KernelMainThread()
KPrint("Starting Network Interface Manager...");
NIManager->StartService();
printf("\eCCCCCC[\e00AEFFKernel Thread\eCCCCCC] Setting up userspace");
if (!Config.BootAnimation)
Display->SetBuffer(0);
Execute::SpawnData ret = {Execute::ExStatus::Unknown, nullptr, nullptr};
Tasking::TCB *ExecuteThread = nullptr;
KPrint("Setting up userspace");
int ExitCode = -1;
ExecuteThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)Execute::LibraryManagerService);
ExecuteThread->Rename("Library Manager");
ExecuteThread->SetCritical(true);
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)
Tasking::TCB *initThread = nullptr;
int tid = SpawnInit();
if (tid < 0)
{
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, ret.Status);
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, tid);
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);
TaskManager->GetCurrentThread()->SetPriority(Tasking::Idle);
thisThread->SetPriority(Tasking::Idle);
TaskManager->WaitForThread(ret.Thread);
ExitCode = ret.Thread->GetExitCode();
TaskManager->WaitForThread(initThread);
ExitCode = initThread->GetExitCode();
Exit:
if (ExitCode == 0)
{
@ -505,25 +546,27 @@ Exit:
CPU::Halt(true);
}
KPrint("\eE85230Userspace process exited with code %d (%#x)", ExitCode,
ExitCode < 0 ? -ExitCode : ExitCode);
KPrint("Dropping to recovery screen...");
TaskManager->Sleep(2500);
KPrint("\eE85230Userspace process exited with code %d (%#x)",
ExitCode, ExitCode < 0 ? -ExitCode : ExitCode);
KPrint("Dropping to kernel shell...");
TaskManager->Sleep(1000);
TaskManager->WaitForThread(blaThread);
RecoveryScreen = new Recovery::KernelRecovery;
TaskManager->CreateThread(thisProcess,
Tasking::IP(KShellThread))
->Rename("Kernel Shell");
CPU::Halt(true);
}
NewLock(ShutdownLock);
void __no_stack_protector KernelShutdownThread(bool Reboot)
{
SmartLock(ShutdownLock);
debug("KernelShutdownThread(%s)", Reboot ? "true" : "false");
if (Config.BootAnimation && TaskManager)
{
if (RecoveryScreen)
delete RecoveryScreen, RecoveryScreen = nullptr;
Tasking::TCB *elaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)ExitLogoAnimationThread);
Tasking::TCB *elaThread =
TaskManager->CreateThread(thisProcess,
Tasking::IP(ExitLogoAnimationThread));
elaThread->Rename("Logo Animation");
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
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
hardware resources and providing essential services to user-level
applications.
Copyright (C) 2023 EnderIce2
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
@ -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,
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.
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
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 is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

View File

@ -17,29 +17,35 @@
#include <bitmap.hpp>
bool Bitmap::operator[](uint64_t index) { return Get(index); }
bool Bitmap::Get(uint64_t index)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
}
bool Bitmap::Set(uint64_t index, bool value)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
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)
{
UNUSED(ps);
size_t count = 0;
while (len > 0)
@ -792,21 +793,31 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz
__chk_fail();
void *ret = nullptr;
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memcpy_sse4_2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memcpy_sse4_1(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memcpy_ssse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memcpy_sse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2)
ret = memcpy_sse2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE)
ret = memcpy_sse(dest, src, len);
if (0) /* FIXME */
{
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memcpy_sse4_2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memcpy_sse4_1(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memcpy_ssse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memcpy_sse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2)
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
{
static int once = 0;
if (!once++)
fixme("SIMD memcpy disabled");
ret = memcpy_unsafe(dest, src, len);
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
@ -857,21 +868,31 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len,
__chk_fail();
void *ret = nullptr;
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memset_sse4_2(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memset_sse4_1(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memset_ssse3(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memset_sse3(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2)
ret = memset_sse2(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE)
ret = memset_sse(dest, val, len);
if (0) /* FIXME */
{
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memset_sse4_2(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memset_sse4_1(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memset_ssse3(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memset_sse3(dest, val, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2)
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
{
static int once = 0;
if (!once++)
fixme("SIMD memset disabled");
ret = memset_unsafe(dest, val, len);
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
@ -928,21 +949,31 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si
__chk_fail();
void *ret = nullptr;
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memmove_sse4_2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memmove_sse4_1(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memmove_ssse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memmove_sse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2)
ret = memmove_sse2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE)
ret = memmove_sse(dest, src, len);
if (0) /* FIXME */
{
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memmove_sse4_2(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE41)
ret = memmove_sse4_1(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSSE3)
ret = memmove_ssse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE3)
ret = memmove_sse3(dest, src, len);
else if (simd & CPU::x86SIMDType::SIMD_SSE2)
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
{
static int once = 0;
if (!once++)
fixme("SIMD memmove disabled");
ret = memmove_unsafe(dest, src, len);
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{

View File

@ -37,10 +37,25 @@ namespace __cxxabiv1
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)
{
debug("Registering atexit function %p( %p, %p )",
f, objptr, dso);
if (KernelSymbolTable)
{
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)
return -1;
@ -53,23 +68,38 @@ namespace __cxxabiv1
extern "C" void __cxa_finalize(void *f)
{
fixme("__cxa_finalize( %p ) called.", f);
function("%p", f);
uarch_t i = __atexit_func_count;
if (!f)
if (f == nullptr)
{
while (i--)
{
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);
}
}
return;
}
while (i--)
{
if (__atexit_funcs[i].destructor_func == f)
{
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__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)
@ -122,8 +152,8 @@ namespace __cxxabiv1
{
if (TaskManager && !TaskManager->IsPanic())
{
TaskManager->KillThread(TaskManager->GetCurrentThread(), Tasking::KILL_CXXABI_EXCEPTION);
TaskManager->Schedule();
TaskManager->KillThread(thisThread, Tasking::KILL_CXXABI_EXCEPTION);
TaskManager->Yield();
}
error("No task manager to kill thread!");

View File

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

View File

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

View File

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