mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-25 22:14:37 +00:00
Update kernel
This commit is contained in:
parent
3b65386399
commit
2c51e4432f
14
.vscode/c_boilerplates.code-snippets
vendored
14
.vscode/c_boilerplates.code-snippets
vendored
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
3
.vscode/c_cpp_properties.json
vendored
3
.vscode/c_cpp_properties.json
vendored
@ -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
78
.vscode/launch.json
vendored
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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]; }
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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)
|
||||
|
23
Core/CPU.cpp
23
Core/CPU.cpp
@ -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
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
306
Core/Lock.cpp
306
Core/Lock.cpp
@ -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;
|
||||
}
|
||||
|
@ -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
@ -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)) : "");
|
||||
}
|
||||
}
|
||||
|
@ -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() {}
|
||||
}
|
||||
|
@ -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 *)§ions[bInfo.Kernel.Symbols.EntSize * i];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[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
15
Core/Memory/SmartHeap.cpp
Normal 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);
|
||||
}
|
||||
}
|
153
Core/Power.cpp
153
Core/Power.cpp
@ -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
|
||||
|
398
Core/Symbols.cpp
398
Core/Symbols.cpp
@ -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 *)§ions[EntSize * i];
|
||||
Elf_Shdr *str = (Elf_Shdr *)§ions[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() {}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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?
|
||||
|
60
DAPI.hpp
60
DAPI.hpp
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
@ -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};
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
115
ExecutionLayer/BinaryParse.cpp
Normal file
115
ExecutionLayer/BinaryParse.cpp
Normal 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;
|
||||
}
|
||||
}
|
791
ExecutionLayer/Elf/ElfLoader.cpp
Normal file
791
ExecutionLayer/Elf/ElfLoader.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
203
ExecutionLayer/Elf/ElfParse.cpp
Normal file
203
ExecutionLayer/Elf/ElfParse.cpp
Normal 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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
161
ExecutionLayer/Spawn.cpp
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
434
FileSystem/FileDescriptor.cpp
Normal file
434
FileSystem/FileDescriptor.cpp
Normal 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
197
FileSystem/FileNode.cpp
Normal 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
157
FileSystem/Kernel_IO.cpp
Normal 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;
|
||||
}
|
218
GUI/GUITools.cpp
218
GUI/GUITools.cpp
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
253
GUI/Icons.cpp
253
GUI/Icons.cpp
@ -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, //
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
141
GUI/Widgets.cpp
141
GUI/Widgets.cpp
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
85
Kernel.cpp
85
Kernel.cpp
@ -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()
|
||||
{
|
||||
|
426
KernelConfig.cpp
426
KernelConfig.cpp
@ -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");
|
||||
}
|
||||
|
55
KernelShell/Commands/cat.cpp
Normal file
55
KernelShell/Commands/cat.cpp
Normal 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);
|
||||
}
|
46
KernelShell/Commands/cd.cpp
Normal file
46
KernelShell/Commands/cd.cpp
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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__
|
@ -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);
|
||||
}
|
37
KernelShell/Commands/killall.cpp
Normal file
37
KernelShell/Commands/killall.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
57
KernelShell/Commands/ls.cpp
Normal file
57
KernelShell/Commands/ls.cpp
Normal 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);
|
||||
}
|
||||
}
|
35
KernelShell/Commands/lsof.cpp
Normal file
35
KernelShell/Commands/lsof.cpp
Normal 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());
|
||||
}
|
||||
}
|
41
KernelShell/Commands/lspci.cpp
Normal file
41
KernelShell/Commands/lspci.cpp
Normal 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));
|
||||
}
|
||||
}
|
64
KernelShell/Commands/mem.cpp
Normal file
64
KernelShell/Commands/mem.cpp
Normal 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)));
|
||||
}
|
33
KernelShell/Commands/ps.cpp
Normal file
33
KernelShell/Commands/ps.cpp
Normal 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);
|
||||
}
|
32
KernelShell/Commands/reboot.cpp
Normal file
32
KernelShell/Commands/reboot.cpp
Normal 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);
|
||||
}
|
32
KernelShell/Commands/shutdown.cpp
Normal file
32
KernelShell/Commands/shutdown.cpp
Normal 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);
|
||||
}
|
46
KernelShell/Commands/top.cpp
Normal file
46
KernelShell/Commands/top.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
65
KernelShell/Commands/uname.cpp
Normal file
65
KernelShell/Commands/uname.cpp
Normal 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");
|
||||
}
|
||||
}
|
51
KernelShell/Commands/uptime.cpp
Normal file
51
KernelShell/Commands/uptime.cpp
Normal 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");
|
||||
}
|
||||
}
|
29
KernelShell/Commands/whoami.cpp
Normal file
29
KernelShell/Commands/whoami.cpp
Normal 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
422
KernelShell/Shell.cpp
Normal 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;
|
||||
}
|
@ -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__
|
263
KernelThread.cpp
263
KernelThread.cpp
@ -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
10
LICENSE
@ -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.
|
||||
|
@ -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); }
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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!");
|
||||
|
@ -26,6 +26,9 @@ namespace __cxxabiv1
|
||||
unsigned outer) const
|
||||
{
|
||||
#ifndef __GXX_RTTI
|
||||
UNUSED(ThrowType);
|
||||
UNUSED(ThrowObject);
|
||||
UNUSED(outer);
|
||||
return false;
|
||||
#else
|
||||
if (*this == *ThrowType)
|
||||
|
@ -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))
|
||||
|
@ -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
81
Library/std/mutex.cpp
Normal 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
Loading…
x
Reference in New Issue
Block a user