mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-30 08:17:58 +00:00
Updated kernel (tl;dr: improved filesystem, tasking, loading files, etc..)
This commit is contained in:
parent
640f6a412a
commit
a592b85ce5
@ -168,27 +168,35 @@ namespace Driver
|
||||
Driver::Driver()
|
||||
{
|
||||
SmartCriticalSection(DriverInitLock);
|
||||
FileSystem::FILE *DriverDirectory = vfs->Open(Config.DriverDirectory);
|
||||
if (DriverDirectory->Status == FileSystem::FileStatus::OK)
|
||||
foreach (auto driver in DriverDirectory->Node->Children)
|
||||
if (driver->Flags == FileSystem::NodeFlags::FS_FILE)
|
||||
shared_ptr<VirtualFileSystem::File> DriverDirectory = vfs->Open(Config.DriverDirectory);
|
||||
if (DriverDirectory->Status == VirtualFileSystem::FileStatus::OK)
|
||||
{
|
||||
foreach (auto driver in DriverDirectory->node->Children)
|
||||
if (driver->Flags == VirtualFileSystem::NodeFlags::FILE)
|
||||
if (cwk_path_has_extension(driver->Name))
|
||||
{
|
||||
const char *extension;
|
||||
cwk_path_get_extension(driver->Name, &extension, nullptr);
|
||||
if (!strcmp(extension, ".fex") || !strcmp(extension, ".elf"))
|
||||
debug("Driver: %s; Extension: %s", driver->Name, extension);
|
||||
if (strcmp(extension, ".fex") == 0 || strcmp(extension, ".elf") == 0)
|
||||
{
|
||||
uintptr_t ret = this->LoadDriver(driver->Address, driver->Length);
|
||||
char RetString[128];
|
||||
if (ret == DriverCode::OK)
|
||||
strncpy(RetString, "\e058C19OK", 10);
|
||||
else if (ret == DriverCode::NOT_AVAILABLE)
|
||||
else if (ret == DriverCode::NOT_AVAILABLE)
|
||||
strncpy(RetString, "\eFF7900NOT AVAILABLE", 21);
|
||||
else
|
||||
sprintf(RetString, "\eE85230FAILED (%#lx)", ret);
|
||||
KPrint("%s %s", driver->Name, RetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrint("\eE85230Failed to open driver directory: %s", Config.DriverDirectory);
|
||||
CPU::Stop();
|
||||
}
|
||||
vfs->Close(DriverDirectory);
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ namespace Interrupts
|
||||
if (likely(Frame->InterruptNumber < CPU::x64::IRQ223 && Frame->InterruptNumber > CPU::x64::ISR0))
|
||||
{
|
||||
Handler *handler = (Handler *)RegisteredEvents->Get(Frame->InterruptNumber);
|
||||
if (likely(handler != (Handler *)0xdeadbeef))
|
||||
if (likely(handler != (Handler *)HASHMAP_ERROR))
|
||||
handler->OnInterruptReceived(Frame);
|
||||
else
|
||||
error("IRQ%ld is unhandled on CPU %d.", Frame->InterruptNumber - 32, Core);
|
||||
@ -151,7 +151,7 @@ namespace Interrupts
|
||||
|
||||
Handler::Handler(int InterruptNumber)
|
||||
{
|
||||
if (RegisteredEvents->Get(InterruptNumber) != (uint64_t)0xdeadbeef)
|
||||
if (RegisteredEvents->Get(InterruptNumber) != (uint64_t)HASHMAP_ERROR)
|
||||
{
|
||||
warn("IRQ%d is already registered.", InterruptNumber - 32);
|
||||
return;
|
||||
@ -165,7 +165,7 @@ namespace Interrupts
|
||||
Handler::~Handler()
|
||||
{
|
||||
debug("Unregistering interrupt handler for IRQ%d.", InterruptNumber - 32);
|
||||
if (RegisteredEvents->DeleteNode(InterruptNumber) == 0xdeadbeef)
|
||||
if (RegisteredEvents->DeleteNode(InterruptNumber) == (uint64_t)HASHMAP_ERROR)
|
||||
warn("Node %d not found.", InterruptNumber);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ __no_instrument_function void InitializeMemoryManagement(BootInfo *Info)
|
||||
#endif
|
||||
|
||||
trace("Initializing Physical Memory Manager");
|
||||
KernelAllocator = Physical();
|
||||
// KernelAllocator = Physical(); <- Already called in the constructor
|
||||
KernelAllocator.Init(Info);
|
||||
debug("Memory Info: %lldMB / %lldMB (%lldMB reserved)",
|
||||
TO_MB(KernelAllocator.GetUsedMemory()),
|
||||
@ -338,28 +338,34 @@ void *operator new(size_t Size)
|
||||
{
|
||||
return HeapMalloc(Size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t Size)
|
||||
{
|
||||
return HeapMalloc(Size);
|
||||
}
|
||||
|
||||
void *operator new(unsigned long Size, std::align_val_t Alignment)
|
||||
{
|
||||
fixme("operator new with alignment(%#lx) is not implemented", Alignment);
|
||||
return HeapMalloc(Size);
|
||||
}
|
||||
|
||||
void operator delete(void *Pointer)
|
||||
{
|
||||
HeapFree(Pointer);
|
||||
}
|
||||
|
||||
void operator delete[](void *Pointer)
|
||||
{
|
||||
HeapFree(Pointer);
|
||||
}
|
||||
|
||||
void operator delete(void *Pointer, long unsigned int Size)
|
||||
{
|
||||
HeapFree(Pointer);
|
||||
UNUSED(Size);
|
||||
}
|
||||
|
||||
void operator delete[](void *Pointer, long unsigned int Size)
|
||||
{
|
||||
HeapFree(Pointer);
|
||||
|
@ -1,18 +1,62 @@
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
ReadFSFunction(MEM_Read)
|
||||
{
|
||||
if (!Size)
|
||||
Size = node->Length;
|
||||
if (Offset > node->Length)
|
||||
return 0;
|
||||
if (Offset + Size > node->Length)
|
||||
Size = node->Length - Offset;
|
||||
memcpy(Buffer, (uint8_t *)(node->Address + Offset), Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
WriteFSFunction(MEM_Write)
|
||||
{
|
||||
if (!Size)
|
||||
Size = node->Length;
|
||||
if (Offset > node->Length)
|
||||
return 0;
|
||||
if (Offset + Size > node->Length)
|
||||
Size = node->Length - Offset;
|
||||
memcpy((uint8_t *)(node->Address + Offset), Buffer, Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
VirtualFileSystem::FileSystemOperations mem_op = {
|
||||
.Name = "mem",
|
||||
.Read = MEM_Read,
|
||||
.Write = MEM_Write,
|
||||
};
|
||||
|
||||
uint64_t MemMgr::GetAllocatedMemorySize()
|
||||
{
|
||||
uint64_t Size = 0;
|
||||
foreach (auto var in AllocatedPagesList)
|
||||
Size += var.PageCount;
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
Size += ap.PageCount;
|
||||
return FROM_PAGES(Size);
|
||||
}
|
||||
|
||||
bool MemMgr::Add(void *Address, size_t Count)
|
||||
{
|
||||
if (Address == nullptr)
|
||||
{
|
||||
error("Address is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
error("Count is 0!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
|
||||
{
|
||||
if (AllocatedPagesList[i].Address == Address)
|
||||
@ -20,8 +64,7 @@ namespace Memory
|
||||
error("Address already exists!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
|
||||
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
|
||||
{
|
||||
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
|
||||
{
|
||||
@ -39,15 +82,47 @@ namespace Memory
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
void *MemMgr::RequestPages(size_t Count, bool User)
|
||||
{
|
||||
void *Address = KernelAllocator.RequestPages(Count);
|
||||
for (size_t i = 0; i < Count; i++)
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
{
|
||||
int Flags = Memory::PTFlag::RW;
|
||||
if (User)
|
||||
Flags |= Memory::PTFlag::US;
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Flags);
|
||||
}
|
||||
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
|
||||
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
|
||||
if (n) // If null, error or file already exists
|
||||
{
|
||||
n->Address = (uintptr_t)Address;
|
||||
n->Length = Count * PAGE_SIZE;
|
||||
n->Operator = &mem_op;
|
||||
}
|
||||
}
|
||||
|
||||
AllocatedPagesList.push_back({Address, Count});
|
||||
return Address;
|
||||
}
|
||||
@ -57,39 +132,80 @@ namespace Memory
|
||||
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.
|
||||
/** 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("FreePages: Page count mismatch! (Allocated: %lld, Requested: %lld)", AllocatedPagesList[i].PageCount, Count);
|
||||
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", AllocatedPagesList[i].PageCount, Count);
|
||||
return;
|
||||
}
|
||||
|
||||
KernelAllocator.FreePages(Address, Count);
|
||||
for (size_t i = 0; i < Count; i++)
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
|
||||
// Memory::Virtual(this->PageTable).Unmap((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
|
||||
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
|
||||
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
|
||||
if (s != VirtualFileSystem::FileStatus::OK)
|
||||
error("Failed to delete file %s", FileName);
|
||||
}
|
||||
|
||||
AllocatedPagesList.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MemMgr::MemMgr(PageTable4 *PageTable)
|
||||
void MemMgr::DetachAddress(void *Address)
|
||||
{
|
||||
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
|
||||
if (AllocatedPagesList[i].Address == Address)
|
||||
{
|
||||
if (this->Directory)
|
||||
{
|
||||
char FileName[64];
|
||||
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, AllocatedPagesList[i].PageCount);
|
||||
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
|
||||
if (s != VirtualFileSystem::FileStatus::OK)
|
||||
error("Failed to delete file %s", FileName);
|
||||
}
|
||||
|
||||
AllocatedPagesList.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MemMgr::MemMgr(PageTable4 *PageTable, VirtualFileSystem::Node *Directory)
|
||||
{
|
||||
if (PageTable)
|
||||
this->PageTable = PageTable;
|
||||
else
|
||||
this->PageTable = (PageTable4 *)CPU::x64::readcr3().raw;
|
||||
debug("MemMgr initialized.");
|
||||
|
||||
this->Directory = Directory;
|
||||
debug("+ %#lx", this);
|
||||
}
|
||||
|
||||
MemMgr::~MemMgr()
|
||||
{
|
||||
foreach (auto var in AllocatedPagesList)
|
||||
foreach (auto ap in AllocatedPagesList)
|
||||
{
|
||||
KernelAllocator.FreePages(var.Address, var.PageCount);
|
||||
for (size_t i = 0; i < var.PageCount; i++)
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)var.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)var.Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
|
||||
KernelAllocator.FreePages(ap.Address, ap.PageCount);
|
||||
for (size_t i = 0; i < ap.PageCount; i++)
|
||||
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
|
||||
}
|
||||
debug("MemMgr destroyed.");
|
||||
|
||||
if (this->Directory)
|
||||
foreach (auto Child in this->Directory->Children)
|
||||
vfs->Delete(Child, true);
|
||||
|
||||
debug("- %#lx", this);
|
||||
}
|
||||
}
|
||||
|
162
Execute/Elf/BaseLoad.cpp
Normal file
162
Execute/Elf/BaseLoad.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
#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, Tasking::TaskCompatibility Compatibility)
|
||||
{
|
||||
/* We get the base name ("app.elf") */
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
|
||||
|
||||
shared_ptr<File> ExFile = vfs->Open(Path);
|
||||
|
||||
if (ExFile->Status != FileStatus::OK)
|
||||
{
|
||||
vfs->Close(ExFile);
|
||||
error("Failed to open file: %s", Path);
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ExFile->node->Flags != 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->node->Length;
|
||||
|
||||
/* Allocate elf in memory */
|
||||
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize));
|
||||
/* Copy the file to the allocated memory */
|
||||
memcpy(ElfFile, (void *)ExFile->node->Address, ExFileSize);
|
||||
debug("Image Size: %#lx - %#lx (length: %ld)", ElfFile, (uintptr_t)ElfFile + ExFileSize, ExFileSize);
|
||||
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_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)
|
||||
{
|
||||
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
fixme("ELF32 LSB");
|
||||
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
fixme("ELF32 MSB");
|
||||
else
|
||||
fixme("ELF32 Unknown");
|
||||
}
|
||||
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
{
|
||||
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
fixme("ELF64 LSB");
|
||||
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
fixme("ELF64 MSB");
|
||||
else
|
||||
fixme("ELF64 Unknown");
|
||||
}
|
||||
else
|
||||
fixme("Unknown ELF");
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User, ElfFile);
|
||||
Memory::Virtual pV = Memory::Virtual(Process->PageTable);
|
||||
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
|
||||
pV.Remap((void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
// for (size_t i = 0; i < TO_PAGES(ElfLazyResolverSize); i++)
|
||||
// pV.Remap((void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
/* We prepare the ELF for execution (allocate memory, etc...) */
|
||||
ELFBaseLoad bl;
|
||||
|
||||
switch (ELFHeader->e_type)
|
||||
{
|
||||
case ET_REL:
|
||||
bl = ELFLoadRel(ElfFile, ExFile.Get(), Process);
|
||||
break;
|
||||
case ET_EXEC:
|
||||
bl = ELFLoadExec(ElfFile, ExFile.Get(), Process);
|
||||
break;
|
||||
case ET_DYN:
|
||||
bl = ELFLoadDyn(ElfFile, ExFile.Get(), Process);
|
||||
break;
|
||||
case ET_CORE:
|
||||
{
|
||||
fixme("ET_CORE not implemented");
|
||||
TaskManager->RevertProcessCreation(Process);
|
||||
vfs->Close(ExFile);
|
||||
return {};
|
||||
}
|
||||
case ET_NONE:
|
||||
default:
|
||||
{
|
||||
error("Unknown ELF Type: %d", ELFHeader->e_type);
|
||||
vfs->Close(ExFile);
|
||||
TaskManager->RevertProcessCreation(Process);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
bl.InstructionPointer,
|
||||
argv, envp, bl.auxv,
|
||||
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
|
||||
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.sd.Process = Process;
|
||||
bl.sd.Thread = Thread;
|
||||
bl.sd.Status = ExStatus::OK;
|
||||
vfs->Close(ExFile);
|
||||
return bl;
|
||||
}
|
||||
}
|
24
Execute/Elf/Dyn.cpp
Normal file
24
Execute/Elf/Dyn.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#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
|
||||
{
|
||||
ELFBaseLoad ELFLoadDyn(void *BaseImage,
|
||||
VirtualFileSystem::File *ExFile,
|
||||
Tasking::PCB *Process)
|
||||
{
|
||||
fixme("Not implemented");
|
||||
return {};
|
||||
}
|
||||
}
|
@ -14,102 +14,62 @@ using namespace Tasking;
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
void ELFLoadExec(void *BaseImage,
|
||||
size_t Length,
|
||||
Elf64_Ehdr *ELFHeader,
|
||||
Memory::Virtual &pva,
|
||||
SpawnData *ret,
|
||||
char *Path,
|
||||
Tasking::PCB *Process,
|
||||
const char **argv,
|
||||
const char **envp,
|
||||
Tasking::TaskArchitecture Arch,
|
||||
Tasking::TaskCompatibility Comp)
|
||||
ELFBaseLoad ELFLoadExec(void *ElfFile,
|
||||
VirtualFileSystem::File *ExFile,
|
||||
Tasking::PCB *Process)
|
||||
{
|
||||
trace("Executable");
|
||||
Elf64_Phdr *ProgramHeader = (Elf64_Phdr *)(((char *)BaseImage) + ELFHeader->e_phoff);
|
||||
debug("p_paddr: %#lx | p_vaddr: %#lx | p_filesz: %#lx | p_memsz: %#lx | p_offset: %#lx", ProgramHeader->p_paddr, ProgramHeader->p_vaddr, ProgramHeader->p_filesz, ProgramHeader->p_memsz, ProgramHeader->p_offset);
|
||||
debug("Executable");
|
||||
ELFBaseLoad ELFBase = {};
|
||||
/* This should be deleted inside BaseLoad.cpp */
|
||||
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
|
||||
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||
Memory::Virtual pV(Process->PageTable);
|
||||
|
||||
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||
uint64_t ElfAppSize = 0;
|
||||
uintptr_t EntryPoint = ELFHeader->e_entry;
|
||||
|
||||
Elf64_Phdr ItrProgramHeader;
|
||||
Elf64_Phdr ItrPhdr;
|
||||
|
||||
/* Get base address */
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
|
||||
}
|
||||
debug("BaseAddress %#lx", BaseAddress);
|
||||
|
||||
/* Get size */
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
uintptr_t SegmentEnd;
|
||||
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz;
|
||||
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
|
||||
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
||||
}
|
||||
debug("ElfAppSize %ld", ElfAppSize);
|
||||
|
||||
uint8_t *MemoryImage = nullptr;
|
||||
|
||||
// check for TEXTREL
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
if (ItrProgramHeader.p_type == DT_TEXTREL)
|
||||
{
|
||||
warn("TEXTREL ELF is not fully tested yet!");
|
||||
MemoryImage = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(ElfAppSize));
|
||||
memset(MemoryImage, 0, ElfAppSize);
|
||||
for (uint64_t i = 0; i < TO_PAGES(ElfAppSize); i++)
|
||||
{
|
||||
pva.Remap((void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
debug("Mapping: %#lx -> %#lx", (uintptr_t)MemoryImage + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MemoryImage)
|
||||
{
|
||||
debug("Allocating %ld pages for image", TO_PAGES(ElfAppSize));
|
||||
MemoryImage = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(ElfAppSize));
|
||||
memset(MemoryImage, 0, ElfAppSize);
|
||||
for (uint64_t i = 0; i < TO_PAGES(ElfAppSize); i++)
|
||||
{
|
||||
uintptr_t Address = (uintptr_t)ProgramHeader->p_vaddr;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
pva.Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
debug("Mapping: %#lx -> %#lx", (uintptr_t)Address + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
debug("BaseAddress: %#lx | ElfAppSize: %#lx (%ld, %ld KB)", BaseAddress, ElfAppSize, ElfAppSize, TO_KB(ElfAppSize));
|
||||
|
||||
debug("Solving symbols for address: %#llx", (uintptr_t)BaseImage);
|
||||
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff);
|
||||
Elf64_Shdr *Dynamic = nullptr;
|
||||
Elf64_Shdr *DynamicSymbol = nullptr;
|
||||
/* If required, MemoryImage will be at virtual address. (unless has PIE)
|
||||
*
|
||||
* tl;dr this is where the code is stored. */
|
||||
void *MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, pV, ElfFile, ElfAppSize);
|
||||
|
||||
debug("Solving symbols for address: %#llx", (uintptr_t)ElfFile);
|
||||
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)ElfFile + ELFHeader->e_shoff);
|
||||
Elf64_Shdr *DynamicString = nullptr;
|
||||
Elf64_Shdr *SymbolTable = nullptr;
|
||||
Elf64_Shdr *StringTable = nullptr;
|
||||
Elf64_Shdr *RelaPlt = nullptr;
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
|
||||
{
|
||||
char *DynamicStringTable = (char *)((uintptr_t)BaseImage + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
|
||||
char *DynamicStringTable = (char *)((uintptr_t)ElfFile + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
|
||||
|
||||
if (strcmp(DynamicStringTable, ".dynamic") == 0)
|
||||
{
|
||||
Dynamic = &ElfSections[i];
|
||||
debug("Found .dynamic");
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".dynsym") == 0)
|
||||
{
|
||||
DynamicSymbol = &ElfSections[i];
|
||||
debug("Found .dynsym");
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".dynstr") == 0)
|
||||
if (strcmp(DynamicStringTable, ".dynstr") == 0)
|
||||
{
|
||||
DynamicString = &ElfSections[i];
|
||||
debug("Found .dynstr");
|
||||
@ -119,76 +79,57 @@ namespace Execute
|
||||
StringTable = &ElfSections[i];
|
||||
debug("Found .strtab");
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".rela.plt") == 0)
|
||||
{
|
||||
RelaPlt = &ElfSections[i];
|
||||
debug("Found .rela.plt");
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".symtab") == 0)
|
||||
{
|
||||
SymbolTable = &ElfSections[i];
|
||||
debug("Found .symtab");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Unknown section: %s", DynamicStringTable);
|
||||
}
|
||||
}
|
||||
|
||||
UNUSED(Dynamic);
|
||||
UNUSED(DynamicSymbol);
|
||||
UNUSED(SymbolTable);
|
||||
UNUSED(RelaPlt);
|
||||
|
||||
char *NeededLibraries[256];
|
||||
uint64_t InitAddress = 0;
|
||||
uint64_t FiniAddress = 0;
|
||||
|
||||
UNUSED(NeededLibraries);
|
||||
UNUSED(InitAddress);
|
||||
UNUSED(FiniAddress);
|
||||
Vector<char *> NeededLibraries;
|
||||
|
||||
if (!DynamicString)
|
||||
DynamicString = StringTable;
|
||||
|
||||
/* Calculate entry point */
|
||||
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff, sizeof(Elf64_Phdr));
|
||||
if (ItrPhdr.p_vaddr == 0)
|
||||
EntryPoint += (uintptr_t)MemoryImage;
|
||||
|
||||
char InterpreterPath[256];
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
uintptr_t MAddr;
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
switch (ItrProgramHeader.p_type)
|
||||
switch (ItrPhdr.p_type)
|
||||
{
|
||||
case PT_NULL:
|
||||
fixme("PT_NULL");
|
||||
break;
|
||||
case PT_LOAD:
|
||||
{
|
||||
debug("PT_LOAD - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
|
||||
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
|
||||
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
|
||||
MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
|
||||
debug("MAddr: %#lx", MAddr);
|
||||
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
|
||||
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
|
||||
fixme("Address: %#lx %s%s%s", MAddr,
|
||||
(ItrPhdr.p_flags & PF_R) ? "R" : "",
|
||||
(ItrPhdr.p_flags & PF_W) ? "W" : "",
|
||||
(ItrPhdr.p_flags & PF_X) ? "X" : "");
|
||||
|
||||
memcpy((void *)MAddr, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, ItrProgramHeader.p_filesz);
|
||||
debug("memcpy operation: %#lx to %#lx for length %ld", (uint8_t *)BaseImage + ItrProgramHeader.p_offset, MemoryImage + MAddr, ItrProgramHeader.p_filesz);
|
||||
memcpy((void *)MAddr, (uint8_t *)ElfFile + ItrPhdr.p_offset, ItrPhdr.p_filesz);
|
||||
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)ElfFile + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
|
||||
break;
|
||||
}
|
||||
case PT_DYNAMIC:
|
||||
{
|
||||
debug("PT_DYNAMIC - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
|
||||
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
|
||||
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
|
||||
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||
|
||||
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)BaseImage + ItrProgramHeader.p_offset);
|
||||
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
|
||||
|
||||
for (uint64_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||
{
|
||||
switch (Dynamic[i].d_tag)
|
||||
{
|
||||
case DT_NULL:
|
||||
debug("DT_NULL");
|
||||
break;
|
||||
case DT_NEEDED:
|
||||
if (Dynamic[i].d_tag == DT_NEEDED)
|
||||
{
|
||||
if (!DynamicString)
|
||||
{
|
||||
@ -196,240 +137,71 @@ namespace Execute
|
||||
break;
|
||||
}
|
||||
|
||||
debug("DT_NEEDED - Name[%ld]: %s", i, (uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr);
|
||||
NeededLibraries[i] = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
char *ReqLib = (char *)kmalloc(256);
|
||||
strcpy(ReqLib, (char *)((uintptr_t)ElfFile + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr));
|
||||
debug("DT_NEEDED - Name[%ld]: %s", i, ReqLib);
|
||||
NeededLibraries.push_back(ReqLib);
|
||||
}
|
||||
case DT_PLTRELSZ:
|
||||
{
|
||||
fixme("DT_PLTRELSZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_PLTGOT:
|
||||
{
|
||||
fixme("DT_PLTGOT - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_HASH:
|
||||
{
|
||||
fixme("DT_HASH - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_STRTAB:
|
||||
{
|
||||
fixme("DT_STRTAB - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_SYMTAB:
|
||||
{
|
||||
fixme("DT_SYMTAB - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_RELA:
|
||||
{
|
||||
fixme("DT_RELA - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_RELASZ:
|
||||
{
|
||||
fixme("DT_RELASZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_RELAENT:
|
||||
{
|
||||
fixme("DT_RELAENT - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_STRSZ:
|
||||
{
|
||||
fixme("DT_STRSZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_SYMENT:
|
||||
{
|
||||
fixme("DT_SYMENT - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_INIT:
|
||||
{
|
||||
debug("DT_INIT - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
InitAddress = Dynamic[i].d_un.d_ptr;
|
||||
break;
|
||||
}
|
||||
case DT_FINI:
|
||||
{
|
||||
debug("DT_FINI - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
FiniAddress = Dynamic[i].d_un.d_ptr;
|
||||
break;
|
||||
}
|
||||
case DT_SONAME:
|
||||
{
|
||||
fixme("DT_SONAME - Name: %s", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_RPATH:
|
||||
{
|
||||
fixme("DT_RPATH - Name: %s", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_SYMBOLIC:
|
||||
{
|
||||
fixme("DT_SYMBOLIC - Name: %s", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_REL:
|
||||
{
|
||||
fixme("DT_REL - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_RELSZ:
|
||||
{
|
||||
fixme("DT_RELSZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_RELENT:
|
||||
{
|
||||
fixme("DT_RELENT - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_PLTREL:
|
||||
{
|
||||
fixme("DT_PLTREL - Type: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_DEBUG:
|
||||
{
|
||||
fixme("DT_DEBUG - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_TEXTREL:
|
||||
{
|
||||
fixme("DT_TEXTREL - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_JMPREL:
|
||||
{
|
||||
fixme("DT_JMPREL - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_BIND_NOW:
|
||||
{
|
||||
fixme("DT_BIND_NOW - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_INIT_ARRAY:
|
||||
{
|
||||
fixme("DT_INIT_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_FINI_ARRAY:
|
||||
{
|
||||
fixme("DT_FINI_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_INIT_ARRAYSZ:
|
||||
{
|
||||
fixme("DT_INIT_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_FINI_ARRAYSZ:
|
||||
{
|
||||
fixme("DT_FINI_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_RUNPATH:
|
||||
{
|
||||
fixme("DT_RUNPATH - Name: %s", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_FLAGS:
|
||||
{
|
||||
fixme("DT_FLAGS - Flags: %#lx", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
case DT_PREINIT_ARRAY:
|
||||
{
|
||||
fixme("DT_PREINIT_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
|
||||
break;
|
||||
}
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
{
|
||||
fixme("DT_PREINIT_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
|
||||
break;
|
||||
}
|
||||
/* ... */
|
||||
default:
|
||||
fixme("DT: %ld", Dynamic[i].d_tag);
|
||||
break;
|
||||
}
|
||||
|
||||
if (Dynamic[i].d_tag == DT_NULL)
|
||||
else if (Dynamic[i].d_tag == DT_NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PT_INTERP: // Do I have to do anything here?
|
||||
case PT_INTERP:
|
||||
{
|
||||
debug("PT_INTERP - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
|
||||
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
|
||||
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
|
||||
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||
|
||||
char InterpreterPath[256];
|
||||
memcpy((void *)InterpreterPath, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, 256);
|
||||
fixme("Interpreter: %s", InterpreterPath);
|
||||
FileSystem::FILE *InterpreterFile = vfs->Open(InterpreterPath);
|
||||
if (InterpreterFile->Status != FileSystem::FileStatus::OK)
|
||||
{
|
||||
memcpy((void *)InterpreterPath, (uint8_t *)ElfFile + ItrPhdr.p_offset, 256);
|
||||
debug("Interpreter: %s", InterpreterPath);
|
||||
|
||||
shared_ptr<VirtualFileSystem::File> InterpreterFile = vfs->Open(InterpreterPath);
|
||||
if (InterpreterFile->Status != VirtualFileSystem::FileStatus::OK)
|
||||
warn("Failed to open interpreter file: %s", InterpreterPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Load interpreter file
|
||||
fixme("Interpreter file loaded: %s", InterpreterPath);
|
||||
}
|
||||
vfs->Close(InterpreterFile);
|
||||
|
||||
vfs->Close(InterpreterFile);
|
||||
break;
|
||||
}
|
||||
/* ... */
|
||||
case PT_PHDR:
|
||||
{
|
||||
debug("PT_PHDR - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
|
||||
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
|
||||
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
|
||||
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
warn("Unknown or unsupported program header type: %d", ItrProgramHeader.p_type);
|
||||
warn("Unknown or unsupported program header type: %d", ItrPhdr.p_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("Entry Point: %#lx", ELFHeader->e_entry);
|
||||
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, pV, InterpreterPath);
|
||||
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
debug("Entry Point: %#lx", EntryPoint);
|
||||
|
||||
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)Path}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t) "x86_64"}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)ELFHeader->e_entry}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader->e_phnum}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader->e_phentsize}}});
|
||||
auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader->e_phoff}}});
|
||||
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true);
|
||||
strcpy(aux_platform, "x86_64");
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)ELFHeader->e_entry,
|
||||
argv, envp, auxv,
|
||||
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
|
||||
Arch,
|
||||
Comp);
|
||||
ret->Process = Process;
|
||||
ret->Thread = Thread;
|
||||
ret->Status = ExStatus::OK;
|
||||
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)vfs->GetPathFromNode(ExFile->node).Get()}}});
|
||||
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}}});
|
||||
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;
|
||||
|
||||
foreach (auto var in NeededLibraries)
|
||||
kfree(var);
|
||||
|
||||
ELFBase.Success = true;
|
||||
return ELFBase;
|
||||
}
|
||||
}
|
||||
|
284
Execute/Elf/Parse.cpp
Normal file
284
Execute/Elf/Parse.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <msexec.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../Fex.hpp"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
void *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
|
||||
{
|
||||
Elf64_Shdr *SymbolTable = nullptr;
|
||||
Elf64_Shdr *StringTable = nullptr;
|
||||
Elf64_Sym *Symbol = nullptr;
|
||||
char *String = 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable == nullptr || StringTable == nullptr)
|
||||
return nullptr;
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
|
||||
{
|
||||
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
if (strcmp(String, Name) == 0)
|
||||
return (void *)Symbol->st_value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
|
||||
{
|
||||
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 = ELFLookupSymbol(Header, Name);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag)
|
||||
{
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||
|
||||
Elf64_Phdr ItrPhdr;
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
if (ItrPhdr.p_type == PT_DYNAMIC)
|
||||
{
|
||||
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
|
||||
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||
{
|
||||
if (Dynamic[i].d_tag == Tag)
|
||||
{
|
||||
debug("Found dynamic tag %d at %#lx [d_val: %#lx].", Tag, &Dynamic[i], Dynamic[i].d_un.d_val);
|
||||
return &Dynamic[i];
|
||||
}
|
||||
if (Dynamic[i].d_tag == DT_NULL)
|
||||
{
|
||||
debug("Reached end of dynamic tag list for tag %d.", Tag);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
debug("Dynamic tag %d not found.", Tag);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length)
|
||||
{
|
||||
void *MemoryImage = nullptr;
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||
|
||||
/* TODO: Not sure what I am supposed to do with this.
|
||||
* It is supposed to detect if it's PIC or not but I
|
||||
* don't know if it's right. */
|
||||
if (ELFGetDynamicTag(ElfFile, DT_TEXTREL))
|
||||
{
|
||||
fixme("Text relocation is not(?) tested yet!");
|
||||
MemoryImage = (uint8_t *)mem->RequestPages(TO_PAGES(Length), true);
|
||||
memset(MemoryImage, 0, Length);
|
||||
return MemoryImage;
|
||||
}
|
||||
|
||||
Elf64_Phdr ItrPhdr;
|
||||
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
|
||||
|
||||
bool FirstProgramHeader = false;
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
if (ItrPhdr.p_type == PT_LOAD && !FirstProgramHeader)
|
||||
{
|
||||
FirstProgramHeaderVirtualAddress = ItrPhdr.p_vaddr;
|
||||
FirstProgramHeader = true;
|
||||
}
|
||||
|
||||
if (ItrPhdr.p_type == PT_LOAD && ItrPhdr.p_vaddr == 0)
|
||||
{
|
||||
debug("p_vaddr is 0, allocating %ld pages for image", TO_PAGES(Length));
|
||||
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
|
||||
memset(MemoryImage, 0, Length);
|
||||
return MemoryImage;
|
||||
}
|
||||
}
|
||||
|
||||
debug("Allocating %ld pages for image", TO_PAGES(Length));
|
||||
MemoryImage = mem->RequestPages(TO_PAGES(Length));
|
||||
memset(MemoryImage, 0, Length);
|
||||
|
||||
if (FirstProgramHeaderVirtualAddress != 0)
|
||||
FirstProgramHeaderVirtualAddress &= 0xFFFFFFFFFFFFF000;
|
||||
else
|
||||
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
|
||||
|
||||
for (size_t i = 0; i < TO_PAGES(Length); i++)
|
||||
{
|
||||
pV.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
|
||||
}
|
||||
return MemoryImage;
|
||||
}
|
||||
|
||||
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &pV, 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, the GetBinaryType() call above does that. */
|
||||
shared_ptr<VirtualFileSystem::File> File = vfs->Open(Interpreter);
|
||||
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)File->node->Address;
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *InterpreterType[6] = {
|
||||
"ET_NONE",
|
||||
"ET_REL",
|
||||
"ET_EXEC",
|
||||
"ET_DYN",
|
||||
"ET_CORE",
|
||||
"ET_LOPROC - ET_HIPROC"};
|
||||
Elf64_Half IntType = ELFHeader->e_type;
|
||||
if (IntType > 5)
|
||||
IntType = 5;
|
||||
debug("Interpreter type: %s - %#x", InterpreterType[IntType], ELFHeader->e_type);
|
||||
#endif
|
||||
|
||||
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||
uint64_t ElfAppSize = 0;
|
||||
|
||||
Elf64_Phdr ItrPhdr;
|
||||
|
||||
/* Get base address */
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
|
||||
}
|
||||
|
||||
/* Get size */
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
uintptr_t SegmentEnd;
|
||||
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
|
||||
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
||||
}
|
||||
|
||||
void *MemoryImage = ELFCreateMemoryImage(mem, pV, (void *)File->node->Address, ElfAppSize);
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrPhdr,
|
||||
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||
sizeof(Elf64_Phdr));
|
||||
|
||||
if (ItrPhdr.p_type == PT_LOAD)
|
||||
{
|
||||
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
|
||||
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
|
||||
fixme("Address: %#lx %s%s%s", MAddr,
|
||||
(ItrPhdr.p_flags & PF_R) ? "R" : "",
|
||||
(ItrPhdr.p_flags & PF_W) ? "W" : "",
|
||||
(ItrPhdr.p_flags & PF_X) ? "X" : "");
|
||||
|
||||
memcpy((void *)MAddr, (uint8_t *)File->node->Address + ItrPhdr.p_offset, ItrPhdr.p_filesz);
|
||||
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)File->node->Address + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
|
||||
}
|
||||
}
|
||||
|
||||
vfs->Close(File);
|
||||
debug("Interpreter entry point: %#lx (%#lx + %#lx)", (uintptr_t)MemoryImage + ELFHeader->e_entry,
|
||||
(uintptr_t)MemoryImage, ELFHeader->e_entry);
|
||||
return (uintptr_t)MemoryImage + ELFHeader->e_entry;
|
||||
}
|
||||
}
|
93
Execute/Elf/Rel.cpp
Normal file
93
Execute/Elf/Rel.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <msexec.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../../Fex.hpp"
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||
|
||||
ELFBaseLoad ELFLoadRel(void *BaseImage,
|
||||
VirtualFileSystem::File *ExFile,
|
||||
Tasking::PCB *Process)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_NOBITS)
|
||||
{
|
||||
if (!Section->sh_size)
|
||||
continue;
|
||||
if (Section->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size));
|
||||
memset(Buffer, 0, Section->sh_size);
|
||||
|
||||
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
|
||||
for (size_t i = 0; i < TO_PAGES(Section->sh_size); i++)
|
||||
pva.Map((void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), (void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
|
||||
debug("Section %ld", Section->sh_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_REL)
|
||||
{
|
||||
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
|
||||
{
|
||||
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
|
||||
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
|
||||
|
||||
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
|
||||
uint64_t SymbolValue = 0;
|
||||
|
||||
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
|
||||
{
|
||||
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
|
||||
if (SymbolValue == 0xdead)
|
||||
{
|
||||
delete ELFBase.TmpMem;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
switch (ELF64_R_TYPE(RelTable->r_info))
|
||||
{
|
||||
case R_386_NONE:
|
||||
break;
|
||||
case R_386_32:
|
||||
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
|
||||
break;
|
||||
case R_386_PC32:
|
||||
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
|
||||
delete ELFBase.TmpMem;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
debug("Symbol value: %#lx", SymbolValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ELFBase;
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ namespace Execute
|
||||
void StartExecuteService()
|
||||
{
|
||||
mem = new Memory::MemMgr;
|
||||
return;
|
||||
// return;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -53,7 +53,7 @@ namespace Execute
|
||||
}
|
||||
}
|
||||
|
||||
SharedLibraries *AddLibrary(char *Identifier, void *LibraryImage, size_t Length)
|
||||
SharedLibraries *AddLibrary(char *Identifier, void *ElfImage, size_t Length, const Memory::Virtual &pV)
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
SharedLibraries sl;
|
||||
@ -62,12 +62,47 @@ namespace Execute
|
||||
sl.Timeout = TimeManager->CalculateTarget(600000); /* 10 minutes */
|
||||
sl.RefCount = 0;
|
||||
|
||||
void *BaseLibImage = mem->RequestPages(TO_PAGES(Length));
|
||||
memcpy(BaseLibImage, (void *)LibraryImage, Length);
|
||||
sl.Address = BaseLibImage;
|
||||
void *LibFile = mem->RequestPages(TO_PAGES(Length), true);
|
||||
memcpy(LibFile, (void *)ElfImage, Length);
|
||||
|
||||
Memory::Virtual ncpV = pV;
|
||||
sl.MemoryImage = ELFCreateMemoryImage(mem, ncpV, LibFile, Length);
|
||||
|
||||
{
|
||||
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||
Elf64_Phdr ItrProgramHeader;
|
||||
|
||||
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_phoff + ((Elf64_Ehdr *)LibFile)->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
|
||||
}
|
||||
|
||||
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_phoff + ((Elf64_Ehdr *)LibFile)->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
if (ItrProgramHeader.p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
|
||||
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
|
||||
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
|
||||
uintptr_t MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)sl.MemoryImage;
|
||||
fixme("Address: %#lx %s%s%s", MAddr,
|
||||
(ItrProgramHeader.p_flags & PF_R) ? "R" : "",
|
||||
(ItrProgramHeader.p_flags & PF_W) ? "W" : "",
|
||||
(ItrProgramHeader.p_flags & PF_X) ? "X" : "");
|
||||
|
||||
memcpy((void *)MAddr, (uint8_t *)LibFile + ItrProgramHeader.p_offset, ItrProgramHeader.p_filesz);
|
||||
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)LibFile + ItrProgramHeader.p_offset, (uintptr_t)MAddr, ItrProgramHeader.p_filesz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sl.Address = LibFile;
|
||||
sl.Length = Length;
|
||||
|
||||
debug("Library %s loaded at %#lx", Identifier, BaseLibImage);
|
||||
debug("Library %s loaded at %#lx (full file: %#lx)", Identifier, sl.MemoryImage, LibFile);
|
||||
|
||||
Libs.push_back(sl);
|
||||
return &Libs[Libs.size() - 1];
|
||||
@ -77,262 +112,4 @@ namespace Execute
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
}
|
||||
|
||||
void AttachLibrary(SharedLibraries *Lib, void *BaseImage)
|
||||
{
|
||||
SmartLock(ExecuteServiceLock);
|
||||
|
||||
BinaryType Type = GetBinaryType(BaseImage);
|
||||
switch (Type)
|
||||
{
|
||||
case BinaryType::BinTypeFex:
|
||||
{
|
||||
fixme("Fex is not supported yet");
|
||||
return;
|
||||
}
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)BaseImage;
|
||||
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||
size_t ElfAppSize = 0;
|
||||
Elf64_Phdr ItrProgramHeader;
|
||||
|
||||
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff);
|
||||
Elf64_Shdr *Dynamic = nullptr;
|
||||
Elf64_Shdr *DynamicSymbol = nullptr;
|
||||
Elf64_Shdr *DynamicString = nullptr;
|
||||
Elf64_Shdr *SymbolTable = nullptr;
|
||||
Elf64_Shdr *StringTable = nullptr;
|
||||
Elf64_Shdr *RelaPlt = nullptr;
|
||||
Elf64_Shdr *GotPlt = nullptr;
|
||||
size_t SymbolCount = 0;
|
||||
|
||||
size_t GOTSize = 0;
|
||||
Elf64_Addr *GOTEntry = 0;
|
||||
|
||||
uintptr_t RelaOffset = 0;
|
||||
uint64_t RelaEnt = 0;
|
||||
size_t RelaSize = 0;
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
|
||||
}
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||
{
|
||||
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||
uintptr_t SegmentEnd;
|
||||
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz;
|
||||
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
||||
|
||||
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
|
||||
{
|
||||
char *DynamicStringTable = (char *)((uintptr_t)BaseImage + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
|
||||
|
||||
if (strcmp(DynamicStringTable, ".dynamic") == 0)
|
||||
{
|
||||
Dynamic = &ElfSections[i];
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".dynsym") == 0)
|
||||
{
|
||||
DynamicSymbol = &ElfSections[i];
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".dynstr") == 0)
|
||||
{
|
||||
DynamicString = &ElfSections[i];
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".strtab") == 0)
|
||||
{
|
||||
StringTable = &ElfSections[i];
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".rela.plt") == 0)
|
||||
{
|
||||
RelaPlt = &ElfSections[i];
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".got.plt") == 0)
|
||||
{
|
||||
GotPlt = &ElfSections[i];
|
||||
}
|
||||
else if (strcmp(DynamicStringTable, ".symtab") == 0)
|
||||
{
|
||||
SymbolTable = &ElfSections[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ItrProgramHeader.p_type == PT_DYNAMIC)
|
||||
{
|
||||
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)BaseImage + ItrProgramHeader.p_offset);
|
||||
|
||||
for (uint64_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||
{
|
||||
switch (Dynamic[i].d_tag)
|
||||
{
|
||||
case DT_PLTRELSZ:
|
||||
{
|
||||
GOTSize = Dynamic[i].d_un.d_val;
|
||||
break;
|
||||
}
|
||||
case DT_PLTGOT:
|
||||
{
|
||||
GOTEntry = (Elf64_Addr *)Dynamic[i].d_un.d_ptr;
|
||||
break;
|
||||
}
|
||||
case DT_RELA:
|
||||
{
|
||||
RelaOffset = Dynamic[i].d_un.d_ptr;
|
||||
break;
|
||||
}
|
||||
case DT_RELASZ:
|
||||
{
|
||||
RelaSize = Dynamic[i].d_un.d_val;
|
||||
break;
|
||||
}
|
||||
case DT_RELAENT:
|
||||
{
|
||||
RelaEnt = Dynamic[i].d_un.d_val;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (Dynamic[i].d_tag == DT_NULL)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("BaseAddress: %#lx Size: %ld", BaseAddress, ElfAppSize);
|
||||
|
||||
if (RelaOffset != 0)
|
||||
{
|
||||
if (RelaEnt != sizeof(Elf64_Rela))
|
||||
{
|
||||
error("RelaEnt != sizeof(Elf64_Rela)");
|
||||
/* I should exit here I guess... */
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t RelaOffsetItr = 0; RelaOffsetItr < RelaSize; RelaOffsetItr += RelaEnt)
|
||||
{
|
||||
Elf64_Rela *Rela = (Elf64_Rela *)(((char *)BaseImage) + RelaOffset + RelaOffsetItr);
|
||||
|
||||
switch (Rela->r_info)
|
||||
{
|
||||
case R_X86_64_RELATIVE:
|
||||
{
|
||||
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)BaseImage + Rela->r_offset);
|
||||
*Ptr = (uintptr_t)Lib->Address + Rela->r_addend;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fixme("Rela: %ld", Rela->r_info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
debug("No Rela");
|
||||
|
||||
if (DynamicSymbol != nullptr)
|
||||
SymbolCount = DynamicSymbol->sh_size / sizeof(Elf64_Sym);
|
||||
else if (SymbolTable != nullptr)
|
||||
SymbolCount = SymbolTable->sh_size / sizeof(Elf64_Sym);
|
||||
|
||||
debug("GOT Address %#lx Size %#lx Entry %#lx",
|
||||
GOTEntry, GOTSize, GOTEntry ? GOTEntry : 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpData("Old GOT", (void *)GOTEntry, GOTSize);
|
||||
|
||||
if (DynamicSymbol && DynamicString)
|
||||
for (size_t i = 0; i < SymbolCount; i++)
|
||||
{
|
||||
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
|
||||
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
|
||||
if (GOTEntry)
|
||||
if (GOTEntry[i])
|
||||
{
|
||||
uintptr_t SymbolAddress = GOTEntry[i];
|
||||
debug("New GOTEntry[%d] - Symbol %s Address %#lx", i, SymbolName, SymbolAddress);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < GOTSize; i++)
|
||||
if (GOTEntry)
|
||||
if (GOTEntry[i])
|
||||
debug("GOTEntry[%d] = %#lx", i, GOTEntry[i]);
|
||||
#endif
|
||||
|
||||
GOTEntry[1] = (uintptr_t)BaseImage;
|
||||
GOTEntry[2] = (uintptr_t)ElfLazyResolver;
|
||||
|
||||
if (DynamicSymbol && DynamicString && GOTEntry)
|
||||
for (size_t i = 0; i < SymbolCount; i++)
|
||||
{
|
||||
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
|
||||
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
|
||||
|
||||
switch (ELF64_ST_TYPE(Symbol->st_info))
|
||||
{
|
||||
case STT_OBJECT:
|
||||
fixme("STT_OBJECT");
|
||||
case STT_FUNC:
|
||||
{
|
||||
uintptr_t SymbolAddress = (uintptr_t)ELFLookupSymbol((Elf64_Ehdr *)Lib->Address, SymbolName);
|
||||
if (SymbolAddress == 0)
|
||||
{
|
||||
error("Symbol %s not found", SymbolName);
|
||||
continue;
|
||||
}
|
||||
GOTEntry[i] = (uintptr_t)Lib->Address + SymbolAddress;
|
||||
debug("%d %#lx Symbol %s at %#lx (%#lx)", i, &GOTEntry[i], SymbolName, SymbolAddress, (uintptr_t)Lib->Address + SymbolAddress);
|
||||
break;
|
||||
}
|
||||
case STT_NOTYPE:
|
||||
break;
|
||||
default:
|
||||
error("Unsupported symbol type %d", ELF64_ST_TYPE(Symbol->st_info));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpData("New GOT", (void *)GOTEntry, GOTSize);
|
||||
|
||||
if (DynamicSymbol && DynamicString)
|
||||
for (size_t i = 0; i < SymbolCount; i++)
|
||||
{
|
||||
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
|
||||
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
|
||||
if (GOTEntry)
|
||||
if (GOTEntry[i])
|
||||
{
|
||||
uintptr_t SymbolAddress = GOTEntry[i];
|
||||
debug("New GOTEntry[%d] - Symbol %s Address %#lx", i, SymbolName, SymbolAddress);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < GOTSize; i++)
|
||||
if (GOTEntry)
|
||||
if (GOTEntry[i])
|
||||
debug("GOTEntry[%d] = %#lx", i, GOTEntry[i]);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
fixme("Unsupported binary type %d", Type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Lib->RefCount++;
|
||||
debug("Attached library %s", Lib->Identifier);
|
||||
}
|
||||
}
|
||||
|
21
Execute/Fex/BaseLoad.cpp
Normal file
21
Execute/Fex/BaseLoad.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#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
|
||||
{
|
||||
void FEXLoad()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -7,227 +7,77 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
BinaryType GetBinaryType(void *Image)
|
||||
{
|
||||
Fex *FexHdr = (Fex *)Image;
|
||||
|
||||
/* Elf64_Ehdr and Elf32_Ehdr are very similar (Elf64_Half and
|
||||
Elf32_Half are the same size type) so we can use directly Elf64_Ehdr. */
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_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;
|
||||
FileSystem::FILE *ExFile = vfs->Open(Path);
|
||||
shared_ptr<VirtualFileSystem::File> ExFile = vfs->Open(Path);
|
||||
|
||||
if (ExFile->Status == FileSystem::FileStatus::OK)
|
||||
if (ExFile->Status == VirtualFileSystem::FileStatus::OK)
|
||||
{
|
||||
if (ExFile->Node->Flags == FileSystem::NodeFlags::FS_FILE)
|
||||
{
|
||||
Fex *FexHdr = (Fex *)ExFile->Node->Address;
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ExFile->Node->Address;
|
||||
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)ExFile->Node->Address;
|
||||
if (FexHdr->Magic[0] == 'F' && FexHdr->Magic[1] == 'E' && FexHdr->Magic[2] == 'X' && FexHdr->Magic[3] == '\0')
|
||||
{
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
trace("%s - Fex", Path);
|
||||
Type = BinaryType::BinTypeFex;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
trace("%s - ELF", Path);
|
||||
Type = BinaryType::BinTypeELF;
|
||||
goto Exit;
|
||||
}
|
||||
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
|
||||
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
|
||||
if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
{
|
||||
trace("%s - NE", Path);
|
||||
Type = BinaryType::BinTypeNE;
|
||||
}
|
||||
else if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
trace("%s - PE", Path);
|
||||
Type = BinaryType::BinTypePE;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("%s - MZ", Path);
|
||||
Type = BinaryType::BinTypeMZ;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
Type = BinaryType::BinTypeUnknown;
|
||||
}
|
||||
debug("File opened: %s", Path);
|
||||
Type = GetBinaryType((void *)ExFile->node->Address);
|
||||
}
|
||||
Exit:
|
||||
|
||||
vfs->Close(ExFile);
|
||||
return Type;
|
||||
}
|
||||
|
||||
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||
|
||||
static inline Elf64_Shdr *GetElfSheader(Elf64_Ehdr *Header) { return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff); }
|
||||
static inline Elf64_Shdr *GetElfSection(Elf64_Ehdr *Header, uint64_t Index) { return &GetElfSheader(Header)[Index]; }
|
||||
|
||||
static inline char *GetElfStringTable(Elf64_Ehdr *Header)
|
||||
{
|
||||
if (Header->e_shstrndx == SHN_UNDEF)
|
||||
return nullptr;
|
||||
return (char *)Header + GetElfSection(Header, Header->e_shstrndx)->sh_offset;
|
||||
}
|
||||
|
||||
static inline char *elf_lookup_string(Elf64_Ehdr *Header, uintptr_t Offset)
|
||||
{
|
||||
char *StringTable = GetElfStringTable(Header);
|
||||
if (StringTable == nullptr)
|
||||
return nullptr;
|
||||
return StringTable + Offset;
|
||||
}
|
||||
|
||||
static void *ElfLookupSymbol(Elf64_Ehdr *Header, const char *Name)
|
||||
{
|
||||
Elf64_Shdr *SymbolTable = nullptr;
|
||||
Elf64_Shdr *StringTable = nullptr;
|
||||
Elf64_Sym *Symbol = nullptr;
|
||||
char *String = 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (SymbolTable == nullptr || StringTable == nullptr)
|
||||
return nullptr;
|
||||
|
||||
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
|
||||
{
|
||||
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
if (strcmp(String, Name) == 0)
|
||||
return (void *)Symbol->st_value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint32_t Index)
|
||||
{
|
||||
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
|
||||
return 0;
|
||||
Elf64_Shdr *SymbolTable = GetElfSection(Header, Table);
|
||||
|
||||
uint32_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;
|
||||
Elf32_Sym *Symbol = &((Elf32_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 = ElfLookupSymbol(Header, Name);
|
||||
if (Target == nullptr)
|
||||
{
|
||||
if (ELF32_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;
|
||||
}
|
||||
}
|
||||
|
||||
void *ELFLoadRel(Elf64_Ehdr *Header)
|
||||
{
|
||||
Elf64_Shdr *shdr = GetElfSheader(Header);
|
||||
for (uint64_t i = 0; i < Header->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_NOBITS)
|
||||
{
|
||||
if (!Section->sh_size)
|
||||
continue;
|
||||
if (Section->sh_flags & SHF_ALLOC)
|
||||
{
|
||||
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size));
|
||||
memset(Buffer, 0, Section->sh_size);
|
||||
|
||||
Memory::Virtual pva = Memory::Virtual(/* TODO TODO TODO TODO TODO TODO */);
|
||||
for (size_t i = 0; i < TO_PAGES(Section->sh_size); i++)
|
||||
pva.Map((void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), (void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
Section->sh_offset = (uint64_t)Buffer - (uint64_t)Header;
|
||||
debug("Section %ld", Section->sh_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < Header->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_REL)
|
||||
{
|
||||
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
|
||||
{
|
||||
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)Header + Section->sh_offset))[Index];
|
||||
Elf64_Shdr *Target = GetElfSection(Header, Section->sh_info);
|
||||
|
||||
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)Header + Target->sh_offset) + RelTable->r_offset);
|
||||
uint64_t SymbolValue = 0;
|
||||
|
||||
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
|
||||
{
|
||||
SymbolValue = ELFGetSymbolValue(Header, Section->sh_link, ELF64_R_SYM(RelTable->r_info));
|
||||
if (SymbolValue == 0xdead)
|
||||
return (void *)0xdeadbeef;
|
||||
}
|
||||
|
||||
switch (ELF64_R_TYPE(RelTable->r_info))
|
||||
{
|
||||
case R_386_NONE:
|
||||
break;
|
||||
case R_386_32:
|
||||
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
|
||||
break;
|
||||
case R_386_PC32:
|
||||
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
|
||||
break;
|
||||
default:
|
||||
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
|
||||
return (void *)0xdeadbeef;
|
||||
}
|
||||
debug("Symbol value: %#lx", SymbolValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (void *)Header->e_entry;
|
||||
}
|
||||
}
|
||||
|
@ -20,175 +20,74 @@ namespace Execute
|
||||
.Process = nullptr,
|
||||
.Thread = nullptr};
|
||||
|
||||
FileSystem::FILE *ExFile = vfs->Open(Path);
|
||||
if (ExFile->Status == FileSystem::FileStatus::OK)
|
||||
shared_ptr<VirtualFileSystem::File> ExFile = vfs->Open(Path);
|
||||
|
||||
if (ExFile->Status == VirtualFileSystem::FileStatus::OK)
|
||||
{
|
||||
if (ExFile->Node->Flags == FileSystem::NodeFlags::FS_FILE)
|
||||
if (ExFile->node->Flags != VirtualFileSystem::NodeFlags::FILE)
|
||||
{
|
||||
BinaryType Type = GetBinaryType(Path);
|
||||
switch (Type)
|
||||
{
|
||||
case BinaryType::BinTypeFex:
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
|
||||
Fex *FexHdr = (Fex *)ExFile->Node->Address;
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User);
|
||||
|
||||
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->Node->Length));
|
||||
memcpy(BaseImage, (void *)ExFile->Node->Address, ExFile->Node->Length);
|
||||
|
||||
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
|
||||
for (uint64_t i = 0; i < TO_PAGES(ExFile->Node->Length); i++)
|
||||
pva.Map((void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), (void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
Vector<AuxiliaryVector> auxv; // TODO!
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)FexHdr->EntryPoint,
|
||||
argv, envp, auxv,
|
||||
(IPOffset)BaseImage,
|
||||
TaskArchitecture::x64,
|
||||
TaskCompatibility::Native);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
#elif defined(__i386__)
|
||||
if (1)
|
||||
{
|
||||
#elif defined(__aarch64__)
|
||||
if (1)
|
||||
{
|
||||
#endif
|
||||
goto Exit;
|
||||
}
|
||||
ret.Status = ExStatus::InvalidFileHeader;
|
||||
goto Exit;
|
||||
}
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
|
||||
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->Node->Length));
|
||||
memcpy(BaseImage, (void *)ExFile->Node->Address, ExFile->Node->Length);
|
||||
debug("Image Size: %#lx - %#lx (length: %ld)", BaseImage, (uintptr_t)BaseImage + ExFile->Node->Length, ExFile->Node->Length);
|
||||
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User, BaseImage);
|
||||
|
||||
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
|
||||
for (uint64_t i = 0; i < TO_PAGES(ExFile->Node->Length); i++)
|
||||
pva.Remap((void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), (void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)BaseImage;
|
||||
|
||||
TaskArchitecture Arch = TaskArchitecture::x64;
|
||||
TaskCompatibility Comp = TaskCompatibility::Native;
|
||||
if (ELFHeader->e_machine == EM_386)
|
||||
Arch = TaskArchitecture::x32;
|
||||
else if (ELFHeader->e_machine == EM_AMD64)
|
||||
Arch = TaskArchitecture::x64;
|
||||
else if (ELFHeader->e_machine == EM_AARCH64)
|
||||
Arch = TaskArchitecture::ARM64;
|
||||
else
|
||||
Arch = TaskArchitecture::UnknownArchitecture;
|
||||
|
||||
// TODO: Should I care about this?
|
||||
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
|
||||
{
|
||||
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
fixme("ELF32 LSB");
|
||||
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
fixme("ELF32 MSB");
|
||||
else
|
||||
fixme("ELF32 Unknown");
|
||||
}
|
||||
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
{
|
||||
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
fixme("ELF64 LSB");
|
||||
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
fixme("ELF64 MSB");
|
||||
else
|
||||
fixme("ELF64 Unknown");
|
||||
}
|
||||
else
|
||||
fixme("Unknown ELF");
|
||||
|
||||
if (ELFHeader->e_type == ET_EXEC)
|
||||
{
|
||||
ELFLoadExec(BaseImage, ExFile->Node->Length, ELFHeader, pva, &ret, Path, Process, argv, envp, Arch, Comp);
|
||||
goto Exit;
|
||||
}
|
||||
else if (ELFHeader->e_type == ET_DYN)
|
||||
{
|
||||
fixme("Shared Object");
|
||||
}
|
||||
else if (ELFHeader->e_type == ET_REL)
|
||||
{
|
||||
trace("Relocatable");
|
||||
void *EP = ELFLoadRel(ELFHeader);
|
||||
if (EP == (void *)0xdeadbeef || EP == 0x0)
|
||||
{
|
||||
ret.Status = ExStatus::InvalidFileEntryPoint;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
fixme("auxv");
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)EP,
|
||||
argv, envp, auxv,
|
||||
(IPOffset)BaseImage,
|
||||
Arch,
|
||||
Comp);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
goto Exit;
|
||||
}
|
||||
else if (ELFHeader->e_type == ET_CORE)
|
||||
{
|
||||
fixme("Core");
|
||||
}
|
||||
else
|
||||
{
|
||||
fixme("Unknown");
|
||||
}
|
||||
ret.Status = ExStatus::InvalidFileHeader;
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
goto Exit;
|
||||
}
|
||||
default:
|
||||
ret.Status = ExStatus::Unsupported;
|
||||
goto Exit;
|
||||
}
|
||||
ret.Status = ExStatus::InvalidFilePath;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
switch (GetBinaryType(Path))
|
||||
{
|
||||
case BinaryType::BinTypeFex:
|
||||
{
|
||||
Fex *FexHdr = (Fex *)ExFile->node->Address;
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User);
|
||||
|
||||
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->node->Length));
|
||||
memcpy(BaseImage, (void *)ExFile->node->Address, ExFile->node->Length);
|
||||
|
||||
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
|
||||
for (size_t i = 0; i < TO_PAGES(ExFile->node->Length); i++)
|
||||
pva.Map((void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), (void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
Vector<AuxiliaryVector> auxv; // TODO!
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)FexHdr->EntryPoint,
|
||||
argv, envp, auxv,
|
||||
(IPOffset)BaseImage,
|
||||
TaskArchitecture::x64,
|
||||
TaskCompatibility::Native);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
}
|
||||
|
||||
ret.Status = ExStatus::InvalidFileHeader;
|
||||
goto Exit;
|
||||
}
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
ELFBaseLoad bl = ELFLoad(Path, argv, envp);
|
||||
if (!bl.Success)
|
||||
{
|
||||
ret.Status = ExStatus::GenericError;
|
||||
goto Exit;
|
||||
}
|
||||
ret = bl.sd;
|
||||
goto Exit;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ret.Status = ExStatus::Unsupported;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ExFile->Status == FileSystem::FileStatus::NOT_FOUND)
|
||||
{
|
||||
else if (ExFile->Status == VirtualFileSystem::FileStatus::NotFound)
|
||||
ret.Status = ExStatus::InvalidFilePath;
|
||||
goto Exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Status = ExStatus::InvalidFile;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (ret.Status != ExStatus::OK)
|
||||
if (ret.Process)
|
||||
ret.Process->Status = TaskStatus::Terminated;
|
||||
vfs->Close(ExFile);
|
||||
return ret;
|
||||
}
|
||||
|
@ -5,21 +5,21 @@
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
ReadFSFunction(USTAR_Read)
|
||||
{
|
||||
if (!Size)
|
||||
Size = Node->Length;
|
||||
if (Offset > Node->Length)
|
||||
Size = node->Length;
|
||||
if (Offset > node->Length)
|
||||
return 0;
|
||||
if (Offset + Size > Node->Length)
|
||||
Size = Node->Length - Offset;
|
||||
memcpy(Buffer, (uint8_t *)(Node->Address + Offset), Size);
|
||||
if (Offset + Size > node->Length)
|
||||
Size = node->Length - Offset;
|
||||
memcpy(Buffer, (uint8_t *)(node->Address + Offset), Size);
|
||||
return Size;
|
||||
}
|
||||
|
||||
FileSystemOperations ustar = {
|
||||
FileSystemOperations ustar_op = {
|
||||
.Name = "ustar",
|
||||
.Read = USTAR_Read,
|
||||
};
|
||||
@ -39,9 +39,7 @@ namespace FileSystem
|
||||
string2int(((FileHeader *)Address)->mode),
|
||||
((FileHeader *)Address)->size);
|
||||
|
||||
vfs->CreateRoot(&ustar, "/");
|
||||
|
||||
int ErrorsAllowed = 20;
|
||||
vfs->CreateRoot("/", &ustar_op);
|
||||
|
||||
for (size_t i = 0;; i++)
|
||||
{
|
||||
@ -52,7 +50,7 @@ namespace FileSystem
|
||||
if (header->name[strlen(header->name) - 1] == '/')
|
||||
header->name[strlen(header->name) - 1] = 0;
|
||||
size_t size = getsize(header->size);
|
||||
FileSystemNode *node = nullptr;
|
||||
Node *node = nullptr;
|
||||
|
||||
// if (!isempty((char *)header->name))
|
||||
// KPrint("Adding file \e88AACC%s\eCCCCCC (\e88AACC%lu \eCCCCCCbytes)", header->name, size);
|
||||
@ -62,10 +60,12 @@ namespace FileSystem
|
||||
if (isempty((char *)header->name))
|
||||
goto NextFileAddress;
|
||||
|
||||
node = vfs->Create(nullptr, header->name);
|
||||
node = vfs->Create(header->name, NodeFlags::NODE_FLAG_ERROR);
|
||||
debug("Added node: %s", node->Name);
|
||||
if (node == nullptr)
|
||||
{
|
||||
static int ErrorsAllowed = 20;
|
||||
|
||||
if (ErrorsAllowed > 0)
|
||||
{
|
||||
ErrorsAllowed--;
|
||||
@ -73,7 +73,7 @@ namespace FileSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Adding USTAR files failed because too many files were corrputed or invalid.");
|
||||
error("Adding USTAR files failed because too many files were corrupted or invalid.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -90,19 +90,19 @@ namespace FileSystem
|
||||
switch (header->typeflag[0])
|
||||
{
|
||||
case REGULAR_FILE:
|
||||
node->Flags = NodeFlags::FS_FILE;
|
||||
node->Flags = NodeFlags::FILE;
|
||||
break;
|
||||
case SYMLINK:
|
||||
node->Flags = NodeFlags::FS_SYMLINK;
|
||||
node->Flags = NodeFlags::SYMLINK;
|
||||
break;
|
||||
case DIRECTORY:
|
||||
node->Flags = NodeFlags::FS_DIRECTORY;
|
||||
node->Flags = NodeFlags::DIRECTORY;
|
||||
break;
|
||||
case CHARDEV:
|
||||
node->Flags = NodeFlags::FS_CHARDEVICE;
|
||||
node->Flags = NodeFlags::CHARDEVICE;
|
||||
break;
|
||||
case BLOCKDEV:
|
||||
node->Flags = NodeFlags::FS_BLOCKDEVICE;
|
||||
node->Flags = NodeFlags::BLOCKDEVICE;
|
||||
break;
|
||||
default:
|
||||
warn("Unknown type: %d", header->typeflag[0]);
|
||||
|
@ -9,14 +9,23 @@
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
// show debug messages
|
||||
// #define DEBUG_FILESYSTEM 1
|
||||
|
||||
#ifdef DEBUG_FILESYSTEM
|
||||
#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__)
|
||||
#else
|
||||
#define vfsdbg(m, ...)
|
||||
#endif
|
||||
|
||||
NewLock(VFSLock);
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
char *Virtual::GetPathFromNode(FileSystemNode *Node)
|
||||
shared_ptr<char> Virtual::GetPathFromNode(Node *node)
|
||||
{
|
||||
vfsdbg("GetPathFromNode( Node: \"%s\" )", Node->Name);
|
||||
FileSystemNode *Parent = Node;
|
||||
vfsdbg("GetPathFromNode( Node: \"%s\" )", node->Name);
|
||||
Node *Parent = node;
|
||||
char **Path = nullptr;
|
||||
size_t Size = 1;
|
||||
size_t PathSize = 0;
|
||||
@ -25,7 +34,7 @@ namespace FileSystem
|
||||
while (Parent != FileSystemRoot && Parent != nullptr)
|
||||
{
|
||||
bool Found = false;
|
||||
for (const auto &Children : FileSystemRoot->Children)
|
||||
foreach (const auto &Children in FileSystemRoot->Children)
|
||||
if (Children == Parent)
|
||||
{
|
||||
Found = true;
|
||||
@ -64,7 +73,9 @@ namespace FileSystem
|
||||
}
|
||||
|
||||
// Allocate a new string for the final path
|
||||
char *FinalPath = new char[Size];
|
||||
shared_ptr<char> FinalPath;
|
||||
FinalPath.reset(new char[Size]);
|
||||
|
||||
size_t Offset = 0;
|
||||
|
||||
// Concatenate the elements of the Path array into the FinalPath string
|
||||
@ -75,443 +86,533 @@ namespace FileSystem
|
||||
continue;
|
||||
}
|
||||
size_t ElementSize = strlen(Path[i]);
|
||||
memcpy(FinalPath + Offset, Path[i], ElementSize);
|
||||
memcpy(FinalPath.Get() + Offset, Path[i], ElementSize);
|
||||
Offset += ElementSize;
|
||||
}
|
||||
|
||||
// Add a null terminator to the final path string
|
||||
FinalPath[Size - 1] = '\0';
|
||||
FinalPath.Get()[Size - 1] = '\0';
|
||||
|
||||
// Deallocate the Path array
|
||||
delete[] Path;
|
||||
|
||||
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath);
|
||||
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath.Get());
|
||||
return FinalPath;
|
||||
}
|
||||
|
||||
FileSystemNode *Virtual::GetNodeFromPath(FileSystemNode *Parent, const char *Path)
|
||||
Node *Virtual::GetNodeFromPath(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("GetNodeFromPath( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
||||
vfsdbg("GetNodeFromPath( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : "(null)");
|
||||
|
||||
if (Parent == nullptr)
|
||||
Parent = FileSystemRoot;
|
||||
Node *ReturnNode = Parent;
|
||||
bool IsAbsolutePath = cwk_path_is_absolute(Path);
|
||||
|
||||
if (strcmp(Parent->Name, Path))
|
||||
if (!ReturnNode)
|
||||
ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
|
||||
if (IsAbsolutePath)
|
||||
ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
|
||||
cwk_segment segment;
|
||||
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
|
||||
{
|
||||
cwk_segment segment;
|
||||
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
|
||||
{
|
||||
error("Path doesn't have any segments.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
GetNodeFromPathNextParent:
|
||||
foreach (auto var in Parent->Children)
|
||||
{
|
||||
if (!strcmp(var->Name, SegmentName))
|
||||
{
|
||||
Parent = var;
|
||||
goto GetNodeFromPathNextParent;
|
||||
}
|
||||
}
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
const char *basename;
|
||||
cwk_path_get_basename(Path, &basename, nullptr);
|
||||
if (!strcmp(basename, Parent->Name))
|
||||
{
|
||||
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name);
|
||||
return Parent;
|
||||
}
|
||||
|
||||
vfsdbg("GetNodeFromPath()->\"%s\"", nullptr);
|
||||
error("Path doesn't have any segments.");
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
|
||||
do
|
||||
{
|
||||
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name);
|
||||
return Parent;
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
vfsdbg("GetNodeFromPath()->SegmentName: \"%s\"", SegmentName);
|
||||
GetNodeFromPathNextParent:
|
||||
foreach (auto Child in ReturnNode->Children)
|
||||
{
|
||||
vfsdbg("comparing \"%s\" with \"%s\"", Child->Name, SegmentName);
|
||||
if (strcmp(Child->Name, SegmentName) == 0)
|
||||
{
|
||||
ReturnNode = Child;
|
||||
goto GetNodeFromPathNextParent;
|
||||
}
|
||||
}
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
const char *basename;
|
||||
cwk_path_get_basename(Path, &basename, nullptr);
|
||||
vfsdbg("BaseName: \"%s\" NodeName: \"%s\"", basename, ReturnNode->Name);
|
||||
|
||||
if (strcmp(basename, ReturnNode->Name) == 0)
|
||||
{
|
||||
vfsdbg("GetNodeFromPath()->\"%s\"", ReturnNode->Name);
|
||||
return ReturnNode;
|
||||
}
|
||||
|
||||
vfsdbg("GetNodeFromPath()->\"(null)\"");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSystemNode *AddNewChild(FileSystemNode *Parent, const char *Name)
|
||||
shared_ptr<File> Virtual::ConvertNodeToFILE(Node *node)
|
||||
{
|
||||
vfsdbg("AddNewChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
|
||||
FileSystemNode *newNode = new FileSystemNode;
|
||||
newNode->Parent = Parent;
|
||||
strncpy(newNode->Name, Name, FILENAME_LENGTH);
|
||||
if (likely(Parent))
|
||||
newNode->Operator = Parent->Operator;
|
||||
else
|
||||
newNode->Operator = nullptr;
|
||||
shared_ptr<File> file = make_shared<File>();
|
||||
file->Status = FileStatus::OK;
|
||||
file->node = node;
|
||||
return file;
|
||||
}
|
||||
|
||||
Node *Virtual::GetParent(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("GetParent( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
|
||||
if (Parent)
|
||||
{
|
||||
vfsdbg("GetParent()->\"%s\"", Parent->Name);
|
||||
return Parent;
|
||||
}
|
||||
|
||||
Node *ParentNode = nullptr;
|
||||
if (FileSystemRoot->Children.size() >= 1)
|
||||
{
|
||||
if (FileSystemRoot->Children[0] == nullptr)
|
||||
panic("Root node is null!");
|
||||
|
||||
ParentNode = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Check if here is a bug or something...
|
||||
const char *PathCopy;
|
||||
PathCopy = (char *)Path;
|
||||
size_t length;
|
||||
cwk_path_get_root(PathCopy, &length); // not working?
|
||||
if (length > 0)
|
||||
{
|
||||
foreach (auto Child in FileSystemRoot->Children)
|
||||
{
|
||||
if (strcmp(Child->Name, PathCopy) == 0)
|
||||
{
|
||||
ParentNode = Child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vfsdbg("GetParent()->\"%s\"", ParentNode->Name);
|
||||
return ParentNode;
|
||||
}
|
||||
|
||||
Node *Virtual::AddNewChild(const char *Name, Node *Parent)
|
||||
{
|
||||
if (!Parent)
|
||||
{
|
||||
error("Parent is null!");
|
||||
return nullptr;
|
||||
}
|
||||
vfsdbg("AddNewChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
|
||||
|
||||
Node *newNode = new Node;
|
||||
newNode->Parent = Parent;
|
||||
strcpy(newNode->Name, Name);
|
||||
|
||||
newNode->Operator = Parent->Operator;
|
||||
Parent->Children.push_back(newNode);
|
||||
|
||||
if (likely(Parent))
|
||||
Parent->Children.push_back(newNode);
|
||||
vfsdbg("AddNewChild()->\"%s\"", newNode->Name);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
FileSystemNode *GetChild(FileSystemNode *Parent, const char *Name)
|
||||
Node *Virtual::GetChild(const char *Name, Node *Parent)
|
||||
{
|
||||
vfsdbg("GetChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
|
||||
if (likely(Parent))
|
||||
foreach (auto var in Parent->Children)
|
||||
if (strcmp(var->Name, Name) == 0)
|
||||
{
|
||||
vfsdbg("GetChild()->\"%s\"", var->Name);
|
||||
return var;
|
||||
}
|
||||
vfsdbg("GetChild()->nullptr");
|
||||
vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
|
||||
if (!Parent)
|
||||
{
|
||||
vfsdbg("GetChild()->nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
foreach (auto Child in Parent->Children)
|
||||
if (strcmp(Child->Name, Name) == 0)
|
||||
{
|
||||
vfsdbg("GetChild()->\"%s\"", Child->Name);
|
||||
return Child;
|
||||
}
|
||||
vfsdbg("GetChild()->nullptr (not found)");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileStatus RemoveChild(FileSystemNode *Parent, const char *Name)
|
||||
FileStatus Virtual::RemoveChild(const char *Name, Node *Parent)
|
||||
{
|
||||
vfsdbg("RemoveChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
|
||||
for (uintptr_t i = 0; i < Parent->Children.size(); i++)
|
||||
vfsdbg("RemoveChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
|
||||
for (size_t i = 0; i < Parent->Children.size(); i++)
|
||||
{
|
||||
if (strcmp(Parent->Children[i]->Name, Name) == 0)
|
||||
{
|
||||
delete Parent->Children[i];
|
||||
Parent->Children.remove(i);
|
||||
vfsdbg("RemoveChild()->OK");
|
||||
return FileStatus::OK;
|
||||
}
|
||||
vfsdbg("RemoveChild()->NOT_FOUND");
|
||||
return FileStatus::NOT_FOUND;
|
||||
}
|
||||
vfsdbg("RemoveChild()->NotFound");
|
||||
return FileStatus::NotFound;
|
||||
}
|
||||
|
||||
char *Virtual::NormalizePath(FileSystemNode *Parent, const char *Path)
|
||||
shared_ptr<char> Virtual::NormalizePath(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("NormalizePath( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
||||
vfsdbg("NormalizePath( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
|
||||
char *NormalizedPath = new char[strlen((char *)Path) + 1];
|
||||
char *RelativePath = nullptr;
|
||||
shared_ptr<char> RelativePath;
|
||||
|
||||
cwk_path_normalize(Path, NormalizedPath, strlen((char *)Path) + 1);
|
||||
|
||||
if (cwk_path_is_relative(NormalizedPath))
|
||||
{
|
||||
char *ParentPath = GetPathFromNode(Parent);
|
||||
size_t PathSize = cwk_path_get_absolute(ParentPath, NormalizedPath, nullptr, 0);
|
||||
RelativePath = new char[PathSize + 1];
|
||||
cwk_path_get_absolute(ParentPath, NormalizedPath, RelativePath, PathSize + 1);
|
||||
delete[] ParentPath;
|
||||
shared_ptr<char> ParentPath = GetPathFromNode(Parent);
|
||||
size_t PathSize = cwk_path_get_absolute(ParentPath.Get(), NormalizedPath, nullptr, 0);
|
||||
RelativePath.reset(new char[PathSize + 1]);
|
||||
cwk_path_get_absolute(ParentPath.Get(), NormalizedPath, RelativePath.Get(), PathSize + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RelativePath = new char[strlen(NormalizedPath) + 1];
|
||||
strcpy(RelativePath, NormalizedPath);
|
||||
RelativePath.reset(new char[strlen(NormalizedPath) + 1]);
|
||||
strcpy(RelativePath.Get(), NormalizedPath);
|
||||
}
|
||||
delete[] NormalizedPath;
|
||||
vfsdbg("NormalizePath()->\"%s\"", RelativePath);
|
||||
vfsdbg("NormalizePath()->\"%s\"", RelativePath.Get());
|
||||
return RelativePath;
|
||||
}
|
||||
|
||||
FileStatus Virtual::FileExists(FileSystemNode *Parent, const char *Path)
|
||||
bool Virtual::PathExists(const char *Path, Node *Parent)
|
||||
{
|
||||
vfsdbg("FileExists( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
||||
if (isempty((char *)Path))
|
||||
return FileStatus::INVALID_PATH;
|
||||
{
|
||||
vfsdbg("PathExists()->PathIsEmpty");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Parent == nullptr)
|
||||
Parent = FileSystemRoot;
|
||||
|
||||
char *NormalizedPath = NormalizePath(Parent, Path);
|
||||
FileSystemNode *Node = GetNodeFromPath(Parent, NormalizedPath);
|
||||
vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
|
||||
|
||||
if (!Node)
|
||||
if (GetNodeFromPath(NormalizePath(Path, Parent).Get(), Parent))
|
||||
{
|
||||
vfsdbg("FileExists()->NOT_FOUND");
|
||||
return FileStatus::NOT_FOUND;
|
||||
}
|
||||
else
|
||||
{
|
||||
vfsdbg("FileExists()->OK");
|
||||
return FileStatus::OK;
|
||||
vfsdbg("PathExists()->OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
vfsdbg("PathExists()->NotFound");
|
||||
return false;
|
||||
}
|
||||
|
||||
FileSystemNode *Virtual::Create(FileSystemNode *Parent, const char *Path)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
|
||||
if (isempty((char *)Path))
|
||||
return nullptr;
|
||||
|
||||
vfsdbg("Virtual::Create( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
||||
|
||||
FileSystemNode *CurrentParent = nullptr;
|
||||
|
||||
if (!Parent)
|
||||
{
|
||||
if (FileSystemRoot->Children.size() >= 1)
|
||||
{
|
||||
if (FileSystemRoot->Children[0] == nullptr)
|
||||
panic("Root node is null!");
|
||||
|
||||
CurrentParent = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check if here is a bug or something...
|
||||
const char *PathCopy;
|
||||
size_t length;
|
||||
PathCopy = (char *)Path;
|
||||
cwk_path_get_root(PathCopy, &length); // not working?
|
||||
foreach (auto var in FileSystemRoot->Children)
|
||||
if (!strcmp(var->Name, PathCopy))
|
||||
{
|
||||
CurrentParent = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
CurrentParent = Parent;
|
||||
|
||||
char *CleanPath = NormalizePath(CurrentParent, Path);
|
||||
|
||||
if (FileExists(CurrentParent, CleanPath) != FileStatus::NOT_FOUND)
|
||||
{
|
||||
error("File %s already exists.", CleanPath);
|
||||
goto CreatePathError;
|
||||
}
|
||||
|
||||
cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(CleanPath, &segment))
|
||||
{
|
||||
error("Path doesn't have any segments.");
|
||||
goto CreatePathError;
|
||||
}
|
||||
|
||||
warn("Virtual::Create( ) is not working properly.");
|
||||
do
|
||||
{
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
|
||||
if (GetChild(CurrentParent, SegmentName) == nullptr)
|
||||
CurrentParent = AddNewChild(CurrentParent, SegmentName);
|
||||
else
|
||||
CurrentParent = GetChild(CurrentParent, SegmentName);
|
||||
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
delete CleanPath;
|
||||
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
|
||||
return CurrentParent;
|
||||
|
||||
CreatePathError:
|
||||
vfsdbg("Virtual::Create()->nullptr");
|
||||
delete CleanPath;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSystemNode *Virtual::CreateRoot(FileSystemOperations *Operator, const char *RootName)
|
||||
Node *Virtual::CreateRoot(const char *RootName, FileSystemOperations *Operator)
|
||||
{
|
||||
if (Operator == nullptr)
|
||||
return nullptr;
|
||||
vfsdbg("Setting root to %s", RootName);
|
||||
FileSystemNode *newNode = new FileSystemNode;
|
||||
vfsdbg("Creating root %s", RootName);
|
||||
Node *newNode = new Node;
|
||||
strncpy(newNode->Name, RootName, FILENAME_LENGTH);
|
||||
newNode->Flags = NodeFlags::FS_DIRECTORY;
|
||||
newNode->Flags = NodeFlags::DIRECTORY;
|
||||
newNode->Operator = Operator;
|
||||
FileSystemRoot->Children.push_back(newNode);
|
||||
return newNode;
|
||||
}
|
||||
|
||||
FILE *Virtual::Mount(FileSystemOperations *Operator, const char *Path)
|
||||
/* TODO: Further testing needed */
|
||||
Node *Virtual::Create(const char *Path, NodeFlags Flag, Node *Parent)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
|
||||
if (unlikely(!Operator))
|
||||
if (isempty((char *)Path))
|
||||
return nullptr;
|
||||
|
||||
Node *RootNode = FileSystemRoot->Children[0];
|
||||
Node *CurrentParent = this->GetParent(Path, Parent);
|
||||
vfsdbg("Virtual::Create( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : CurrentParent->Name);
|
||||
|
||||
shared_ptr<char> CleanPath = this->NormalizePath(Path, CurrentParent);
|
||||
vfsdbg("CleanPath: \"%s\"", CleanPath.Get());
|
||||
|
||||
if (PathExists(CleanPath.Get(), CurrentParent))
|
||||
{
|
||||
error("Path %s already exists.", CleanPath.Get());
|
||||
goto CreatePathError;
|
||||
}
|
||||
|
||||
cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(CleanPath.Get(), &segment))
|
||||
{
|
||||
error("Path doesn't have any segments.");
|
||||
goto CreatePathError;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
char *SegmentName = new char[segment.end - segment.begin + 1];
|
||||
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
||||
vfsdbg("SegmentName: \"%s\"", SegmentName);
|
||||
|
||||
if (Parent)
|
||||
if (GetChild(SegmentName, RootNode) != nullptr)
|
||||
{
|
||||
RootNode = GetChild(SegmentName, RootNode);
|
||||
delete[] SegmentName;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetChild(SegmentName, CurrentParent) == nullptr)
|
||||
{
|
||||
CurrentParent = AddNewChild(SegmentName, CurrentParent);
|
||||
CurrentParent->Flags = Flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentParent = GetChild(SegmentName, CurrentParent);
|
||||
}
|
||||
|
||||
delete[] SegmentName;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
|
||||
vfsdbg("Path created: \"%s\"", GetPathFromNode(CurrentParent).Get());
|
||||
return CurrentParent;
|
||||
|
||||
CreatePathError:
|
||||
vfsdbg("Virtual::Create()->nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileStatus Virtual::Delete(const char *Path, bool Recursive, Node *Parent)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : "(null)");
|
||||
|
||||
if (isempty((char *)Path))
|
||||
return InvalidParameter;
|
||||
|
||||
if (Parent == nullptr)
|
||||
Parent = FileSystemRoot;
|
||||
|
||||
shared_ptr<char> CleanPath = this->NormalizePath(Path, Parent);
|
||||
vfsdbg("CleanPath: \"%s\"", CleanPath.Get());
|
||||
|
||||
if (!PathExists(CleanPath.Get(), Parent))
|
||||
{
|
||||
vfsdbg("Path %s doesn't exist.", CleanPath.Get());
|
||||
return InvalidPath;
|
||||
}
|
||||
|
||||
Node *NodeToDelete = GetNodeFromPath(CleanPath.Get(), Parent);
|
||||
Node *ParentNode = GetParent(CleanPath.Get(), Parent);
|
||||
|
||||
if (NodeToDelete->Flags == NodeFlags::DIRECTORY)
|
||||
{
|
||||
if (Recursive)
|
||||
{
|
||||
foreach (auto Child in NodeToDelete->Children)
|
||||
{
|
||||
FileStatus Status = Delete(GetPathFromNode(Child).Get(), true);
|
||||
if (Status != FileStatus::OK)
|
||||
{
|
||||
vfsdbg("Failed to delete child %s with status %d. (%s)", Child->Name, Status, Path);
|
||||
return PartiallyCompleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NodeToDelete->Children.size() > 0)
|
||||
{
|
||||
vfsdbg("Directory %s is not empty.", CleanPath.Get());
|
||||
return DirectoryNotEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
if (RemoveChild(NodeToDelete->Name, ParentNode) != FileStatus::OK)
|
||||
{
|
||||
vfsdbg("Failed to remove child %s from parent %s. (%s)", NodeToDelete->Name, ParentNode->Name, Path);
|
||||
return NotFound;
|
||||
}
|
||||
|
||||
vfsdbg("Virtual::Delete()->OK");
|
||||
return OK;
|
||||
}
|
||||
|
||||
FileStatus Virtual::Delete(Node *Path, bool Recursive, Node *Parent) { return Delete(GetPathFromNode(Path).Get(), Recursive, Parent); }
|
||||
|
||||
/* TODO: REWORK */
|
||||
shared_ptr<File> Virtual::Mount(const char *Path, FileSystemOperations *Operator)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
shared_ptr<File> file = make_shared<File>();
|
||||
|
||||
if (unlikely(!Operator))
|
||||
{
|
||||
file->Status = FileStatus::InvalidOperator;
|
||||
return file;
|
||||
}
|
||||
|
||||
if (unlikely(isempty((char *)Path)))
|
||||
return nullptr;
|
||||
{
|
||||
file->Status = FileStatus::InvalidParameter;
|
||||
return file;
|
||||
}
|
||||
|
||||
vfsdbg("Mounting %s", Path);
|
||||
FILE *file = new FILE;
|
||||
cwk_path_get_basename(Path, &file->Name, 0);
|
||||
const char *PathCopy;
|
||||
cwk_path_get_basename(Path, &PathCopy, 0);
|
||||
strcpy(file->Name, PathCopy);
|
||||
file->Status = FileStatus::OK;
|
||||
file->Node = Create(nullptr, Path);
|
||||
file->Node->Operator = Operator;
|
||||
file->Node->Flags = NodeFlags::FS_MOUNTPOINT;
|
||||
file->node = Create(Path, NodeFlags::MOUNTPOINT);
|
||||
file->node->Operator = Operator;
|
||||
return file;
|
||||
}
|
||||
|
||||
FileStatus Virtual::Unmount(FILE *File)
|
||||
FileStatus Virtual::Unmount(shared_ptr<File> File)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
if (unlikely(File))
|
||||
return FileStatus::INVALID_PARAMETER;
|
||||
vfsdbg("Unmounting %s", File->Name);
|
||||
if (unlikely(File.Get()))
|
||||
return FileStatus::InvalidParameter;
|
||||
fixme("Unmounting %s", File->Name);
|
||||
return FileStatus::OK;
|
||||
}
|
||||
|
||||
FILE *Virtual::Open(const char *Path, FileSystemNode *Parent)
|
||||
size_t Virtual::Read(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
vfsdbg("Opening %s with parent %s", Path, Parent->Name);
|
||||
if (unlikely(!File.Get()))
|
||||
return 0;
|
||||
|
||||
if (unlikely(!File->node))
|
||||
{
|
||||
File->Status = FileStatus::InvalidNode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(!File->node->Operator))
|
||||
{
|
||||
File->Status = FileStatus::InvalidOperator;
|
||||
return 0;
|
||||
}
|
||||
|
||||
File->Status = FileStatus::OK;
|
||||
|
||||
vfsdbg("Reading %s out->%016x", File->Name, Buffer);
|
||||
return File->node->Operator->Read(File->node, Offset, Size, Buffer);
|
||||
}
|
||||
|
||||
size_t Virtual::Write(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
if (unlikely(!File.Get()))
|
||||
return 0;
|
||||
|
||||
if (unlikely(!File->node))
|
||||
{
|
||||
File->Status = FileStatus::InvalidNode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(!File->node->Operator))
|
||||
{
|
||||
File->Status = FileStatus::InvalidOperator;
|
||||
return 0;
|
||||
}
|
||||
|
||||
File->Status = FileStatus::OK;
|
||||
|
||||
vfsdbg("Writing %s out->%016x", File->Name, Buffer);
|
||||
return File->node->Operator->Write(File->node, Offset, Size, Buffer);
|
||||
}
|
||||
|
||||
/* TODO: CHECK Open */
|
||||
shared_ptr<File> Virtual::Open(const char *Path, Node *Parent)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
vfsdbg("Opening %s with parent %s", Path, Parent ? Parent->Name : "(null)");
|
||||
const char *basename;
|
||||
|
||||
if (strcmp(Path, ".") == 0)
|
||||
{
|
||||
FILE *file = new FILE;
|
||||
file->Node = Parent;
|
||||
if (unlikely(!file->Node))
|
||||
file->Status = FileStatus::NOT_FOUND;
|
||||
const char *basename;
|
||||
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr);
|
||||
file->Name = basename;
|
||||
shared_ptr<File> file = make_shared<File>();
|
||||
file->node = Parent;
|
||||
if (unlikely(!file->node))
|
||||
file->Status = FileStatus::NotFound;
|
||||
cwk_path_get_basename(GetPathFromNode(Parent).Get(), &basename, nullptr);
|
||||
strcpy(file->Name, basename);
|
||||
return file;
|
||||
}
|
||||
|
||||
if (strcmp(Path, "..") == 0)
|
||||
{
|
||||
if (Parent->Parent != nullptr)
|
||||
Parent = Parent->Parent;
|
||||
shared_ptr<File> file = make_shared<File>();
|
||||
|
||||
FILE *file = new FILE;
|
||||
file->Node = Parent;
|
||||
if (!file->Node)
|
||||
file->Status = FileStatus::NOT_FOUND;
|
||||
const char *basename;
|
||||
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr);
|
||||
file->Name = basename;
|
||||
if (Parent->Parent != nullptr)
|
||||
file->node = Parent->Parent;
|
||||
|
||||
if (!file->node)
|
||||
file->Status = FileStatus::NotFound;
|
||||
cwk_path_get_basename(GetPathFromNode(Parent).Get(), &basename, nullptr);
|
||||
strcpy(file->Name, basename);
|
||||
return file;
|
||||
}
|
||||
|
||||
if (Parent == nullptr)
|
||||
{
|
||||
if (FileSystemRoot->Children.size() >= 1)
|
||||
Parent = FileSystemRoot->Children[0]; // 0 - filesystem root
|
||||
else
|
||||
{
|
||||
// TODO: check if here is a bug or something...
|
||||
const char *PathCopy;
|
||||
size_t length;
|
||||
PathCopy = (char *)Path;
|
||||
cwk_path_get_root(PathCopy, &length); // not working?
|
||||
foreach (auto var in FileSystemRoot->Children)
|
||||
if (!strcmp(var->Name, PathCopy))
|
||||
{
|
||||
Parent = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Node *CurrentParent = this->GetParent(Path, Parent);
|
||||
shared_ptr<char> CleanPath = NormalizePath(Path, CurrentParent);
|
||||
|
||||
char *CleanPath = NormalizePath(Parent, Path);
|
||||
|
||||
FILE *file = new FILE;
|
||||
FileStatus filestatus = FileStatus::OK;
|
||||
filestatus = FileExists(Parent, CleanPath);
|
||||
shared_ptr<File> file = make_shared<File>();
|
||||
/* TODO: Check for other errors */
|
||||
|
||||
if (filestatus != FileStatus::OK)
|
||||
if (!PathExists(CleanPath.Get(), CurrentParent))
|
||||
{
|
||||
foreach (auto var in FileSystemRoot->Children)
|
||||
if (!strcmp(var->Name, CleanPath))
|
||||
{
|
||||
file->Node = var;
|
||||
if (file->Node == nullptr)
|
||||
goto OpenNodeFail;
|
||||
const char *basename;
|
||||
cwk_path_get_basename(GetPathFromNode(var), &basename, nullptr);
|
||||
file->Name = basename;
|
||||
goto OpenNodeExit;
|
||||
}
|
||||
|
||||
file->Node = GetNodeFromPath(FileSystemRoot->Children[0], CleanPath);
|
||||
if (file->Node)
|
||||
foreach (auto Child in FileSystemRoot->Children)
|
||||
{
|
||||
const char *basename;
|
||||
cwk_path_get_basename(GetPathFromNode(file->Node), &basename, nullptr);
|
||||
file->Name = basename;
|
||||
goto OpenNodeExit;
|
||||
if (strcmp(Child->Name, CleanPath.Get()) == 0)
|
||||
{
|
||||
file->node = Child;
|
||||
if (file->node == nullptr)
|
||||
{
|
||||
file->Status = FileStatus::UnknownFileStatusError;
|
||||
file->node = nullptr;
|
||||
return file;
|
||||
}
|
||||
cwk_path_get_basename(GetPathFromNode(Child).Get(), &basename, nullptr);
|
||||
strcpy(file->Name, basename);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
OpenNodeFail:
|
||||
file->Status = filestatus;
|
||||
file->Node = nullptr;
|
||||
file->node = GetNodeFromPath(CleanPath.Get(), FileSystemRoot->Children[0]);
|
||||
if (file->node)
|
||||
{
|
||||
cwk_path_get_basename(GetPathFromNode(file->node).Get(), &basename, nullptr);
|
||||
strcpy(file->Name, basename);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file->Node = GetNodeFromPath(Parent, CleanPath);
|
||||
if (unlikely(!file->Node))
|
||||
file->Status = FileStatus::NOT_FOUND;
|
||||
const char *basename;
|
||||
cwk_path_get_basename(CleanPath, &basename, nullptr);
|
||||
file->Name = basename;
|
||||
file->node = GetNodeFromPath(CleanPath.Get(), CurrentParent);
|
||||
cwk_path_get_basename(CleanPath.Get(), &basename, nullptr);
|
||||
strcpy(file->Name, basename);
|
||||
return file;
|
||||
}
|
||||
OpenNodeExit:
|
||||
|
||||
file->Status = FileStatus::NotFound;
|
||||
return file;
|
||||
}
|
||||
|
||||
size_t Virtual::Read(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size)
|
||||
FileStatus Virtual::Close(shared_ptr<File> File)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
if (unlikely(!File))
|
||||
return 0;
|
||||
|
||||
File->Status = FileStatus::OK;
|
||||
|
||||
if (unlikely(!File->Node))
|
||||
{
|
||||
File->Status = FileStatus::INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(!File->Node->Operator))
|
||||
{
|
||||
File->Status = FileStatus::INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
vfsdbg("Reading %s out->%016x", File->Name, Buffer);
|
||||
return File->Node->Operator->Read(File->Node, Offset, Size, Buffer);
|
||||
}
|
||||
|
||||
size_t Virtual::Write(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
if (unlikely(!File))
|
||||
return 0;
|
||||
|
||||
File->Status = FileStatus::OK;
|
||||
|
||||
if (unlikely(!File->Node))
|
||||
{
|
||||
File->Status = FileStatus::INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(!File->Node->Operator))
|
||||
{
|
||||
File->Status = FileStatus::INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
vfsdbg("Writing %s out->%016x", File->Name, Buffer);
|
||||
return File->Node->Operator->Write(File->Node, Offset, Size, Buffer);
|
||||
}
|
||||
|
||||
FileStatus Virtual::Close(FILE *File)
|
||||
{
|
||||
SmartLock(VFSLock);
|
||||
if (unlikely(!File))
|
||||
return FileStatus::INVALID_HANDLE;
|
||||
if (unlikely(!File.Get()))
|
||||
return FileStatus::InvalidHandle;
|
||||
vfsdbg("Closing %s", File->Name);
|
||||
delete File;
|
||||
return FileStatus::OK;
|
||||
}
|
||||
|
||||
Virtual::Virtual()
|
||||
{
|
||||
trace("Initializing virtual file system...");
|
||||
FileSystemRoot = new FileSystemNode;
|
||||
FileSystemRoot->Flags = NodeFlags::FS_MOUNTPOINT;
|
||||
FileSystemRoot = new Node;
|
||||
FileSystemRoot->Flags = NodeFlags::MOUNTPOINT;
|
||||
FileSystemRoot->Operator = nullptr;
|
||||
FileSystemRoot->Parent = nullptr;
|
||||
strncpy(FileSystemRoot->Name, "root", 4);
|
||||
@ -520,6 +621,6 @@ namespace FileSystem
|
||||
|
||||
Virtual::~Virtual()
|
||||
{
|
||||
warn("Tried to deinitialize Virtual File System!");
|
||||
trace("Destroying virtual file system...");
|
||||
}
|
||||
}
|
||||
|
126
KThread.cpp
126
KThread.cpp
@ -11,23 +11,61 @@
|
||||
#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;
|
||||
|
||||
#ifdef DEBUG
|
||||
void TreeFS(Node *node, int Depth)
|
||||
{
|
||||
return;
|
||||
foreach (auto Chld in node->Children)
|
||||
{
|
||||
printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name);
|
||||
Display->SetBuffer(0);
|
||||
TreeFS(Chld, Depth + 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Execute::SpawnData SpawnInit()
|
||||
{
|
||||
const char *envp[9] = {
|
||||
"PATH=/system:/system/bin",
|
||||
"TERM=tty",
|
||||
"HOME=/",
|
||||
"USER=root",
|
||||
"SHELL=/system/sh",
|
||||
"PWD=/",
|
||||
"LANG=en_US.UTF-8",
|
||||
"TZ=UTC",
|
||||
nullptr};
|
||||
|
||||
const char *argv[4] = {
|
||||
Config.InitPath,
|
||||
"--init",
|
||||
"--critical",
|
||||
nullptr};
|
||||
|
||||
return Execute::Spawn(Config.InitPath, argv, envp);
|
||||
}
|
||||
|
||||
void KernelMainThread()
|
||||
{
|
||||
TaskManager->InitIPC();
|
||||
TaskManager->GetCurrentThread()->SetPriority(100);
|
||||
CPU::Interrupts(CPU::Disable);
|
||||
TaskManager->GetCurrentThread()->SetPriority(Tasking::Critical);
|
||||
|
||||
KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
|
||||
KPrint("C++ Language Version (__cplusplus): %ld", __cplusplus);
|
||||
|
||||
KPrint("Initializing Filesystem...");
|
||||
vfs = new FileSystem::Virtual;
|
||||
new FileSystem::USTAR((uintptr_t)bInfo->Modules[0].Address, vfs); // TODO: Detect initrd
|
||||
KPrint("Initializing Disk Manager...");
|
||||
DiskManager = new Disk::Manager;
|
||||
|
||||
@ -49,43 +87,69 @@ void KernelMainThread()
|
||||
KPrint("Starting Network Interface Manager...");
|
||||
NIManager->StartService();
|
||||
|
||||
KPrint("Setting up userspace...");
|
||||
KPrint("Setting up userspace");
|
||||
|
||||
const char *envp[9] = {
|
||||
"PATH=/system:/system/bin",
|
||||
"TERM=tty",
|
||||
"HOME=/",
|
||||
"USER=root",
|
||||
"SHELL=/system/sh",
|
||||
"PWD=/",
|
||||
"LANG=en_US.UTF-8",
|
||||
"TZ=UTC",
|
||||
nullptr};
|
||||
#ifdef DEBUG
|
||||
TreeFS(vfs->GetRootNode(), 0);
|
||||
#endif
|
||||
|
||||
const char *argv[4] = {
|
||||
Config.InitPath,
|
||||
"--init",
|
||||
"--critical",
|
||||
nullptr};
|
||||
const char *USpace_msg = "Setting up userspace";
|
||||
for (size_t i = 0; i < strlen(USpace_msg); i++)
|
||||
Display->Print(USpace_msg[i], 0);
|
||||
|
||||
Display->SetBuffer(0);
|
||||
|
||||
Execute::SpawnData ret = {Execute::ExStatus::Unknown, nullptr, nullptr};
|
||||
Tasking::TCB *ExecuteThread = nullptr;
|
||||
int ExitCode = -1;
|
||||
|
||||
Display->Print('.', 0);
|
||||
Display->SetBuffer(0);
|
||||
|
||||
ExecuteThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)Execute::StartExecuteService);
|
||||
ExecuteThread->Rename("Library Manager");
|
||||
ExecuteThread->SetCritical(true);
|
||||
ExecuteThread->SetPriority(Tasking::Idle);
|
||||
|
||||
Display->Print('.', 0);
|
||||
Display->SetBuffer(0);
|
||||
|
||||
CPU::Interrupts(CPU::Disable);
|
||||
ret = SpawnInit();
|
||||
|
||||
Display->Print('.', 0);
|
||||
Display->Print('\n', 0);
|
||||
Display->SetBuffer(0);
|
||||
|
||||
Execute::SpawnData ret = Execute::Spawn(Config.InitPath, argv, envp);
|
||||
if (ret.Status != Execute::ExStatus::OK)
|
||||
{
|
||||
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, ret.Status);
|
||||
CPU::Interrupts(CPU::Enable);
|
||||
goto Exit;
|
||||
}
|
||||
TaskManager->GetSecurityManager()->TrustToken(ret.Process->Security.UniqueToken, Tasking::TTL::FullTrust);
|
||||
TaskManager->GetSecurityManager()->TrustToken(ret.Thread->Security.UniqueToken, Tasking::TTL::FullTrust);
|
||||
ret.Thread->SetCritical(true);
|
||||
KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath);
|
||||
CPU::Interrupts(CPU::Enable);
|
||||
TaskManager->GetCurrentThread()->SetPriority(1);
|
||||
TaskManager->GetCurrentThread()->SetPriority(Tasking::Idle);
|
||||
TaskManager->WaitForThread(ret.Thread);
|
||||
KPrint("\eE85230Userspace process exited with code %d", ret.Thread->GetExitCode());
|
||||
error("Userspace process exited with code %d (%#x)", ret.Thread->GetExitCode(), ret.Thread->GetExitCode());
|
||||
ExitCode = ret.Thread->GetExitCode();
|
||||
if (ExitCode != 0)
|
||||
KPrint("\eE85230Userspace process exited with code %d", ExitCode);
|
||||
error("Userspace process exited with code %d (%#x)", ExitCode, ExitCode);
|
||||
Exit:
|
||||
KPrint("%s exited with code %d! Dropping to recovery screen...", Config.InitPath, ret.Thread->GetExitCode());
|
||||
TaskManager->Sleep(1000);
|
||||
RecoveryScreen = new Recovery::KernelRecovery;
|
||||
if (ExitCode != 0)
|
||||
{
|
||||
KPrint("Dropping to recovery screen...", ExitCode);
|
||||
TaskManager->Sleep(5000);
|
||||
RecoveryScreen = new Recovery::KernelRecovery;
|
||||
}
|
||||
else
|
||||
{
|
||||
KPrint("\eFF7900%s process exited with code %d and it didn't invoked the shutdown function.",
|
||||
Config.InitPath, ExitCode);
|
||||
KPrint("System Halted");
|
||||
}
|
||||
CPU::Halt(true);
|
||||
}
|
||||
|
||||
@ -93,7 +157,7 @@ void KernelShutdownThread(bool Reboot)
|
||||
{
|
||||
BeforeShutdown();
|
||||
|
||||
trace("Shutting Down/Rebooting...");
|
||||
trace("%s...", Reboot ? "Rebooting" : "Shutting down");
|
||||
if (Reboot)
|
||||
PowerManager->Reboot();
|
||||
else
|
||||
|
100
Kernel.cpp
100
Kernel.cpp
@ -1,6 +1,7 @@
|
||||
#include "kernel.h"
|
||||
|
||||
#include <boot/protocols/multiboot2.h>
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <interrupts.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <convert.h>
|
||||
@ -12,6 +13,7 @@
|
||||
#include <io.h>
|
||||
|
||||
#include "Core/smbios.hpp"
|
||||
#include "Tests/t.h"
|
||||
|
||||
/**
|
||||
* Fennix Kernel
|
||||
@ -29,6 +31,12 @@
|
||||
* - [ ] Optimize SMP.
|
||||
* - [ ] Support IPv6.
|
||||
* - [ ] Endianess of the network stack (currently: [HOST](LSB)<=>[NETWORK](MSB)). Not sure if this is a standard or not.
|
||||
* - [ ] Support 32-bit applications (ELF, PE, etc).
|
||||
* - [ ] Do not map the entire memory. Map only the needed memory address at allocation time.
|
||||
* - [ ] Implementation of logging (beside serial) with log rotation.
|
||||
* - [ ] Implement a better task manager. (replace struct P/TCB with classes)
|
||||
* - [?] Rewrite virtual file system. (it's very bad, I don't know how I wrote it this bad)
|
||||
* - [ ] Colors in crash screen are not following the kernel color scheme.
|
||||
*
|
||||
* BUGS:
|
||||
* - [ ] Kernel crashes when receiving interrupts for drivers only if the system has one core and the tasking is running.
|
||||
@ -37,13 +45,13 @@
|
||||
* CREDITS AND REFERENCES:
|
||||
* - General:
|
||||
* https://wiki.osdev.org/Main_Page
|
||||
*
|
||||
*
|
||||
* - Font:
|
||||
* http://www.fial.com/~scott/tamsyn-font/
|
||||
*
|
||||
*
|
||||
* - CPU XCR0 structure:
|
||||
* https://wiki.osdev.org/CPU_Registers_x86#XCR0
|
||||
*
|
||||
*
|
||||
* - CPUID 0x7:
|
||||
* https://en.wikipedia.org/wiki/CPUID
|
||||
*
|
||||
@ -67,6 +75,22 @@
|
||||
* http://realtek.info/pdf/rtl8139cp.pdf
|
||||
* https://en.wikipedia.org/wiki/IPv4
|
||||
* https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml
|
||||
*
|
||||
* - Loading ELF shared libraries and dynamic linking:
|
||||
* https://www.akkadia.org/drepper/dsohowto.pdf
|
||||
* https://wiki.osdev.org/Dynamic_Linker
|
||||
* https://github.com/tyler569/nightingale
|
||||
* https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html
|
||||
* https://www.youtube.com/watch?v=kUk5pw4w0h4
|
||||
* https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-42444/index.html
|
||||
* https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got
|
||||
*
|
||||
* - IPC:
|
||||
* https://docs.oracle.com/cd/E19048-01/chorus5/806-6897/architecture-103/index.html
|
||||
* https://www.scaler.com/topics/operating-system/inter-process-communication-in-os/
|
||||
* https://en.wikipedia.org/wiki/Inter-process_communication
|
||||
* https://www.geeksforgeeks.org/inter-process-communication-ipc/
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __amd64__
|
||||
@ -89,6 +113,11 @@
|
||||
|
||||
NewLock(KernelLock);
|
||||
|
||||
using VirtualFileSystem::File;
|
||||
using VirtualFileSystem::FileStatus;
|
||||
using VirtualFileSystem::Node;
|
||||
using VirtualFileSystem::NodeFlags;
|
||||
|
||||
BootInfo *bInfo = nullptr;
|
||||
Video::Display *Display = nullptr;
|
||||
SymbolResolver::Symbols *KernelSymbolTable = nullptr;
|
||||
@ -96,7 +125,7 @@ Power::Power *PowerManager = nullptr;
|
||||
PCI::PCI *PCIManager = nullptr;
|
||||
Tasking::Task *TaskManager = nullptr;
|
||||
Time::time *TimeManager = nullptr;
|
||||
FileSystem::Virtual *vfs = nullptr;
|
||||
VirtualFileSystem::Virtual *vfs = nullptr;
|
||||
|
||||
KernelConfig Config;
|
||||
Time::Clock BootClock;
|
||||
@ -110,7 +139,7 @@ EXTERNC void KPrint(const char *Format, ...)
|
||||
{
|
||||
SmartLock(KernelLock);
|
||||
Time::Clock tm = Time::ReadClock();
|
||||
printf("\eCCCCCC[\e00AEFF%02ld:%02ld:%02ld\eCCCCCC] ", tm.Hour, tm.Minute, tm.Second);
|
||||
printf("\eCCCCCC[\e00AEFF%02d:%02d:%02d\eCCCCCC] ", tm.Hour, tm.Minute, tm.Second);
|
||||
va_list args;
|
||||
va_start(args, Format);
|
||||
vprintf(Format, args);
|
||||
@ -236,8 +265,57 @@ EXTERNC __no_instrument_function void Main(BootInfo *Info)
|
||||
else
|
||||
KPrint("SMBIOS: \eFF0000Not Found");
|
||||
|
||||
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
|
||||
KPrint("Initializing Filesystem...");
|
||||
vfs = new VirtualFileSystem::Virtual;
|
||||
new VirtualFileSystem::USTAR((uintptr_t)bInfo->Modules[0].Address, vfs); // TODO: Detect initrd
|
||||
|
||||
if (!vfs->PathExists("/system"))
|
||||
vfs->Create("/system", NodeFlags::DIRECTORY);
|
||||
|
||||
if (!vfs->PathExists("/system/dev"))
|
||||
DevFS = vfs->Create("/system/dev", NodeFlags::DIRECTORY);
|
||||
else
|
||||
{
|
||||
shared_ptr<File> dev = vfs->Open("/system/dev");
|
||||
if (dev->node->Flags != NodeFlags::DIRECTORY)
|
||||
{
|
||||
KPrint("\eE85230/system/dev is not a directory! Halting...");
|
||||
CPU::Halt(true);
|
||||
}
|
||||
vfs->Close(dev);
|
||||
DevFS = dev->node;
|
||||
}
|
||||
|
||||
if (!vfs->PathExists("/system/mnt"))
|
||||
MntFS = vfs->Create("/system/mnt", NodeFlags::DIRECTORY);
|
||||
else
|
||||
{
|
||||
shared_ptr<File> mnt = vfs->Open("/system/mnt");
|
||||
if (mnt->node->Flags != NodeFlags::DIRECTORY)
|
||||
{
|
||||
KPrint("\eE85230/system/mnt is not a directory! Halting...");
|
||||
CPU::Halt(true);
|
||||
}
|
||||
vfs->Close(mnt);
|
||||
MntFS = mnt->node;
|
||||
}
|
||||
|
||||
if (!vfs->PathExists("/system/proc"))
|
||||
ProcFS = vfs->Create("/system/proc", NodeFlags::DIRECTORY);
|
||||
else
|
||||
{
|
||||
shared_ptr<File> proc = vfs->Open("/system/proc", nullptr);
|
||||
if (proc->node->Flags != NodeFlags::DIRECTORY)
|
||||
{
|
||||
KPrint("\eE85230/system/proc is not a directory! Halting...");
|
||||
CPU::Halt(true);
|
||||
}
|
||||
vfs->Close(proc);
|
||||
ProcFS = proc->node;
|
||||
}
|
||||
|
||||
KPrint("\e058C19################################");
|
||||
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
|
||||
CPU::Halt(true);
|
||||
}
|
||||
|
||||
@ -254,6 +332,16 @@ EXTERNC __no_stack_protector __no_instrument_function void Entry(BootInfo *Info)
|
||||
(*func)();
|
||||
|
||||
InitializeMemoryManagement(Info);
|
||||
|
||||
/* I had to do this because KernelAllocator
|
||||
* is a global constructor but we need
|
||||
* memory management to be initialized first.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
// Running tests
|
||||
TestString();
|
||||
#endif
|
||||
|
||||
EnableProfiler = true;
|
||||
Main(Info);
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ EXTERNC unsigned int isdelim(char c, char *delim)
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERNC int abs(int i) { return i < 0 ? -i : i; }
|
||||
EXTERNC long abs(long i) { return i < 0 ? -i : i; }
|
||||
|
||||
EXTERNC void swap(char *x, char *y)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace NetworkInterfaceManager
|
||||
|
||||
NetworkInterface::NetworkInterface()
|
||||
{
|
||||
mem = new Memory::MemMgr;
|
||||
mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
|
||||
if (DriverManager->GetDrivers().size() > 0)
|
||||
{
|
||||
foreach (auto Driver in DriverManager->GetDrivers())
|
||||
@ -74,7 +74,7 @@ namespace NetworkInterfaceManager
|
||||
|
||||
void NetworkInterface::StartNetworkStack()
|
||||
{
|
||||
TaskManager->GetCurrentThread()->SetPriority(100);
|
||||
TaskManager->GetCurrentThread()->SetPriority(Tasking::TaskPriority::Critical);
|
||||
DeviceInterface *DefaultDevice = nullptr;
|
||||
foreach (auto var in Interfaces)
|
||||
if (var && var->DriverCallBackAddress)
|
||||
@ -131,7 +131,7 @@ namespace NetworkInterfaceManager
|
||||
/* TODO: Store everything in an vector and initialize all network cards */
|
||||
}
|
||||
|
||||
TaskManager->GetCurrentThread()->SetPriority(1);
|
||||
TaskManager->GetCurrentThread()->SetPriority(Tasking::TaskPriority::Idle);
|
||||
CPU::Pause(true);
|
||||
}
|
||||
|
||||
@ -157,9 +157,7 @@ namespace NetworkInterfaceManager
|
||||
void NetworkInterface::StartService()
|
||||
{
|
||||
this->NetSvcProcess = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), "Network Service", Tasking::TaskTrustLevel::System);
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
|
||||
this->NetSvcThread = TaskManager->CreateThread(this->NetSvcProcess, (Tasking::IP)CallStartNetworkStackWrapper, nullptr, nullptr, auxv);
|
||||
this->NetSvcThread = TaskManager->CreateThread(this->NetSvcProcess, (Tasking::IP)CallStartNetworkStackWrapper);
|
||||
}
|
||||
|
||||
void NetworkInterface::DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size)
|
||||
|
@ -86,7 +86,7 @@ namespace NetworkUDP
|
||||
|
||||
Socket *GoodSocket = nullptr;
|
||||
|
||||
foreach (auto var in RegisteredEvents)
|
||||
foreach (auto &var in RegisteredEvents)
|
||||
{
|
||||
netdbg("UDP->SKT[]: LP:%d | LIP:%s | RP:%d | RIP:%s | LST:%d",
|
||||
b16(var.UDPSocket->LocalPort),
|
||||
|
@ -33,12 +33,10 @@ namespace Recovery
|
||||
|
||||
gui = new GraphicalUserInterface::GUI;
|
||||
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
|
||||
// TaskManager->CreateThread(proc, (IP)RecoveryThreadWrapper, nullptr, nullptr, auxv);
|
||||
TCB *guiThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)GUIWrapper, nullptr, nullptr, auxv);
|
||||
TCB *guiThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)GUIWrapper);
|
||||
guiThread->Rename("GUI Thread");
|
||||
guiThread->SetPriority(100);
|
||||
guiThread->SetPriority(Tasking::TaskPriority::Critical);
|
||||
|
||||
Rect RecoveryModeWindow;
|
||||
RecoveryModeWindow.Width = 460;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <syscalls.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
@ -7,19 +8,54 @@
|
||||
#include "../kernel.h"
|
||||
|
||||
#include "../../Userspace/libs/include/sysbase.h"
|
||||
#include "../ipc.h"
|
||||
|
||||
NewLock(SyscallsLock);
|
||||
|
||||
using InterProcessCommunication::IPC;
|
||||
using InterProcessCommunication::IPCID;
|
||||
using Tasking::Token;
|
||||
using Tasking::TTL;
|
||||
using Tasking::TTL::Trusted;
|
||||
using Tasking::TTL::TrustedByKernel;
|
||||
using Tasking::TTL::UnknownTrustLevel;
|
||||
using Tasking::TTL::Untrusted;
|
||||
|
||||
static inline bool CheckTrust(int TrustLevel)
|
||||
{
|
||||
// SmartTimeoutLock(SyscallsLock, 10000); - This is already done in the caller
|
||||
Token token = TaskManager->GetCurrentThread()->Security.UniqueToken;
|
||||
if (TaskManager->GetSecurityManager()->IsTokenTrusted(token, TrustLevel))
|
||||
return true;
|
||||
|
||||
warn("Thread %s(%lld) tried to access a system call \"%s\" with insufficient trust level",
|
||||
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0))), TaskManager->GetCurrentThread()->Name, TaskManager->GetCurrentThread()->ID);
|
||||
debug("Token: token=%#lx, trust=%d", token, TaskManager->GetSecurityManager()->GetTokenTrustLevel(token));
|
||||
return false;
|
||||
}
|
||||
|
||||
static int sys_exit(SyscallsFrame *Frame, int code)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Allow everyone to exit */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted | UnknownTrustLevel))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
|
||||
trace("Userspace thread %s(%lld) exited with code %#llx", TaskManager->GetCurrentThread()->Name, TaskManager->GetCurrentThread()->ID, code);
|
||||
TaskManager->GetCurrentThread()->ExitCode = code;
|
||||
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated;
|
||||
UNUSED(Frame);
|
||||
return 0;
|
||||
return SYSCALL_OK;
|
||||
}
|
||||
|
||||
static int sys_print(SyscallsFrame *Frame, char Char, int Index)
|
||||
{
|
||||
int ret = Display->Print(Char, Index, true);
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Only trusted threads can write to the kernel console */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
|
||||
char ret = Display->Print(Char, Index, true);
|
||||
#ifdef DEBUG
|
||||
Display->SetBuffer(Index);
|
||||
#endif
|
||||
@ -29,19 +65,43 @@ static int sys_print(SyscallsFrame *Frame, char Char, int Index)
|
||||
|
||||
static uintptr_t sys_request_pages(SyscallsFrame *Frame, size_t Count)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Allow everyone to request pages */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
UNUSED(Frame);
|
||||
return (uintptr_t)TaskManager->GetCurrentThread()->Memory->RequestPages(Count);
|
||||
return (uintptr_t)TaskManager->GetCurrentThread()->Memory->RequestPages(Count, true);
|
||||
}
|
||||
|
||||
static int sys_free_pages(SyscallsFrame *Frame, uintptr_t Address, size_t Count)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Allow everyone to free pages */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
TaskManager->GetCurrentThread()->Memory->FreePages((void *)Address, Count);
|
||||
UNUSED(Frame);
|
||||
return 0;
|
||||
return SYSCALL_OK;
|
||||
}
|
||||
|
||||
static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
|
||||
static int sys_detach_address(SyscallsFrame *Frame, uintptr_t Address)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Only trusted threads can detach allocated addresses */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
TaskManager->GetCurrentThread()->Memory->DetachAddress((void *)Address);
|
||||
UNUSED(Frame);
|
||||
return SYSCALL_OK;
|
||||
}
|
||||
|
||||
static uintptr_t sys_kernelctl(SyscallsFrame *Frame, enum KCtl Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Only trusted threads can use kernelctl */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case KCTL_GET_PID:
|
||||
@ -53,7 +113,7 @@ static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint6
|
||||
default:
|
||||
{
|
||||
warn("KernelCTL: Unknown command: %lld", Command);
|
||||
return -1;
|
||||
return SYSCALL_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,121 +122,152 @@ static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint6
|
||||
UNUSED(Arg3);
|
||||
UNUSED(Arg4);
|
||||
UNUSED(Frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sys_ipc(SyscallsFrame *Frame, int Command, int Type, int ID, int Flags, void *Buffer, size_t Size)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
/* Allow everyone to use IPC */
|
||||
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted))
|
||||
return SYSCALL_ACCESS_DENIED;
|
||||
|
||||
IPC *ipc = TaskManager->GetCurrentProcess()->IPC;
|
||||
|
||||
UNUSED(Frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_file_open(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_file_open: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_file_close(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_file_close: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_file_read(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_file_read: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_file_write(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_file_write: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_file_seek(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_file_seek: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_file_status(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_file_status: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_wait(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_wait: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_kill(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_kill: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_spawn(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_spawn: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_spawn_thread(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_spawn_thread: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_get_thread_list_of_process(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_get_thread_list_of_process: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_get_current_process(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_get_current_process: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_get_current_thread(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_get_current_thread: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_get_process_by_pid(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_get_process_by_pid: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_get_thread_by_tid(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_get_thread_by_tid: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_kill_process(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_kill_process: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_kill_thread(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_kill_thread: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_sys_reserved_create_process(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_sys_reserved_create_process: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static int sys_sys_reserved_create_thread(SyscallsFrame *Frame)
|
||||
{
|
||||
SmartTimeoutLock(SyscallsLock, 10000);
|
||||
fixme("sys_sys_reserved_create_thread: %#lx", Frame);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static void *NativeSyscallsTable[] = {
|
||||
@ -185,8 +276,10 @@ static void *NativeSyscallsTable[] = {
|
||||
|
||||
[_RequestPages] = (void *)sys_request_pages,
|
||||
[_FreePages] = (void *)sys_free_pages,
|
||||
[_DetachAddress] = (void *)sys_detach_address,
|
||||
|
||||
[_KernelCTL] = (void *)sys_kernelctl,
|
||||
[_IPC] = (void *)sys_ipc,
|
||||
|
||||
[_FileOpen] = (void *)sys_file_open,
|
||||
[_FileClose] = (void *)sys_file_close,
|
||||
@ -217,14 +310,14 @@ uintptr_t HandleNativeSyscalls(SyscallsFrame *Frame)
|
||||
if (Frame->rax > sizeof(NativeSyscallsTable))
|
||||
{
|
||||
fixme("Syscall %lld not implemented", Frame->rax);
|
||||
return -1;
|
||||
return SYSCALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
uintptr_t (*call)(uintptr_t, ...) = reinterpret_cast<uintptr_t (*)(uintptr_t, ...)>(NativeSyscallsTable[Frame->rax]);
|
||||
if (!call)
|
||||
{
|
||||
error("Syscall %#llx failed.", Frame->rax);
|
||||
return -1;
|
||||
return SYSCALL_INTERNAL_ERROR;
|
||||
}
|
||||
debug("[%#lx]->( %#lx %#lx %#lx %#lx %#lx %#lx )", Frame->rax, Frame->rdi, Frame->rsi, Frame->rdx, Frame->rcx, Frame->r8, Frame->r9);
|
||||
uintptr_t ret = call((uintptr_t)Frame, Frame->rdi, Frame->rsi, Frame->rdx, Frame->r10, Frame->r8, Frame->r9);
|
||||
|
@ -1,141 +1,161 @@
|
||||
#include <ipc.hpp>
|
||||
|
||||
#include <lock.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
NewLock(IPCLock);
|
||||
|
||||
InterProcessCommunication::IPC *ipc = nullptr;
|
||||
|
||||
namespace InterProcessCommunication
|
||||
{
|
||||
IPCHandle *IPC::RegisterHandle(IPCPort Port)
|
||||
IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16])
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Port == 0)
|
||||
return nullptr;
|
||||
|
||||
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
|
||||
|
||||
if (pcb->IPCHandles->Get((int)Port) != 0)
|
||||
return nullptr;
|
||||
|
||||
IPCHandle *handle = new IPCHandle;
|
||||
handle->ID = -1;
|
||||
handle->Buffer = nullptr;
|
||||
handle->Length = 0;
|
||||
handle->Operation = IPCOperationNone;
|
||||
handle->Listening = 0;
|
||||
handle->Error = IPCUnknown;
|
||||
pcb->IPCHandles->AddNode(Port, (uintptr_t)handle);
|
||||
return handle;
|
||||
IPCHandle *Handle = (IPCHandle *)mem->RequestPages(TO_PAGES(sizeof(IPCHandle)));
|
||||
Handle->ID = NextID++;
|
||||
Handle->Node = vfs->Create(UniqueToken, VirtualFileSystem::NodeFlags::FILE, IPCNode);
|
||||
Handle->Node->Address = (uintptr_t)mem->RequestPages(TO_PAGES(sizeof(4096)));
|
||||
Handle->Node->Length = 4096;
|
||||
Handles.push_back(Handle);
|
||||
return Handle;
|
||||
}
|
||||
|
||||
IPCError IPC::Listen(IPCPort Port)
|
||||
IPCErrorCode IPC::Destroy(IPCID ID)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Port == 0)
|
||||
return IPCError{IPCInvalidPort};
|
||||
|
||||
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
|
||||
|
||||
if (pcb->IPCHandles->Get((int)Port) == 0)
|
||||
return IPCError{IPCPortNotRegistered};
|
||||
|
||||
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
|
||||
handle->Listening = 1;
|
||||
return IPCError{IPCSuccess};
|
||||
}
|
||||
|
||||
IPCHandle *IPC::Wait(IPCPort Port)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Port == 0)
|
||||
return nullptr;
|
||||
|
||||
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
|
||||
|
||||
if (pcb->IPCHandles->Get((int)Port) == 0)
|
||||
return nullptr;
|
||||
|
||||
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
|
||||
|
||||
while (handle->Listening == 1)
|
||||
CPU::Pause();
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
IPCError IPC::Read(Tasking::UPID ID, IPCPort Port, uint8_t *&Buffer, long &Size)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Port == 0)
|
||||
return IPCError{IPCInvalidPort};
|
||||
|
||||
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
|
||||
|
||||
if (pcb->IPCHandles->Get((int)Port) == 0)
|
||||
return IPCError{IPCInvalidPort};
|
||||
|
||||
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
|
||||
|
||||
if (handle->Listening == 0)
|
||||
return IPCError{IPCPortInUse};
|
||||
|
||||
Buffer = handle->Buffer;
|
||||
Size = handle->Length;
|
||||
handle->Operation = IPCOperationRead;
|
||||
handle->Listening = 1;
|
||||
handle->Error = IPCSuccess;
|
||||
|
||||
// FIXME: ID is not used.
|
||||
UNUSED(ID);
|
||||
|
||||
return IPCError{IPCSuccess};
|
||||
}
|
||||
|
||||
IPCError IPC::Write(Tasking::UPID ID, IPCPort Port, uint8_t *Buffer, long Size)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Port == 0)
|
||||
return IPCError{IPCInvalidPort};
|
||||
|
||||
Vector<Tasking::PCB *> Processes = TaskManager->GetProcessList();
|
||||
|
||||
for (size_t i = 0; i < Processes.size(); i++)
|
||||
for (size_t i = 0; i < Handles.size(); i++)
|
||||
{
|
||||
Tasking::PCB *pcb = Processes[i];
|
||||
|
||||
if (pcb->ID == ID)
|
||||
if (Handles[i]->ID == ID)
|
||||
{
|
||||
if (pcb->IPCHandles->Get((int)Port) == 0)
|
||||
return IPCError{IPCInvalidPort};
|
||||
|
||||
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
|
||||
|
||||
if (handle->Listening == 0)
|
||||
return IPCError{IPCNotListening};
|
||||
|
||||
handle->Buffer = Buffer;
|
||||
handle->Length = Size;
|
||||
handle->Operation = IPCOperationWrite;
|
||||
handle->Listening = 0;
|
||||
handle->Error = IPCSuccess;
|
||||
mem->FreePages(Handles[i], TO_PAGES(sizeof(IPCHandle)));
|
||||
Handles.remove(i);
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
return IPCError{IPCIDNotFound};
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPC::IPC()
|
||||
IPCErrorCode IPC::Read(IPCID ID, uint8_t *Buffer, long Size)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
trace("Starting IPC Service...");
|
||||
if (Size < 0)
|
||||
return IPCError;
|
||||
|
||||
foreach (auto Handle in Handles)
|
||||
{
|
||||
if (Handle->ID == ID)
|
||||
{
|
||||
if (Handle->Listening)
|
||||
return IPCNotListening;
|
||||
if (Handle->Length < Size)
|
||||
return IPCError;
|
||||
memcpy(Buffer, Handle->Buffer, Size);
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Write(IPCID ID, uint8_t *Buffer, long Size)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Size < 0)
|
||||
return IPCError;
|
||||
|
||||
foreach (auto Handle in Handles)
|
||||
{
|
||||
if (Handle->ID == ID)
|
||||
{
|
||||
if (!Handle->Listening)
|
||||
return IPCNotListening;
|
||||
if (Handle->Length < Size)
|
||||
return IPCError;
|
||||
memcpy(Handle->Buffer, Buffer, Size);
|
||||
Handle->Listening = false;
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Listen(IPCID ID)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
foreach (auto Handle in Handles)
|
||||
{
|
||||
if (Handle->ID == ID)
|
||||
{
|
||||
Handle->Listening = true;
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCHandle *IPC::Wait(IPCID ID)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
foreach (auto &Handle in Handles)
|
||||
{
|
||||
if (Handle->ID == ID)
|
||||
{
|
||||
while (Handle->Listening)
|
||||
CPU::Pause();
|
||||
return Handle;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Allocate(IPCID ID, long Size)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
if (Size < 0)
|
||||
return IPCError;
|
||||
|
||||
foreach (auto Handle in Handles)
|
||||
{
|
||||
if (Handle->ID == ID)
|
||||
{
|
||||
if (Handle->Buffer != nullptr || Handle->Length != 0)
|
||||
return IPCAlreadyAllocated;
|
||||
|
||||
Handle->Buffer = (uint8_t *)mem->RequestPages(TO_PAGES(Size));
|
||||
Handle->Length = Size;
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Deallocate(IPCID ID)
|
||||
{
|
||||
SmartLock(IPCLock);
|
||||
foreach (auto Handle in Handles)
|
||||
{
|
||||
if (Handle->ID == ID)
|
||||
{
|
||||
if (Handle->Buffer == nullptr || Handle->Length == 0)
|
||||
return IPCNotAllocated;
|
||||
|
||||
mem->FreePages(Handle->Buffer, TO_PAGES(Handle->Length));
|
||||
Handle->Buffer = nullptr;
|
||||
Handle->Length = 0;
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPC::IPC(void *Process)
|
||||
{
|
||||
this->Process = Process;
|
||||
mem = new Memory::MemMgr(nullptr, ((Tasking::PCB *)Process)->memDirectory);
|
||||
IPCNode = vfs->Create("ipc", VirtualFileSystem::NodeFlags::DIRECTORY, ((Tasking::PCB *)this->Process)->ProcessDirectory);
|
||||
}
|
||||
|
||||
IPC::~IPC()
|
||||
{
|
||||
delete mem;
|
||||
vfs->Delete(IPCNode, true);
|
||||
}
|
||||
}
|
||||
|
688
Tasking/Scheduler.cpp
Normal file
688
Tasking/Scheduler.cpp
Normal file
@ -0,0 +1,688 @@
|
||||
#include <task.hpp>
|
||||
|
||||
#include <dumper.hpp>
|
||||
#include <convert.h>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
#if defined(__amd64__)
|
||||
#include "../Architecture/amd64/cpu/apic.hpp"
|
||||
#include "../Architecture/amd64/cpu/gdt.hpp"
|
||||
#elif defined(__i386__)
|
||||
#include "../Architecture/i686/cpu/apic.hpp"
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
|
||||
NewLock(SchedulerLock);
|
||||
|
||||
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
|
||||
|
||||
// #define DEBUG_SCHEDULER 1
|
||||
// #define DEBUG_GET_NEXT_AVAILABLE_PROCESS 1
|
||||
// #define DEBUG_GET_NEXT_AVAILABLE_THREAD 1
|
||||
// #define DEBUG_FIND_NEW_PROCESS 1
|
||||
// #define DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD 1
|
||||
// #define DEBUG_WAKE_UP_THREADS 1
|
||||
|
||||
/* Global */
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
|
||||
#define DEBUG_GET_NEXT_AVAILABLE_PROCESS 1
|
||||
#define DEBUG_GET_NEXT_AVAILABLE_THREAD 1
|
||||
#define DEBUG_FIND_NEW_PROCESS 1
|
||||
#define DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD 1
|
||||
#define DEBUG_WAKE_UP_THREADS 1
|
||||
|
||||
#define schedbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define schedbg(m, ...)
|
||||
#endif
|
||||
|
||||
/* GetNextAvailableThread */
|
||||
#ifdef DEBUG_GET_NEXT_AVAILABLE_PROCESS
|
||||
#define gnap_schedbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define gnap_schedbg(m, ...)
|
||||
#endif
|
||||
|
||||
/* GetNextAvailableProcess */
|
||||
#ifdef DEBUG_GET_NEXT_AVAILABLE_THREAD
|
||||
#define gnat_schedbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define gnat_schedbg(m, ...)
|
||||
#endif
|
||||
|
||||
/* FindNewProcess */
|
||||
#ifdef DEBUG_FIND_NEW_PROCESS
|
||||
#define fnp_schedbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define fnp_schedbg(m, ...)
|
||||
#endif
|
||||
|
||||
/* SchedulerSearchProcessThread */
|
||||
#ifdef DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD
|
||||
#define sspt_schedbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define sspt_schedbg(m, ...)
|
||||
#endif
|
||||
|
||||
/* WakeUpThreads */
|
||||
#ifdef DEBUG_WAKE_UP_THREADS
|
||||
#define wut_schedbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define wut_schedbg(m, ...)
|
||||
#endif
|
||||
|
||||
extern "C" SafeFunction __no_instrument_function void TaskingScheduler_OneShot(int TimeSlice)
|
||||
{
|
||||
if (TimeSlice == 0)
|
||||
TimeSlice = 10;
|
||||
#if defined(__amd64__)
|
||||
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x64::IRQ16, TimeSlice);
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
#if defined(__amd64__)
|
||||
SafeFunction __no_instrument_function bool Task::FindNewProcess(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
fnp_schedbg("%d processes", ListProcess.size());
|
||||
#ifdef DEBUG_FIND_NEW_PROCESS
|
||||
foreach (auto pcb in ListProcess)
|
||||
fnp_schedbg("Process %d %s", pcb->ID, pcb->Name);
|
||||
#endif
|
||||
foreach (auto pcb in ListProcess)
|
||||
{
|
||||
if (InvalidPCB(pcb))
|
||||
continue;
|
||||
|
||||
switch (pcb->Status)
|
||||
{
|
||||
case TaskStatus::Ready:
|
||||
fnp_schedbg("Ready process (%s)%d", pcb->Name, pcb->ID);
|
||||
break;
|
||||
default:
|
||||
fnp_schedbg("Process \"%s\"(%d) status %d", pcb->Name, pcb->ID, pcb->Status);
|
||||
/* We don't actually remove the process. RemoveProcess
|
||||
firstly checks if it's terminated, if not, it will
|
||||
loop through Threads and call RemoveThread on
|
||||
terminated threads. */
|
||||
RemoveProcess(pcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (auto tcb in pcb->Threads)
|
||||
{
|
||||
if (InvalidTCB(tcb))
|
||||
continue;
|
||||
|
||||
if (tcb->Status != TaskStatus::Ready)
|
||||
continue;
|
||||
|
||||
CurrentCPU->CurrentProcess = pcb;
|
||||
CurrentCPU->CurrentThread = tcb;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fnp_schedbg("No process to run.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
for (size_t i = 0; i < CurrentCPU->CurrentProcess->Threads.size(); i++)
|
||||
{
|
||||
if (CurrentCPU->CurrentProcess->Threads[i] == CurrentCPU->CurrentThread)
|
||||
{
|
||||
size_t TempIndex = i;
|
||||
RetryAnotherThread:
|
||||
TCB *thread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
|
||||
if (unlikely(InvalidTCB(thread)))
|
||||
{
|
||||
if (TempIndex > CurrentCPU->CurrentProcess->Threads.size())
|
||||
break;
|
||||
TempIndex++;
|
||||
gnat_schedbg("Thread %#lx is invalid", thread);
|
||||
goto RetryAnotherThread;
|
||||
}
|
||||
|
||||
gnat_schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)", CurrentCPU->CurrentProcess->Threads[i]->Name, CurrentCPU->CurrentProcess->Threads[i]->ID, thread->Name, thread->ID);
|
||||
|
||||
if (thread->Status != TaskStatus::Ready)
|
||||
{
|
||||
gnat_schedbg("Thread %d is not ready", thread->ID);
|
||||
TempIndex++;
|
||||
goto RetryAnotherThread;
|
||||
}
|
||||
|
||||
CurrentCPU->CurrentThread = thread;
|
||||
gnat_schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d", thread->ID, thread->Parent->Name, CurrentCPU->CurrentProcess->Threads.size(), ListProcess.size());
|
||||
return true;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
{
|
||||
gnat_schedbg("Thread %d is not the current one", CurrentCPU->CurrentProcess->Threads[i]->ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
bool Skip = true;
|
||||
foreach (auto pcb in ListProcess)
|
||||
{
|
||||
if (pcb == CurrentCPU->CurrentProcess)
|
||||
{
|
||||
Skip = false;
|
||||
gnap_schedbg("Found current process %#lx", pcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Skip)
|
||||
{
|
||||
gnap_schedbg("Skipping process %#lx", pcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidPCB(pcb))
|
||||
{
|
||||
gnap_schedbg("Invalid process %#lx", pcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pcb->Status != TaskStatus::Ready)
|
||||
{
|
||||
gnap_schedbg("Process %d is not ready", pcb->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (auto tcb in pcb->Threads)
|
||||
{
|
||||
if (InvalidTCB(tcb))
|
||||
{
|
||||
gnap_schedbg("Invalid thread %#lx", tcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tcb->Status != TaskStatus::Ready)
|
||||
{
|
||||
gnap_schedbg("Thread %d is not ready", tcb->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
CurrentCPU->CurrentProcess = pcb;
|
||||
CurrentCPU->CurrentThread = tcb;
|
||||
gnap_schedbg("[cur proc+1 -> first thd] Scheduling thread %d %s->%d (Total Procs %d)", tcb->ID, tcb->Name, pcb->Threads.size(), ListProcess.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
gnap_schedbg("No process to run.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::SchedulerCleanupProcesses()
|
||||
{
|
||||
foreach (auto pcb in ListProcess)
|
||||
{
|
||||
if (InvalidPCB(pcb))
|
||||
continue;
|
||||
RemoveProcess(pcb);
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
foreach (auto pcb in ListProcess)
|
||||
{
|
||||
if (InvalidPCB(pcb))
|
||||
{
|
||||
sspt_schedbg("Invalid process %#lx", pcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pcb->Status != TaskStatus::Ready)
|
||||
{
|
||||
sspt_schedbg("Process %d is not ready", pcb->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (auto tcb in pcb->Threads)
|
||||
{
|
||||
if (InvalidTCB(tcb))
|
||||
{
|
||||
sspt_schedbg("Invalid thread %#lx", tcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tcb->Status != TaskStatus::Ready)
|
||||
{
|
||||
sspt_schedbg("Thread %d is not ready", tcb->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
CurrentCPU->CurrentProcess = pcb;
|
||||
CurrentCPU->CurrentThread = tcb;
|
||||
sspt_schedbg("[proc 0 -> end -> first thd] Scheduling thread %d parent of %s->%d (Procs %d)", tcb->ID, tcb->Parent->Name, pcb->Threads.size(), ListProcess.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::UpdateProcessStatus()
|
||||
{
|
||||
foreach (auto pcb in ListProcess)
|
||||
{
|
||||
if (InvalidPCB(pcb))
|
||||
continue;
|
||||
|
||||
if (pcb->Status == TaskStatus::Terminated ||
|
||||
pcb->Status == TaskStatus::Stopped)
|
||||
continue;
|
||||
|
||||
bool AllThreadsSleeping = true;
|
||||
foreach (auto tcb in pcb->Threads)
|
||||
{
|
||||
if (tcb->Status != TaskStatus::Sleeping)
|
||||
{
|
||||
AllThreadsSleeping = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (AllThreadsSleeping)
|
||||
pcb->Status = TaskStatus::Sleeping;
|
||||
else if (pcb->Status == TaskStatus::Sleeping)
|
||||
pcb->Status = TaskStatus::Ready;
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::WakeUpThreads(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
foreach (auto pcb in ListProcess)
|
||||
{
|
||||
if (InvalidPCB(pcb))
|
||||
continue;
|
||||
|
||||
if (pcb->Status == TaskStatus::Terminated ||
|
||||
pcb->Status == TaskStatus::Stopped)
|
||||
continue;
|
||||
|
||||
foreach (auto tcb in pcb->Threads)
|
||||
{
|
||||
if (InvalidTCB(tcb))
|
||||
continue;
|
||||
|
||||
if (tcb->Status != TaskStatus::Sleeping)
|
||||
continue;
|
||||
|
||||
/* Check if the thread is ready to wake up. */
|
||||
if (tcb->Info.SleepUntil < TimeManager->GetCounter())
|
||||
{
|
||||
if (pcb->Status == TaskStatus::Sleeping)
|
||||
pcb->Status = TaskStatus::Ready;
|
||||
tcb->Status = TaskStatus::Ready;
|
||||
|
||||
tcb->Info.SleepUntil = 0;
|
||||
wut_schedbg("Thread \"%s\"(%d) woke up.", tcb->Name, tcb->ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
wut_schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)", tcb->Name, tcb->ID, tcb->Info.SleepUntil, TimeManager->GetCounter());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::Schedule(CPU::x64::TrapFrame *Frame)
|
||||
{
|
||||
SmartCriticalSection(SchedulerLock);
|
||||
if (StopScheduler)
|
||||
{
|
||||
warn("Scheduler stopped.");
|
||||
return;
|
||||
}
|
||||
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); /* Restore kernel page table for safety reasons. */
|
||||
CPUData *CurrentCPU = GetCurrentCPU();
|
||||
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
|
||||
schedbg("%d: %ld%%", CurrentCPU->ID, GetUsage(CurrentCPU->ID));
|
||||
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
int SuccessSource = 0;
|
||||
static int sanity;
|
||||
const char *Statuses[] = {
|
||||
"FF0000", /* Unknown */
|
||||
"AAFF00", /* Ready */
|
||||
"00AA00", /* Running */
|
||||
"FFAA00", /* Sleeping */
|
||||
"FFAA00", /* Waiting */
|
||||
"FF0088", /* Stopped */
|
||||
"FF0000", /* Terminated */
|
||||
};
|
||||
const char *StatusesSign[] = {
|
||||
"Unknown",
|
||||
"Ready",
|
||||
"Run",
|
||||
"Sleep",
|
||||
"Wait",
|
||||
"Stop",
|
||||
"Terminated",
|
||||
};
|
||||
const char *SuccessSourceStrings[] = {
|
||||
"Unknown",
|
||||
"GetNextAvailableThread",
|
||||
"GetNextAvailableProcess",
|
||||
"SchedulerSearchProcessThread",
|
||||
};
|
||||
uint32_t tmpX, tmpY;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
{
|
||||
schedbg("================================================================");
|
||||
schedbg("Status: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
|
||||
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
|
||||
size_t ds;
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||
Frame->ss, Frame->cs, ds);
|
||||
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||
schedbg("================================================================");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess) || InvalidTCB(CurrentCPU->CurrentThread)))
|
||||
{
|
||||
schedbg("Invalid process or thread. Finding a new one.");
|
||||
if (this->FindNewProcess(CurrentCPU))
|
||||
goto Success;
|
||||
else
|
||||
goto Idle;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentCPU->CurrentThread->Registers = *Frame;
|
||||
CPU::x64::fxsave(CurrentCPU->CurrentThread->FPU);
|
||||
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
|
||||
|
||||
if (CurrentCPU->CurrentProcess->Status == TaskStatus::Running)
|
||||
CurrentCPU->CurrentProcess->Status = TaskStatus::Ready;
|
||||
if (CurrentCPU->CurrentThread->Status == TaskStatus::Running)
|
||||
CurrentCPU->CurrentThread->Status = TaskStatus::Ready;
|
||||
|
||||
this->UpdateProcessStatus();
|
||||
schedbg("Passed UpdateProcessStatus");
|
||||
|
||||
this->WakeUpThreads(CurrentCPU);
|
||||
schedbg("Passed WakeUpThreads");
|
||||
|
||||
if (this->GetNextAvailableThread(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
SuccessSource = 1;
|
||||
#endif
|
||||
goto Success;
|
||||
}
|
||||
schedbg("Passed GetNextAvailableThread");
|
||||
|
||||
if (this->GetNextAvailableProcess(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
SuccessSource = 2;
|
||||
#endif
|
||||
goto Success;
|
||||
}
|
||||
schedbg("Passed GetNextAvailableProcess");
|
||||
|
||||
this->SchedulerCleanupProcesses();
|
||||
schedbg("Passed SchedulerCleanupProcesses");
|
||||
|
||||
if (SchedulerSearchProcessThread(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
SuccessSource = 3;
|
||||
#endif
|
||||
schedbg("Passed SchedulerSearchProcessThread");
|
||||
goto Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
schedbg("SchedulerSearchProcessThread failed. Going idle.");
|
||||
goto Idle;
|
||||
}
|
||||
}
|
||||
|
||||
/* [this]->RealEnd */
|
||||
warn("Unwanted reach!");
|
||||
TaskingScheduler_OneShot(100);
|
||||
goto RealEnd;
|
||||
|
||||
/* Idle-->Success */
|
||||
Idle:
|
||||
CurrentCPU->CurrentProcess = IdleProcess;
|
||||
CurrentCPU->CurrentThread = IdleThread;
|
||||
|
||||
/* Success-->End */
|
||||
Success:
|
||||
schedbg("Process \"%s\"(%d) Thread \"%s\"(%d) is now running on CPU %d",
|
||||
CurrentCPU->CurrentProcess->Name, CurrentCPU->CurrentProcess->ID,
|
||||
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID);
|
||||
|
||||
CurrentCPU->CurrentProcess->Status = TaskStatus::Running;
|
||||
CurrentCPU->CurrentThread->Status = TaskStatus::Running;
|
||||
|
||||
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||
|
||||
for (size_t i = 0; i < sizeof(CurrentCPU->CurrentThread->IPHistory) / sizeof(CurrentCPU->CurrentThread->IPHistory[0]); i++)
|
||||
CurrentCPU->CurrentThread->IPHistory[i + 1] = CurrentCPU->CurrentThread->IPHistory[i];
|
||||
|
||||
CurrentCPU->CurrentThread->IPHistory[0] = Frame->rip;
|
||||
|
||||
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
|
||||
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
|
||||
/* Not sure if this is needed, but it's better to be safe than sorry. */
|
||||
asmv("movq %cr3, %rax");
|
||||
asmv("movq %rax, %cr3");
|
||||
CPU::x64::fxrstor(CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
|
||||
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
for (int i = 0; i < 340; i++)
|
||||
for (int j = 0; j < 200; j++)
|
||||
Display->SetPixel(i, j, 0x222222, 0);
|
||||
Display->GetBufferCursor(0, &tmpX, &tmpY);
|
||||
Display->SetBufferCursor(0, 0, 0);
|
||||
foreach (auto var in ListProcess)
|
||||
{
|
||||
int Status = var->Status;
|
||||
printf("\e%s-> \eAABBCC%s \e00AAAA%s\n",
|
||||
Statuses[Status], var->Name, StatusesSign[Status]);
|
||||
foreach (auto var2 in var->Threads)
|
||||
{
|
||||
Status = var2->Status;
|
||||
printf(" \e%s-> \eAABBCC%s \e00AAAA%s\n\eAABBCC",
|
||||
Statuses[Status], var2->Name, StatusesSign[Status]);
|
||||
}
|
||||
}
|
||||
printf("Sanity: %d\nSched. Source: %s", sanity++, SuccessSourceStrings[SuccessSource]);
|
||||
if (sanity > 1000)
|
||||
sanity = 0;
|
||||
Display->SetBufferCursor(0, tmpX, tmpY);
|
||||
Display->SetBuffer(0);
|
||||
for (int i = 0; i < 50000; i++)
|
||||
inb(0x80);
|
||||
#endif
|
||||
|
||||
switch (CurrentCPU->CurrentProcess->Security.TrustLevel)
|
||||
{
|
||||
case TaskTrustLevel::System:
|
||||
case TaskTrustLevel::Kernel:
|
||||
// wrmsr(MSR_SHADOW_GS_BASE, (uint64_t)CurrentCPU->CurrentThread);
|
||||
break;
|
||||
case TaskTrustLevel::User:
|
||||
// wrmsr(MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->gs);
|
||||
break;
|
||||
default:
|
||||
error("Unknown trust level %d.", CurrentCPU->CurrentProcess->Security.TrustLevel);
|
||||
break;
|
||||
}
|
||||
|
||||
/* End-->RealEnd */
|
||||
// End:
|
||||
/* TODO: This is not accurate. */
|
||||
if (CurrentCPU->CurrentProcess->Security.TrustLevel == TaskTrustLevel::User)
|
||||
UpdateUserTime(&CurrentCPU->CurrentProcess->Info);
|
||||
else
|
||||
UpdateKernelTime(&CurrentCPU->CurrentProcess->Info);
|
||||
|
||||
if (CurrentCPU->CurrentThread->Security.TrustLevel == TaskTrustLevel::User)
|
||||
UpdateUserTime(&CurrentCPU->CurrentThread->Info);
|
||||
else
|
||||
UpdateKernelTime(&CurrentCPU->CurrentThread->Info);
|
||||
|
||||
UpdateUsage(&CurrentCPU->CurrentProcess->Info, CurrentCPU->ID);
|
||||
UpdateUsage(&CurrentCPU->CurrentThread->Info, CurrentCPU->ID);
|
||||
TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority);
|
||||
|
||||
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
||||
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
|
||||
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID,
|
||||
CurrentCPU->CurrentThread->Registers.rip,
|
||||
CurrentCPU->CurrentThread->Registers.rbp,
|
||||
CurrentCPU->CurrentThread->Registers.rsp);
|
||||
|
||||
schedbg("================================================================");
|
||||
schedbg("Technical Informations on Thread %s[%ld]:", CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID);
|
||||
uint64_t ds;
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||
Frame->ss, Frame->cs, ds);
|
||||
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||
schedbg("================================================================");
|
||||
|
||||
/* RealEnd->[Function Exit] */
|
||||
RealEnd:
|
||||
__sync_synchronize(); /* TODO: Is this really needed? */
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame) { this->Schedule(Frame); }
|
||||
#elif defined(__i386__)
|
||||
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::SchedulerCleanupProcesses()
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::Schedule(void *Frame)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
|
||||
#elif defined(__aarch64__)
|
||||
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::SchedulerCleanupProcesses()
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::Schedule(void *Frame)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
|
||||
#endif
|
||||
}
|
@ -6,64 +6,131 @@
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
struct TokenData
|
||||
{
|
||||
Token token;
|
||||
enum TokenTrustLevel TrustLevel;
|
||||
uint64_t OwnerID;
|
||||
bool Process;
|
||||
};
|
||||
|
||||
Vector<TokenData> Tokens;
|
||||
|
||||
Token Security::CreateToken()
|
||||
{
|
||||
uint64_t ret = Random::rand64();
|
||||
uint64_t ret = 0;
|
||||
Retry:
|
||||
ret = Random::rand64();
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == ret)
|
||||
goto Retry;
|
||||
|
||||
Tokens.push_back({ret, UnknownTrustLevel, 0, false});
|
||||
debug("Created token %#lx", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Security::TrustToken(Token token,
|
||||
TokenTrustLevel TrustLevel)
|
||||
bool Security::TrustToken(Token token, TTL TrustLevel)
|
||||
{
|
||||
enum TokenTrustLevel Level = static_cast<enum TokenTrustLevel>(TrustLevel);
|
||||
|
||||
foreach (auto var in Tokens)
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (var.token == token)
|
||||
if (t.token == token)
|
||||
{
|
||||
var.TrustLevel = Level;
|
||||
debug("Trusted token %#lx", token);
|
||||
t.TrustLevel = TrustLevel;
|
||||
debug("Trusted token %#lx to level %d", token, t.TrustLevel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
debug("Failed to trust token %#lx", token);
|
||||
warn("Failed to trust token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::UntrustToken(Token token)
|
||||
{
|
||||
fixme("UntrustToken->false");
|
||||
UNUSED(token);
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel = Untrusted;
|
||||
debug("Untrusted token %#lx", token);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to untrust token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::AddTrustLevel(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel |= TrustLevel;
|
||||
debug("Added trust level %d to token %#lx", t.TrustLevel, token);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to add trust level %d to token %#lx", TrustLevel, token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::RemoveTrustLevel(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel &= ~TrustLevel;
|
||||
debug("Removed trust level %d from token %#lx", t.TrustLevel, token);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to remove trust level %d from token %#lx", TrustLevel, token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::DestroyToken(Token token)
|
||||
{
|
||||
fixme("DestroyToken->false");
|
||||
fixme("DestroyToken->true");
|
||||
UNUSED(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Security::IsTokenTrusted(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == token)
|
||||
{
|
||||
if (t.TrustLevel == TrustLevel)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
warn("Failed to check trust level of token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
Security::Security()
|
||||
bool Security::IsTokenTrusted(Token token, int TrustLevel)
|
||||
{
|
||||
trace("Initializing Tasking Security");
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == token)
|
||||
{
|
||||
if (t.TrustLevel & TrustLevel)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
warn("Failed to check trust level of token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
int Security::GetTokenTrustLevel(Token token)
|
||||
{
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == token)
|
||||
return t.TrustLevel;
|
||||
|
||||
warn("Failed to get trust level of token %#lx", token);
|
||||
return UnknownTrustLevel;
|
||||
}
|
||||
|
||||
Security::Security() {}
|
||||
|
||||
Security::~Security()
|
||||
{
|
||||
trace("Destroying Tasking Security");
|
||||
for (size_t i = 0; i < Tokens.size(); i++)
|
||||
Tokens.remove(i);
|
||||
}
|
||||
|
764
Tasking/Task.cpp
764
Tasking/Task.cpp
@ -17,37 +17,25 @@
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
|
||||
// #define DEBUG_SCHEDULER 1
|
||||
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
|
||||
// #define DEBUG_TASKING 1
|
||||
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
#define schedbg(m, ...) \
|
||||
#ifdef DEBUG_TASKING
|
||||
#define tskdbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync_synchronize()
|
||||
#else
|
||||
#define schedbg(m, ...)
|
||||
#define tskdbg(m, ...)
|
||||
#endif
|
||||
|
||||
NewLock(TaskingLock);
|
||||
NewLock(SchedulerLock);
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
extern "C" SafeFunction __no_instrument_function void OneShot(int TimeSlice)
|
||||
{
|
||||
if (TimeSlice == 0)
|
||||
TimeSlice = 10;
|
||||
#if defined(__amd64__)
|
||||
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x64::IRQ16, TimeSlice);
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
}
|
||||
|
||||
void Task::Schedule()
|
||||
{
|
||||
if (!StopScheduler)
|
||||
OneShot(100);
|
||||
TaskingScheduler_OneShot(100);
|
||||
// APIC::InterruptCommandRegisterLow icr;
|
||||
// icr.Vector = CPU::x64::IRQ16;
|
||||
// icr.Level = APIC::APICLevel::Assert;
|
||||
@ -71,9 +59,11 @@ namespace Tasking
|
||||
{
|
||||
if (!pcb)
|
||||
return true;
|
||||
if (pcb >= (PCB *)(UINTPTR_MAX - 0x1000))
|
||||
if (pcb >= (PCB *)(UINTPTR_MAX - 0x1000)) /* Uninitialized pointers may have uintptr_t max value instead of nullptr. */
|
||||
return true;
|
||||
if (!Memory::Virtual().Check((void *)pcb))
|
||||
if (pcb < (PCB *)(0x1000)) /* In this section of the memory is reserved by the kernel. */
|
||||
return true;
|
||||
if (!Memory::Virtual().Check((void *)pcb)) /* Check if it's mapped. */
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -82,9 +72,11 @@ namespace Tasking
|
||||
{
|
||||
if (!tcb)
|
||||
return true;
|
||||
if (tcb >= (TCB *)(UINTPTR_MAX - 0x1000))
|
||||
if (tcb >= (TCB *)(UINTPTR_MAX - 0x1000)) /* Uninitialized pointers may have uintptr_t max value instead of nullptr. */
|
||||
return true;
|
||||
if (!Memory::Virtual().Check((void *)tcb))
|
||||
if (tcb < (TCB *)(0x1000)) /* In this section of the memory is reserved by the kernel. */
|
||||
return true;
|
||||
if (!Memory::Virtual().Check((void *)tcb)) /* Check if it's mapped. */
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -126,11 +118,27 @@ namespace Tasking
|
||||
{
|
||||
trace("Process \"%s\"(%d) removed from the list", Process->Name, Process->ID);
|
||||
// Free memory
|
||||
delete ListProcess[i]->IPCHandles;
|
||||
delete ListProcess[i]->IPC;
|
||||
delete ListProcess[i]->ELFSymbolTable;
|
||||
SecurityManager.DestroyToken(ListProcess[i]->Security.UniqueToken);
|
||||
if (ListProcess[i]->Security.TrustLevel == TaskTrustLevel::User)
|
||||
KernelAllocator.FreePages((void *)ListProcess[i]->PageTable, TO_PAGES(PAGE_SIZE));
|
||||
|
||||
// Remove the process from parent's children list
|
||||
if (ListProcess[i]->Parent)
|
||||
for (size_t j = 0; j < ListProcess[i]->Parent->Children.size(); j++)
|
||||
{
|
||||
if (ListProcess[i]->Parent->Children[j] == ListProcess[i])
|
||||
{
|
||||
ListProcess[i]->Parent->Children.remove(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete process directory
|
||||
vfs->Delete(ListProcess[i]->ProcessDirectory, true);
|
||||
|
||||
// Free memory
|
||||
delete ListProcess[i];
|
||||
// Remove from the list
|
||||
ListProcess.remove(i);
|
||||
@ -182,579 +190,6 @@ namespace Tasking
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__amd64__)
|
||||
SafeFunction __no_instrument_function bool Task::FindNewProcess(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
schedbg("%d processes", ListProcess.size());
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
foreach (auto var in ListProcess)
|
||||
{
|
||||
schedbg("Process %d %s", var->ID, var->Name);
|
||||
}
|
||||
#endif
|
||||
// Find a new process to execute.
|
||||
foreach (PCB *pcb in ListProcess)
|
||||
{
|
||||
if (unlikely(InvalidPCB(pcb)))
|
||||
continue;
|
||||
|
||||
// Check process status.
|
||||
switch (pcb->Status)
|
||||
{
|
||||
case TaskStatus::Ready:
|
||||
schedbg("Ready process (%s)%d", pcb->Name, pcb->ID);
|
||||
break;
|
||||
default:
|
||||
schedbg("Process \"%s\"(%d) status %d", pcb->Name, pcb->ID, pcb->Status);
|
||||
RemoveProcess(pcb);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get first available thread from the list.
|
||||
foreach (TCB *tcb in pcb->Threads)
|
||||
{
|
||||
if (unlikely(InvalidTCB(tcb)))
|
||||
continue;
|
||||
|
||||
if (tcb->Status != TaskStatus::Ready)
|
||||
continue;
|
||||
|
||||
// Set process and thread as the current one's.
|
||||
CurrentCPU->CurrentProcess = pcb;
|
||||
CurrentCPU->CurrentThread = tcb;
|
||||
// Success!
|
||||
return true;
|
||||
}
|
||||
}
|
||||
schedbg("No process to run.");
|
||||
// No process found. Idling...
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
for (size_t i = 0; i < CurrentCPU->CurrentProcess->Threads.size(); i++)
|
||||
{
|
||||
// Loop until we find the current thread from the process thread list.
|
||||
if (CurrentCPU->CurrentProcess->Threads[i] == CurrentCPU->CurrentThread)
|
||||
{
|
||||
// Check if the next thread is valid. If not, we search until we find, but if we reach the end of the list, we go to the next process.
|
||||
size_t TempIndex = i;
|
||||
RetryAnotherThread:
|
||||
TCB *thread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
|
||||
if (unlikely(InvalidTCB(thread)))
|
||||
{
|
||||
if (TempIndex > CurrentCPU->CurrentProcess->Threads.size())
|
||||
break;
|
||||
TempIndex++;
|
||||
goto RetryAnotherThread;
|
||||
}
|
||||
|
||||
schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)", CurrentCPU->CurrentProcess->Threads[i]->Name, CurrentCPU->CurrentProcess->Threads[i]->ID, thread->Name, thread->ID);
|
||||
|
||||
// Check if the thread is ready to be executed.
|
||||
if (thread->Status != TaskStatus::Ready)
|
||||
{
|
||||
schedbg("Thread %d is not ready", thread->ID);
|
||||
goto RetryAnotherThread;
|
||||
}
|
||||
|
||||
// Everything is fine, we can set the new thread as the current one.
|
||||
CurrentCPU->CurrentThread = thread;
|
||||
schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d", thread->ID, thread->Parent->Name, CurrentCPU->CurrentProcess->Threads.size(), ListProcess.size());
|
||||
// Yay! We found a new thread to execute.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
for (size_t i = 0; i < ListProcess.size(); i++)
|
||||
{
|
||||
// Loop until we find the current process from the process list.
|
||||
if (ListProcess[i] == CurrentCPU->CurrentProcess)
|
||||
{
|
||||
// Check if the next process is valid. If not, we search until we find.
|
||||
size_t TempIndex = i;
|
||||
RetryAnotherProcess:
|
||||
PCB *pcb = ListProcess[TempIndex + 1];
|
||||
if (unlikely(InvalidPCB(pcb)))
|
||||
{
|
||||
if (TempIndex > ListProcess.size())
|
||||
{
|
||||
schedbg("Exceeded the process list.");
|
||||
break;
|
||||
}
|
||||
TempIndex++;
|
||||
schedbg("Invalid process %#lx", pcb);
|
||||
goto RetryAnotherProcess;
|
||||
}
|
||||
else
|
||||
{
|
||||
schedbg("Found process %d", pcb->ID);
|
||||
}
|
||||
|
||||
if (pcb->Status != TaskStatus::Ready)
|
||||
{
|
||||
schedbg("Process %d is not ready", pcb->ID);
|
||||
TempIndex++;
|
||||
goto RetryAnotherProcess;
|
||||
}
|
||||
|
||||
// Everything good, now search for a thread.
|
||||
for (size_t j = 0; j < pcb->Threads.size(); j++)
|
||||
{
|
||||
TCB *tcb = pcb->Threads[j];
|
||||
if (unlikely(InvalidTCB(tcb)))
|
||||
{
|
||||
schedbg("Invalid thread %#lx", tcb);
|
||||
continue;
|
||||
}
|
||||
if (tcb->Status != TaskStatus::Ready)
|
||||
{
|
||||
schedbg("Thread %d is not ready", tcb->ID);
|
||||
continue;
|
||||
}
|
||||
// Success! We set as the current one and restore the stuff.
|
||||
CurrentCPU->CurrentProcess = pcb;
|
||||
CurrentCPU->CurrentThread = tcb;
|
||||
schedbg("[cur proc+1 -> first thd] Scheduling thread %d %s->%d (Total Procs %d)", tcb->ID, tcb->Name, pcb->Threads.size(), ListProcess.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
schedbg("No process to run.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::SchedulerCleanupProcesses()
|
||||
{
|
||||
foreach (PCB *pcb in ListProcess)
|
||||
{
|
||||
if (unlikely(InvalidPCB(pcb)))
|
||||
continue;
|
||||
RemoveProcess(pcb);
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
foreach (PCB *pcb in ListProcess)
|
||||
{
|
||||
if (unlikely(InvalidPCB(pcb)))
|
||||
continue;
|
||||
if (pcb->Status != TaskStatus::Ready)
|
||||
continue;
|
||||
|
||||
// Now do the thread search!
|
||||
foreach (TCB *tcb in pcb->Threads)
|
||||
{
|
||||
if (unlikely(InvalidTCB(tcb)))
|
||||
continue;
|
||||
if (tcb->Status != TaskStatus::Ready)
|
||||
continue;
|
||||
// \o/ We found a new thread to execute.
|
||||
CurrentCPU->CurrentProcess = pcb;
|
||||
CurrentCPU->CurrentThread = tcb;
|
||||
schedbg("[proc 0 -> end -> first thd] Scheduling thread %d parent of %s->%d (Procs %d)", tcb->ID, tcb->Parent->Name, pcb->Threads.size(), ListProcess.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::WakeUpThreads(void *CPUDataPointer)
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
// Loop through all the processes.
|
||||
foreach (PCB *pcb in ListProcess)
|
||||
{
|
||||
if (unlikely(InvalidPCB(pcb)))
|
||||
continue;
|
||||
|
||||
// Check process status.
|
||||
if (pcb->Status == TaskStatus::Terminated)
|
||||
continue;
|
||||
|
||||
// Loop through all the threads.
|
||||
foreach (TCB *tcb in pcb->Threads)
|
||||
{
|
||||
if (unlikely(InvalidTCB(tcb)))
|
||||
continue;
|
||||
|
||||
// Check if the thread is sleeping.
|
||||
if (tcb->Status != TaskStatus::Sleeping || pcb->Status == TaskStatus::Terminated)
|
||||
continue;
|
||||
|
||||
// Check if the thread is ready to wake up.
|
||||
if (tcb->Info.SleepUntil < TimeManager->GetCounter())
|
||||
{
|
||||
tcb->Status = TaskStatus::Ready;
|
||||
if (tcb->Parent->Threads.size() == 1 && tcb->Parent->Status == TaskStatus::Sleeping)
|
||||
tcb->Parent->Status = TaskStatus::Ready;
|
||||
tcb->Info.SleepUntil = 0;
|
||||
schedbg("Thread \"%s\"(%d) woke up.", tcb->Name, tcb->ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)", tcb->Name, tcb->ID, tcb->Info.SleepUntil, TimeManager->GetCounter());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::Schedule(CPU::x64::TrapFrame *Frame)
|
||||
{
|
||||
SmartCriticalSection(SchedulerLock);
|
||||
if (StopScheduler)
|
||||
{
|
||||
warn("Scheduler stopped.");
|
||||
return;
|
||||
}
|
||||
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); // Restore kernel page table for safety reasons.
|
||||
CPUData *CurrentCPU = GetCurrentCPU();
|
||||
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
|
||||
schedbg("%d: %ld%%", CurrentCPU->ID, GetUsage(CurrentCPU->ID));
|
||||
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
int SuccessSource = 0;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
{
|
||||
schedbg("================================================================");
|
||||
schedbg("Status: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
|
||||
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
|
||||
size_t ds;
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||
Frame->ss, Frame->cs, ds);
|
||||
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||
schedbg("================================================================");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Null or invalid process/thread? Let's find a new one to execute.
|
||||
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess) || InvalidTCB(CurrentCPU->CurrentThread)))
|
||||
{
|
||||
schedbg("Invalid process or thread. Finding a new one.");
|
||||
if (this->FindNewProcess(CurrentCPU))
|
||||
goto Success;
|
||||
else
|
||||
goto Idle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save current process and thread registries, gs, fs, fpu, etc...
|
||||
CurrentCPU->CurrentThread->Registers = *Frame;
|
||||
CPU::x64::fxsave(CurrentCPU->CurrentThread->FPU);
|
||||
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
|
||||
|
||||
// Set the process & thread as ready if they are running.
|
||||
if (CurrentCPU->CurrentProcess->Status == TaskStatus::Running)
|
||||
CurrentCPU->CurrentProcess->Status = TaskStatus::Ready;
|
||||
if (CurrentCPU->CurrentThread->Status == TaskStatus::Running)
|
||||
CurrentCPU->CurrentThread->Status = TaskStatus::Ready;
|
||||
|
||||
// Loop through all threads and find which one is ready.
|
||||
this->WakeUpThreads(CurrentCPU);
|
||||
schedbg("Passed WakeUpThreads");
|
||||
// Get next available thread from the list.
|
||||
if (this->GetNextAvailableThread(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
SuccessSource = 1;
|
||||
#endif
|
||||
goto Success;
|
||||
}
|
||||
schedbg("Passed GetNextAvailableThread");
|
||||
// If we didn't find a thread to execute, we search for a new process.
|
||||
if (this->GetNextAvailableProcess(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
SuccessSource = 2;
|
||||
#endif
|
||||
goto Success;
|
||||
}
|
||||
schedbg("Passed GetNextAvailableProcess");
|
||||
// Before checking from the beginning, we remove everything that is terminated.
|
||||
this->SchedulerCleanupProcesses();
|
||||
schedbg("Passed SchedulerCleanupProcesses");
|
||||
// If we didn't find anything, we check from the start of the list. This is the last chance to find something or we go idle.
|
||||
if (SchedulerSearchProcessThread(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
SuccessSource = 3;
|
||||
#endif
|
||||
schedbg("Passed SchedulerSearchProcessThread");
|
||||
goto Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
schedbg("SchedulerSearchProcessThread failed. Going idle.");
|
||||
goto Idle;
|
||||
}
|
||||
}
|
||||
goto UnwantedReach; // This should never happen.
|
||||
|
||||
Idle:
|
||||
{
|
||||
CurrentCPU->CurrentProcess = IdleProcess;
|
||||
CurrentCPU->CurrentThread = IdleThread;
|
||||
goto Success;
|
||||
}
|
||||
|
||||
Success:
|
||||
{
|
||||
schedbg("Process \"%s\"(%d) Thread \"%s\"(%d) is now running on CPU %d",
|
||||
CurrentCPU->CurrentProcess->Name, CurrentCPU->CurrentProcess->ID,
|
||||
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID);
|
||||
|
||||
CurrentCPU->CurrentProcess->Status = TaskStatus::Running;
|
||||
CurrentCPU->CurrentThread->Status = TaskStatus::Running;
|
||||
|
||||
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||
|
||||
// FIXME: Untested
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
if (CurrentCPU->CurrentThread->IPHistory[i] == 0)
|
||||
{
|
||||
CurrentCPU->CurrentThread->IPHistory[i] = Frame->rip;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 127)
|
||||
{
|
||||
for (int j = 0; j < 127; j++)
|
||||
CurrentCPU->CurrentThread->IPHistory[j] = CurrentCPU->CurrentThread->IPHistory[j + 1];
|
||||
CurrentCPU->CurrentThread->IPHistory[127] = Frame->rip;
|
||||
}
|
||||
}
|
||||
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
|
||||
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
|
||||
// Not sure if this is needed, but it's better to be safe than sorry.
|
||||
asmv("movq %cr3, %rax");
|
||||
asmv("movq %rax, %cr3");
|
||||
CPU::x64::fxrstor(CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
|
||||
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
static int sanity;
|
||||
const char *Statuses[] = {
|
||||
"FF0000", // Unknown
|
||||
"AAFF00", // Ready
|
||||
"00AA00", // Running
|
||||
"FFAA00", // Sleeping
|
||||
"FFAA00", // Waiting
|
||||
"FF0088", // Stopped
|
||||
"FF0000", // Terminated
|
||||
};
|
||||
const char *StatusesSign[] = {
|
||||
"U", // Unknown
|
||||
"R", // Ready
|
||||
"r", // Running
|
||||
"S", // Sleeping
|
||||
"W", // Waiting
|
||||
"s", // Stopped
|
||||
"T", // Terminated
|
||||
};
|
||||
const char *SuccessSourceStrings[] = {
|
||||
"Unknown",
|
||||
"GetNextAvailableThread",
|
||||
"GetNextAvailableProcess",
|
||||
"SchedulerSearchProcessThread",
|
||||
};
|
||||
for (int i = 0; i < 340; i++)
|
||||
for (int j = 0; j < 200; j++)
|
||||
Display->SetPixel(i, j, 0x222222, 0);
|
||||
uint32_t tmpX, tmpY;
|
||||
Display->GetBufferCursor(0, &tmpX, &tmpY);
|
||||
Display->SetBufferCursor(0, 0, 0);
|
||||
foreach (auto var in ListProcess)
|
||||
{
|
||||
int Status = var->Status;
|
||||
printf("\e%s-> \eAABBCC%s\eCCCCCC[%d] \e00AAAA%s\n",
|
||||
Statuses[Status], var->Name, Status, StatusesSign[Status]);
|
||||
foreach (auto var2 in var->Threads)
|
||||
{
|
||||
Status = var2->Status;
|
||||
printf(" \e%s-> \eAABBCC%s\eCCCCCC[%d] \e00AAAA%s\n\eAABBCC",
|
||||
Statuses[Status], var2->Name, Status, StatusesSign[Status]);
|
||||
}
|
||||
}
|
||||
printf("%d - SOURCE: %s", sanity++, SuccessSourceStrings[SuccessSource]);
|
||||
if (sanity > 1000)
|
||||
sanity = 0;
|
||||
Display->SetBufferCursor(0, tmpX, tmpY);
|
||||
Display->SetBuffer(0);
|
||||
for (int i = 0; i < 50000; i++)
|
||||
inb(0x80);
|
||||
#endif
|
||||
|
||||
switch (CurrentCPU->CurrentProcess->Security.TrustLevel)
|
||||
{
|
||||
case TaskTrustLevel::System:
|
||||
case TaskTrustLevel::Idle:
|
||||
case TaskTrustLevel::Kernel:
|
||||
// wrmsr(MSR_SHADOW_GS_BASE, (uint64_t)CurrentCPU->CurrentThread);
|
||||
break;
|
||||
case TaskTrustLevel::User:
|
||||
// wrmsr(MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->gs);
|
||||
break;
|
||||
default:
|
||||
error("Unknown trust level %d.", CurrentCPU->CurrentProcess->Security.TrustLevel);
|
||||
break;
|
||||
}
|
||||
goto End;
|
||||
}
|
||||
UnwantedReach:
|
||||
{
|
||||
warn("Unwanted reach!");
|
||||
OneShot(100);
|
||||
goto RealEnd;
|
||||
}
|
||||
End:
|
||||
{
|
||||
// TODO: This is not accurate.
|
||||
if (CurrentCPU->CurrentProcess->Security.TrustLevel == TaskTrustLevel::User)
|
||||
UpdateUserTime(&CurrentCPU->CurrentProcess->Info);
|
||||
else
|
||||
UpdateKernelTime(&CurrentCPU->CurrentProcess->Info);
|
||||
|
||||
if (CurrentCPU->CurrentThread->Security.TrustLevel == TaskTrustLevel::User)
|
||||
UpdateUserTime(&CurrentCPU->CurrentThread->Info);
|
||||
else
|
||||
UpdateKernelTime(&CurrentCPU->CurrentThread->Info);
|
||||
|
||||
UpdateUsage(&CurrentCPU->CurrentProcess->Info, CurrentCPU->ID);
|
||||
UpdateUsage(&CurrentCPU->CurrentThread->Info, CurrentCPU->ID);
|
||||
OneShot(CurrentCPU->CurrentThread->Info.Priority);
|
||||
}
|
||||
{
|
||||
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
||||
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
|
||||
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID,
|
||||
CurrentCPU->CurrentThread->Registers.rip,
|
||||
CurrentCPU->CurrentThread->Registers.rbp,
|
||||
CurrentCPU->CurrentThread->Registers.rsp);
|
||||
}
|
||||
{
|
||||
schedbg("================================================================");
|
||||
schedbg("Technical Informations on Thread %s[%ld]:", CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID);
|
||||
uint64_t ds;
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||
Frame->ss, Frame->cs, ds);
|
||||
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||
schedbg("================================================================");
|
||||
}
|
||||
RealEnd:
|
||||
{
|
||||
__sync_synchronize(); // TODO: Is this really needed?
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction __no_instrument_function void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame) { this->Schedule(Frame); }
|
||||
#elif defined(__i386__)
|
||||
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::SchedulerCleanupProcesses()
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::Schedule(void *Frame)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
|
||||
#elif defined(__aarch64__)
|
||||
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::SchedulerCleanupProcesses()
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::Schedule(void *Frame)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
|
||||
#endif
|
||||
|
||||
void ThreadDoExit()
|
||||
{
|
||||
// TODO: How I can lock the scheduler without causing a deadlock?
|
||||
@ -789,6 +224,28 @@ namespace Tasking
|
||||
CPU::Halt();
|
||||
}
|
||||
|
||||
void Task::WaitForProcessStatus(PCB *pcb, TaskStatus status)
|
||||
{
|
||||
if (!pcb)
|
||||
return;
|
||||
if (pcb->Status == TaskStatus::UnknownStatus)
|
||||
return;
|
||||
debug("Waiting for process \"%s\"(%d) to reach status: %d", pcb->Name, pcb->ID, status);
|
||||
while (pcb->Status != status)
|
||||
CPU::Halt();
|
||||
}
|
||||
|
||||
void Task::WaitForThreadStatus(TCB *tcb, TaskStatus status)
|
||||
{
|
||||
if (!tcb)
|
||||
return;
|
||||
if (tcb->Status == TaskStatus::UnknownStatus)
|
||||
return;
|
||||
debug("Waiting for thread \"%s\"(%d) to reach status: %d", tcb->Name, tcb->ID, status);
|
||||
while (tcb->Status != status)
|
||||
CPU::Halt();
|
||||
}
|
||||
|
||||
void Task::Sleep(uint64_t Milliseconds)
|
||||
{
|
||||
SmartCriticalSection(TaskingLock);
|
||||
@ -797,11 +254,11 @@ namespace Tasking
|
||||
if (thread->Parent->Threads.size() == 1)
|
||||
thread->Parent->Status = TaskStatus::Sleeping;
|
||||
thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds);
|
||||
schedbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil);
|
||||
// OneShot(1);
|
||||
tskdbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil);
|
||||
// TaskingScheduler_OneShot(1);
|
||||
// IRQ16
|
||||
TaskingLock.Unlock();
|
||||
asmv("int $0x30");
|
||||
asmv("int $0x30"); /* This will trigger the IRQ16 instantly so we won't execute the next instruction */
|
||||
}
|
||||
|
||||
void Task::SignalShutdown()
|
||||
@ -811,11 +268,59 @@ namespace Tasking
|
||||
// This should hang until all processes are terminated
|
||||
}
|
||||
|
||||
void Task::RevertProcessCreation(PCB *Process)
|
||||
{
|
||||
for (size_t i = 0; i < ListProcess.size(); i++)
|
||||
{
|
||||
if (ListProcess[i] == Process)
|
||||
{
|
||||
SecurityManager.DestroyToken(Process->Security.UniqueToken);
|
||||
if (Process->Security.TrustLevel == TaskTrustLevel::User)
|
||||
KernelAllocator.FreePages((void *)Process->PageTable, TO_PAGES(PAGE_SIZE));
|
||||
|
||||
if (Process->Parent)
|
||||
for (size_t j = 0; j < Process->Parent->Children.size(); j++)
|
||||
{
|
||||
if (Process->Parent->Children[j] == Process)
|
||||
{
|
||||
Process->Parent->Children.remove(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete Process->IPC;
|
||||
delete Process->ELFSymbolTable;
|
||||
delete Process;
|
||||
ListProcess.remove(i);
|
||||
NextPID--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Task::RevertThreadCreation(TCB *Thread)
|
||||
{
|
||||
for (size_t j = 0; j < Thread->Parent->Threads.size(); j++)
|
||||
{
|
||||
if (Thread->Parent->Threads[j] == Thread)
|
||||
{
|
||||
Thread->Parent->Threads.remove(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete Thread->Stack;
|
||||
delete Thread->Memory;
|
||||
SecurityManager.DestroyToken(Thread->Security.UniqueToken);
|
||||
delete Thread;
|
||||
NextTID--;
|
||||
}
|
||||
|
||||
TCB *Task::CreateThread(PCB *Parent,
|
||||
IP EntryPoint,
|
||||
const char **argv,
|
||||
const char **envp,
|
||||
Vector<AuxiliaryVector> &auxv,
|
||||
const Vector<AuxiliaryVector> &auxv,
|
||||
IPOffset Offset,
|
||||
TaskArchitecture Architecture,
|
||||
TaskCompatibility Compatibility)
|
||||
@ -848,10 +353,13 @@ namespace Tasking
|
||||
Thread->Offset = Offset;
|
||||
Thread->ExitCode = 0xdead;
|
||||
Thread->Status = TaskStatus::Ready;
|
||||
Thread->Memory = new Memory::MemMgr(Parent->PageTable);
|
||||
Thread->Memory = new Memory::MemMgr(Parent->PageTable, Parent->memDirectory);
|
||||
Thread->FPU = (CPU::x64::FXState *)Thread->Memory->RequestPages(TO_PAGES(sizeof(CPU::x64::FXState)));
|
||||
memset(Thread->FPU, 0, FROM_PAGES(TO_PAGES(sizeof(CPU::x64::FXState))));
|
||||
|
||||
Thread->Security.TrustLevel = Parent->Security.TrustLevel;
|
||||
Thread->Security.UniqueToken = SecurityManager.CreateToken();
|
||||
|
||||
// TODO: Is really a good idea to use the FPU in kernel mode?
|
||||
Thread->FPU->mxcsr = 0b0001111110000000;
|
||||
Thread->FPU->mxcsrmask = 0b1111111110111111;
|
||||
@ -881,12 +389,11 @@ namespace Tasking
|
||||
case TaskTrustLevel::System:
|
||||
warn("Trust level not supported.");
|
||||
[[fallthrough]];
|
||||
case TaskTrustLevel::Idle:
|
||||
case TaskTrustLevel::Kernel:
|
||||
{
|
||||
Thread->Stack = new Memory::StackGuard(false, Parent->PageTable);
|
||||
#if defined(__amd64__)
|
||||
SecurityManager.TrustToken(Thread->Security.UniqueToken, TokenTrustLevel::TrustedByKernel);
|
||||
SecurityManager.TrustToken(Thread->Security.UniqueToken, TTL::TrustedByKernel);
|
||||
Thread->GSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_GS_BASE);
|
||||
Thread->FSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_FS_BASE);
|
||||
Thread->Registers.cs = GDT_KERNEL_CODE;
|
||||
@ -905,7 +412,7 @@ namespace Tasking
|
||||
{
|
||||
Thread->Stack = new Memory::StackGuard(true, Parent->PageTable);
|
||||
#if defined(__amd64__)
|
||||
SecurityManager.TrustToken(Thread->Security.UniqueToken, TokenTrustLevel::Untrusted);
|
||||
SecurityManager.TrustToken(Thread->Security.UniqueToken, TTL::Untrusted);
|
||||
Thread->GSBase = 0;
|
||||
Thread->FSBase = 0;
|
||||
Thread->Registers.cs = GDT_USER_CODE;
|
||||
@ -981,8 +488,13 @@ namespace Tasking
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
|
||||
// auxv_array is initialized with auxv elements. If the array is empty then we add a null terminator
|
||||
Vector<AuxiliaryVector> auxv_array = auxv;
|
||||
if (auxv_array.size() == 0)
|
||||
auxv_array.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
|
||||
|
||||
// Store auxillary vector
|
||||
foreach (AuxiliaryVector var in auxv)
|
||||
foreach (AuxiliaryVector var in auxv_array)
|
||||
{
|
||||
// Subtract the size of the auxillary vector
|
||||
Stack64 -= sizeof(Elf64_auxv_t) / sizeof(uintptr_t);
|
||||
@ -1052,7 +564,7 @@ namespace Tasking
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__aarch64__)
|
||||
#endif
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
#ifdef DEBUG_TASKING
|
||||
DumpData(Thread->Name, Thread->Stack, STACK_SIZE);
|
||||
#endif
|
||||
break;
|
||||
@ -1067,9 +579,6 @@ namespace Tasking
|
||||
}
|
||||
}
|
||||
|
||||
Thread->Security.TrustLevel = Parent->Security.TrustLevel;
|
||||
// Thread->Security.UniqueToken = SecurityManager.CreateToken();
|
||||
|
||||
Thread->Info = {};
|
||||
Thread->Info.SpawnTime = CPU::Counter();
|
||||
Thread->Info.Year = 0;
|
||||
@ -1083,7 +592,7 @@ namespace Tasking
|
||||
Thread->Info.Usage[i] = 0;
|
||||
Thread->Info.Affinity[i] = true;
|
||||
}
|
||||
Thread->Info.Priority = 10;
|
||||
Thread->Info.Priority = TaskPriority::Normal;
|
||||
Thread->Info.Architecture = Architecture;
|
||||
Thread->Info.Compatibility = Compatibility;
|
||||
|
||||
@ -1128,19 +637,22 @@ namespace Tasking
|
||||
Process->Status = TaskStatus::Ready;
|
||||
|
||||
Process->Security.TrustLevel = TrustLevel;
|
||||
// Process->Security.UniqueToken = SecurityManager.CreateToken();
|
||||
Process->Security.UniqueToken = SecurityManager.CreateToken();
|
||||
|
||||
Process->IPCHandles = new HashMap<InterProcessCommunication::IPCPort, uintptr_t>;
|
||||
char ProcFSName[16];
|
||||
sprintf(ProcFSName, "%ld", Process->ID);
|
||||
Process->ProcessDirectory = vfs->Create(ProcFSName, VirtualFileSystem::NodeFlags::DIRECTORY, ProcFS);
|
||||
Process->memDirectory = vfs->Create("mem", VirtualFileSystem::NodeFlags::DIRECTORY, Process->ProcessDirectory);
|
||||
Process->IPC = new InterProcessCommunication::IPC((void *)Process);
|
||||
|
||||
switch (TrustLevel)
|
||||
{
|
||||
case TaskTrustLevel::System:
|
||||
warn("Trust level not supported.");
|
||||
[[fallthrough]];
|
||||
case TaskTrustLevel::Idle:
|
||||
case TaskTrustLevel::Kernel:
|
||||
{
|
||||
SecurityManager.TrustToken(Process->Security.UniqueToken, TokenTrustLevel::TrustedByKernel);
|
||||
SecurityManager.TrustToken(Process->Security.UniqueToken, TTL::TrustedByKernel);
|
||||
#if defined(__amd64__)
|
||||
if (!DoNotCreatePageTable)
|
||||
Process->PageTable = (Memory::PageTable4 *)CPU::x64::readcr3().raw;
|
||||
@ -1151,7 +663,7 @@ namespace Tasking
|
||||
}
|
||||
case TaskTrustLevel::User:
|
||||
{
|
||||
SecurityManager.TrustToken(Process->Security.UniqueToken, TokenTrustLevel::Untrusted);
|
||||
SecurityManager.TrustToken(Process->Security.UniqueToken, TTL::Untrusted);
|
||||
#if defined(__amd64__)
|
||||
if (!DoNotCreatePageTable)
|
||||
{
|
||||
@ -1187,7 +699,7 @@ namespace Tasking
|
||||
Process->Info.Usage[i] = 0;
|
||||
Process->Info.Affinity[i] = true;
|
||||
}
|
||||
Process->Info.Priority = 10;
|
||||
Process->Info.Priority = TaskPriority::Normal;
|
||||
|
||||
debug("Process page table: %#lx", Process->PageTable);
|
||||
debug("Created process \"%s\"(%d) in process \"%s\"(%d)",
|
||||
@ -1229,8 +741,7 @@ namespace Tasking
|
||||
TaskArchitecture Arch = TaskArchitecture::ARM64;
|
||||
#endif
|
||||
PCB *kproc = CreateProcess(nullptr, "Kernel", TaskTrustLevel::Kernel);
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, auxv, 0, Arch);
|
||||
TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, Vector<AuxiliaryVector>(), 0, Arch);
|
||||
kthrd->Rename("Main Thread");
|
||||
debug("Created Kernel Process: %s and Thread: %s", kproc->Name, kthrd->Name);
|
||||
TaskingLock.Lock(__FUNCTION__);
|
||||
@ -1277,15 +788,14 @@ namespace Tasking
|
||||
}
|
||||
|
||||
TaskingLock.Unlock();
|
||||
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskTrustLevel::Idle);
|
||||
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskTrustLevel::Kernel);
|
||||
for (int i = 0; i < SMP::CPUCores; i++)
|
||||
{
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
IdleThread = CreateThread(IdleProcess, reinterpret_cast<uintptr_t>(IdleProcessLoop), nullptr, nullptr, auxv);
|
||||
IdleThread = CreateThread(IdleProcess, reinterpret_cast<uintptr_t>(IdleProcessLoop));
|
||||
char IdleName[16];
|
||||
sprintf(IdleName, "Idle Thread %d", i);
|
||||
IdleThread->Rename(IdleName);
|
||||
IdleThread->SetPriority(1);
|
||||
IdleThread->SetPriority(Idle);
|
||||
break;
|
||||
}
|
||||
debug("Tasking Started");
|
||||
@ -1310,23 +820,21 @@ namespace Tasking
|
||||
{
|
||||
SmartCriticalSection(TaskingLock);
|
||||
trace("Stopping tasking");
|
||||
foreach (auto Process in ListProcess)
|
||||
foreach (PCB *Process in ListProcess)
|
||||
{
|
||||
for (auto &Thread : Process->Threads)
|
||||
{
|
||||
foreach (TCB *Thread in Process->Threads)
|
||||
Thread->Status = TaskStatus::Terminated;
|
||||
}
|
||||
|
||||
Process->Status = TaskStatus::Terminated;
|
||||
}
|
||||
|
||||
TaskingLock.Unlock();
|
||||
SchedulerLock.Unlock();
|
||||
|
||||
while (ListProcess.size() > 0)
|
||||
{
|
||||
trace("Waiting for %d processes to terminate", ListProcess.size());
|
||||
int NotTerminated = 0;
|
||||
foreach (auto Process in ListProcess)
|
||||
foreach (PCB *Process in ListProcess)
|
||||
{
|
||||
debug("Process %s(%d) is still running (or waiting to be removed status %#lx)", Process->Name, Process->ID, Process->Status);
|
||||
if (Process->Status == TaskStatus::Terminated)
|
||||
@ -1335,7 +843,7 @@ namespace Tasking
|
||||
}
|
||||
if (NotTerminated == 0)
|
||||
break;
|
||||
OneShot(100);
|
||||
TaskingScheduler_OneShot(100);
|
||||
}
|
||||
|
||||
trace("Tasking stopped");
|
||||
|
@ -64,4 +64,4 @@ __constructor void TestRandom()
|
||||
debug("Random 64: %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld", Seeds64[0], Seeds64[1], Seeds64[2], Seeds64[3], Seeds64[4], Seeds64[5], Seeds64[6], Seeds64[7], Seeds64[8], Seeds64[9], Seeds64[10], Seeds64[11], Seeds64[12], Seeds64[13], Seeds64[14], Seeds64[15]);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // DEBUG
|
||||
|
@ -13,7 +13,7 @@ extern "C"
|
||||
int isalpha(int c);
|
||||
int isupper(int c);
|
||||
unsigned int isdelim(char c, char *delim);
|
||||
int abs(int i);
|
||||
long abs(long i);
|
||||
void swap(char *x, char *y);
|
||||
char *reverse(char *Buffer, int i, int j);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
/* 32-bit ELF base types. */
|
||||
typedef uint32_t Elf32_Addr;
|
||||
typedef uint64_t Elf32_Half;
|
||||
typedef uint16_t Elf32_Half;
|
||||
typedef uint32_t Elf32_Off;
|
||||
typedef int32_t Elf32_Sword;
|
||||
typedef uint32_t Elf32_Word;
|
||||
@ -153,6 +153,13 @@ struct Elf64_Dyn
|
||||
} d_un;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Elf64_Addr r_offset;
|
||||
Elf64_Xword r_info;
|
||||
Elf64_Sxword r_addend;
|
||||
} Elf64_Rela;
|
||||
|
||||
enum Elf_Ident
|
||||
{
|
||||
EI_MAG0 = 0, // 0x7F
|
||||
@ -184,7 +191,7 @@ enum Elf_OSABI
|
||||
ELFOSABI_OPENVMS = 13,
|
||||
ELFOSABI_NSK = 14,
|
||||
ELFOSABI_AROS = 15,
|
||||
ELFOSABI_FENIXOS = 16, /* Wait... what? */
|
||||
ELFOSABI_FENIXOS = 16,
|
||||
ELFOSABI_CLOUDABI = 17,
|
||||
ELFOSABI_OPENVOS = 18,
|
||||
ELFOSABI_C6000_ELFABI = 64,
|
||||
@ -208,7 +215,28 @@ enum RtT_Types
|
||||
{
|
||||
R_386_NONE = 0, // No relocation
|
||||
R_386_32 = 1, // Symbol + Offset
|
||||
R_386_PC32 = 2 // Symbol + Offset - Section Offset
|
||||
R_386_PC32 = 2, // Symbol + Offset - Section Offset
|
||||
|
||||
R_X86_64_NONE = 0,
|
||||
R_X86_64_64 = 1,
|
||||
R_X86_64_PC32 = 2,
|
||||
R_X86_64_GOT32 = 3,
|
||||
R_X86_64_PLT32 = 4,
|
||||
R_X86_64_COPY = 5,
|
||||
R_X86_64_GLOB_DAT = 6,
|
||||
R_X86_64_JUMP_SLOT = 7,
|
||||
R_X86_64_RELATIVE = 8,
|
||||
R_X86_64_GOTPCREL = 9,
|
||||
R_X86_64_32 = 10,
|
||||
R_X86_64_32S = 11,
|
||||
R_X86_64_16 = 12,
|
||||
};
|
||||
|
||||
enum ProgFlags_Types
|
||||
{
|
||||
PF_X = 1,
|
||||
PF_W = 2,
|
||||
PF_R = 4
|
||||
};
|
||||
|
||||
enum StT_Bindings
|
||||
@ -359,11 +387,13 @@ enum DynamicArrayTags
|
||||
#define DO_64_64(S, A) ((S) + (A))
|
||||
#define DO_64_PC32(S, A, P) ((S) + (A) - (P))
|
||||
|
||||
#define ELF32_R_SYM(INFO) ((INFO) >> 8)
|
||||
#define ELF32_R_TYPE(INFO) ((uint8_t)(INFO))
|
||||
#define ELF32_R_SYM(i) ((i) >> 8)
|
||||
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||
#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t))
|
||||
|
||||
#define ELF64_R_SYM(INFO) ((INFO) >> 8)
|
||||
#define ELF64_R_TYPE(INFO) ((uint8_t)(INFO))
|
||||
#define ELF64_R_SYM(i) ((i) >> 32)
|
||||
#define ELF64_R_TYPE(i) ((i)&0xffffffffL)
|
||||
#define ELF64_R_INFO(s, t) (((s) << 32) + ((t)&0xffffffffL))
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_ABS 0xfff1
|
||||
@ -374,10 +404,12 @@ enum DynamicArrayTags
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_ALLOC 0x2
|
||||
|
||||
#define EM_386 (3) // x86 Machine Type
|
||||
#define EM_AMD64 (0x3E) // 64bit
|
||||
#define EM_AARCH64 (0xb7) // ARM64
|
||||
#define EV_CURRENT (1) // ELF Current Version
|
||||
#define EM_386 0x3 // x86 Machine Type
|
||||
#define EM_X86_64 0x3E // 64bit
|
||||
#define EM_ARM 0x28 // ARM
|
||||
#define EM_AARCH64 0xb7 // ARM64
|
||||
|
||||
#define EV_CURRENT 0x1 // ELF Current Version
|
||||
|
||||
#define ELFMAG0 0x7F // e_ident[EI_MAG0]
|
||||
#define ELFMAG1 'E' // e_ident[EI_MAG1]
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <task.hpp>
|
||||
#include <elf.h>
|
||||
|
||||
@ -21,9 +22,10 @@ namespace Execute
|
||||
|
||||
enum ExStatus
|
||||
{
|
||||
OK,
|
||||
Unknown,
|
||||
OK,
|
||||
Unsupported,
|
||||
GenericError,
|
||||
InvalidFile,
|
||||
InvalidFileFormat,
|
||||
InvalidFileHeader,
|
||||
@ -39,21 +41,78 @@ namespace Execute
|
||||
Tasking::TCB *Thread;
|
||||
};
|
||||
|
||||
struct SharedLibraries
|
||||
{
|
||||
char Identifier[256];
|
||||
uint64_t Timeout;
|
||||
long RefCount;
|
||||
|
||||
void *Address;
|
||||
void *MemoryImage;
|
||||
size_t Length;
|
||||
};
|
||||
|
||||
struct ELFBaseLoad
|
||||
{
|
||||
bool Success;
|
||||
SpawnData sd;
|
||||
Tasking::IP InstructionPointer;
|
||||
|
||||
/* This should be deleted after copying the allocated pages to the thread
|
||||
Intended to be used only inside BaseLoad.cpp */
|
||||
Memory::MemMgr *TmpMem;
|
||||
|
||||
/* Same as above, for BaseLoad.cpp only */
|
||||
Vector<AuxiliaryVector> auxv;
|
||||
};
|
||||
|
||||
BinaryType GetBinaryType(void *Image);
|
||||
BinaryType GetBinaryType(char *Path);
|
||||
|
||||
SpawnData Spawn(char *Path, const char **argv, const char **envp);
|
||||
|
||||
void *ELFLoadRel(Elf64_Ehdr *Header);
|
||||
void ELFLoadExec(void *BaseImage,
|
||||
size_t Length,
|
||||
Elf64_Ehdr *ELFHeader,
|
||||
Memory::Virtual &pva,
|
||||
SpawnData *ret,
|
||||
char *Path,
|
||||
Tasking::PCB *Process,
|
||||
const char **argv,
|
||||
const char **envp,
|
||||
Tasking::TaskArchitecture Arch,
|
||||
Tasking::TaskCompatibility Comp);
|
||||
ELFBaseLoad ELFLoad(char *Path, const char **argv, const char **envp,
|
||||
Tasking::TaskCompatibility Compatibility = Tasking::TaskCompatibility::Native);
|
||||
|
||||
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header);
|
||||
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index);
|
||||
char *GetELFStringTable(Elf64_Ehdr *Header);
|
||||
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset);
|
||||
void *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name);
|
||||
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index);
|
||||
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag);
|
||||
|
||||
/**
|
||||
* @brief Create a ELF Memory Image
|
||||
*
|
||||
* @param mem The memory manager to use
|
||||
* @param pV Memory::Virtual object to use
|
||||
* @param ElfFile ELF file loaded in memory (FULL FILE)
|
||||
* @param Length Length of @p ElfFile
|
||||
* @return void* The Memory Image
|
||||
*/
|
||||
void *ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length);
|
||||
|
||||
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &pV, const char *Interpreter);
|
||||
|
||||
ELFBaseLoad ELFLoadRel(void *ElfFile,
|
||||
VirtualFileSystem::File *ExFile,
|
||||
Tasking::PCB *Process);
|
||||
|
||||
ELFBaseLoad ELFLoadExec(void *ElfFile,
|
||||
VirtualFileSystem::File *ExFile,
|
||||
Tasking::PCB *Process);
|
||||
|
||||
ELFBaseLoad ELFLoadDyn(void *ElfFile,
|
||||
VirtualFileSystem::File *ExFile,
|
||||
Tasking::PCB *Process);
|
||||
|
||||
void StartExecuteService();
|
||||
SharedLibraries *AddLibrary(char *Identifier,
|
||||
void *ElfImage,
|
||||
size_t Length,
|
||||
const Memory::Virtual &pV = Memory::Virtual());
|
||||
void SearchLibrary(char *Identifier);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__
|
||||
|
@ -3,90 +3,75 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <smartptr.hpp>
|
||||
#include <vector.hpp>
|
||||
|
||||
// show debug messages
|
||||
// #define DEBUG_FILESYSTEM 1
|
||||
|
||||
#ifdef DEBUG_FILESYSTEM
|
||||
#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__)
|
||||
#else
|
||||
#define vfsdbg(m, ...)
|
||||
#endif
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
#define FILENAME_LENGTH 256
|
||||
|
||||
struct FileSystemNode;
|
||||
struct Node;
|
||||
|
||||
typedef size_t (*OperationMount)(const char *, unsigned long, const void *);
|
||||
typedef size_t (*OperationUmount)(int);
|
||||
typedef size_t (*OperationRead)(FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer);
|
||||
typedef size_t (*OperationWrite)(FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer);
|
||||
typedef void (*OperationOpen)(FileSystemNode *Node, uint8_t Mode, uint8_t Flags);
|
||||
typedef void (*OperationClose)(FileSystemNode *Node);
|
||||
typedef size_t (*OperationRead)(Node *node, size_t Offset, size_t Size, uint8_t *Buffer);
|
||||
typedef size_t (*OperationWrite)(Node *node, size_t Offset, size_t Size, uint8_t *Buffer);
|
||||
typedef void (*OperationOpen)(Node *node, uint8_t Mode, uint8_t Flags);
|
||||
typedef void (*OperationClose)(Node *node);
|
||||
typedef size_t (*OperationSync)(void);
|
||||
typedef void (*OperationCreate)(FileSystemNode *Node, char *Name, uint16_t NameLength);
|
||||
typedef void (*OperationMkdir)(FileSystemNode *Node, char *Name, uint16_t NameLength);
|
||||
typedef void (*OperationCreate)(Node *node, char *Name, uint16_t NameLength);
|
||||
typedef void (*OperationMkdir)(Node *node, char *Name, uint16_t NameLength);
|
||||
|
||||
#define MountFSFunction(name) size_t name(const char *unknown0, unsigned long unknown1, const uint8_t *unknown2)
|
||||
#define UMountFSFunction(name) size_t name(int unknown0)
|
||||
|
||||
#define ReadFSFunction(name) size_t name(FileSystem::FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer)
|
||||
#define WriteFSFunction(name) size_t name(FileSystem::FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer)
|
||||
#define OpenFSFunction(name) void name(FileSystem::FileSystemNode *Node, uint8_t Mode, uint8_t Flags)
|
||||
#define CloseFSFunction(name) void name(FileSystem::FileSystemNode *Node)
|
||||
#define ReadFSFunction(name) size_t name(VirtualFileSystem::Node *node, size_t Offset, size_t Size, uint8_t *Buffer)
|
||||
#define WriteFSFunction(name) size_t name(VirtualFileSystem::Node *node, size_t Offset, size_t Size, uint8_t *Buffer)
|
||||
#define OpenFSFunction(name) void name(VirtualFileSystem::Node *node, uint8_t Mode, uint8_t Flags)
|
||||
#define CloseFSFunction(name) void name(VirtualFileSystem::Node *node)
|
||||
#define SyncFSFunction(name) size_t name(void)
|
||||
#define CreateFSFunction(name) void name(FileSystem::FileSystemNode *Node, char *Name, uint16_t NameLength)
|
||||
#define MkdirFSFunction(name) void name(FileSystem::FileSystemNode *Node, char *Name, uint16_t NameLength)
|
||||
#define CreateFSFunction(name) void name(VirtualFileSystem::Node *node, char *Name, uint16_t NameLength)
|
||||
#define MkdirFSFunction(name) void name(VirtualFileSystem::Node *node, char *Name, uint16_t NameLength)
|
||||
|
||||
enum FileStatus
|
||||
{
|
||||
OK = 0,
|
||||
NOT_FOUND = 1,
|
||||
ACCESS_DENIED = 2,
|
||||
INVALID_NAME = 3,
|
||||
INVALID_PARAMETER = 4,
|
||||
INVALID_HANDLE = 5,
|
||||
INVALID_PATH = 6,
|
||||
INVALID_FILE = 7,
|
||||
INVALID_DEVICE = 8,
|
||||
NOT_EMPTY = 9,
|
||||
NOT_SUPPORTED = 10,
|
||||
INVALID_DRIVE = 11,
|
||||
VOLUME_IN_USE = 12,
|
||||
TIMEOUT = 13,
|
||||
NO_MORE_FILES = 14,
|
||||
END_OF_FILE = 15,
|
||||
FILE_EXISTS = 16,
|
||||
PIPE_BUSY = 17,
|
||||
PIPE_DISCONNECTED = 18,
|
||||
MORE_DATA = 19,
|
||||
NO_DATA = 20,
|
||||
PIPE_NOT_CONNECTED = 21,
|
||||
MORE_ENTRIES = 22,
|
||||
DIRECTORY_NOT_EMPTY = 23,
|
||||
NOT_A_DIRECTORY = 24,
|
||||
FILE_IS_A_DIRECTORY = 25,
|
||||
DIRECTORY_NOT_ROOT = 26,
|
||||
DIRECTORY_NOT_EMPTY_2 = 27,
|
||||
END_OF_MEDIA = 28,
|
||||
NO_MEDIA = 29,
|
||||
UNRECOGNIZED_MEDIA = 30,
|
||||
SECTOR_NOT_FOUND = 31
|
||||
OK,
|
||||
NotFound,
|
||||
NotEmpty,
|
||||
NotSupported,
|
||||
AccessDenied,
|
||||
Timeout,
|
||||
SectorNotFound,
|
||||
PartiallyCompleted,
|
||||
|
||||
InvalidName,
|
||||
InvalidParameter,
|
||||
InvalidHandle,
|
||||
InvalidPath,
|
||||
InvalidDevice,
|
||||
InvalidOperator,
|
||||
InvalidNode,
|
||||
|
||||
FileExists,
|
||||
FileIsADirectory,
|
||||
FileIsInvalid,
|
||||
|
||||
DirectoryNotEmpty,
|
||||
NotADirectory,
|
||||
|
||||
UnknownFileStatusError
|
||||
};
|
||||
|
||||
enum NodeFlags
|
||||
{
|
||||
FS_ERROR = 0x0,
|
||||
FS_FILE = 0x01,
|
||||
FS_DIRECTORY = 0x02,
|
||||
FS_CHARDEVICE = 0x03,
|
||||
FS_BLOCKDEVICE = 0x04,
|
||||
FS_PIPE = 0x05,
|
||||
FS_SYMLINK = 0x06,
|
||||
FS_MOUNTPOINT = 0x08
|
||||
NODE_FLAG_ERROR = 0x0,
|
||||
FILE = 0x01,
|
||||
DIRECTORY = 0x02,
|
||||
CHARDEVICE = 0x03,
|
||||
BLOCKDEVICE = 0x04,
|
||||
PIPE = 0x05,
|
||||
SYMLINK = 0x06,
|
||||
MOUNTPOINT = 0x08
|
||||
};
|
||||
|
||||
struct FileSystemOperations
|
||||
@ -102,62 +87,67 @@ namespace FileSystem
|
||||
OperationMkdir MakeDirectory = nullptr;
|
||||
};
|
||||
|
||||
struct FileSystemNode
|
||||
struct Node
|
||||
{
|
||||
char Name[FILENAME_LENGTH];
|
||||
uint64_t IndexNode = 0;
|
||||
uint64_t Mask = 0;
|
||||
uint64_t Mode = 0;
|
||||
int Flags = NodeFlags::FS_ERROR;
|
||||
NodeFlags Flags = NodeFlags::NODE_FLAG_ERROR;
|
||||
uint64_t UserIdentifier = 0, GroupIdentifier = 0;
|
||||
uintptr_t Address = 0;
|
||||
size_t Length = 0;
|
||||
FileSystemNode *Parent = nullptr;
|
||||
Node *Parent = nullptr;
|
||||
FileSystemOperations *Operator = nullptr;
|
||||
/* For root node:
|
||||
0 - root "/"
|
||||
1 - etc
|
||||
...
|
||||
*/
|
||||
Vector<FileSystemNode *> Children;
|
||||
Vector<Node *> Children;
|
||||
};
|
||||
|
||||
struct FILE
|
||||
struct File
|
||||
{
|
||||
const char *Name;
|
||||
char Name[FILENAME_LENGTH];
|
||||
FileStatus Status;
|
||||
FileSystemNode *Node;
|
||||
Node *node;
|
||||
};
|
||||
|
||||
/* Manage / etc.. */
|
||||
class Virtual
|
||||
{
|
||||
private:
|
||||
FileSystemNode *FileSystemRoot = nullptr;
|
||||
Node *FileSystemRoot = nullptr;
|
||||
|
||||
public:
|
||||
FileSystemNode *GetRootNode() { return FileSystemRoot; }
|
||||
FILE *ConvertNodeToFILE(FileSystemNode *Node)
|
||||
{
|
||||
FILE *File = new FILE;
|
||||
File->Name = Node->Name;
|
||||
File->Status = FileStatus::OK;
|
||||
File->Node = Node;
|
||||
return File;
|
||||
}
|
||||
char *GetPathFromNode(FileSystemNode *Node);
|
||||
FileSystemNode *GetNodeFromPath(FileSystemNode *Parent, const char *Path);
|
||||
char *NormalizePath(FileSystemNode *Parent, const char *Path);
|
||||
shared_ptr<char> GetPathFromNode(Node *node);
|
||||
Node *GetNodeFromPath(const char *Path, Node *Parent = nullptr);
|
||||
shared_ptr<File> ConvertNodeToFILE(Node *node);
|
||||
|
||||
FileStatus FileExists(FileSystemNode *Parent, const char *Path);
|
||||
FILE *Mount(FileSystemOperations *Operator, const char *Path);
|
||||
FileStatus Unmount(FILE *File);
|
||||
FILE *Open(const char *Path, FileSystemNode *Parent = nullptr);
|
||||
size_t Read(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size);
|
||||
size_t Write(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size);
|
||||
FileStatus Close(FILE *File);
|
||||
FileSystemNode *CreateRoot(FileSystemOperations *Operator, const char *RootName);
|
||||
FileSystemNode *Create(FileSystemNode *Parent, const char *Path);
|
||||
Node *GetParent(const char *Path, Node *Parent);
|
||||
Node *GetRootNode() { return FileSystemRoot; }
|
||||
|
||||
Node *AddNewChild(const char *Name, Node *Parent);
|
||||
Node *GetChild(const char *Name, Node *Parent);
|
||||
FileStatus RemoveChild(const char *Name, Node *Parent);
|
||||
|
||||
shared_ptr<char> NormalizePath(const char *Path, Node *Parent = nullptr);
|
||||
bool PathExists(const char *Path, Node *Parent = nullptr);
|
||||
Node *CreateRoot(const char *RootName, FileSystemOperations *Operator);
|
||||
Node *Create(const char *Path, NodeFlags Flag, Node *Parent = nullptr);
|
||||
|
||||
FileStatus Delete(const char *Path, bool Recursive = false, Node *Parent = nullptr);
|
||||
FileStatus Delete(Node *Path, bool Recursive = false, Node *Parent = nullptr);
|
||||
|
||||
shared_ptr<File> Mount(const char *Path, FileSystemOperations *Operator);
|
||||
FileStatus Unmount(shared_ptr<File> File);
|
||||
|
||||
size_t Read(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size);
|
||||
size_t Write(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size);
|
||||
|
||||
shared_ptr<File> Open(const char *Path, Node *Parent = nullptr);
|
||||
FileStatus Close(shared_ptr<File> File);
|
||||
|
||||
Virtual();
|
||||
~Virtual();
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
class EXT2
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
class FAT
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
class Initrd
|
||||
{
|
||||
|
@ -5,13 +5,13 @@
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
/* Manage /system/dev */
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
FileSystemNode *AddFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
|
||||
Node *AddFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
|
||||
Device();
|
||||
~Device();
|
||||
};
|
||||
@ -20,7 +20,7 @@ namespace FileSystem
|
||||
class Mount
|
||||
{
|
||||
public:
|
||||
FileSystemNode *MountFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name);
|
||||
Node *MountFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name);
|
||||
void DetectAndMountFS(void *drive);
|
||||
Mount();
|
||||
~Mount();
|
||||
@ -38,7 +38,7 @@ namespace FileSystem
|
||||
class Driver
|
||||
{
|
||||
public:
|
||||
FileSystemNode *AddDriver(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
|
||||
Node *AddDriver(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
|
||||
Driver();
|
||||
~Driver();
|
||||
};
|
||||
@ -47,7 +47,7 @@ namespace FileSystem
|
||||
class Network
|
||||
{
|
||||
public:
|
||||
FileSystemNode *AddNetworkCard(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
|
||||
Node *AddNetworkCard(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
|
||||
Network();
|
||||
~Network();
|
||||
};
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
namespace FileSystem
|
||||
namespace VirtualFileSystem
|
||||
{
|
||||
class USTAR
|
||||
{
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define HASHMAP_ERROR -0x8A50
|
||||
|
||||
template <typename K, typename V>
|
||||
class HashNode
|
||||
{
|
||||
@ -33,6 +35,15 @@ public:
|
||||
DummyNode = new HashNode<K, V>(-1, -1);
|
||||
}
|
||||
|
||||
~HashMap()
|
||||
{
|
||||
for (int i = 0; i < HashMapCapacity; i++)
|
||||
if (Nodes[i] != nullptr)
|
||||
delete Nodes[i];
|
||||
delete[] Nodes;
|
||||
delete DummyNode;
|
||||
}
|
||||
|
||||
int HashCode(K Key) { return Key % HashMapCapacity; }
|
||||
|
||||
void AddNode(K Key, V Value)
|
||||
@ -67,7 +78,7 @@ public:
|
||||
Index++;
|
||||
Index %= HashMapCapacity;
|
||||
}
|
||||
return 0xdeadbeef;
|
||||
return HASHMAP_ERROR;
|
||||
}
|
||||
|
||||
V Get(int Key)
|
||||
@ -78,14 +89,14 @@ public:
|
||||
while (Nodes[Index] != nullptr)
|
||||
{
|
||||
if (Iterate++ > HashMapCapacity)
|
||||
return 0xdeadbeef;
|
||||
return HASHMAP_ERROR;
|
||||
|
||||
if (Nodes[Index]->Key == (K)Key)
|
||||
return Nodes[Index]->Value;
|
||||
Index++;
|
||||
Index %= HashMapCapacity;
|
||||
}
|
||||
return 0xdeadbeef;
|
||||
return HASHMAP_ERROR;
|
||||
}
|
||||
|
||||
int Size() { return HashMapSize; }
|
||||
|
@ -2,75 +2,72 @@
|
||||
#define __FENNIX_KERNEL_IPC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <vector.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
|
||||
namespace InterProcessCommunication
|
||||
{
|
||||
typedef int IPCPort;
|
||||
typedef int IPCID;
|
||||
|
||||
enum IPCOperationType
|
||||
enum IPCType
|
||||
{
|
||||
IPCOperationNone,
|
||||
IPCOperationWrite,
|
||||
IPCOperationRead
|
||||
IPCNone,
|
||||
IPCMessagePassing,
|
||||
IPCPort,
|
||||
IPCSharedMemory,
|
||||
IPCPipe,
|
||||
IPCSocket
|
||||
};
|
||||
|
||||
enum IPCErrorCode
|
||||
{
|
||||
IPCUnknown,
|
||||
IPCError = -1,
|
||||
IPCSuccess,
|
||||
IPCNotListening,
|
||||
IPCTimeout,
|
||||
IPCInvalidPort,
|
||||
IPCPortInUse,
|
||||
IPCPortNotRegistered,
|
||||
IPCAlreadyAllocated,
|
||||
IPCNotAllocated,
|
||||
IPCIDInUse,
|
||||
IPCIDNotRegistered,
|
||||
IPCIDNotFound
|
||||
};
|
||||
|
||||
typedef struct
|
||||
struct IPCHandle
|
||||
{
|
||||
int ID;
|
||||
IPCID ID;
|
||||
long Length;
|
||||
uint8_t *Buffer;
|
||||
bool Listening;
|
||||
IPCOperationType Operation;
|
||||
VirtualFileSystem::Node *Node;
|
||||
IPCErrorCode Error;
|
||||
LockClass Lock;
|
||||
} IPCHandle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ID;
|
||||
long Length;
|
||||
IPCOperationType Operation;
|
||||
IPCErrorCode Error;
|
||||
uint8_t *Buffer;
|
||||
|
||||
// Reserved
|
||||
IPCHandle *HandleBuffer;
|
||||
} __attribute__((packed)) IPCSyscallHandle;
|
||||
|
||||
struct IPCError
|
||||
{
|
||||
uint64_t ErrorCode;
|
||||
};
|
||||
|
||||
class IPC
|
||||
{
|
||||
private:
|
||||
NewLock(IPCLock);
|
||||
IPCID NextID = 0;
|
||||
Vector<IPCHandle *> Handles;
|
||||
Memory::MemMgr *mem;
|
||||
VirtualFileSystem::Node *IPCNode;
|
||||
void *Process;
|
||||
|
||||
public:
|
||||
IPC();
|
||||
IPC(void *Process);
|
||||
~IPC();
|
||||
|
||||
IPCHandle *RegisterHandle(IPCPort Port);
|
||||
IPCError Listen(IPCPort Port);
|
||||
IPCHandle *Wait(IPCPort Port);
|
||||
IPCError Read(unsigned long /* Tasking::UPID */ ID, IPCPort Port, uint8_t *&Buffer, long &Size);
|
||||
IPCError Write(unsigned long /* Tasking::UPID */ ID, IPCPort Port, uint8_t *Buffer, long Size);
|
||||
IPCHandle *Create(IPCType Type, char UniqueToken[16]);
|
||||
IPCErrorCode Destroy(IPCID ID);
|
||||
IPCErrorCode Read(IPCID ID, uint8_t *Buffer, long Size);
|
||||
IPCErrorCode Write(IPCID ID, uint8_t *Buffer, long Size);
|
||||
IPCErrorCode Listen(IPCID ID);
|
||||
IPCHandle *Wait(IPCID ID);
|
||||
IPCErrorCode Allocate(IPCID ID, long Size);
|
||||
IPCErrorCode Deallocate(IPCID ID);
|
||||
};
|
||||
}
|
||||
|
||||
extern InterProcessCommunication::IPC *ipc;
|
||||
|
||||
#endif // !__FENNIX_KERNEL_IPC_H__
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <filesystem.hpp>
|
||||
#include <boot/binfo.h>
|
||||
#include <bitmap.hpp>
|
||||
#include <vector.hpp>
|
||||
@ -634,28 +635,32 @@ namespace Memory
|
||||
|
||||
class MemMgr
|
||||
{
|
||||
private:
|
||||
Bitmap PageBitmap;
|
||||
PageTable4 *PageTable;
|
||||
|
||||
public:
|
||||
struct AllocatedPages
|
||||
{
|
||||
void *Address;
|
||||
size_t PageCount;
|
||||
};
|
||||
|
||||
Vector<AllocatedPages> AllocatedPagesList;
|
||||
|
||||
public:
|
||||
Vector<AllocatedPages> GetAllocatedPagesList() { return AllocatedPagesList; }
|
||||
uint64_t GetAllocatedMemorySize();
|
||||
|
||||
bool Add(void *Address, size_t Count);
|
||||
|
||||
void *RequestPages(size_t Count);
|
||||
void *RequestPages(size_t Count, bool User = false);
|
||||
void FreePages(void *Address, size_t Count);
|
||||
|
||||
MemMgr(PageTable4 *PageTable = nullptr);
|
||||
void DetachAddress(void *Address);
|
||||
|
||||
MemMgr(PageTable4 *PageTable = nullptr, VirtualFileSystem::Node *Directory = nullptr);
|
||||
~MemMgr();
|
||||
|
||||
private:
|
||||
Bitmap PageBitmap;
|
||||
PageTable4 *PageTable;
|
||||
VirtualFileSystem::Node *Directory;
|
||||
|
||||
Vector<AllocatedPages> AllocatedPagesList;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -29,31 +29,31 @@
|
||||
template <class T>
|
||||
class smart_ptr
|
||||
{
|
||||
T *RealPointer;
|
||||
T *m_RealPointer;
|
||||
|
||||
public:
|
||||
explicit smart_ptr(T *p = nullptr)
|
||||
explicit smart_ptr(T *Pointer = nullptr)
|
||||
{
|
||||
spdbg("Smart pointer created (%#lx)", RealPointer);
|
||||
RealPointer = p;
|
||||
spdbg("Smart pointer created (%#lx)", m_RealPointer);
|
||||
m_RealPointer = Pointer;
|
||||
}
|
||||
|
||||
~smart_ptr()
|
||||
{
|
||||
spdbg("Smart pointer deleted (%#lx)", RealPointer);
|
||||
delete (RealPointer);
|
||||
spdbg("Smart pointer deleted (%#lx)", m_RealPointer);
|
||||
delete (m_RealPointer);
|
||||
}
|
||||
|
||||
T &operator*()
|
||||
{
|
||||
spdbg("Smart pointer dereferenced (%#lx)", RealPointer);
|
||||
return *RealPointer;
|
||||
spdbg("Smart pointer dereferenced (%#lx)", m_RealPointer);
|
||||
return *m_RealPointer;
|
||||
}
|
||||
|
||||
T *operator->()
|
||||
{
|
||||
spdbg("Smart pointer dereferenced (%#lx)", RealPointer);
|
||||
return RealPointer;
|
||||
spdbg("Smart pointer dereferenced (%#lx)", m_RealPointer);
|
||||
return m_RealPointer;
|
||||
}
|
||||
};
|
||||
|
||||
@ -67,6 +67,11 @@ class unique_ptr
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class weak_ptr
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class shared_ptr
|
||||
{
|
||||
@ -74,81 +79,190 @@ private:
|
||||
class Counter
|
||||
{
|
||||
private:
|
||||
unsigned int RefCount{};
|
||||
unsigned int m_RefCount{};
|
||||
|
||||
public:
|
||||
Counter() : RefCount(0){};
|
||||
Counter() : m_RefCount(0) { spdbg("Counter %#lx created", this); };
|
||||
Counter(const Counter &) = delete;
|
||||
Counter &operator=(const Counter &) = delete;
|
||||
~Counter() {}
|
||||
void Reset() { RefCount = 0; }
|
||||
unsigned int Get() { return RefCount; }
|
||||
void operator++() { RefCount++; }
|
||||
void operator++(int) { RefCount++; }
|
||||
void operator--() { RefCount--; }
|
||||
void operator--(int) { RefCount--; }
|
||||
~Counter() { spdbg("Counter %#lx deleted", this); }
|
||||
void Reset()
|
||||
{
|
||||
m_RefCount = 0;
|
||||
spdbg("Counter reset");
|
||||
}
|
||||
|
||||
unsigned int Get()
|
||||
{
|
||||
return m_RefCount;
|
||||
spdbg("Counter returned");
|
||||
}
|
||||
|
||||
void operator++()
|
||||
{
|
||||
m_RefCount++;
|
||||
spdbg("Counter incremented");
|
||||
}
|
||||
|
||||
void operator++(int)
|
||||
{
|
||||
m_RefCount++;
|
||||
spdbg("Counter incremented");
|
||||
}
|
||||
|
||||
void operator--()
|
||||
{
|
||||
m_RefCount--;
|
||||
spdbg("Counter decremented");
|
||||
}
|
||||
|
||||
void operator--(int)
|
||||
{
|
||||
m_RefCount--;
|
||||
spdbg("Counter decremented");
|
||||
}
|
||||
};
|
||||
|
||||
Counter *ReferenceCounter;
|
||||
T *RealPointer;
|
||||
Counter *m_ReferenceCounter;
|
||||
T *m_RealPointer;
|
||||
|
||||
public:
|
||||
explicit shared_ptr(T *Pointer = nullptr)
|
||||
{
|
||||
spdbg("Shared pointer created (%#lx)", RealPointer);
|
||||
RealPointer = Pointer;
|
||||
ReferenceCounter = new Counter();
|
||||
m_RealPointer = Pointer;
|
||||
m_ReferenceCounter = new Counter();
|
||||
spdbg("[%#lx] Shared pointer created (ptr=%#lx, ref=%#lx)", this, Pointer, m_ReferenceCounter);
|
||||
if (Pointer)
|
||||
(*ReferenceCounter)++;
|
||||
(*m_ReferenceCounter)++;
|
||||
}
|
||||
|
||||
shared_ptr(shared_ptr<T> &SPtr)
|
||||
{
|
||||
spdbg("Shared pointer copied (%#lx)", RealPointer);
|
||||
RealPointer = SPtr.RealPointer;
|
||||
ReferenceCounter = SPtr.ReferenceCounter;
|
||||
(*ReferenceCounter)++;
|
||||
spdbg("[%#lx] Shared pointer copied (ptr=%#lx, ref=%#lx)", this, SPtr.m_RealPointer, SPtr.m_ReferenceCounter);
|
||||
m_RealPointer = SPtr.m_RealPointer;
|
||||
m_ReferenceCounter = SPtr.m_ReferenceCounter;
|
||||
(*m_ReferenceCounter)++;
|
||||
}
|
||||
|
||||
~shared_ptr()
|
||||
{
|
||||
spdbg("Shared pointer deleted (%#lx)", RealPointer);
|
||||
(*ReferenceCounter)--;
|
||||
if (ReferenceCounter->Get() == 0)
|
||||
spdbg("[%#lx] Shared pointer destructor called", this);
|
||||
(*m_ReferenceCounter)--;
|
||||
if (m_ReferenceCounter->Get() == 0)
|
||||
{
|
||||
delete ReferenceCounter;
|
||||
delete RealPointer;
|
||||
spdbg("[%#lx] Shared pointer deleted (ptr=%#lx, ref=%#lx)", this, m_RealPointer, m_ReferenceCounter);
|
||||
delete m_ReferenceCounter;
|
||||
delete m_RealPointer;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int GetCount()
|
||||
{
|
||||
spdbg("Shared pointer count (%#lx)", RealPointer);
|
||||
return ReferenceCounter->Get();
|
||||
spdbg("[%#lx] Shared pointer count (%d)", this, m_ReferenceCounter->Get());
|
||||
return m_ReferenceCounter->Get();
|
||||
}
|
||||
|
||||
T *Get()
|
||||
{
|
||||
spdbg("Shared pointer get (%#lx)", RealPointer);
|
||||
return RealPointer;
|
||||
spdbg("[%#lx] Shared pointer get (%#lx)", this, m_RealPointer);
|
||||
return m_RealPointer;
|
||||
}
|
||||
|
||||
T &operator*()
|
||||
{
|
||||
spdbg("Shared pointer dereference (%#lx)", RealPointer);
|
||||
return *RealPointer;
|
||||
spdbg("[%#lx] Shared pointer dereference (ptr*=%#lx)", this, *m_RealPointer);
|
||||
return *m_RealPointer;
|
||||
}
|
||||
|
||||
T *operator->()
|
||||
{
|
||||
spdbg("Shared pointer dereference (%#lx)", RealPointer);
|
||||
return RealPointer;
|
||||
spdbg("[%#lx] Shared pointer dereference (ptr->%#lx)", this, m_RealPointer);
|
||||
return m_RealPointer;
|
||||
}
|
||||
|
||||
void reset(T *Pointer = nullptr)
|
||||
{
|
||||
if (m_RealPointer == Pointer)
|
||||
return;
|
||||
spdbg("[%#lx] Shared pointer reset (ptr=%#lx, ref=%#lx)", this, Pointer, m_ReferenceCounter);
|
||||
(*m_ReferenceCounter)--;
|
||||
if (m_ReferenceCounter->Get() == 0)
|
||||
{
|
||||
delete m_ReferenceCounter;
|
||||
delete m_RealPointer;
|
||||
}
|
||||
m_RealPointer = Pointer;
|
||||
m_ReferenceCounter = new Counter();
|
||||
if (Pointer)
|
||||
(*m_ReferenceCounter)++;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
spdbg("[%#lx] Shared pointer reset (ptr=%#lx, ref=%#lx)", this, m_RealPointer, m_ReferenceCounter);
|
||||
if (m_ReferenceCounter->Get() == 1)
|
||||
{
|
||||
delete m_RealPointer;
|
||||
delete m_ReferenceCounter;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*m_ReferenceCounter)--;
|
||||
}
|
||||
m_RealPointer = nullptr;
|
||||
m_ReferenceCounter = nullptr;
|
||||
}
|
||||
|
||||
void swap(shared_ptr<T> &Other)
|
||||
{
|
||||
spdbg("[%#lx] Shared pointer swap (ptr=%#lx, ref=%#lx <=> ptr=%#lx, ref=%#lx)",
|
||||
this, m_RealPointer, m_ReferenceCounter, Other.m_RealPointer, Other.m_ReferenceCounter);
|
||||
T *tempRealPointer = m_RealPointer;
|
||||
Counter *tempReferenceCounter = m_ReferenceCounter;
|
||||
m_RealPointer = Other.m_RealPointer;
|
||||
m_ReferenceCounter = Other.m_ReferenceCounter;
|
||||
Other.m_RealPointer = tempRealPointer;
|
||||
Other.m_ReferenceCounter = tempReferenceCounter;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class weak_ptr
|
||||
template <typename T>
|
||||
struct remove_reference
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct remove_reference<T &>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct remove_reference<T &&>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
|
||||
template <typename T>
|
||||
T &&forward(remove_reference_t<T> &t)
|
||||
{
|
||||
return static_cast<T &&>(t);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T &&forward(remove_reference_t<T> &&t)
|
||||
{
|
||||
return static_cast<T &&>(t);
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
shared_ptr<T> make_shared(Args &&...args)
|
||||
{
|
||||
return shared_ptr<T>(new T(forward<Args>(args)...));
|
||||
};
|
||||
|
||||
#endif // !__FENNIX_KERNEL_SMART_POINTER_H__
|
||||
|
6
include/stddef.h
Normal file
6
include/stddef.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __FENNIX_KERNEL_STDDEF_STUB_H__
|
||||
#define __FENNIX_KERNEL_STDDEF_STUB_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#endif // !__FENNIX_KERNEL_STDDEF_STUB_H__
|
@ -19,6 +19,7 @@ namespace SymbolResolver
|
||||
Symbols(uintptr_t ImageAddress);
|
||||
~Symbols();
|
||||
const char *GetSymbolFromAddress(uintptr_t Address);
|
||||
void AddSymbol(uintptr_t Address, const char *Name);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <interrupts.hpp>
|
||||
#include <hashmap.hpp>
|
||||
#include <symbols.hpp>
|
||||
#include <vector.hpp>
|
||||
#include <memory.hpp>
|
||||
@ -25,7 +25,7 @@ namespace Tasking
|
||||
UnknownArchitecture,
|
||||
x32,
|
||||
x64,
|
||||
ARM,
|
||||
ARM32,
|
||||
ARM64
|
||||
};
|
||||
|
||||
@ -42,7 +42,6 @@ namespace Tasking
|
||||
UnknownElevation,
|
||||
Kernel,
|
||||
System,
|
||||
Idle,
|
||||
User
|
||||
};
|
||||
|
||||
@ -57,6 +56,16 @@ namespace Tasking
|
||||
Terminated
|
||||
};
|
||||
|
||||
enum TaskPriority
|
||||
{
|
||||
UnknownPriority = 0,
|
||||
Idle = 1,
|
||||
Low = 25,
|
||||
Normal = 50,
|
||||
High = 75,
|
||||
Critical = 100
|
||||
};
|
||||
|
||||
struct TaskSecurity
|
||||
{
|
||||
TaskTrustLevel TrustLevel;
|
||||
@ -76,7 +85,7 @@ namespace Tasking
|
||||
uint64_t Year, Month, Day, Hour, Minute, Second;
|
||||
uint64_t Usage[256]; // MAX_CPU
|
||||
bool Affinity[256]; // MAX_CPU
|
||||
int Priority;
|
||||
TaskPriority Priority;
|
||||
TaskArchitecture Architecture;
|
||||
TaskCompatibility Compatibility;
|
||||
};
|
||||
@ -123,7 +132,7 @@ namespace Tasking
|
||||
}
|
||||
}
|
||||
|
||||
void SetPriority(int priority)
|
||||
void SetPriority(TaskPriority priority)
|
||||
{
|
||||
CriticalSection cs;
|
||||
trace("Setting priority of thread %s to %d", Name, priority);
|
||||
@ -165,27 +174,46 @@ namespace Tasking
|
||||
TaskInfo Info;
|
||||
Vector<TCB *> Threads;
|
||||
Vector<PCB *> Children;
|
||||
HashMap<InterProcessCommunication::IPCPort, uintptr_t> *IPCHandles;
|
||||
InterProcessCommunication::IPC *IPC;
|
||||
Memory::PageTable4 *PageTable;
|
||||
SymbolResolver::Symbols *ELFSymbolTable;
|
||||
VirtualFileSystem::Node *ProcessDirectory;
|
||||
VirtualFileSystem::Node *memDirectory;
|
||||
};
|
||||
|
||||
enum TokenTrustLevel
|
||||
/** @brief Token Trust Level */
|
||||
enum TTL
|
||||
{
|
||||
UnknownTrustLevel,
|
||||
Untrusted,
|
||||
Trusted,
|
||||
TrustedByKernel
|
||||
UnknownTrustLevel = 0b0001,
|
||||
Untrusted = 0b0010,
|
||||
Trusted = 0b0100,
|
||||
TrustedByKernel = 0b1000,
|
||||
FullTrust = Trusted | TrustedByKernel
|
||||
};
|
||||
|
||||
class Security
|
||||
{
|
||||
private:
|
||||
struct TokenData
|
||||
{
|
||||
Token token;
|
||||
int TrustLevel;
|
||||
uint64_t OwnerID;
|
||||
bool Process;
|
||||
};
|
||||
|
||||
Vector<TokenData> Tokens;
|
||||
|
||||
public:
|
||||
Token CreateToken();
|
||||
bool TrustToken(Token token,
|
||||
TokenTrustLevel TrustLevel);
|
||||
bool TrustToken(Token token, TTL TrustLevel);
|
||||
bool AddTrustLevel(Token token, TTL TrustLevel);
|
||||
bool RemoveTrustLevel(Token token, TTL TrustLevel);
|
||||
bool UntrustToken(Token token);
|
||||
bool DestroyToken(Token token);
|
||||
bool IsTokenTrusted(Token token, TTL TrustLevel);
|
||||
bool IsTokenTrusted(Token token, int TrustLevel);
|
||||
int GetTokenTrustLevel(Token token);
|
||||
Security();
|
||||
~Security();
|
||||
};
|
||||
@ -194,7 +222,6 @@ namespace Tasking
|
||||
{
|
||||
private:
|
||||
Security SecurityManager;
|
||||
InterProcessCommunication::IPC *IPCManager = nullptr;
|
||||
UPID NextPID = 0;
|
||||
UTID NextTID = 0;
|
||||
|
||||
@ -217,6 +244,7 @@ namespace Tasking
|
||||
bool GetNextAvailableProcess(void *CPUDataPointer);
|
||||
void SchedulerCleanupProcesses();
|
||||
bool SchedulerSearchProcessThread(void *CPUDataPointer);
|
||||
void UpdateProcessStatus();
|
||||
void WakeUpThreads(void *CPUDataPointer);
|
||||
|
||||
#if defined(__amd64__)
|
||||
@ -232,16 +260,13 @@ namespace Tasking
|
||||
bool StopScheduler = false;
|
||||
|
||||
public:
|
||||
void InitIPC()
|
||||
{
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
this->IPCManager = new InterProcessCommunication::IPC();
|
||||
}
|
||||
Vector<PCB *> GetProcessList() { return ListProcess; }
|
||||
Security *GetSecurityManager() { return &SecurityManager; }
|
||||
void Panic() { StopScheduler = true; }
|
||||
void Schedule();
|
||||
void SignalShutdown();
|
||||
void RevertProcessCreation(PCB *Process);
|
||||
void RevertThreadCreation(TCB *Thread);
|
||||
long GetUsage(int Core)
|
||||
{
|
||||
if (IdleProcess)
|
||||
@ -279,6 +304,9 @@ namespace Tasking
|
||||
/** @brief Wait for thread to terminate */
|
||||
void WaitForThread(TCB *tcb);
|
||||
|
||||
void WaitForProcessStatus(PCB *pcb, TaskStatus Status);
|
||||
void WaitForThreadStatus(TCB *tcb, TaskStatus Status);
|
||||
|
||||
/**
|
||||
* @brief Sleep for a given amount of milliseconds
|
||||
*
|
||||
@ -294,9 +322,9 @@ namespace Tasking
|
||||
|
||||
TCB *CreateThread(PCB *Parent,
|
||||
IP EntryPoint,
|
||||
const char **argv,
|
||||
const char **envp,
|
||||
Vector<AuxiliaryVector> &auxv,
|
||||
const char **argv = nullptr,
|
||||
const char **envp = nullptr,
|
||||
const Vector<AuxiliaryVector> &auxv = Vector<AuxiliaryVector>(),
|
||||
IPOffset Offset = 0,
|
||||
TaskArchitecture Architecture = TaskArchitecture::x64,
|
||||
TaskCompatibility Compatibility = TaskCompatibility::Native);
|
||||
@ -306,4 +334,6 @@ namespace Tasking
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void TaskingScheduler_OneShot(int TimeSlice);
|
||||
|
||||
#endif // !__FENNIX_KERNEL_TASKING_H__
|
||||
|
57
ipc.h
Normal file
57
ipc.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef __FENNIX_KERNEL_IPC_SYSCALLS_H__
|
||||
#define __FENNIX_KERNEL_IPC_SYSCALLS_H__
|
||||
|
||||
enum IPCCommand
|
||||
{
|
||||
IPC_NULL,
|
||||
IPC_CREATE,
|
||||
IPC_READ,
|
||||
IPC_WRITE,
|
||||
IPC_DELETE,
|
||||
IPC_GET,
|
||||
IPC_SET,
|
||||
IPC_GET_COUNT,
|
||||
IPC_GET_SIZE,
|
||||
IPC_GET_FLAGS,
|
||||
IPC_SET_FLAGS,
|
||||
IPC_GET_OWNER,
|
||||
IPC_SET_OWNER,
|
||||
IPC_GET_GROUP,
|
||||
IPC_SET_GROUP,
|
||||
IPC_GET_MODE,
|
||||
IPC_SET_MODE,
|
||||
IPC_GET_NAME,
|
||||
IPC_SET_NAME,
|
||||
IPC_GET_TYPE,
|
||||
IPC_SET_TYPE,
|
||||
IPC_GET_ID,
|
||||
IPC_SET_ID,
|
||||
IPC_GET_INDEX,
|
||||
IPC_SET_INDEX,
|
||||
};
|
||||
|
||||
enum IPCType
|
||||
{
|
||||
IPC_TYPE_None,
|
||||
IPC_TYPE_MessagePassing,
|
||||
IPC_TYPE_Port,
|
||||
IPC_TYPE_SharedMemory,
|
||||
IPC_TYPE_Pipe,
|
||||
IPC_TYPE_Socket
|
||||
};
|
||||
|
||||
enum IPCErrorCode
|
||||
{
|
||||
IPC_E_CODE_Error = -1,
|
||||
IPC_E_CODE_Success,
|
||||
IPC_E_CODE_NotListening,
|
||||
IPC_E_CODE_Timeout,
|
||||
IPC_E_CODE_InvalidPort,
|
||||
IPC_E_CODE_AlreadyAllocated,
|
||||
IPC_E_CODE_NotAllocated,
|
||||
IPC_E_CODE_IDInUse,
|
||||
IPC_E_CODE_IDNotRegistered,
|
||||
IPC_E_CODE_IDNotFound
|
||||
};
|
||||
|
||||
#endif // !__FENNIX_KERNEL_IPC_SYSCALLS_H__
|
7
kernel.h
7
kernel.h
@ -28,16 +28,19 @@ extern PCI::PCI *PCIManager;
|
||||
extern KernelConfig Config;
|
||||
extern Tasking::Task *TaskManager;
|
||||
extern Time::time *TimeManager;
|
||||
extern FileSystem::Virtual *vfs;
|
||||
extern VirtualFileSystem::Virtual *vfs;
|
||||
extern Driver::Driver *DriverManager;
|
||||
extern Disk::Manager *DiskManager;
|
||||
extern NetworkInterfaceManager::NetworkInterface *NIManager;
|
||||
extern Recovery::KernelRecovery *RecoveryScreen;
|
||||
extern VirtualFileSystem::Node *DevFS;
|
||||
extern VirtualFileSystem::Node *MntFS;
|
||||
extern VirtualFileSystem::Node *ProcFS;
|
||||
|
||||
#define PEXIT(Code) TaskManager->GetCurrentProcess()->ExitCode = Code
|
||||
#define TEXIT(Code) TaskManager->GetCurrentThread()->ExitCode = Code
|
||||
|
||||
#endif
|
||||
#endif // __cplusplus
|
||||
|
||||
EXTERNC void putchar(char c);
|
||||
EXTERNC void KPrint(const char *format, ...);
|
||||
|
151
syscalls.h
151
syscalls.h
@ -1,40 +1,189 @@
|
||||
#ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__
|
||||
#define __FENNIX_KERNEL_SYSCALLS_LIST_H__
|
||||
|
||||
#include <types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @enum NativeSyscalls
|
||||
* Enumeration of all the native syscalls available in the kernel
|
||||
*/
|
||||
enum NativeSyscalls
|
||||
{
|
||||
/** @brief Exit the process.
|
||||
* @fn int Exit(int Code)
|
||||
* This syscall is used to exit the current process with the provided exit code.
|
||||
*/
|
||||
_Exit = 0,
|
||||
/** @brief Print a message to the kernel console
|
||||
* @fn int Print(char Char, int Index)
|
||||
* This syscall is used to print a message to the kernel console.
|
||||
*/
|
||||
_Print,
|
||||
|
||||
/** @brief Request pages of memory
|
||||
* @fn uintptr_t RequestPages(size_t Count)
|
||||
* This syscall is used to request a specific number of pages of memory from the kernel.
|
||||
*/
|
||||
_RequestPages,
|
||||
/** @brief Free pages of memory
|
||||
* @fn int FreePages(uintptr_t Address, size_t Count)
|
||||
* This syscall is used to free a specific number of pages of memory that were previously requested.
|
||||
*/
|
||||
_FreePages,
|
||||
/** @brief Detach memory address
|
||||
* @fn int DetachAddress(uintptr_t Address)
|
||||
* This syscall is used to detach a specific memory address from the current process.
|
||||
*/
|
||||
_DetachAddress,
|
||||
|
||||
/** @brief Kernel Control
|
||||
* @fn uintptr_t KernelCTL(enum KCtl Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
|
||||
* This syscall is used to control certain aspects of the kernel or get information about it.
|
||||
*/
|
||||
_KernelCTL,
|
||||
|
||||
/**
|
||||
* @brief Creates/Reads/Writes/Deletes an IPC Pipe/Shared Memory/Message Queue/etc.
|
||||
* @fn int IPC(enum IPCCommand Command, enum IPCType Type, int ID, int Flags, void *Buffer, size_t Size)
|
||||
* This syscall is used to create, read, write or delete an IPC Pipe/Shared Memory/Message Queue/etc.
|
||||
*/
|
||||
_IPC,
|
||||
|
||||
/** @brief Open a file
|
||||
* @fn
|
||||
* This syscall is used to open a file with the provided path and flags.
|
||||
*/
|
||||
_FileOpen,
|
||||
/** @brief Close a file
|
||||
* @fn
|
||||
* This syscall is used to close a file that was previously opened.
|
||||
*/
|
||||
_FileClose,
|
||||
/** @brief Read from a file
|
||||
* @fn
|
||||
* This syscall is used to read a specific number of bytes from a file at a specific offset.
|
||||
*/
|
||||
_FileRead,
|
||||
/** @brief Write to a file
|
||||
* @fn
|
||||
* This syscall is used to write a specific number of bytes to a file at a specific offset.
|
||||
*/
|
||||
_FileWrite,
|
||||
/** @brief Seek in a file
|
||||
* @fn
|
||||
* This syscall is used to change the current offset in a file.
|
||||
*/
|
||||
_FileSeek,
|
||||
/** @brief Get file status
|
||||
* @fn
|
||||
* This syscall is used to retrieve information about a file such as its size, permissions, etc.
|
||||
*/
|
||||
_FileStatus,
|
||||
|
||||
/** @brief Wait for a process or a thread
|
||||
* @fn
|
||||
* This syscall is used to wait for a specific process or thread to terminate. It returns the exit code of the process or thread.
|
||||
*/
|
||||
_Wait,
|
||||
/** @brief Kill a process or a thread
|
||||
* @fn
|
||||
* This syscall is used to send a termination signal to a specific process or thread
|
||||
*/
|
||||
_Kill,
|
||||
/** @brief Spawn a new process
|
||||
* @fn
|
||||
* This syscall is used to create a new process with the provided path and arguments.
|
||||
*/
|
||||
_Spawn,
|
||||
/** @brief Spawn a new thread
|
||||
* @fn
|
||||
* This syscall is used to create a new thread within the current process with the provided function and arguments.
|
||||
*/
|
||||
_SpawnThread,
|
||||
/** @brief Get thread list of a process
|
||||
* @fn
|
||||
* This syscall is used to retrieve a list of all the threads within a specific process.
|
||||
*/
|
||||
_GetThreadListOfProcess,
|
||||
/** @brief Get current process
|
||||
* @fn
|
||||
* This syscall is used to retrieve information about the current process.
|
||||
*/
|
||||
_GetCurrentProcess,
|
||||
/** @brief Get current thread
|
||||
* @fn
|
||||
* This syscall is used to retrieve information about the current thread.
|
||||
*/
|
||||
_GetCurrentThread,
|
||||
/** @brief Get process by PID
|
||||
* @fn
|
||||
* This syscall is used to retrieve information about a specific process by its PID.
|
||||
*/
|
||||
_GetProcessByPID,
|
||||
/** @brief Get thread by TID
|
||||
* @fn
|
||||
* This syscall is used to retrieve information about a specific thread by its TID.
|
||||
*/
|
||||
_GetThreadByTID,
|
||||
/** @brief Kill a process
|
||||
* @fn
|
||||
* This syscall is used to send a termination signal to a specific process.
|
||||
*/
|
||||
_KillProcess,
|
||||
/** @brief Kill a thread
|
||||
* @fn
|
||||
* This syscall is used to send a termination signal to a specific thread.
|
||||
*/
|
||||
_KillThread,
|
||||
/** @brief Reserved syscall */
|
||||
_SysReservedCreateProcess,
|
||||
/** @brief Reserved syscall */
|
||||
_SysReservedCreateThread,
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum SyscallsErrorCodes
|
||||
* Enumeration of all the error codes that can be returned by a syscall
|
||||
*/
|
||||
enum SyscallsErrorCodes
|
||||
{
|
||||
/**
|
||||
* @brief Access denied
|
||||
* This error code is returned when the current thread does not have the required permissions to perform the requested operation.
|
||||
*/
|
||||
SYSCALL_ACCESS_DENIED = -0xDEADACC,
|
||||
/**
|
||||
* @brief Invalid argument
|
||||
* This error code is returned when an invalid argument is passed to a syscall.
|
||||
*/
|
||||
SYSCALL_INVALID_ARGUMENT = -0xBADAEE,
|
||||
/**
|
||||
* @brief Invalid syscall
|
||||
* This error code is returned when an invalid syscall number is passed to the syscall handler.
|
||||
*/
|
||||
SYSCALL_INVALID_SYSCALL = -0xBAD55CA,
|
||||
/**
|
||||
* @brief Internal error
|
||||
* This error code is returned when an internal error occurs in the syscall handler.
|
||||
*/
|
||||
SYSCALL_INTERNAL_ERROR = -0xBADBAD5,
|
||||
/**
|
||||
* @brief Not implemented
|
||||
* This error code is returned when a syscall is not implemented.
|
||||
*/
|
||||
SYSCALL_NOT_IMPLEMENTED = -0xBAD5EED,
|
||||
/**
|
||||
* @brief Generic error
|
||||
* This error code is returned when a syscall fails for an unknown reason.
|
||||
*/
|
||||
SYSCALL_ERROR = -1,
|
||||
/**
|
||||
* @brief Success
|
||||
* This error code is returned when a syscall succeeds.
|
||||
*/
|
||||
SYSCALL_OK = 0,
|
||||
};
|
||||
|
||||
static inline long syscall0(long syscall)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user