From a592b85ce5c8fa59706308f3141bfe5be3769787 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Feb 2023 19:35:44 +0200 Subject: [PATCH] Updated kernel (tl;dr: improved filesystem, tasking, loading files, etc..) --- Core/Driver/Driver.cpp | 20 +- Core/Interrupts/IntManager.cpp | 6 +- Core/Memory/Memory.cpp | 8 +- Core/Memory/MemoryManager.cpp | 146 ++++- Execute/Elf/BaseLoad.cpp | 162 ++++++ Execute/Elf/Dyn.cpp | 24 + Execute/Elf/Exec.cpp | 426 ++++---------- Execute/Elf/Parse.cpp | 284 ++++++++++ Execute/Elf/Rel.cpp | 93 ++++ Execute/Elf/SharedObjects.cpp | 305 ++-------- Execute/Fex/BaseLoad.cpp | 21 + Execute/Parse.cpp | 278 +++------- Execute/Spawn.cpp | 217 ++------ FileSystem/FS/ustar.cpp | 36 +- FileSystem/Filesystem.cpp | 731 +++++++++++++----------- KThread.cpp | 126 +++-- Kernel.cpp | 100 +++- Library/Convert.cpp | 2 +- Network/NetworkController.cpp | 10 +- Network/UserDatagramProtocol.cpp | 2 +- Recovery/RecoveryMain.cpp | 6 +- SystemCalls/Native.cpp | 149 ++++- Tasking/InterProcessCommunication.cpp | 244 ++++---- Tasking/Scheduler.cpp | 688 +++++++++++++++++++++++ Tasking/Security.cpp | 119 +++- Tasking/Task.cpp | 764 +++++--------------------- Tests/RandomNumberGenerator.cpp | 2 +- include/convert.h | 2 +- include/elf.h | 54 +- include/exec.hpp | 85 ++- include/filesystem.hpp | 174 +++--- include/filesystem/ext2.hpp | 2 +- include/filesystem/fat.hpp | 2 +- include/filesystem/initrd.hpp | 2 +- include/filesystem/mounts.hpp | 10 +- include/filesystem/ustar.hpp | 2 +- include/hashmap.hpp | 17 +- include/ipc.hpp | 73 ++- include/memory.hpp | 23 +- include/smartptr.hpp | 202 +++++-- include/stddef.h | 6 + include/symbols.hpp | 1 + include/task.hpp | 76 ++- ipc.h | 57 ++ kernel.h | 7 +- syscalls.h | 151 ++++- 46 files changed, 3503 insertions(+), 2412 deletions(-) create mode 100644 Execute/Elf/BaseLoad.cpp create mode 100644 Execute/Elf/Dyn.cpp create mode 100644 Execute/Elf/Parse.cpp create mode 100644 Execute/Elf/Rel.cpp create mode 100644 Execute/Fex/BaseLoad.cpp create mode 100644 Tasking/Scheduler.cpp create mode 100644 include/stddef.h create mode 100644 ipc.h diff --git a/Core/Driver/Driver.cpp b/Core/Driver/Driver.cpp index 2783052d..131303b9 100644 --- a/Core/Driver/Driver.cpp +++ b/Core/Driver/Driver.cpp @@ -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 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); } diff --git a/Core/Interrupts/IntManager.cpp b/Core/Interrupts/IntManager.cpp index e31e371d..4e85f99d 100644 --- a/Core/Interrupts/IntManager.cpp +++ b/Core/Interrupts/IntManager.cpp @@ -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); } diff --git a/Core/Memory/Memory.cpp b/Core/Memory/Memory.cpp index bed192d1..daf2e0de 100644 --- a/Core/Memory/Memory.cpp +++ b/Core/Memory/Memory.cpp @@ -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); diff --git a/Core/Memory/MemoryManager.cpp b/Core/Memory/MemoryManager.cpp index 5cef7570..d9930fac 100644 --- a/Core/Memory/MemoryManager.cpp +++ b/Core/Memory/MemoryManager.cpp @@ -1,18 +1,62 @@ #include #include +#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); } } diff --git a/Execute/Elf/BaseLoad.cpp b/Execute/Elf/BaseLoad.cpp new file mode 100644 index 00000000..9de940cf --- /dev/null +++ b/Execute/Elf/BaseLoad.cpp @@ -0,0 +1,162 @@ +#include + +#include +#include +#include +#include +#include +#include + +#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 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; + } +} diff --git a/Execute/Elf/Dyn.cpp b/Execute/Elf/Dyn.cpp new file mode 100644 index 00000000..e55a279d --- /dev/null +++ b/Execute/Elf/Dyn.cpp @@ -0,0 +1,24 @@ +#include + +#include +#include +#include +#include +#include +#include + +#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 {}; + } +} diff --git a/Execute/Elf/Exec.cpp b/Execute/Elf/Exec.cpp index 64182583..373b56b8 100644 --- a/Execute/Elf/Exec.cpp +++ b/Execute/Elf/Exec.cpp @@ -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 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 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 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; } } diff --git a/Execute/Elf/Parse.cpp b/Execute/Elf/Parse.cpp new file mode 100644 index 00000000..9fed28c5 --- /dev/null +++ b/Execute/Elf/Parse.cpp @@ -0,0 +1,284 @@ +#include + +#include + +#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 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; + } +} diff --git a/Execute/Elf/Rel.cpp b/Execute/Elf/Rel.cpp new file mode 100644 index 00000000..5b5e57d2 --- /dev/null +++ b/Execute/Elf/Rel.cpp @@ -0,0 +1,93 @@ +#include + +#include + +#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; + } +} diff --git a/Execute/Elf/SharedObjects.cpp b/Execute/Elf/SharedObjects.cpp index 136014e0..cb3d6207 100644 --- a/Execute/Elf/SharedObjects.cpp +++ b/Execute/Elf/SharedObjects.cpp @@ -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); - } } diff --git a/Execute/Fex/BaseLoad.cpp b/Execute/Fex/BaseLoad.cpp new file mode 100644 index 00000000..98162552 --- /dev/null +++ b/Execute/Fex/BaseLoad.cpp @@ -0,0 +1,21 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "../../kernel.h" +#include "../../Fex.hpp" + +using namespace Tasking; + +namespace Execute +{ + void FEXLoad() + { + + } +} diff --git a/Execute/Parse.cpp b/Execute/Parse.cpp index eea3186a..726a9405 100644 --- a/Execute/Parse.cpp +++ b/Execute/Parse.cpp @@ -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 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; - } } diff --git a/Execute/Spawn.cpp b/Execute/Spawn.cpp index 31b40724..24c76825 100644 --- a/Execute/Spawn.cpp +++ b/Execute/Spawn.cpp @@ -20,175 +20,74 @@ namespace Execute .Process = nullptr, .Thread = nullptr}; - FileSystem::FILE *ExFile = vfs->Open(Path); - if (ExFile->Status == FileSystem::FileStatus::OK) + shared_ptr 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 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 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 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; } diff --git a/FileSystem/FS/ustar.cpp b/FileSystem/FS/ustar.cpp index c75fc6bb..7f06bd99 100644 --- a/FileSystem/FS/ustar.cpp +++ b/FileSystem/FS/ustar.cpp @@ -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]); diff --git a/FileSystem/Filesystem.cpp b/FileSystem/Filesystem.cpp index c180300b..f630b63e 100644 --- a/FileSystem/Filesystem.cpp +++ b/FileSystem/Filesystem.cpp @@ -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 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 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 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 = make_shared(); + 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 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 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 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 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 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 Virtual::Mount(const char *Path, FileSystemOperations *Operator) + { + SmartLock(VFSLock); + shared_ptr file = make_shared(); + + 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) { 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, 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, 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 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 = make_shared(); + 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 = make_shared(); - 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 CleanPath = NormalizePath(Path, CurrentParent); - char *CleanPath = NormalizePath(Parent, Path); - - FILE *file = new FILE; - FileStatus filestatus = FileStatus::OK; - filestatus = FileExists(Parent, CleanPath); + shared_ptr file = make_shared(); /* 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) { 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..."); } } diff --git a/KThread.cpp b/KThread.cpp index ad812f35..af35f015 100644 --- a/KThread.cpp +++ b/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 diff --git a/Kernel.cpp b/Kernel.cpp index bdb53298..2ecbe454 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -1,6 +1,7 @@ #include "kernel.h" #include +#include #include #include #include @@ -12,6 +13,7 @@ #include #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 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 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 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); } diff --git a/Library/Convert.cpp b/Library/Convert.cpp index f99c8e45..46fcf41d 100644 --- a/Library/Convert.cpp +++ b/Library/Convert.cpp @@ -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) { diff --git a/Network/NetworkController.cpp b/Network/NetworkController.cpp index a8bd052f..3b64b1c8 100644 --- a/Network/NetworkController.cpp +++ b/Network/NetworkController.cpp @@ -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 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) diff --git a/Network/UserDatagramProtocol.cpp b/Network/UserDatagramProtocol.cpp index f1e55e5d..d329e10d 100644 --- a/Network/UserDatagramProtocol.cpp +++ b/Network/UserDatagramProtocol.cpp @@ -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), diff --git a/Recovery/RecoveryMain.cpp b/Recovery/RecoveryMain.cpp index c991e98c..83d1d7e9 100644 --- a/Recovery/RecoveryMain.cpp +++ b/Recovery/RecoveryMain.cpp @@ -33,12 +33,10 @@ namespace Recovery gui = new GraphicalUserInterface::GUI; - Vector 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; diff --git a/SystemCalls/Native.cpp b/SystemCalls/Native.cpp index 32e6d04f..8b25d752 100644 --- a/SystemCalls/Native.cpp +++ b/SystemCalls/Native.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -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(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); diff --git a/Tasking/InterProcessCommunication.cpp b/Tasking/InterProcessCommunication.cpp index a16c0194..275961ea 100644 --- a/Tasking/InterProcessCommunication.cpp +++ b/Tasking/InterProcessCommunication.cpp @@ -1,141 +1,161 @@ #include -#include #include #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 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); } } diff --git a/Tasking/Scheduler.cpp b/Tasking/Scheduler.cpp new file mode 100644 index 00000000..6c176074 --- /dev/null +++ b/Tasking/Scheduler.cpp @@ -0,0 +1,688 @@ +#include + +#include +#include +#include +#include +#include +#include + +#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 +} diff --git a/Tasking/Security.cpp b/Tasking/Security.cpp index c185f278..0d3b4ab3 100644 --- a/Tasking/Security.cpp +++ b/Tasking/Security.cpp @@ -6,64 +6,131 @@ namespace Tasking { - struct TokenData - { - Token token; - enum TokenTrustLevel TrustLevel; - uint64_t OwnerID; - bool Process; - }; - - Vector 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(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); } diff --git a/Tasking/Task.cpp b/Tasking/Task.cpp index deaf0289..0e4d089f 100644 --- a/Tasking/Task.cpp +++ b/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 &auxv, + const Vector &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 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; + 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 auxv; - TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, auxv, 0, Arch); + TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, Vector(), 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 auxv; - IdleThread = CreateThread(IdleProcess, reinterpret_cast(IdleProcessLoop), nullptr, nullptr, auxv); + IdleThread = CreateThread(IdleProcess, reinterpret_cast(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"); diff --git a/Tests/RandomNumberGenerator.cpp b/Tests/RandomNumberGenerator.cpp index 412b23b6..ca573265 100644 --- a/Tests/RandomNumberGenerator.cpp +++ b/Tests/RandomNumberGenerator.cpp @@ -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 diff --git a/include/convert.h b/include/convert.h index 2c20dd4b..70fe5c49 100644 --- a/include/convert.h +++ b/include/convert.h @@ -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); diff --git a/include/elf.h b/include/elf.h index 5e0ca890..e8c60a27 100644 --- a/include/elf.h +++ b/include/elf.h @@ -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] diff --git a/include/exec.hpp b/include/exec.hpp index 315c5d62..50a8322f 100644 --- a/include/exec.hpp +++ b/include/exec.hpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -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 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__ diff --git a/include/filesystem.hpp b/include/filesystem.hpp index 27226e5d..d325f984 100644 --- a/include/filesystem.hpp +++ b/include/filesystem.hpp @@ -3,90 +3,75 @@ #include +#include #include -// 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 Children; + Vector 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 GetPathFromNode(Node *node); + Node *GetNodeFromPath(const char *Path, Node *Parent = nullptr); + shared_ptr 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 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 Mount(const char *Path, FileSystemOperations *Operator); + FileStatus Unmount(shared_ptr File); + + size_t Read(shared_ptr File, size_t Offset, uint8_t *Buffer, size_t Size); + size_t Write(shared_ptr File, size_t Offset, uint8_t *Buffer, size_t Size); + + shared_ptr Open(const char *Path, Node *Parent = nullptr); + FileStatus Close(shared_ptr File); Virtual(); ~Virtual(); diff --git a/include/filesystem/ext2.hpp b/include/filesystem/ext2.hpp index c4279e9e..9aaf68d5 100644 --- a/include/filesystem/ext2.hpp +++ b/include/filesystem/ext2.hpp @@ -5,7 +5,7 @@ #include -namespace FileSystem +namespace VirtualFileSystem { class EXT2 { diff --git a/include/filesystem/fat.hpp b/include/filesystem/fat.hpp index 5ebe2c90..ac39a29b 100644 --- a/include/filesystem/fat.hpp +++ b/include/filesystem/fat.hpp @@ -5,7 +5,7 @@ #include -namespace FileSystem +namespace VirtualFileSystem { class FAT { diff --git a/include/filesystem/initrd.hpp b/include/filesystem/initrd.hpp index 911ad259..e47c90b6 100644 --- a/include/filesystem/initrd.hpp +++ b/include/filesystem/initrd.hpp @@ -5,7 +5,7 @@ #include -namespace FileSystem +namespace VirtualFileSystem { class Initrd { diff --git a/include/filesystem/mounts.hpp b/include/filesystem/mounts.hpp index 7b75a1f1..00075417 100644 --- a/include/filesystem/mounts.hpp +++ b/include/filesystem/mounts.hpp @@ -5,13 +5,13 @@ #include -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(); }; diff --git a/include/filesystem/ustar.hpp b/include/filesystem/ustar.hpp index 31900ffe..28d69d54 100644 --- a/include/filesystem/ustar.hpp +++ b/include/filesystem/ustar.hpp @@ -5,7 +5,7 @@ #include -namespace FileSystem +namespace VirtualFileSystem { class USTAR { diff --git a/include/hashmap.hpp b/include/hashmap.hpp index 429a7230..d9ca486f 100644 --- a/include/hashmap.hpp +++ b/include/hashmap.hpp @@ -1,5 +1,7 @@ #pragma once +#define HASHMAP_ERROR -0x8A50 + template class HashNode { @@ -33,6 +35,15 @@ public: DummyNode = new HashNode(-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; } diff --git a/include/ipc.hpp b/include/ipc.hpp index ca74896b..284a211b 100644 --- a/include/ipc.hpp +++ b/include/ipc.hpp @@ -2,75 +2,72 @@ #define __FENNIX_KERNEL_IPC_H__ #include - +#include +#include +#include #include 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 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__ diff --git a/include/memory.hpp b/include/memory.hpp index 9b117dd0..6be83740 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -2,6 +2,7 @@ #define __FENNIX_KERNEL_INTERNAL_MEMORY_H__ #ifdef __cplusplus +#include #include #include #include @@ -634,28 +635,32 @@ namespace Memory class MemMgr { - private: - Bitmap PageBitmap; - PageTable4 *PageTable; - + public: struct AllocatedPages { void *Address; size_t PageCount; }; - Vector AllocatedPagesList; - - public: + Vector 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 AllocatedPagesList; }; } diff --git a/include/smartptr.hpp b/include/smartptr.hpp index 0d4cc991..85ea9d77 100644 --- a/include/smartptr.hpp +++ b/include/smartptr.hpp @@ -29,31 +29,31 @@ template 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 weak_ptr +{ +}; + template 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 &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 &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 weak_ptr +template +struct remove_reference { + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +struct remove_reference +{ + typedef T type; +}; + +template +using remove_reference_t = typename remove_reference::type; + +template +T &&forward(remove_reference_t &t) +{ + return static_cast(t); +}; + +template +T &&forward(remove_reference_t &&t) +{ + return static_cast(t); +}; + +template +shared_ptr make_shared(Args &&...args) +{ + return shared_ptr(new T(forward(args)...)); }; #endif // !__FENNIX_KERNEL_SMART_POINTER_H__ diff --git a/include/stddef.h b/include/stddef.h new file mode 100644 index 00000000..bfe20a96 --- /dev/null +++ b/include/stddef.h @@ -0,0 +1,6 @@ +#ifndef __FENNIX_KERNEL_STDDEF_STUB_H__ +#define __FENNIX_KERNEL_STDDEF_STUB_H__ + +#include + +#endif // !__FENNIX_KERNEL_STDDEF_STUB_H__ diff --git a/include/symbols.hpp b/include/symbols.hpp index 3b207074..3af7236e 100644 --- a/include/symbols.hpp +++ b/include/symbols.hpp @@ -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); }; } diff --git a/include/task.hpp b/include/task.hpp index 2869c852..2f0b3f36 100644 --- a/include/task.hpp +++ b/include/task.hpp @@ -3,8 +3,8 @@ #include +#include #include -#include #include #include #include @@ -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 Threads; Vector Children; - HashMap *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 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 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 &auxv, + const char **argv = nullptr, + const char **envp = nullptr, + const Vector &auxv = Vector(), 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__ diff --git a/ipc.h b/ipc.h new file mode 100644 index 00000000..9d241c4a --- /dev/null +++ b/ipc.h @@ -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__ diff --git a/kernel.h b/kernel.h index 63d55239..9d6f624b 100644 --- a/kernel.h +++ b/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, ...); diff --git a/syscalls.h b/syscalls.h index 8b5f57bd..2131bfd9 100644 --- a/syscalls.h +++ b/syscalls.h @@ -1,40 +1,189 @@ #ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__ #define __FENNIX_KERNEL_SYSCALLS_LIST_H__ -#include +#include +/** + * @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;