Updated kernel (tl;dr: improved filesystem, tasking, loading files, etc..)

This commit is contained in:
Alex 2023-02-06 19:35:44 +02:00
parent 640f6a412a
commit a592b85ce5
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
46 changed files with 3503 additions and 2412 deletions

View File

@ -168,27 +168,35 @@ namespace Driver
Driver::Driver()
{
SmartCriticalSection(DriverInitLock);
FileSystem::FILE *DriverDirectory = vfs->Open(Config.DriverDirectory);
if (DriverDirectory->Status == FileSystem::FileStatus::OK)
foreach (auto driver in DriverDirectory->Node->Children)
if (driver->Flags == FileSystem::NodeFlags::FS_FILE)
shared_ptr<VirtualFileSystem::File> DriverDirectory = vfs->Open(Config.DriverDirectory);
if (DriverDirectory->Status == VirtualFileSystem::FileStatus::OK)
{
foreach (auto driver in DriverDirectory->node->Children)
if (driver->Flags == VirtualFileSystem::NodeFlags::FILE)
if (cwk_path_has_extension(driver->Name))
{
const char *extension;
cwk_path_get_extension(driver->Name, &extension, nullptr);
if (!strcmp(extension, ".fex") || !strcmp(extension, ".elf"))
debug("Driver: %s; Extension: %s", driver->Name, extension);
if (strcmp(extension, ".fex") == 0 || strcmp(extension, ".elf") == 0)
{
uintptr_t ret = this->LoadDriver(driver->Address, driver->Length);
char RetString[128];
if (ret == DriverCode::OK)
strncpy(RetString, "\e058C19OK", 10);
else if (ret == DriverCode::NOT_AVAILABLE)
else if (ret == DriverCode::NOT_AVAILABLE)
strncpy(RetString, "\eFF7900NOT AVAILABLE", 21);
else
sprintf(RetString, "\eE85230FAILED (%#lx)", ret);
KPrint("%s %s", driver->Name, RetString);
}
}
}
else
{
KPrint("\eE85230Failed to open driver directory: %s", Config.DriverDirectory);
CPU::Stop();
}
vfs->Close(DriverDirectory);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -1,18 +1,62 @@
#include <memory.hpp>
#include <debug.h>
#include "../../kernel.h"
namespace Memory
{
ReadFSFunction(MEM_Read)
{
if (!Size)
Size = node->Length;
if (Offset > node->Length)
return 0;
if (Offset + Size > node->Length)
Size = node->Length - Offset;
memcpy(Buffer, (uint8_t *)(node->Address + Offset), Size);
return Size;
}
WriteFSFunction(MEM_Write)
{
if (!Size)
Size = node->Length;
if (Offset > node->Length)
return 0;
if (Offset + Size > node->Length)
Size = node->Length - Offset;
memcpy((uint8_t *)(node->Address + Offset), Buffer, Size);
return Size;
}
VirtualFileSystem::FileSystemOperations mem_op = {
.Name = "mem",
.Read = MEM_Read,
.Write = MEM_Write,
};
uint64_t MemMgr::GetAllocatedMemorySize()
{
uint64_t Size = 0;
foreach (auto var in AllocatedPagesList)
Size += var.PageCount;
foreach (auto ap in AllocatedPagesList)
Size += ap.PageCount;
return FROM_PAGES(Size);
}
bool MemMgr::Add(void *Address, size_t Count)
{
if (Address == nullptr)
{
error("Address is null!");
return false;
}
if (Count == 0)
{
error("Count is 0!");
return false;
}
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
{
if (AllocatedPagesList[i].Address == Address)
@ -20,8 +64,7 @@ namespace Memory
error("Address already exists!");
return false;
}
if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
{
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (uintptr_t)AllocatedPagesList[i].Address)
{
@ -39,15 +82,47 @@ namespace Memory
}
}
if (this->Directory)
{
char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
if (n)
{
n->Address = (uintptr_t)Address;
n->Length = Count * PAGE_SIZE;
n->Operator = &mem_op;
}
}
AllocatedPagesList.push_back({Address, Count});
return true;
}
void *MemMgr::RequestPages(size_t Count)
void *MemMgr::RequestPages(size_t Count, bool User)
{
void *Address = KernelAllocator.RequestPages(Count);
for (size_t i = 0; i < Count; i++)
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
{
int Flags = Memory::PTFlag::RW;
if (User)
Flags |= Memory::PTFlag::US;
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Flags);
}
if (this->Directory)
{
char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
if (n) // If null, error or file already exists
{
n->Address = (uintptr_t)Address;
n->Length = Count * PAGE_SIZE;
n->Operator = &mem_op;
}
}
AllocatedPagesList.push_back({Address, Count});
return Address;
}
@ -57,39 +132,80 @@ namespace Memory
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
if (AllocatedPagesList[i].Address == Address)
{
// TODO: Advanced checks. Allow if the page count is less than the requested one.
/** TODO: Advanced checks. Allow if the page count is less than the requested one.
* This will allow the user to free only a part of the allocated pages.
*
* But this will be in a separate function because we need to specify if we
* want to free from the start or from the end and return the new address.
*/
if (AllocatedPagesList[i].PageCount != Count)
{
error("FreePages: Page count mismatch! (Allocated: %lld, Requested: %lld)", AllocatedPagesList[i].PageCount, Count);
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", AllocatedPagesList[i].PageCount, Count);
return;
}
KernelAllocator.FreePages(Address, Count);
for (size_t i = 0; i < Count; i++)
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uint64_t)Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
// Memory::Virtual(this->PageTable).Unmap((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
if (this->Directory)
{
char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
if (s != VirtualFileSystem::FileStatus::OK)
error("Failed to delete file %s", FileName);
}
AllocatedPagesList.remove(i);
return;
}
}
MemMgr::MemMgr(PageTable4 *PageTable)
void MemMgr::DetachAddress(void *Address)
{
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
if (AllocatedPagesList[i].Address == Address)
{
if (this->Directory)
{
char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, AllocatedPagesList[i].PageCount);
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
if (s != VirtualFileSystem::FileStatus::OK)
error("Failed to delete file %s", FileName);
}
AllocatedPagesList.remove(i);
return;
}
}
MemMgr::MemMgr(PageTable4 *PageTable, VirtualFileSystem::Node *Directory)
{
if (PageTable)
this->PageTable = PageTable;
else
this->PageTable = (PageTable4 *)CPU::x64::readcr3().raw;
debug("MemMgr initialized.");
this->Directory = Directory;
debug("+ %#lx", this);
}
MemMgr::~MemMgr()
{
foreach (auto var in AllocatedPagesList)
foreach (auto ap in AllocatedPagesList)
{
KernelAllocator.FreePages(var.Address, var.PageCount);
for (size_t i = 0; i < var.PageCount; i++)
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)var.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)var.Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
KernelAllocator.FreePages(ap.Address, ap.PageCount);
for (size_t i = 0; i < ap.PageCount; i++)
Memory::Virtual(this->PageTable).Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), Memory::PTFlag::RW);
}
debug("MemMgr destroyed.");
if (this->Directory)
foreach (auto Child in this->Directory->Children)
vfs->Delete(Child, true);
debug("- %#lx", this);
}
}

162
Execute/Elf/BaseLoad.cpp Normal file
View File

@ -0,0 +1,162 @@
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::NodeFlags;
namespace Execute
{
ELFBaseLoad ELFLoad(char *Path, const char **argv, const char **envp, Tasking::TaskCompatibility Compatibility)
{
/* We get the base name ("app.elf") */
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
shared_ptr<File> ExFile = vfs->Open(Path);
if (ExFile->Status != FileStatus::OK)
{
vfs->Close(ExFile);
error("Failed to open file: %s", Path);
return {};
}
else
{
if (ExFile->node->Flags != NodeFlags::FILE)
{
vfs->Close(ExFile);
error("Invalid file path: %s", Path);
return {};
}
else if (GetBinaryType(Path) != BinaryType::BinTypeELF)
{
vfs->Close(ExFile);
error("Invalid file type: %s", Path);
return {};
}
}
size_t ExFileSize = ExFile->node->Length;
/* Allocate elf in memory */
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize));
/* Copy the file to the allocated memory */
memcpy(ElfFile, (void *)ExFile->node->Address, ExFileSize);
debug("Image Size: %#lx - %#lx (length: %ld)", ElfFile, (uintptr_t)ElfFile + ExFileSize, ExFileSize);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
switch (ELFHeader->e_machine)
{
case EM_386:
Arch = TaskArchitecture::x32;
break;
case EM_X86_64:
Arch = TaskArchitecture::x64;
break;
case EM_ARM:
Arch = TaskArchitecture::ARM32;
break;
case EM_AARCH64:
Arch = TaskArchitecture::ARM64;
break;
default:
break;
}
// TODO: This shouldn't be ignored
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
{
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
fixme("ELF32 LSB");
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
fixme("ELF32 MSB");
else
fixme("ELF32 Unknown");
}
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
{
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
fixme("ELF64 LSB");
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
fixme("ELF64 MSB");
else
fixme("ELF64 Unknown");
}
else
fixme("Unknown ELF");
/* ------------------------------------------------------------------------------------------------------------------------------ */
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User, ElfFile);
Memory::Virtual pV = Memory::Virtual(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
pV.Remap((void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
// for (size_t i = 0; i < TO_PAGES(ElfLazyResolverSize); i++)
// pV.Remap((void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
/* We prepare the ELF for execution (allocate memory, etc...) */
ELFBaseLoad bl;
switch (ELFHeader->e_type)
{
case ET_REL:
bl = ELFLoadRel(ElfFile, ExFile.Get(), Process);
break;
case ET_EXEC:
bl = ELFLoadExec(ElfFile, ExFile.Get(), Process);
break;
case ET_DYN:
bl = ELFLoadDyn(ElfFile, ExFile.Get(), Process);
break;
case ET_CORE:
{
fixme("ET_CORE not implemented");
TaskManager->RevertProcessCreation(Process);
vfs->Close(ExFile);
return {};
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader->e_type);
vfs->Close(ExFile);
TaskManager->RevertProcessCreation(Process);
return {};
}
}
TCB *Thread = TaskManager->CreateThread(Process,
bl.InstructionPointer,
argv, envp, bl.auxv,
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
Arch,
Compatibility);
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
Thread->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
}
delete bl.TmpMem;
bl.sd.Process = Process;
bl.sd.Thread = Thread;
bl.sd.Status = ExStatus::OK;
vfs->Close(ExFile);
return bl;
}
}

24
Execute/Elf/Dyn.cpp Normal file
View File

@ -0,0 +1,24 @@
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
namespace Execute
{
ELFBaseLoad ELFLoadDyn(void *BaseImage,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process)
{
fixme("Not implemented");
return {};
}
}

View File

@ -14,102 +14,62 @@ using namespace Tasking;
namespace Execute
{
void ELFLoadExec(void *BaseImage,
size_t Length,
Elf64_Ehdr *ELFHeader,
Memory::Virtual &pva,
SpawnData *ret,
char *Path,
Tasking::PCB *Process,
const char **argv,
const char **envp,
Tasking::TaskArchitecture Arch,
Tasking::TaskCompatibility Comp)
ELFBaseLoad ELFLoadExec(void *ElfFile,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process)
{
trace("Executable");
Elf64_Phdr *ProgramHeader = (Elf64_Phdr *)(((char *)BaseImage) + ELFHeader->e_phoff);
debug("p_paddr: %#lx | p_vaddr: %#lx | p_filesz: %#lx | p_memsz: %#lx | p_offset: %#lx", ProgramHeader->p_paddr, ProgramHeader->p_vaddr, ProgramHeader->p_filesz, ProgramHeader->p_memsz, ProgramHeader->p_offset);
debug("Executable");
ELFBaseLoad ELFBase = {};
/* This should be deleted inside BaseLoad.cpp */
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
Memory::Virtual pV(Process->PageTable);
uintptr_t BaseAddress = UINTPTR_MAX;
uint64_t ElfAppSize = 0;
uintptr_t EntryPoint = ELFHeader->e_entry;
Elf64_Phdr ItrProgramHeader;
Elf64_Phdr ItrPhdr;
/* Get base address */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
}
debug("BaseAddress %#lx", BaseAddress);
/* Get size */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
uintptr_t SegmentEnd;
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz;
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
}
debug("ElfAppSize %ld", ElfAppSize);
uint8_t *MemoryImage = nullptr;
// check for TEXTREL
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrProgramHeader.p_type == DT_TEXTREL)
{
warn("TEXTREL ELF is not fully tested yet!");
MemoryImage = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(ElfAppSize));
memset(MemoryImage, 0, ElfAppSize);
for (uint64_t i = 0; i < TO_PAGES(ElfAppSize); i++)
{
pva.Remap((void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Mapping: %#lx -> %#lx", (uintptr_t)MemoryImage + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
break;
}
}
if (!MemoryImage)
{
debug("Allocating %ld pages for image", TO_PAGES(ElfAppSize));
MemoryImage = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(ElfAppSize));
memset(MemoryImage, 0, ElfAppSize);
for (uint64_t i = 0; i < TO_PAGES(ElfAppSize); i++)
{
uintptr_t Address = (uintptr_t)ProgramHeader->p_vaddr;
Address &= 0xFFFFFFFFFFFFF000;
pva.Remap((void *)((uintptr_t)Address + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Mapping: %#lx -> %#lx", (uintptr_t)Address + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
}
debug("BaseAddress: %#lx | ElfAppSize: %#lx (%ld, %ld KB)", BaseAddress, ElfAppSize, ElfAppSize, TO_KB(ElfAppSize));
debug("Solving symbols for address: %#llx", (uintptr_t)BaseImage);
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff);
Elf64_Shdr *Dynamic = nullptr;
Elf64_Shdr *DynamicSymbol = nullptr;
/* If required, MemoryImage will be at virtual address. (unless has PIE)
*
* tl;dr this is where the code is stored. */
void *MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, pV, ElfFile, ElfAppSize);
debug("Solving symbols for address: %#llx", (uintptr_t)ElfFile);
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)ElfFile + ELFHeader->e_shoff);
Elf64_Shdr *DynamicString = nullptr;
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Shdr *RelaPlt = nullptr;
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
{
char *DynamicStringTable = (char *)((uintptr_t)BaseImage + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
char *DynamicStringTable = (char *)((uintptr_t)ElfFile + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
if (strcmp(DynamicStringTable, ".dynamic") == 0)
{
Dynamic = &ElfSections[i];
debug("Found .dynamic");
}
else if (strcmp(DynamicStringTable, ".dynsym") == 0)
{
DynamicSymbol = &ElfSections[i];
debug("Found .dynsym");
}
else if (strcmp(DynamicStringTable, ".dynstr") == 0)
if (strcmp(DynamicStringTable, ".dynstr") == 0)
{
DynamicString = &ElfSections[i];
debug("Found .dynstr");
@ -119,76 +79,57 @@ namespace Execute
StringTable = &ElfSections[i];
debug("Found .strtab");
}
else if (strcmp(DynamicStringTable, ".rela.plt") == 0)
{
RelaPlt = &ElfSections[i];
debug("Found .rela.plt");
}
else if (strcmp(DynamicStringTable, ".symtab") == 0)
{
SymbolTable = &ElfSections[i];
debug("Found .symtab");
}
else
{
debug("Unknown section: %s", DynamicStringTable);
}
}
UNUSED(Dynamic);
UNUSED(DynamicSymbol);
UNUSED(SymbolTable);
UNUSED(RelaPlt);
char *NeededLibraries[256];
uint64_t InitAddress = 0;
uint64_t FiniAddress = 0;
UNUSED(NeededLibraries);
UNUSED(InitAddress);
UNUSED(FiniAddress);
Vector<char *> NeededLibraries;
if (!DynamicString)
DynamicString = StringTable;
/* Calculate entry point */
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff, sizeof(Elf64_Phdr));
if (ItrPhdr.p_vaddr == 0)
EntryPoint += (uintptr_t)MemoryImage;
char InterpreterPath[256];
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
uintptr_t MAddr;
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
switch (ItrProgramHeader.p_type)
switch (ItrPhdr.p_type)
{
case PT_NULL:
fixme("PT_NULL");
break;
case PT_LOAD:
{
debug("PT_LOAD - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
debug("MAddr: %#lx", MAddr);
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
fixme("Address: %#lx %s%s%s", MAddr,
(ItrPhdr.p_flags & PF_R) ? "R" : "",
(ItrPhdr.p_flags & PF_W) ? "W" : "",
(ItrPhdr.p_flags & PF_X) ? "X" : "");
memcpy((void *)MAddr, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, ItrProgramHeader.p_filesz);
debug("memcpy operation: %#lx to %#lx for length %ld", (uint8_t *)BaseImage + ItrProgramHeader.p_offset, MemoryImage + MAddr, ItrProgramHeader.p_filesz);
memcpy((void *)MAddr, (uint8_t *)ElfFile + ItrPhdr.p_offset, ItrPhdr.p_filesz);
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)ElfFile + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
break;
}
case PT_DYNAMIC:
{
debug("PT_DYNAMIC - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)BaseImage + ItrProgramHeader.p_offset);
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
for (uint64_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(Elf64_Dyn); i++)
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
{
switch (Dynamic[i].d_tag)
{
case DT_NULL:
debug("DT_NULL");
break;
case DT_NEEDED:
if (Dynamic[i].d_tag == DT_NEEDED)
{
if (!DynamicString)
{
@ -196,240 +137,71 @@ namespace Execute
break;
}
debug("DT_NEEDED - Name[%ld]: %s", i, (uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr);
NeededLibraries[i] = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr);
break;
char *ReqLib = (char *)kmalloc(256);
strcpy(ReqLib, (char *)((uintptr_t)ElfFile + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr));
debug("DT_NEEDED - Name[%ld]: %s", i, ReqLib);
NeededLibraries.push_back(ReqLib);
}
case DT_PLTRELSZ:
{
fixme("DT_PLTRELSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_PLTGOT:
{
fixme("DT_PLTGOT - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_HASH:
{
fixme("DT_HASH - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_STRTAB:
{
fixme("DT_STRTAB - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_SYMTAB:
{
fixme("DT_SYMTAB - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RELA:
{
fixme("DT_RELA - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RELASZ:
{
fixme("DT_RELASZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_RELAENT:
{
fixme("DT_RELAENT - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_STRSZ:
{
fixme("DT_STRSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_SYMENT:
{
fixme("DT_SYMENT - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_INIT:
{
debug("DT_INIT - Address: %#lx", Dynamic[i].d_un.d_ptr);
InitAddress = Dynamic[i].d_un.d_ptr;
break;
}
case DT_FINI:
{
debug("DT_FINI - Address: %#lx", Dynamic[i].d_un.d_ptr);
FiniAddress = Dynamic[i].d_un.d_ptr;
break;
}
case DT_SONAME:
{
fixme("DT_SONAME - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RPATH:
{
fixme("DT_RPATH - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_SYMBOLIC:
{
fixme("DT_SYMBOLIC - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_REL:
{
fixme("DT_REL - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_RELSZ:
{
fixme("DT_RELSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_RELENT:
{
fixme("DT_RELENT - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_PLTREL:
{
fixme("DT_PLTREL - Type: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_DEBUG:
{
fixme("DT_DEBUG - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_TEXTREL:
{
fixme("DT_TEXTREL - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_JMPREL:
{
fixme("DT_JMPREL - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_BIND_NOW:
{
fixme("DT_BIND_NOW - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_INIT_ARRAY:
{
fixme("DT_INIT_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_FINI_ARRAY:
{
fixme("DT_FINI_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_INIT_ARRAYSZ:
{
fixme("DT_INIT_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_FINI_ARRAYSZ:
{
fixme("DT_FINI_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
case DT_RUNPATH:
{
fixme("DT_RUNPATH - Name: %s", Dynamic[i].d_un.d_ptr);
break;
}
case DT_FLAGS:
{
fixme("DT_FLAGS - Flags: %#lx", Dynamic[i].d_un.d_val);
break;
}
case DT_PREINIT_ARRAY:
{
fixme("DT_PREINIT_ARRAY - Address: %#lx", Dynamic[i].d_un.d_ptr);
break;
}
case DT_PREINIT_ARRAYSZ:
{
fixme("DT_PREINIT_ARRAYSZ - Size: %ld", Dynamic[i].d_un.d_val);
break;
}
/* ... */
default:
fixme("DT: %ld", Dynamic[i].d_tag);
break;
}
if (Dynamic[i].d_tag == DT_NULL)
else if (Dynamic[i].d_tag == DT_NULL)
break;
}
break;
}
case PT_INTERP: // Do I have to do anything here?
case PT_INTERP:
{
debug("PT_INTERP - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
char InterpreterPath[256];
memcpy((void *)InterpreterPath, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, 256);
fixme("Interpreter: %s", InterpreterPath);
FileSystem::FILE *InterpreterFile = vfs->Open(InterpreterPath);
if (InterpreterFile->Status != FileSystem::FileStatus::OK)
{
memcpy((void *)InterpreterPath, (uint8_t *)ElfFile + ItrPhdr.p_offset, 256);
debug("Interpreter: %s", InterpreterPath);
shared_ptr<VirtualFileSystem::File> InterpreterFile = vfs->Open(InterpreterPath);
if (InterpreterFile->Status != VirtualFileSystem::FileStatus::OK)
warn("Failed to open interpreter file: %s", InterpreterPath);
}
else
{
// TODO: Load interpreter file
fixme("Interpreter file loaded: %s", InterpreterPath);
}
vfs->Close(InterpreterFile);
vfs->Close(InterpreterFile);
break;
}
/* ... */
case PT_PHDR:
{
debug("PT_PHDR - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
break;
}
default:
{
warn("Unknown or unsupported program header type: %d", ItrProgramHeader.p_type);
warn("Unknown or unsupported program header type: %d", ItrPhdr.p_type);
break;
}
}
}
debug("Entry Point: %#lx", ELFHeader->e_entry);
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, pV, InterpreterPath);
Vector<AuxiliaryVector> auxv;
debug("Entry Point: %#lx", EntryPoint);
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)Path}}});
auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t) "x86_64"}}});
auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)ELFHeader->e_entry}}});
auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage}}});
auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader->e_phnum}}});
auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader->e_phentsize}}});
auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader->e_phoff}}});
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true);
strcpy(aux_platform, "x86_64");
TCB *Thread = TaskManager->CreateThread(Process,
(IP)ELFHeader->e_entry,
argv, envp, auxv,
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
Arch,
Comp);
ret->Process = Process;
ret->Thread = Thread;
ret->Status = ExStatus::OK;
ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)vfs->GetPathFromNode(ExFile->node).Get()}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader->e_phnum}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader->e_phentsize}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader->e_phoff}}});
ELFBase.InstructionPointer = EntryPoint;
foreach (auto var in NeededLibraries)
kfree(var);
ELFBase.Success = true;
return ELFBase;
}
}

284
Execute/Elf/Parse.cpp Normal file
View File

@ -0,0 +1,284 @@
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
void *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Sym *Symbol = nullptr;
char *String = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
break;
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return (void *)Symbol->st_value;
}
return nullptr;
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
{
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = ELFLookupSymbol(Header, Name);
if (Target == nullptr)
{
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
}
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag)
{
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
Elf64_Phdr ItrPhdr;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrPhdr.p_type == PT_DYNAMIC)
{
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
{
if (Dynamic[i].d_tag == Tag)
{
debug("Found dynamic tag %d at %#lx [d_val: %#lx].", Tag, &Dynamic[i], Dynamic[i].d_un.d_val);
return &Dynamic[i];
}
if (Dynamic[i].d_tag == DT_NULL)
{
debug("Reached end of dynamic tag list for tag %d.", Tag);
return nullptr;
}
}
}
}
debug("Dynamic tag %d not found.", Tag);
return nullptr;
}
void *ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length)
{
void *MemoryImage = nullptr;
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
/* TODO: Not sure what I am supposed to do with this.
* It is supposed to detect if it's PIC or not but I
* don't know if it's right. */
if (ELFGetDynamicTag(ElfFile, DT_TEXTREL))
{
fixme("Text relocation is not(?) tested yet!");
MemoryImage = (uint8_t *)mem->RequestPages(TO_PAGES(Length), true);
memset(MemoryImage, 0, Length);
return MemoryImage;
}
Elf64_Phdr ItrPhdr;
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
bool FirstProgramHeader = false;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
if (ItrPhdr.p_type == PT_LOAD && !FirstProgramHeader)
{
FirstProgramHeaderVirtualAddress = ItrPhdr.p_vaddr;
FirstProgramHeader = true;
}
if (ItrPhdr.p_type == PT_LOAD && ItrPhdr.p_vaddr == 0)
{
debug("p_vaddr is 0, allocating %ld pages for image", TO_PAGES(Length));
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
memset(MemoryImage, 0, Length);
return MemoryImage;
}
}
debug("Allocating %ld pages for image", TO_PAGES(Length));
MemoryImage = mem->RequestPages(TO_PAGES(Length));
memset(MemoryImage, 0, Length);
if (FirstProgramHeaderVirtualAddress != 0)
FirstProgramHeaderVirtualAddress &= 0xFFFFFFFFFFFFF000;
else
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
for (size_t i = 0; i < TO_PAGES(Length); i++)
{
pV.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
return MemoryImage;
}
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &pV, const char *Interpreter)
{
if (GetBinaryType((char *)Interpreter) != BinaryType::BinTypeELF)
{
error("Interpreter \"%s\" is not an ELF file.", Interpreter);
return 0;
}
/* No need to check if it's valid, the GetBinaryType() call above does that. */
shared_ptr<VirtualFileSystem::File> File = vfs->Open(Interpreter);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)File->node->Address;
#ifdef DEBUG
const char *InterpreterType[6] = {
"ET_NONE",
"ET_REL",
"ET_EXEC",
"ET_DYN",
"ET_CORE",
"ET_LOPROC - ET_HIPROC"};
Elf64_Half IntType = ELFHeader->e_type;
if (IntType > 5)
IntType = 5;
debug("Interpreter type: %s - %#x", InterpreterType[IntType], ELFHeader->e_type);
#endif
uintptr_t BaseAddress = UINTPTR_MAX;
uint64_t ElfAppSize = 0;
Elf64_Phdr ItrPhdr;
/* Get base address */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
}
/* Get size */
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
uintptr_t SegmentEnd;
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
}
void *MemoryImage = ELFCreateMemoryImage(mem, pV, (void *)File->node->Address, ElfAppSize);
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrPhdr,
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
if (ItrPhdr.p_type == PT_LOAD)
{
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
fixme("Address: %#lx %s%s%s", MAddr,
(ItrPhdr.p_flags & PF_R) ? "R" : "",
(ItrPhdr.p_flags & PF_W) ? "W" : "",
(ItrPhdr.p_flags & PF_X) ? "X" : "");
memcpy((void *)MAddr, (uint8_t *)File->node->Address + ItrPhdr.p_offset, ItrPhdr.p_filesz);
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)File->node->Address + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
}
}
vfs->Close(File);
debug("Interpreter entry point: %#lx (%#lx + %#lx)", (uintptr_t)MemoryImage + ELFHeader->e_entry,
(uintptr_t)MemoryImage, ELFHeader->e_entry);
return (uintptr_t)MemoryImage + ELFHeader->e_entry;
}
}

93
Execute/Elf/Rel.cpp Normal file
View File

@ -0,0 +1,93 @@
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
ELFBaseLoad ELFLoadRel(void *BaseImage,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process)
{
debug("Relocatable");
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */
warn("Relocatable ELF is not fully supported yet");
/* This should be deleted after with kfree */
ELFBaseLoad ELFBase = {};
/* This should be deleted inside BaseLoad.cpp */
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_NOBITS)
{
if (!Section->sh_size)
continue;
if (Section->sh_flags & SHF_ALLOC)
{
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size));
memset(Buffer, 0, Section->sh_size);
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(Section->sh_size); i++)
pva.Map((void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), (void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
debug("Section %ld", Section->sh_size);
}
}
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_REL)
{
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
{
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
uint64_t SymbolValue = 0;
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
{
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
{
delete ELFBase.TmpMem;
return {};
}
}
switch (ELF64_R_TYPE(RelTable->r_info))
{
case R_386_NONE:
break;
case R_386_32:
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
break;
case R_386_PC32:
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
break;
default:
{
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
delete ELFBase.TmpMem;
return {};
}
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
return ELFBase;
}
}

View File

@ -26,7 +26,7 @@ namespace Execute
void StartExecuteService()
{
mem = new Memory::MemMgr;
return;
// return;
while (true)
{
@ -53,7 +53,7 @@ namespace Execute
}
}
SharedLibraries *AddLibrary(char *Identifier, void *LibraryImage, size_t Length)
SharedLibraries *AddLibrary(char *Identifier, void *ElfImage, size_t Length, const Memory::Virtual &pV)
{
SmartLock(ExecuteServiceLock);
SharedLibraries sl;
@ -62,12 +62,47 @@ namespace Execute
sl.Timeout = TimeManager->CalculateTarget(600000); /* 10 minutes */
sl.RefCount = 0;
void *BaseLibImage = mem->RequestPages(TO_PAGES(Length));
memcpy(BaseLibImage, (void *)LibraryImage, Length);
sl.Address = BaseLibImage;
void *LibFile = mem->RequestPages(TO_PAGES(Length), true);
memcpy(LibFile, (void *)ElfImage, Length);
Memory::Virtual ncpV = pV;
sl.MemoryImage = ELFCreateMemoryImage(mem, ncpV, LibFile, Length);
{
uintptr_t BaseAddress = UINTPTR_MAX;
Elf64_Phdr ItrProgramHeader;
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_phoff + ((Elf64_Ehdr *)LibFile)->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)LibFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)LibFile + ((Elf64_Ehdr *)LibFile)->e_phoff + ((Elf64_Ehdr *)LibFile)->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrProgramHeader.p_type != PT_LOAD)
continue;
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align);
uintptr_t MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)sl.MemoryImage;
fixme("Address: %#lx %s%s%s", MAddr,
(ItrProgramHeader.p_flags & PF_R) ? "R" : "",
(ItrProgramHeader.p_flags & PF_W) ? "W" : "",
(ItrProgramHeader.p_flags & PF_X) ? "X" : "");
memcpy((void *)MAddr, (uint8_t *)LibFile + ItrProgramHeader.p_offset, ItrProgramHeader.p_filesz);
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)LibFile + ItrProgramHeader.p_offset, (uintptr_t)MAddr, ItrProgramHeader.p_filesz);
break;
}
}
sl.Address = LibFile;
sl.Length = Length;
debug("Library %s loaded at %#lx", Identifier, BaseLibImage);
debug("Library %s loaded at %#lx (full file: %#lx)", Identifier, sl.MemoryImage, LibFile);
Libs.push_back(sl);
return &Libs[Libs.size() - 1];
@ -77,262 +112,4 @@ namespace Execute
{
SmartLock(ExecuteServiceLock);
}
void AttachLibrary(SharedLibraries *Lib, void *BaseImage)
{
SmartLock(ExecuteServiceLock);
BinaryType Type = GetBinaryType(BaseImage);
switch (Type)
{
case BinaryType::BinTypeFex:
{
fixme("Fex is not supported yet");
return;
}
case BinaryType::BinTypeELF:
{
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)BaseImage;
uintptr_t BaseAddress = UINTPTR_MAX;
size_t ElfAppSize = 0;
Elf64_Phdr ItrProgramHeader;
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff);
Elf64_Shdr *Dynamic = nullptr;
Elf64_Shdr *DynamicSymbol = nullptr;
Elf64_Shdr *DynamicString = nullptr;
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Shdr *RelaPlt = nullptr;
Elf64_Shdr *GotPlt = nullptr;
size_t SymbolCount = 0;
size_t GOTSize = 0;
Elf64_Addr *GOTEntry = 0;
uintptr_t RelaOffset = 0;
uint64_t RelaEnt = 0;
size_t RelaSize = 0;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
}
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)BaseImage + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
uintptr_t SegmentEnd;
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++)
{
char *DynamicStringTable = (char *)((uintptr_t)BaseImage + ElfSections[ELFHeader->e_shstrndx].sh_offset + ElfSections[i].sh_name);
if (strcmp(DynamicStringTable, ".dynamic") == 0)
{
Dynamic = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".dynsym") == 0)
{
DynamicSymbol = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".dynstr") == 0)
{
DynamicString = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".strtab") == 0)
{
StringTable = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".rela.plt") == 0)
{
RelaPlt = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".got.plt") == 0)
{
GotPlt = &ElfSections[i];
}
else if (strcmp(DynamicStringTable, ".symtab") == 0)
{
SymbolTable = &ElfSections[i];
}
}
if (ItrProgramHeader.p_type == PT_DYNAMIC)
{
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)BaseImage + ItrProgramHeader.p_offset);
for (uint64_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(Elf64_Dyn); i++)
{
switch (Dynamic[i].d_tag)
{
case DT_PLTRELSZ:
{
GOTSize = Dynamic[i].d_un.d_val;
break;
}
case DT_PLTGOT:
{
GOTEntry = (Elf64_Addr *)Dynamic[i].d_un.d_ptr;
break;
}
case DT_RELA:
{
RelaOffset = Dynamic[i].d_un.d_ptr;
break;
}
case DT_RELASZ:
{
RelaSize = Dynamic[i].d_un.d_val;
break;
}
case DT_RELAENT:
{
RelaEnt = Dynamic[i].d_un.d_val;
break;
}
default:
break;
}
if (Dynamic[i].d_tag == DT_NULL)
break;
}
break;
}
}
debug("BaseAddress: %#lx Size: %ld", BaseAddress, ElfAppSize);
if (RelaOffset != 0)
{
if (RelaEnt != sizeof(Elf64_Rela))
{
error("RelaEnt != sizeof(Elf64_Rela)");
/* I should exit here I guess... */
}
else
{
for (size_t RelaOffsetItr = 0; RelaOffsetItr < RelaSize; RelaOffsetItr += RelaEnt)
{
Elf64_Rela *Rela = (Elf64_Rela *)(((char *)BaseImage) + RelaOffset + RelaOffsetItr);
switch (Rela->r_info)
{
case R_X86_64_RELATIVE:
{
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)BaseImage + Rela->r_offset);
*Ptr = (uintptr_t)Lib->Address + Rela->r_addend;
break;
}
default:
fixme("Rela: %ld", Rela->r_info);
break;
}
}
}
}
else
debug("No Rela");
if (DynamicSymbol != nullptr)
SymbolCount = DynamicSymbol->sh_size / sizeof(Elf64_Sym);
else if (SymbolTable != nullptr)
SymbolCount = SymbolTable->sh_size / sizeof(Elf64_Sym);
debug("GOT Address %#lx Size %#lx Entry %#lx",
GOTEntry, GOTSize, GOTEntry ? GOTEntry : 0);
#ifdef DEBUG
DumpData("Old GOT", (void *)GOTEntry, GOTSize);
if (DynamicSymbol && DynamicString)
for (size_t i = 0; i < SymbolCount; i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
if (GOTEntry)
if (GOTEntry[i])
{
uintptr_t SymbolAddress = GOTEntry[i];
debug("New GOTEntry[%d] - Symbol %s Address %#lx", i, SymbolName, SymbolAddress);
}
}
for (size_t i = 0; i < GOTSize; i++)
if (GOTEntry)
if (GOTEntry[i])
debug("GOTEntry[%d] = %#lx", i, GOTEntry[i]);
#endif
GOTEntry[1] = (uintptr_t)BaseImage;
GOTEntry[2] = (uintptr_t)ElfLazyResolver;
if (DynamicSymbol && DynamicString && GOTEntry)
for (size_t i = 0; i < SymbolCount; i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
switch (ELF64_ST_TYPE(Symbol->st_info))
{
case STT_OBJECT:
fixme("STT_OBJECT");
case STT_FUNC:
{
uintptr_t SymbolAddress = (uintptr_t)ELFLookupSymbol((Elf64_Ehdr *)Lib->Address, SymbolName);
if (SymbolAddress == 0)
{
error("Symbol %s not found", SymbolName);
continue;
}
GOTEntry[i] = (uintptr_t)Lib->Address + SymbolAddress;
debug("%d %#lx Symbol %s at %#lx (%#lx)", i, &GOTEntry[i], SymbolName, SymbolAddress, (uintptr_t)Lib->Address + SymbolAddress);
break;
}
case STT_NOTYPE:
break;
default:
error("Unsupported symbol type %d", ELF64_ST_TYPE(Symbol->st_info));
break;
}
}
#ifdef DEBUG
DumpData("New GOT", (void *)GOTEntry, GOTSize);
if (DynamicSymbol && DynamicString)
for (size_t i = 0; i < SymbolCount; i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)BaseImage + DynamicSymbol->sh_offset + i * sizeof(Elf64_Sym));
char *SymbolName = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Symbol->st_name);
if (GOTEntry)
if (GOTEntry[i])
{
uintptr_t SymbolAddress = GOTEntry[i];
debug("New GOTEntry[%d] - Symbol %s Address %#lx", i, SymbolName, SymbolAddress);
}
}
for (size_t i = 0; i < GOTSize; i++)
if (GOTEntry)
if (GOTEntry[i])
debug("GOTEntry[%d] = %#lx", i, GOTEntry[i]);
#endif
break;
}
default:
{
fixme("Unsupported binary type %d", Type);
return;
}
}
Lib->RefCount++;
debug("Attached library %s", Lib->Identifier);
}
}

21
Execute/Fex/BaseLoad.cpp Normal file
View File

@ -0,0 +1,21 @@
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
namespace Execute
{
void FEXLoad()
{
}
}

View File

@ -7,227 +7,77 @@
namespace Execute
{
BinaryType GetBinaryType(void *Image)
{
Fex *FexHdr = (Fex *)Image;
/* Elf64_Ehdr and Elf32_Ehdr are very similar (Elf64_Half and
Elf32_Half are the same size type) so we can use directly Elf64_Ehdr. */
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)Image;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Image;
/* Check Fex magic */
if (FexHdr->Magic[0] == 'F' && FexHdr->Magic[1] == 'E' && FexHdr->Magic[2] == 'X' && FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
debug("Image - Fex");
return BinaryType::BinTypeFex;
}
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
debug("Fex Driver is not supposed to be executed.");
}
/* Check ELF magic. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
return BinaryType::BinTypeELF;
}
/* Every Windows executable starts with MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Image) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Image) + MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
return BinaryType::BinTypePE;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
return BinaryType::BinTypeNE;
}
else
{
debug("Image - MZ");
return BinaryType::BinTypeMZ;
}
}
/* ... */
return BinaryType::BinTypeUnknown;
}
BinaryType GetBinaryType(char *Path)
{
BinaryType Type = BinaryType::BinTypeInvalid;
FileSystem::FILE *ExFile = vfs->Open(Path);
shared_ptr<VirtualFileSystem::File> ExFile = vfs->Open(Path);
if (ExFile->Status == FileSystem::FileStatus::OK)
if (ExFile->Status == VirtualFileSystem::FileStatus::OK)
{
if (ExFile->Node->Flags == FileSystem::NodeFlags::FS_FILE)
{
Fex *FexHdr = (Fex *)ExFile->Node->Address;
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ExFile->Node->Address;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)ExFile->Node->Address;
if (FexHdr->Magic[0] == 'F' && FexHdr->Magic[1] == 'E' && FexHdr->Magic[2] == 'X' && FexHdr->Magic[3] == '\0')
{
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
trace("%s - Fex", Path);
Type = BinaryType::BinTypeFex;
goto Exit;
}
}
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
trace("%s - ELF", Path);
Type = BinaryType::BinTypeELF;
goto Exit;
}
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
trace("%s - NE", Path);
Type = BinaryType::BinTypeNE;
}
else if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
trace("%s - PE", Path);
Type = BinaryType::BinTypePE;
}
else
{
trace("%s - MZ", Path);
Type = BinaryType::BinTypeMZ;
}
goto Exit;
}
/* ... */
Type = BinaryType::BinTypeUnknown;
}
debug("File opened: %s", Path);
Type = GetBinaryType((void *)ExFile->node->Address);
}
Exit:
vfs->Close(ExFile);
return Type;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
static inline Elf64_Shdr *GetElfSheader(Elf64_Ehdr *Header) { return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff); }
static inline Elf64_Shdr *GetElfSection(Elf64_Ehdr *Header, uint64_t Index) { return &GetElfSheader(Header)[Index]; }
static inline char *GetElfStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetElfSection(Header, Header->e_shstrndx)->sh_offset;
}
static inline char *elf_lookup_string(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetElfStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
static void *ElfLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
Elf64_Sym *Symbol = nullptr;
char *String = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetElfSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetElfSection(Header, shdr->sh_link);
break;
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return (void *)Symbol->st_value;
}
return nullptr;
}
static uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint32_t Index)
{
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetElfSection(Header, Table);
uint32_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf32_Sym *Symbol = &((Elf32_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetElfSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = ElfLookupSymbol(Header, Name);
if (Target == nullptr)
{
if (ELF32_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetElfSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
}
void *ELFLoadRel(Elf64_Ehdr *Header)
{
Elf64_Shdr *shdr = GetElfSheader(Header);
for (uint64_t i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_NOBITS)
{
if (!Section->sh_size)
continue;
if (Section->sh_flags & SHF_ALLOC)
{
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size));
memset(Buffer, 0, Section->sh_size);
Memory::Virtual pva = Memory::Virtual(/* TODO TODO TODO TODO TODO TODO */);
for (size_t i = 0; i < TO_PAGES(Section->sh_size); i++)
pva.Map((void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), (void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Section->sh_offset = (uint64_t)Buffer - (uint64_t)Header;
debug("Section %ld", Section->sh_size);
}
}
}
for (size_t i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *Section = &shdr[i];
if (Section->sh_type == SHT_REL)
{
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
{
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)Header + Section->sh_offset))[Index];
Elf64_Shdr *Target = GetElfSection(Header, Section->sh_info);
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)Header + Target->sh_offset) + RelTable->r_offset);
uint64_t SymbolValue = 0;
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
{
SymbolValue = ELFGetSymbolValue(Header, Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
return (void *)0xdeadbeef;
}
switch (ELF64_R_TYPE(RelTable->r_info))
{
case R_386_NONE:
break;
case R_386_32:
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
break;
case R_386_PC32:
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
break;
default:
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
return (void *)0xdeadbeef;
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
return (void *)Header->e_entry;
}
}

View File

@ -20,175 +20,74 @@ namespace Execute
.Process = nullptr,
.Thread = nullptr};
FileSystem::FILE *ExFile = vfs->Open(Path);
if (ExFile->Status == FileSystem::FileStatus::OK)
shared_ptr<VirtualFileSystem::File> ExFile = vfs->Open(Path);
if (ExFile->Status == VirtualFileSystem::FileStatus::OK)
{
if (ExFile->Node->Flags == FileSystem::NodeFlags::FS_FILE)
if (ExFile->node->Flags != VirtualFileSystem::NodeFlags::FILE)
{
BinaryType Type = GetBinaryType(Path);
switch (Type)
{
case BinaryType::BinTypeFex:
{
#if defined(__amd64__)
Fex *FexHdr = (Fex *)ExFile->Node->Address;
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User);
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->Node->Length));
memcpy(BaseImage, (void *)ExFile->Node->Address, ExFile->Node->Length);
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
for (uint64_t i = 0; i < TO_PAGES(ExFile->Node->Length); i++)
pva.Map((void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), (void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Vector<AuxiliaryVector> auxv; // TODO!
TCB *Thread = TaskManager->CreateThread(Process,
(IP)FexHdr->EntryPoint,
argv, envp, auxv,
(IPOffset)BaseImage,
TaskArchitecture::x64,
TaskCompatibility::Native);
ret.Process = Process;
ret.Thread = Thread;
ret.Status = ExStatus::OK;
#elif defined(__i386__)
if (1)
{
#elif defined(__aarch64__)
if (1)
{
#endif
goto Exit;
}
ret.Status = ExStatus::InvalidFileHeader;
goto Exit;
}
case BinaryType::BinTypeELF:
{
#if defined(__amd64__)
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->Node->Length));
memcpy(BaseImage, (void *)ExFile->Node->Address, ExFile->Node->Length);
debug("Image Size: %#lx - %#lx (length: %ld)", BaseImage, (uintptr_t)BaseImage + ExFile->Node->Length, ExFile->Node->Length);
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User, BaseImage);
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
for (uint64_t i = 0; i < TO_PAGES(ExFile->Node->Length); i++)
pva.Remap((void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), (void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)BaseImage;
TaskArchitecture Arch = TaskArchitecture::x64;
TaskCompatibility Comp = TaskCompatibility::Native;
if (ELFHeader->e_machine == EM_386)
Arch = TaskArchitecture::x32;
else if (ELFHeader->e_machine == EM_AMD64)
Arch = TaskArchitecture::x64;
else if (ELFHeader->e_machine == EM_AARCH64)
Arch = TaskArchitecture::ARM64;
else
Arch = TaskArchitecture::UnknownArchitecture;
// TODO: Should I care about this?
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
{
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
fixme("ELF32 LSB");
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
fixme("ELF32 MSB");
else
fixme("ELF32 Unknown");
}
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
{
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
fixme("ELF64 LSB");
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
fixme("ELF64 MSB");
else
fixme("ELF64 Unknown");
}
else
fixme("Unknown ELF");
if (ELFHeader->e_type == ET_EXEC)
{
ELFLoadExec(BaseImage, ExFile->Node->Length, ELFHeader, pva, &ret, Path, Process, argv, envp, Arch, Comp);
goto Exit;
}
else if (ELFHeader->e_type == ET_DYN)
{
fixme("Shared Object");
}
else if (ELFHeader->e_type == ET_REL)
{
trace("Relocatable");
void *EP = ELFLoadRel(ELFHeader);
if (EP == (void *)0xdeadbeef || EP == 0x0)
{
ret.Status = ExStatus::InvalidFileEntryPoint;
goto Exit;
}
Vector<AuxiliaryVector> auxv;
fixme("auxv");
TCB *Thread = TaskManager->CreateThread(Process,
(IP)EP,
argv, envp, auxv,
(IPOffset)BaseImage,
Arch,
Comp);
ret.Process = Process;
ret.Thread = Thread;
ret.Status = ExStatus::OK;
goto Exit;
}
else if (ELFHeader->e_type == ET_CORE)
{
fixme("Core");
}
else
{
fixme("Unknown");
}
ret.Status = ExStatus::InvalidFileHeader;
#elif defined(__i386__)
#elif defined(__aarch64__)
#endif
goto Exit;
}
default:
ret.Status = ExStatus::Unsupported;
goto Exit;
}
ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
switch (GetBinaryType(Path))
{
case BinaryType::BinTypeFex:
{
Fex *FexHdr = (Fex *)ExFile->node->Address;
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User);
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->node->Length));
memcpy(BaseImage, (void *)ExFile->node->Address, ExFile->node->Length);
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(ExFile->node->Length); i++)
pva.Map((void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), (void *)((uintptr_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
Vector<AuxiliaryVector> auxv; // TODO!
TCB *Thread = TaskManager->CreateThread(Process,
(IP)FexHdr->EntryPoint,
argv, envp, auxv,
(IPOffset)BaseImage,
TaskArchitecture::x64,
TaskCompatibility::Native);
ret.Process = Process;
ret.Thread = Thread;
ret.Status = ExStatus::OK;
}
ret.Status = ExStatus::InvalidFileHeader;
goto Exit;
}
case BinaryType::BinTypeELF:
{
ELFBaseLoad bl = ELFLoad(Path, argv, envp);
if (!bl.Success)
{
ret.Status = ExStatus::GenericError;
goto Exit;
}
ret = bl.sd;
goto Exit;
}
default:
{
ret.Status = ExStatus::Unsupported;
goto Exit;
}
}
}
else if (ExFile->Status == FileSystem::FileStatus::NOT_FOUND)
{
else if (ExFile->Status == VirtualFileSystem::FileStatus::NotFound)
ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
else
{
ret.Status = ExStatus::InvalidFile;
goto Exit;
}
Exit:
if (ret.Status != ExStatus::OK)
if (ret.Process)
ret.Process->Status = TaskStatus::Terminated;
vfs->Close(ExFile);
return ret;
}

View File

@ -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]);

View File

@ -9,14 +9,23 @@
#include "../kernel.h"
// show debug messages
// #define DEBUG_FILESYSTEM 1
#ifdef DEBUG_FILESYSTEM
#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__)
#else
#define vfsdbg(m, ...)
#endif
NewLock(VFSLock);
namespace FileSystem
namespace VirtualFileSystem
{
char *Virtual::GetPathFromNode(FileSystemNode *Node)
shared_ptr<char> Virtual::GetPathFromNode(Node *node)
{
vfsdbg("GetPathFromNode( Node: \"%s\" )", Node->Name);
FileSystemNode *Parent = Node;
vfsdbg("GetPathFromNode( Node: \"%s\" )", node->Name);
Node *Parent = node;
char **Path = nullptr;
size_t Size = 1;
size_t PathSize = 0;
@ -25,7 +34,7 @@ namespace FileSystem
while (Parent != FileSystemRoot && Parent != nullptr)
{
bool Found = false;
for (const auto &Children : FileSystemRoot->Children)
foreach (const auto &Children in FileSystemRoot->Children)
if (Children == Parent)
{
Found = true;
@ -64,7 +73,9 @@ namespace FileSystem
}
// Allocate a new string for the final path
char *FinalPath = new char[Size];
shared_ptr<char> FinalPath;
FinalPath.reset(new char[Size]);
size_t Offset = 0;
// Concatenate the elements of the Path array into the FinalPath string
@ -75,443 +86,533 @@ namespace FileSystem
continue;
}
size_t ElementSize = strlen(Path[i]);
memcpy(FinalPath + Offset, Path[i], ElementSize);
memcpy(FinalPath.Get() + Offset, Path[i], ElementSize);
Offset += ElementSize;
}
// Add a null terminator to the final path string
FinalPath[Size - 1] = '\0';
FinalPath.Get()[Size - 1] = '\0';
// Deallocate the Path array
delete[] Path;
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath);
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath.Get());
return FinalPath;
}
FileSystemNode *Virtual::GetNodeFromPath(FileSystemNode *Parent, const char *Path)
Node *Virtual::GetNodeFromPath(const char *Path, Node *Parent)
{
vfsdbg("GetNodeFromPath( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
vfsdbg("GetNodeFromPath( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : "(null)");
if (Parent == nullptr)
Parent = FileSystemRoot;
Node *ReturnNode = Parent;
bool IsAbsolutePath = cwk_path_is_absolute(Path);
if (strcmp(Parent->Name, Path))
if (!ReturnNode)
ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root
if (IsAbsolutePath)
ReturnNode = FileSystemRoot->Children[0]; // 0 - filesystem root
cwk_segment segment;
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
{
cwk_segment segment;
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
{
error("Path doesn't have any segments.");
return nullptr;
}
do
{
char *SegmentName = new char[segment.end - segment.begin + 1];
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
GetNodeFromPathNextParent:
foreach (auto var in Parent->Children)
{
if (!strcmp(var->Name, SegmentName))
{
Parent = var;
goto GetNodeFromPathNextParent;
}
}
delete[] SegmentName;
} while (cwk_path_get_next_segment(&segment));
const char *basename;
cwk_path_get_basename(Path, &basename, nullptr);
if (!strcmp(basename, Parent->Name))
{
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name);
return Parent;
}
vfsdbg("GetNodeFromPath()->\"%s\"", nullptr);
error("Path doesn't have any segments.");
return nullptr;
}
else
do
{
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name);
return Parent;
char *SegmentName = new char[segment.end - segment.begin + 1];
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
vfsdbg("GetNodeFromPath()->SegmentName: \"%s\"", SegmentName);
GetNodeFromPathNextParent:
foreach (auto Child in ReturnNode->Children)
{
vfsdbg("comparing \"%s\" with \"%s\"", Child->Name, SegmentName);
if (strcmp(Child->Name, SegmentName) == 0)
{
ReturnNode = Child;
goto GetNodeFromPathNextParent;
}
}
delete[] SegmentName;
} while (cwk_path_get_next_segment(&segment));
const char *basename;
cwk_path_get_basename(Path, &basename, nullptr);
vfsdbg("BaseName: \"%s\" NodeName: \"%s\"", basename, ReturnNode->Name);
if (strcmp(basename, ReturnNode->Name) == 0)
{
vfsdbg("GetNodeFromPath()->\"%s\"", ReturnNode->Name);
return ReturnNode;
}
vfsdbg("GetNodeFromPath()->\"(null)\"");
return nullptr;
}
FileSystemNode *AddNewChild(FileSystemNode *Parent, const char *Name)
shared_ptr<File> Virtual::ConvertNodeToFILE(Node *node)
{
vfsdbg("AddNewChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
FileSystemNode *newNode = new FileSystemNode;
newNode->Parent = Parent;
strncpy(newNode->Name, Name, FILENAME_LENGTH);
if (likely(Parent))
newNode->Operator = Parent->Operator;
else
newNode->Operator = nullptr;
shared_ptr<File> file = make_shared<File>();
file->Status = FileStatus::OK;
file->node = node;
return file;
}
Node *Virtual::GetParent(const char *Path, Node *Parent)
{
vfsdbg("GetParent( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
if (Parent)
{
vfsdbg("GetParent()->\"%s\"", Parent->Name);
return Parent;
}
Node *ParentNode = nullptr;
if (FileSystemRoot->Children.size() >= 1)
{
if (FileSystemRoot->Children[0] == nullptr)
panic("Root node is null!");
ParentNode = FileSystemRoot->Children[0]; // 0 - filesystem root
}
else
{
// TODO: Check if here is a bug or something...
const char *PathCopy;
PathCopy = (char *)Path;
size_t length;
cwk_path_get_root(PathCopy, &length); // not working?
if (length > 0)
{
foreach (auto Child in FileSystemRoot->Children)
{
if (strcmp(Child->Name, PathCopy) == 0)
{
ParentNode = Child;
break;
}
}
}
}
vfsdbg("GetParent()->\"%s\"", ParentNode->Name);
return ParentNode;
}
Node *Virtual::AddNewChild(const char *Name, Node *Parent)
{
if (!Parent)
{
error("Parent is null!");
return nullptr;
}
vfsdbg("AddNewChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
Node *newNode = new Node;
newNode->Parent = Parent;
strcpy(newNode->Name, Name);
newNode->Operator = Parent->Operator;
Parent->Children.push_back(newNode);
if (likely(Parent))
Parent->Children.push_back(newNode);
vfsdbg("AddNewChild()->\"%s\"", newNode->Name);
return newNode;
}
FileSystemNode *GetChild(FileSystemNode *Parent, const char *Name)
Node *Virtual::GetChild(const char *Name, Node *Parent)
{
vfsdbg("GetChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
if (likely(Parent))
foreach (auto var in Parent->Children)
if (strcmp(var->Name, Name) == 0)
{
vfsdbg("GetChild()->\"%s\"", var->Name);
return var;
}
vfsdbg("GetChild()->nullptr");
vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
if (!Parent)
{
vfsdbg("GetChild()->nullptr");
return nullptr;
}
foreach (auto Child in Parent->Children)
if (strcmp(Child->Name, Name) == 0)
{
vfsdbg("GetChild()->\"%s\"", Child->Name);
return Child;
}
vfsdbg("GetChild()->nullptr (not found)");
return nullptr;
}
FileStatus RemoveChild(FileSystemNode *Parent, const char *Name)
FileStatus Virtual::RemoveChild(const char *Name, Node *Parent)
{
vfsdbg("RemoveChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
for (uintptr_t i = 0; i < Parent->Children.size(); i++)
vfsdbg("RemoveChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
for (size_t i = 0; i < Parent->Children.size(); i++)
{
if (strcmp(Parent->Children[i]->Name, Name) == 0)
{
delete Parent->Children[i];
Parent->Children.remove(i);
vfsdbg("RemoveChild()->OK");
return FileStatus::OK;
}
vfsdbg("RemoveChild()->NOT_FOUND");
return FileStatus::NOT_FOUND;
}
vfsdbg("RemoveChild()->NotFound");
return FileStatus::NotFound;
}
char *Virtual::NormalizePath(FileSystemNode *Parent, const char *Path)
shared_ptr<char> Virtual::NormalizePath(const char *Path, Node *Parent)
{
vfsdbg("NormalizePath( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
vfsdbg("NormalizePath( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
char *NormalizedPath = new char[strlen((char *)Path) + 1];
char *RelativePath = nullptr;
shared_ptr<char> RelativePath;
cwk_path_normalize(Path, NormalizedPath, strlen((char *)Path) + 1);
if (cwk_path_is_relative(NormalizedPath))
{
char *ParentPath = GetPathFromNode(Parent);
size_t PathSize = cwk_path_get_absolute(ParentPath, NormalizedPath, nullptr, 0);
RelativePath = new char[PathSize + 1];
cwk_path_get_absolute(ParentPath, NormalizedPath, RelativePath, PathSize + 1);
delete[] ParentPath;
shared_ptr<char> ParentPath = GetPathFromNode(Parent);
size_t PathSize = cwk_path_get_absolute(ParentPath.Get(), NormalizedPath, nullptr, 0);
RelativePath.reset(new char[PathSize + 1]);
cwk_path_get_absolute(ParentPath.Get(), NormalizedPath, RelativePath.Get(), PathSize + 1);
}
else
{
RelativePath = new char[strlen(NormalizedPath) + 1];
strcpy(RelativePath, NormalizedPath);
RelativePath.reset(new char[strlen(NormalizedPath) + 1]);
strcpy(RelativePath.Get(), NormalizedPath);
}
delete[] NormalizedPath;
vfsdbg("NormalizePath()->\"%s\"", RelativePath);
vfsdbg("NormalizePath()->\"%s\"", RelativePath.Get());
return RelativePath;
}
FileStatus Virtual::FileExists(FileSystemNode *Parent, const char *Path)
bool Virtual::PathExists(const char *Path, Node *Parent)
{
vfsdbg("FileExists( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
if (isempty((char *)Path))
return FileStatus::INVALID_PATH;
{
vfsdbg("PathExists()->PathIsEmpty");
return false;
}
if (Parent == nullptr)
Parent = FileSystemRoot;
char *NormalizedPath = NormalizePath(Parent, Path);
FileSystemNode *Node = GetNodeFromPath(Parent, NormalizedPath);
vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
if (!Node)
if (GetNodeFromPath(NormalizePath(Path, Parent).Get(), Parent))
{
vfsdbg("FileExists()->NOT_FOUND");
return FileStatus::NOT_FOUND;
}
else
{
vfsdbg("FileExists()->OK");
return FileStatus::OK;
vfsdbg("PathExists()->OK");
return true;
}
vfsdbg("PathExists()->NotFound");
return false;
}
FileSystemNode *Virtual::Create(FileSystemNode *Parent, const char *Path)
{
SmartLock(VFSLock);
if (isempty((char *)Path))
return nullptr;
vfsdbg("Virtual::Create( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
FileSystemNode *CurrentParent = nullptr;
if (!Parent)
{
if (FileSystemRoot->Children.size() >= 1)
{
if (FileSystemRoot->Children[0] == nullptr)
panic("Root node is null!");
CurrentParent = FileSystemRoot->Children[0]; // 0 - filesystem root
}
else
{
// TODO: check if here is a bug or something...
const char *PathCopy;
size_t length;
PathCopy = (char *)Path;
cwk_path_get_root(PathCopy, &length); // not working?
foreach (auto var in FileSystemRoot->Children)
if (!strcmp(var->Name, PathCopy))
{
CurrentParent = var;
break;
}
}
}
else
CurrentParent = Parent;
char *CleanPath = NormalizePath(CurrentParent, Path);
if (FileExists(CurrentParent, CleanPath) != FileStatus::NOT_FOUND)
{
error("File %s already exists.", CleanPath);
goto CreatePathError;
}
cwk_segment segment;
if (!cwk_path_get_first_segment(CleanPath, &segment))
{
error("Path doesn't have any segments.");
goto CreatePathError;
}
warn("Virtual::Create( ) is not working properly.");
do
{
char *SegmentName = new char[segment.end - segment.begin + 1];
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
if (GetChild(CurrentParent, SegmentName) == nullptr)
CurrentParent = AddNewChild(CurrentParent, SegmentName);
else
CurrentParent = GetChild(CurrentParent, SegmentName);
delete[] SegmentName;
} while (cwk_path_get_next_segment(&segment));
delete CleanPath;
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
return CurrentParent;
CreatePathError:
vfsdbg("Virtual::Create()->nullptr");
delete CleanPath;
return nullptr;
}
FileSystemNode *Virtual::CreateRoot(FileSystemOperations *Operator, const char *RootName)
Node *Virtual::CreateRoot(const char *RootName, FileSystemOperations *Operator)
{
if (Operator == nullptr)
return nullptr;
vfsdbg("Setting root to %s", RootName);
FileSystemNode *newNode = new FileSystemNode;
vfsdbg("Creating root %s", RootName);
Node *newNode = new Node;
strncpy(newNode->Name, RootName, FILENAME_LENGTH);
newNode->Flags = NodeFlags::FS_DIRECTORY;
newNode->Flags = NodeFlags::DIRECTORY;
newNode->Operator = Operator;
FileSystemRoot->Children.push_back(newNode);
return newNode;
}
FILE *Virtual::Mount(FileSystemOperations *Operator, const char *Path)
/* TODO: Further testing needed */
Node *Virtual::Create(const char *Path, NodeFlags Flag, Node *Parent)
{
SmartLock(VFSLock);
if (unlikely(!Operator))
if (isempty((char *)Path))
return nullptr;
Node *RootNode = FileSystemRoot->Children[0];
Node *CurrentParent = this->GetParent(Path, Parent);
vfsdbg("Virtual::Create( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : CurrentParent->Name);
shared_ptr<char> CleanPath = this->NormalizePath(Path, CurrentParent);
vfsdbg("CleanPath: \"%s\"", CleanPath.Get());
if (PathExists(CleanPath.Get(), CurrentParent))
{
error("Path %s already exists.", CleanPath.Get());
goto CreatePathError;
}
cwk_segment segment;
if (!cwk_path_get_first_segment(CleanPath.Get(), &segment))
{
error("Path doesn't have any segments.");
goto CreatePathError;
}
do
{
char *SegmentName = new char[segment.end - segment.begin + 1];
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
vfsdbg("SegmentName: \"%s\"", SegmentName);
if (Parent)
if (GetChild(SegmentName, RootNode) != nullptr)
{
RootNode = GetChild(SegmentName, RootNode);
delete[] SegmentName;
continue;
}
if (GetChild(SegmentName, CurrentParent) == nullptr)
{
CurrentParent = AddNewChild(SegmentName, CurrentParent);
CurrentParent->Flags = Flag;
}
else
{
CurrentParent = GetChild(SegmentName, CurrentParent);
}
delete[] SegmentName;
} while (cwk_path_get_next_segment(&segment));
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
vfsdbg("Path created: \"%s\"", GetPathFromNode(CurrentParent).Get());
return CurrentParent;
CreatePathError:
vfsdbg("Virtual::Create()->nullptr");
return nullptr;
}
FileStatus Virtual::Delete(const char *Path, bool Recursive, Node *Parent)
{
SmartLock(VFSLock);
vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : "(null)");
if (isempty((char *)Path))
return InvalidParameter;
if (Parent == nullptr)
Parent = FileSystemRoot;
shared_ptr<char> CleanPath = this->NormalizePath(Path, Parent);
vfsdbg("CleanPath: \"%s\"", CleanPath.Get());
if (!PathExists(CleanPath.Get(), Parent))
{
vfsdbg("Path %s doesn't exist.", CleanPath.Get());
return InvalidPath;
}
Node *NodeToDelete = GetNodeFromPath(CleanPath.Get(), Parent);
Node *ParentNode = GetParent(CleanPath.Get(), Parent);
if (NodeToDelete->Flags == NodeFlags::DIRECTORY)
{
if (Recursive)
{
foreach (auto Child in NodeToDelete->Children)
{
FileStatus Status = Delete(GetPathFromNode(Child).Get(), true);
if (Status != FileStatus::OK)
{
vfsdbg("Failed to delete child %s with status %d. (%s)", Child->Name, Status, Path);
return PartiallyCompleted;
}
}
}
else if (NodeToDelete->Children.size() > 0)
{
vfsdbg("Directory %s is not empty.", CleanPath.Get());
return DirectoryNotEmpty;
}
}
if (RemoveChild(NodeToDelete->Name, ParentNode) != FileStatus::OK)
{
vfsdbg("Failed to remove child %s from parent %s. (%s)", NodeToDelete->Name, ParentNode->Name, Path);
return NotFound;
}
vfsdbg("Virtual::Delete()->OK");
return OK;
}
FileStatus Virtual::Delete(Node *Path, bool Recursive, Node *Parent) { return Delete(GetPathFromNode(Path).Get(), Recursive, Parent); }
/* TODO: REWORK */
shared_ptr<File> Virtual::Mount(const char *Path, FileSystemOperations *Operator)
{
SmartLock(VFSLock);
shared_ptr<File> file = make_shared<File>();
if (unlikely(!Operator))
{
file->Status = FileStatus::InvalidOperator;
return file;
}
if (unlikely(isempty((char *)Path)))
return nullptr;
{
file->Status = FileStatus::InvalidParameter;
return file;
}
vfsdbg("Mounting %s", Path);
FILE *file = new FILE;
cwk_path_get_basename(Path, &file->Name, 0);
const char *PathCopy;
cwk_path_get_basename(Path, &PathCopy, 0);
strcpy(file->Name, PathCopy);
file->Status = FileStatus::OK;
file->Node = Create(nullptr, Path);
file->Node->Operator = Operator;
file->Node->Flags = NodeFlags::FS_MOUNTPOINT;
file->node = Create(Path, NodeFlags::MOUNTPOINT);
file->node->Operator = Operator;
return file;
}
FileStatus Virtual::Unmount(FILE *File)
FileStatus Virtual::Unmount(shared_ptr<File> File)
{
SmartLock(VFSLock);
if (unlikely(File))
return FileStatus::INVALID_PARAMETER;
vfsdbg("Unmounting %s", File->Name);
if (unlikely(File.Get()))
return FileStatus::InvalidParameter;
fixme("Unmounting %s", File->Name);
return FileStatus::OK;
}
FILE *Virtual::Open(const char *Path, FileSystemNode *Parent)
size_t Virtual::Read(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size)
{
SmartLock(VFSLock);
vfsdbg("Opening %s with parent %s", Path, Parent->Name);
if (unlikely(!File.Get()))
return 0;
if (unlikely(!File->node))
{
File->Status = FileStatus::InvalidNode;
return 0;
}
if (unlikely(!File->node->Operator))
{
File->Status = FileStatus::InvalidOperator;
return 0;
}
File->Status = FileStatus::OK;
vfsdbg("Reading %s out->%016x", File->Name, Buffer);
return File->node->Operator->Read(File->node, Offset, Size, Buffer);
}
size_t Virtual::Write(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size)
{
SmartLock(VFSLock);
if (unlikely(!File.Get()))
return 0;
if (unlikely(!File->node))
{
File->Status = FileStatus::InvalidNode;
return 0;
}
if (unlikely(!File->node->Operator))
{
File->Status = FileStatus::InvalidOperator;
return 0;
}
File->Status = FileStatus::OK;
vfsdbg("Writing %s out->%016x", File->Name, Buffer);
return File->node->Operator->Write(File->node, Offset, Size, Buffer);
}
/* TODO: CHECK Open */
shared_ptr<File> Virtual::Open(const char *Path, Node *Parent)
{
SmartLock(VFSLock);
vfsdbg("Opening %s with parent %s", Path, Parent ? Parent->Name : "(null)");
const char *basename;
if (strcmp(Path, ".") == 0)
{
FILE *file = new FILE;
file->Node = Parent;
if (unlikely(!file->Node))
file->Status = FileStatus::NOT_FOUND;
const char *basename;
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr);
file->Name = basename;
shared_ptr<File> file = make_shared<File>();
file->node = Parent;
if (unlikely(!file->node))
file->Status = FileStatus::NotFound;
cwk_path_get_basename(GetPathFromNode(Parent).Get(), &basename, nullptr);
strcpy(file->Name, basename);
return file;
}
if (strcmp(Path, "..") == 0)
{
if (Parent->Parent != nullptr)
Parent = Parent->Parent;
shared_ptr<File> file = make_shared<File>();
FILE *file = new FILE;
file->Node = Parent;
if (!file->Node)
file->Status = FileStatus::NOT_FOUND;
const char *basename;
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr);
file->Name = basename;
if (Parent->Parent != nullptr)
file->node = Parent->Parent;
if (!file->node)
file->Status = FileStatus::NotFound;
cwk_path_get_basename(GetPathFromNode(Parent).Get(), &basename, nullptr);
strcpy(file->Name, basename);
return file;
}
if (Parent == nullptr)
{
if (FileSystemRoot->Children.size() >= 1)
Parent = FileSystemRoot->Children[0]; // 0 - filesystem root
else
{
// TODO: check if here is a bug or something...
const char *PathCopy;
size_t length;
PathCopy = (char *)Path;
cwk_path_get_root(PathCopy, &length); // not working?
foreach (auto var in FileSystemRoot->Children)
if (!strcmp(var->Name, PathCopy))
{
Parent = var;
break;
}
}
}
Node *CurrentParent = this->GetParent(Path, Parent);
shared_ptr<char> CleanPath = NormalizePath(Path, CurrentParent);
char *CleanPath = NormalizePath(Parent, Path);
FILE *file = new FILE;
FileStatus filestatus = FileStatus::OK;
filestatus = FileExists(Parent, CleanPath);
shared_ptr<File> file = make_shared<File>();
/* TODO: Check for other errors */
if (filestatus != FileStatus::OK)
if (!PathExists(CleanPath.Get(), CurrentParent))
{
foreach (auto var in FileSystemRoot->Children)
if (!strcmp(var->Name, CleanPath))
{
file->Node = var;
if (file->Node == nullptr)
goto OpenNodeFail;
const char *basename;
cwk_path_get_basename(GetPathFromNode(var), &basename, nullptr);
file->Name = basename;
goto OpenNodeExit;
}
file->Node = GetNodeFromPath(FileSystemRoot->Children[0], CleanPath);
if (file->Node)
foreach (auto Child in FileSystemRoot->Children)
{
const char *basename;
cwk_path_get_basename(GetPathFromNode(file->Node), &basename, nullptr);
file->Name = basename;
goto OpenNodeExit;
if (strcmp(Child->Name, CleanPath.Get()) == 0)
{
file->node = Child;
if (file->node == nullptr)
{
file->Status = FileStatus::UnknownFileStatusError;
file->node = nullptr;
return file;
}
cwk_path_get_basename(GetPathFromNode(Child).Get(), &basename, nullptr);
strcpy(file->Name, basename);
return file;
}
}
OpenNodeFail:
file->Status = filestatus;
file->Node = nullptr;
file->node = GetNodeFromPath(CleanPath.Get(), FileSystemRoot->Children[0]);
if (file->node)
{
cwk_path_get_basename(GetPathFromNode(file->node).Get(), &basename, nullptr);
strcpy(file->Name, basename);
return file;
}
}
else
{
file->Node = GetNodeFromPath(Parent, CleanPath);
if (unlikely(!file->Node))
file->Status = FileStatus::NOT_FOUND;
const char *basename;
cwk_path_get_basename(CleanPath, &basename, nullptr);
file->Name = basename;
file->node = GetNodeFromPath(CleanPath.Get(), CurrentParent);
cwk_path_get_basename(CleanPath.Get(), &basename, nullptr);
strcpy(file->Name, basename);
return file;
}
OpenNodeExit:
file->Status = FileStatus::NotFound;
return file;
}
size_t Virtual::Read(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size)
FileStatus Virtual::Close(shared_ptr<File> File)
{
SmartLock(VFSLock);
if (unlikely(!File))
return 0;
File->Status = FileStatus::OK;
if (unlikely(!File->Node))
{
File->Status = FileStatus::INVALID_PARAMETER;
return 0;
}
if (unlikely(!File->Node->Operator))
{
File->Status = FileStatus::INVALID_PARAMETER;
return 0;
}
vfsdbg("Reading %s out->%016x", File->Name, Buffer);
return File->Node->Operator->Read(File->Node, Offset, Size, Buffer);
}
size_t Virtual::Write(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size)
{
SmartLock(VFSLock);
if (unlikely(!File))
return 0;
File->Status = FileStatus::OK;
if (unlikely(!File->Node))
{
File->Status = FileStatus::INVALID_PARAMETER;
return 0;
}
if (unlikely(!File->Node->Operator))
{
File->Status = FileStatus::INVALID_PARAMETER;
return 0;
}
vfsdbg("Writing %s out->%016x", File->Name, Buffer);
return File->Node->Operator->Write(File->Node, Offset, Size, Buffer);
}
FileStatus Virtual::Close(FILE *File)
{
SmartLock(VFSLock);
if (unlikely(!File))
return FileStatus::INVALID_HANDLE;
if (unlikely(!File.Get()))
return FileStatus::InvalidHandle;
vfsdbg("Closing %s", File->Name);
delete File;
return FileStatus::OK;
}
Virtual::Virtual()
{
trace("Initializing virtual file system...");
FileSystemRoot = new FileSystemNode;
FileSystemRoot->Flags = NodeFlags::FS_MOUNTPOINT;
FileSystemRoot = new Node;
FileSystemRoot->Flags = NodeFlags::MOUNTPOINT;
FileSystemRoot->Operator = nullptr;
FileSystemRoot->Parent = nullptr;
strncpy(FileSystemRoot->Name, "root", 4);
@ -520,6 +621,6 @@ namespace FileSystem
Virtual::~Virtual()
{
warn("Tried to deinitialize Virtual File System!");
trace("Destroying virtual file system...");
}
}

View File

@ -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

View File

@ -1,6 +1,7 @@
#include "kernel.h"
#include <boot/protocols/multiboot2.h>
#include <filesystem/ustar.hpp>
#include <interrupts.hpp>
#include <memory.hpp>
#include <convert.h>
@ -12,6 +13,7 @@
#include <io.h>
#include "Core/smbios.hpp"
#include "Tests/t.h"
/**
* Fennix Kernel
@ -29,6 +31,12 @@
* - [ ] Optimize SMP.
* - [ ] Support IPv6.
* - [ ] Endianess of the network stack (currently: [HOST](LSB)<=>[NETWORK](MSB)). Not sure if this is a standard or not.
* - [ ] Support 32-bit applications (ELF, PE, etc).
* - [ ] Do not map the entire memory. Map only the needed memory address at allocation time.
* - [ ] Implementation of logging (beside serial) with log rotation.
* - [ ] Implement a better task manager. (replace struct P/TCB with classes)
* - [?] Rewrite virtual file system. (it's very bad, I don't know how I wrote it this bad)
* - [ ] Colors in crash screen are not following the kernel color scheme.
*
* BUGS:
* - [ ] Kernel crashes when receiving interrupts for drivers only if the system has one core and the tasking is running.
@ -37,13 +45,13 @@
* CREDITS AND REFERENCES:
* - General:
* https://wiki.osdev.org/Main_Page
*
*
* - Font:
* http://www.fial.com/~scott/tamsyn-font/
*
*
* - CPU XCR0 structure:
* https://wiki.osdev.org/CPU_Registers_x86#XCR0
*
*
* - CPUID 0x7:
* https://en.wikipedia.org/wiki/CPUID
*
@ -67,6 +75,22 @@
* http://realtek.info/pdf/rtl8139cp.pdf
* https://en.wikipedia.org/wiki/IPv4
* https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml
*
* - Loading ELF shared libraries and dynamic linking:
* https://www.akkadia.org/drepper/dsohowto.pdf
* https://wiki.osdev.org/Dynamic_Linker
* https://github.com/tyler569/nightingale
* https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html
* https://www.youtube.com/watch?v=kUk5pw4w0h4
* https://docs.oracle.com/cd/E19683-01/817-3677/chapter6-42444/index.html
* https://ir0nstone.gitbook.io/notes/types/stack/aslr/plt_and_got
*
* - IPC:
* https://docs.oracle.com/cd/E19048-01/chorus5/806-6897/architecture-103/index.html
* https://www.scaler.com/topics/operating-system/inter-process-communication-in-os/
* https://en.wikipedia.org/wiki/Inter-process_communication
* https://www.geeksforgeeks.org/inter-process-communication-ipc/
*
*/
#ifdef __amd64__
@ -89,6 +113,11 @@
NewLock(KernelLock);
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
BootInfo *bInfo = nullptr;
Video::Display *Display = nullptr;
SymbolResolver::Symbols *KernelSymbolTable = nullptr;
@ -96,7 +125,7 @@ Power::Power *PowerManager = nullptr;
PCI::PCI *PCIManager = nullptr;
Tasking::Task *TaskManager = nullptr;
Time::time *TimeManager = nullptr;
FileSystem::Virtual *vfs = nullptr;
VirtualFileSystem::Virtual *vfs = nullptr;
KernelConfig Config;
Time::Clock BootClock;
@ -110,7 +139,7 @@ EXTERNC void KPrint(const char *Format, ...)
{
SmartLock(KernelLock);
Time::Clock tm = Time::ReadClock();
printf("\eCCCCCC[\e00AEFF%02ld:%02ld:%02ld\eCCCCCC] ", tm.Hour, tm.Minute, tm.Second);
printf("\eCCCCCC[\e00AEFF%02d:%02d:%02d\eCCCCCC] ", tm.Hour, tm.Minute, tm.Second);
va_list args;
va_start(args, Format);
vprintf(Format, args);
@ -236,8 +265,57 @@ EXTERNC __no_instrument_function void Main(BootInfo *Info)
else
KPrint("SMBIOS: \eFF0000Not Found");
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
KPrint("Initializing Filesystem...");
vfs = new VirtualFileSystem::Virtual;
new VirtualFileSystem::USTAR((uintptr_t)bInfo->Modules[0].Address, vfs); // TODO: Detect initrd
if (!vfs->PathExists("/system"))
vfs->Create("/system", NodeFlags::DIRECTORY);
if (!vfs->PathExists("/system/dev"))
DevFS = vfs->Create("/system/dev", NodeFlags::DIRECTORY);
else
{
shared_ptr<File> dev = vfs->Open("/system/dev");
if (dev->node->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/system/dev is not a directory! Halting...");
CPU::Halt(true);
}
vfs->Close(dev);
DevFS = dev->node;
}
if (!vfs->PathExists("/system/mnt"))
MntFS = vfs->Create("/system/mnt", NodeFlags::DIRECTORY);
else
{
shared_ptr<File> mnt = vfs->Open("/system/mnt");
if (mnt->node->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/system/mnt is not a directory! Halting...");
CPU::Halt(true);
}
vfs->Close(mnt);
MntFS = mnt->node;
}
if (!vfs->PathExists("/system/proc"))
ProcFS = vfs->Create("/system/proc", NodeFlags::DIRECTORY);
else
{
shared_ptr<File> proc = vfs->Open("/system/proc", nullptr);
if (proc->node->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/system/proc is not a directory! Halting...");
CPU::Halt(true);
}
vfs->Close(proc);
ProcFS = proc->node;
}
KPrint("\e058C19################################");
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
CPU::Halt(true);
}
@ -254,6 +332,16 @@ EXTERNC __no_stack_protector __no_instrument_function void Entry(BootInfo *Info)
(*func)();
InitializeMemoryManagement(Info);
/* I had to do this because KernelAllocator
* is a global constructor but we need
* memory management to be initialized first.
*/
#ifdef DEBUG
// Running tests
TestString();
#endif
EnableProfiler = true;
Main(Info);
}

View File

@ -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)
{

View File

@ -19,7 +19,7 @@ namespace NetworkInterfaceManager
NetworkInterface::NetworkInterface()
{
mem = new Memory::MemMgr;
mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
if (DriverManager->GetDrivers().size() > 0)
{
foreach (auto Driver in DriverManager->GetDrivers())
@ -74,7 +74,7 @@ namespace NetworkInterfaceManager
void NetworkInterface::StartNetworkStack()
{
TaskManager->GetCurrentThread()->SetPriority(100);
TaskManager->GetCurrentThread()->SetPriority(Tasking::TaskPriority::Critical);
DeviceInterface *DefaultDevice = nullptr;
foreach (auto var in Interfaces)
if (var && var->DriverCallBackAddress)
@ -131,7 +131,7 @@ namespace NetworkInterfaceManager
/* TODO: Store everything in an vector and initialize all network cards */
}
TaskManager->GetCurrentThread()->SetPriority(1);
TaskManager->GetCurrentThread()->SetPriority(Tasking::TaskPriority::Idle);
CPU::Pause(true);
}
@ -157,9 +157,7 @@ namespace NetworkInterfaceManager
void NetworkInterface::StartService()
{
this->NetSvcProcess = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), "Network Service", Tasking::TaskTrustLevel::System);
Vector<AuxiliaryVector> auxv;
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
this->NetSvcThread = TaskManager->CreateThread(this->NetSvcProcess, (Tasking::IP)CallStartNetworkStackWrapper, nullptr, nullptr, auxv);
this->NetSvcThread = TaskManager->CreateThread(this->NetSvcProcess, (Tasking::IP)CallStartNetworkStackWrapper);
}
void NetworkInterface::DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size)

View File

@ -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),

View File

@ -33,12 +33,10 @@ namespace Recovery
gui = new GraphicalUserInterface::GUI;
Vector<AuxiliaryVector> auxv;
auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
// TaskManager->CreateThread(proc, (IP)RecoveryThreadWrapper, nullptr, nullptr, auxv);
TCB *guiThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)GUIWrapper, nullptr, nullptr, auxv);
TCB *guiThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (IP)GUIWrapper);
guiThread->Rename("GUI Thread");
guiThread->SetPriority(100);
guiThread->SetPriority(Tasking::TaskPriority::Critical);
Rect RecoveryModeWindow;
RecoveryModeWindow.Width = 460;

View File

@ -1,5 +1,6 @@
#include <syscalls.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <debug.h>
@ -7,19 +8,54 @@
#include "../kernel.h"
#include "../../Userspace/libs/include/sysbase.h"
#include "../ipc.h"
NewLock(SyscallsLock);
using InterProcessCommunication::IPC;
using InterProcessCommunication::IPCID;
using Tasking::Token;
using Tasking::TTL;
using Tasking::TTL::Trusted;
using Tasking::TTL::TrustedByKernel;
using Tasking::TTL::UnknownTrustLevel;
using Tasking::TTL::Untrusted;
static inline bool CheckTrust(int TrustLevel)
{
// SmartTimeoutLock(SyscallsLock, 10000); - This is already done in the caller
Token token = TaskManager->GetCurrentThread()->Security.UniqueToken;
if (TaskManager->GetSecurityManager()->IsTokenTrusted(token, TrustLevel))
return true;
warn("Thread %s(%lld) tried to access a system call \"%s\" with insufficient trust level",
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0))), TaskManager->GetCurrentThread()->Name, TaskManager->GetCurrentThread()->ID);
debug("Token: token=%#lx, trust=%d", token, TaskManager->GetSecurityManager()->GetTokenTrustLevel(token));
return false;
}
static int sys_exit(SyscallsFrame *Frame, int code)
{
SmartTimeoutLock(SyscallsLock, 10000);
/* Allow everyone to exit */
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted | UnknownTrustLevel))
return SYSCALL_ACCESS_DENIED;
trace("Userspace thread %s(%lld) exited with code %#llx", TaskManager->GetCurrentThread()->Name, TaskManager->GetCurrentThread()->ID, code);
TaskManager->GetCurrentThread()->ExitCode = code;
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated;
UNUSED(Frame);
return 0;
return SYSCALL_OK;
}
static int sys_print(SyscallsFrame *Frame, char Char, int Index)
{
int ret = Display->Print(Char, Index, true);
SmartTimeoutLock(SyscallsLock, 10000);
/* Only trusted threads can write to the kernel console */
if (!CheckTrust(TrustedByKernel | Trusted))
return SYSCALL_ACCESS_DENIED;
char ret = Display->Print(Char, Index, true);
#ifdef DEBUG
Display->SetBuffer(Index);
#endif
@ -29,19 +65,43 @@ static int sys_print(SyscallsFrame *Frame, char Char, int Index)
static uintptr_t sys_request_pages(SyscallsFrame *Frame, size_t Count)
{
SmartTimeoutLock(SyscallsLock, 10000);
/* Allow everyone to request pages */
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted))
return SYSCALL_ACCESS_DENIED;
UNUSED(Frame);
return (uintptr_t)TaskManager->GetCurrentThread()->Memory->RequestPages(Count);
return (uintptr_t)TaskManager->GetCurrentThread()->Memory->RequestPages(Count, true);
}
static int sys_free_pages(SyscallsFrame *Frame, uintptr_t Address, size_t Count)
{
SmartTimeoutLock(SyscallsLock, 10000);
/* Allow everyone to free pages */
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted))
return SYSCALL_ACCESS_DENIED;
TaskManager->GetCurrentThread()->Memory->FreePages((void *)Address, Count);
UNUSED(Frame);
return 0;
return SYSCALL_OK;
}
static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
static int sys_detach_address(SyscallsFrame *Frame, uintptr_t Address)
{
SmartTimeoutLock(SyscallsLock, 10000);
/* Only trusted threads can detach allocated addresses */
if (!CheckTrust(TrustedByKernel | Trusted))
return SYSCALL_ACCESS_DENIED;
TaskManager->GetCurrentThread()->Memory->DetachAddress((void *)Address);
UNUSED(Frame);
return SYSCALL_OK;
}
static uintptr_t sys_kernelctl(SyscallsFrame *Frame, enum KCtl Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
{
SmartTimeoutLock(SyscallsLock, 10000);
/* Only trusted threads can use kernelctl */
if (!CheckTrust(TrustedByKernel | Trusted))
return SYSCALL_ACCESS_DENIED;
switch (Command)
{
case KCTL_GET_PID:
@ -53,7 +113,7 @@ static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint6
default:
{
warn("KernelCTL: Unknown command: %lld", Command);
return -1;
return SYSCALL_INVALID_ARGUMENT;
}
}
@ -62,121 +122,152 @@ static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint6
UNUSED(Arg3);
UNUSED(Arg4);
UNUSED(Frame);
return -1;
}
static int sys_ipc(SyscallsFrame *Frame, int Command, int Type, int ID, int Flags, void *Buffer, size_t Size)
{
SmartTimeoutLock(SyscallsLock, 10000);
/* Allow everyone to use IPC */
if (!CheckTrust(TrustedByKernel | Trusted | Untrusted))
return SYSCALL_ACCESS_DENIED;
IPC *ipc = TaskManager->GetCurrentProcess()->IPC;
UNUSED(Frame);
return 0;
}
static int sys_file_open(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_open: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_file_close(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_close: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_file_read(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_read: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_file_write(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_write: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_file_seek(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_seek: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_file_status(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_status: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_wait(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_wait: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_kill(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_kill: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_spawn(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_spawn: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_spawn_thread(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_spawn_thread: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_get_thread_list_of_process(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_thread_list_of_process: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_get_current_process(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_current_process: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_get_current_thread(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_current_thread: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_get_process_by_pid(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_process_by_pid: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_get_thread_by_tid(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_thread_by_tid: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_kill_process(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_kill_process: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_kill_thread(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_kill_thread: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_sys_reserved_create_process(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_sys_reserved_create_process: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static int sys_sys_reserved_create_thread(SyscallsFrame *Frame)
{
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_sys_reserved_create_thread: %#lx", Frame);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
static void *NativeSyscallsTable[] = {
@ -185,8 +276,10 @@ static void *NativeSyscallsTable[] = {
[_RequestPages] = (void *)sys_request_pages,
[_FreePages] = (void *)sys_free_pages,
[_DetachAddress] = (void *)sys_detach_address,
[_KernelCTL] = (void *)sys_kernelctl,
[_IPC] = (void *)sys_ipc,
[_FileOpen] = (void *)sys_file_open,
[_FileClose] = (void *)sys_file_close,
@ -217,14 +310,14 @@ uintptr_t HandleNativeSyscalls(SyscallsFrame *Frame)
if (Frame->rax > sizeof(NativeSyscallsTable))
{
fixme("Syscall %lld not implemented", Frame->rax);
return -1;
return SYSCALL_NOT_IMPLEMENTED;
}
uintptr_t (*call)(uintptr_t, ...) = reinterpret_cast<uintptr_t (*)(uintptr_t, ...)>(NativeSyscallsTable[Frame->rax]);
if (!call)
{
error("Syscall %#llx failed.", Frame->rax);
return -1;
return SYSCALL_INTERNAL_ERROR;
}
debug("[%#lx]->( %#lx %#lx %#lx %#lx %#lx %#lx )", Frame->rax, Frame->rdi, Frame->rsi, Frame->rdx, Frame->rcx, Frame->r8, Frame->r9);
uintptr_t ret = call((uintptr_t)Frame, Frame->rdi, Frame->rsi, Frame->rdx, Frame->r10, Frame->r8, Frame->r9);

View File

@ -1,141 +1,161 @@
#include <ipc.hpp>
#include <lock.hpp>
#include <task.hpp>
#include "../kernel.h"
NewLock(IPCLock);
InterProcessCommunication::IPC *ipc = nullptr;
namespace InterProcessCommunication
{
IPCHandle *IPC::RegisterHandle(IPCPort Port)
IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16])
{
SmartLock(IPCLock);
if (Port == 0)
return nullptr;
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
if (pcb->IPCHandles->Get((int)Port) != 0)
return nullptr;
IPCHandle *handle = new IPCHandle;
handle->ID = -1;
handle->Buffer = nullptr;
handle->Length = 0;
handle->Operation = IPCOperationNone;
handle->Listening = 0;
handle->Error = IPCUnknown;
pcb->IPCHandles->AddNode(Port, (uintptr_t)handle);
return handle;
IPCHandle *Handle = (IPCHandle *)mem->RequestPages(TO_PAGES(sizeof(IPCHandle)));
Handle->ID = NextID++;
Handle->Node = vfs->Create(UniqueToken, VirtualFileSystem::NodeFlags::FILE, IPCNode);
Handle->Node->Address = (uintptr_t)mem->RequestPages(TO_PAGES(sizeof(4096)));
Handle->Node->Length = 4096;
Handles.push_back(Handle);
return Handle;
}
IPCError IPC::Listen(IPCPort Port)
IPCErrorCode IPC::Destroy(IPCID ID)
{
SmartLock(IPCLock);
if (Port == 0)
return IPCError{IPCInvalidPort};
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
if (pcb->IPCHandles->Get((int)Port) == 0)
return IPCError{IPCPortNotRegistered};
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
handle->Listening = 1;
return IPCError{IPCSuccess};
}
IPCHandle *IPC::Wait(IPCPort Port)
{
SmartLock(IPCLock);
if (Port == 0)
return nullptr;
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
if (pcb->IPCHandles->Get((int)Port) == 0)
return nullptr;
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
while (handle->Listening == 1)
CPU::Pause();
return handle;
}
IPCError IPC::Read(Tasking::UPID ID, IPCPort Port, uint8_t *&Buffer, long &Size)
{
SmartLock(IPCLock);
if (Port == 0)
return IPCError{IPCInvalidPort};
Tasking::PCB *pcb = TaskManager->GetCurrentProcess();
if (pcb->IPCHandles->Get((int)Port) == 0)
return IPCError{IPCInvalidPort};
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
if (handle->Listening == 0)
return IPCError{IPCPortInUse};
Buffer = handle->Buffer;
Size = handle->Length;
handle->Operation = IPCOperationRead;
handle->Listening = 1;
handle->Error = IPCSuccess;
// FIXME: ID is not used.
UNUSED(ID);
return IPCError{IPCSuccess};
}
IPCError IPC::Write(Tasking::UPID ID, IPCPort Port, uint8_t *Buffer, long Size)
{
SmartLock(IPCLock);
if (Port == 0)
return IPCError{IPCInvalidPort};
Vector<Tasking::PCB *> Processes = TaskManager->GetProcessList();
for (size_t i = 0; i < Processes.size(); i++)
for (size_t i = 0; i < Handles.size(); i++)
{
Tasking::PCB *pcb = Processes[i];
if (pcb->ID == ID)
if (Handles[i]->ID == ID)
{
if (pcb->IPCHandles->Get((int)Port) == 0)
return IPCError{IPCInvalidPort};
IPCHandle *handle = (IPCHandle *)pcb->IPCHandles->Get((int)Port);
if (handle->Listening == 0)
return IPCError{IPCNotListening};
handle->Buffer = Buffer;
handle->Length = Size;
handle->Operation = IPCOperationWrite;
handle->Listening = 0;
handle->Error = IPCSuccess;
mem->FreePages(Handles[i], TO_PAGES(sizeof(IPCHandle)));
Handles.remove(i);
return IPCSuccess;
}
}
return IPCError{IPCIDNotFound};
return IPCIDNotFound;
}
IPC::IPC()
IPCErrorCode IPC::Read(IPCID ID, uint8_t *Buffer, long Size)
{
SmartLock(IPCLock);
trace("Starting IPC Service...");
if (Size < 0)
return IPCError;
foreach (auto Handle in Handles)
{
if (Handle->ID == ID)
{
if (Handle->Listening)
return IPCNotListening;
if (Handle->Length < Size)
return IPCError;
memcpy(Buffer, Handle->Buffer, Size);
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPCErrorCode IPC::Write(IPCID ID, uint8_t *Buffer, long Size)
{
SmartLock(IPCLock);
if (Size < 0)
return IPCError;
foreach (auto Handle in Handles)
{
if (Handle->ID == ID)
{
if (!Handle->Listening)
return IPCNotListening;
if (Handle->Length < Size)
return IPCError;
memcpy(Handle->Buffer, Buffer, Size);
Handle->Listening = false;
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPCErrorCode IPC::Listen(IPCID ID)
{
SmartLock(IPCLock);
foreach (auto Handle in Handles)
{
if (Handle->ID == ID)
{
Handle->Listening = true;
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPCHandle *IPC::Wait(IPCID ID)
{
SmartLock(IPCLock);
foreach (auto &Handle in Handles)
{
if (Handle->ID == ID)
{
while (Handle->Listening)
CPU::Pause();
return Handle;
}
}
return nullptr;
}
IPCErrorCode IPC::Allocate(IPCID ID, long Size)
{
SmartLock(IPCLock);
if (Size < 0)
return IPCError;
foreach (auto Handle in Handles)
{
if (Handle->ID == ID)
{
if (Handle->Buffer != nullptr || Handle->Length != 0)
return IPCAlreadyAllocated;
Handle->Buffer = (uint8_t *)mem->RequestPages(TO_PAGES(Size));
Handle->Length = Size;
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPCErrorCode IPC::Deallocate(IPCID ID)
{
SmartLock(IPCLock);
foreach (auto Handle in Handles)
{
if (Handle->ID == ID)
{
if (Handle->Buffer == nullptr || Handle->Length == 0)
return IPCNotAllocated;
mem->FreePages(Handle->Buffer, TO_PAGES(Handle->Length));
Handle->Buffer = nullptr;
Handle->Length = 0;
return IPCSuccess;
}
}
return IPCIDNotFound;
}
IPC::IPC(void *Process)
{
this->Process = Process;
mem = new Memory::MemMgr(nullptr, ((Tasking::PCB *)Process)->memDirectory);
IPCNode = vfs->Create("ipc", VirtualFileSystem::NodeFlags::DIRECTORY, ((Tasking::PCB *)this->Process)->ProcessDirectory);
}
IPC::~IPC()
{
delete mem;
vfs->Delete(IPCNode, true);
}
}

688
Tasking/Scheduler.cpp Normal file
View File

@ -0,0 +1,688 @@
#include <task.hpp>
#include <dumper.hpp>
#include <convert.h>
#include <lock.hpp>
#include <printf.h>
#include <smp.hpp>
#include <io.h>
#include "../kernel.h"
#if defined(__amd64__)
#include "../Architecture/amd64/cpu/apic.hpp"
#include "../Architecture/amd64/cpu/gdt.hpp"
#elif defined(__i386__)
#include "../Architecture/i686/cpu/apic.hpp"
#elif defined(__aarch64__)
#endif
NewLock(SchedulerLock);
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
// #define DEBUG_SCHEDULER 1
// #define DEBUG_GET_NEXT_AVAILABLE_PROCESS 1
// #define DEBUG_GET_NEXT_AVAILABLE_THREAD 1
// #define DEBUG_FIND_NEW_PROCESS 1
// #define DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD 1
// #define DEBUG_WAKE_UP_THREADS 1
/* Global */
#ifdef DEBUG_SCHEDULER
#define DEBUG_GET_NEXT_AVAILABLE_PROCESS 1
#define DEBUG_GET_NEXT_AVAILABLE_THREAD 1
#define DEBUG_FIND_NEW_PROCESS 1
#define DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD 1
#define DEBUG_WAKE_UP_THREADS 1
#define schedbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define schedbg(m, ...)
#endif
/* GetNextAvailableThread */
#ifdef DEBUG_GET_NEXT_AVAILABLE_PROCESS
#define gnap_schedbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define gnap_schedbg(m, ...)
#endif
/* GetNextAvailableProcess */
#ifdef DEBUG_GET_NEXT_AVAILABLE_THREAD
#define gnat_schedbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define gnat_schedbg(m, ...)
#endif
/* FindNewProcess */
#ifdef DEBUG_FIND_NEW_PROCESS
#define fnp_schedbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define fnp_schedbg(m, ...)
#endif
/* SchedulerSearchProcessThread */
#ifdef DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD
#define sspt_schedbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define sspt_schedbg(m, ...)
#endif
/* WakeUpThreads */
#ifdef DEBUG_WAKE_UP_THREADS
#define wut_schedbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define wut_schedbg(m, ...)
#endif
extern "C" SafeFunction __no_instrument_function void TaskingScheduler_OneShot(int TimeSlice)
{
if (TimeSlice == 0)
TimeSlice = 10;
#if defined(__amd64__)
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x64::IRQ16, TimeSlice);
#elif defined(__i386__)
#elif defined(__aarch64__)
#endif
}
namespace Tasking
{
#if defined(__amd64__)
SafeFunction __no_instrument_function bool Task::FindNewProcess(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
fnp_schedbg("%d processes", ListProcess.size());
#ifdef DEBUG_FIND_NEW_PROCESS
foreach (auto pcb in ListProcess)
fnp_schedbg("Process %d %s", pcb->ID, pcb->Name);
#endif
foreach (auto pcb in ListProcess)
{
if (InvalidPCB(pcb))
continue;
switch (pcb->Status)
{
case TaskStatus::Ready:
fnp_schedbg("Ready process (%s)%d", pcb->Name, pcb->ID);
break;
default:
fnp_schedbg("Process \"%s\"(%d) status %d", pcb->Name, pcb->ID, pcb->Status);
/* We don't actually remove the process. RemoveProcess
firstly checks if it's terminated, if not, it will
loop through Threads and call RemoveThread on
terminated threads. */
RemoveProcess(pcb);
continue;
}
foreach (auto tcb in pcb->Threads)
{
if (InvalidTCB(tcb))
continue;
if (tcb->Status != TaskStatus::Ready)
continue;
CurrentCPU->CurrentProcess = pcb;
CurrentCPU->CurrentThread = tcb;
return true;
}
}
fnp_schedbg("No process to run.");
return false;
}
SafeFunction __no_instrument_function bool Task::GetNextAvailableThread(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
for (size_t i = 0; i < CurrentCPU->CurrentProcess->Threads.size(); i++)
{
if (CurrentCPU->CurrentProcess->Threads[i] == CurrentCPU->CurrentThread)
{
size_t TempIndex = i;
RetryAnotherThread:
TCB *thread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
if (unlikely(InvalidTCB(thread)))
{
if (TempIndex > CurrentCPU->CurrentProcess->Threads.size())
break;
TempIndex++;
gnat_schedbg("Thread %#lx is invalid", thread);
goto RetryAnotherThread;
}
gnat_schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)", CurrentCPU->CurrentProcess->Threads[i]->Name, CurrentCPU->CurrentProcess->Threads[i]->ID, thread->Name, thread->ID);
if (thread->Status != TaskStatus::Ready)
{
gnat_schedbg("Thread %d is not ready", thread->ID);
TempIndex++;
goto RetryAnotherThread;
}
CurrentCPU->CurrentThread = thread;
gnat_schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d", thread->ID, thread->Parent->Name, CurrentCPU->CurrentProcess->Threads.size(), ListProcess.size());
return true;
}
#ifdef DEBUG
else
{
gnat_schedbg("Thread %d is not the current one", CurrentCPU->CurrentProcess->Threads[i]->ID);
}
#endif
}
return false;
}
SafeFunction __no_instrument_function bool Task::GetNextAvailableProcess(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
bool Skip = true;
foreach (auto pcb in ListProcess)
{
if (pcb == CurrentCPU->CurrentProcess)
{
Skip = false;
gnap_schedbg("Found current process %#lx", pcb);
continue;
}
if (Skip)
{
gnap_schedbg("Skipping process %#lx", pcb);
continue;
}
if (InvalidPCB(pcb))
{
gnap_schedbg("Invalid process %#lx", pcb);
continue;
}
if (pcb->Status != TaskStatus::Ready)
{
gnap_schedbg("Process %d is not ready", pcb->ID);
continue;
}
foreach (auto tcb in pcb->Threads)
{
if (InvalidTCB(tcb))
{
gnap_schedbg("Invalid thread %#lx", tcb);
continue;
}
if (tcb->Status != TaskStatus::Ready)
{
gnap_schedbg("Thread %d is not ready", tcb->ID);
continue;
}
CurrentCPU->CurrentProcess = pcb;
CurrentCPU->CurrentThread = tcb;
gnap_schedbg("[cur proc+1 -> first thd] Scheduling thread %d %s->%d (Total Procs %d)", tcb->ID, tcb->Name, pcb->Threads.size(), ListProcess.size());
return true;
}
}
gnap_schedbg("No process to run.");
return false;
}
SafeFunction __no_instrument_function void Task::SchedulerCleanupProcesses()
{
foreach (auto pcb in ListProcess)
{
if (InvalidPCB(pcb))
continue;
RemoveProcess(pcb);
}
}
SafeFunction __no_instrument_function bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
foreach (auto pcb in ListProcess)
{
if (InvalidPCB(pcb))
{
sspt_schedbg("Invalid process %#lx", pcb);
continue;
}
if (pcb->Status != TaskStatus::Ready)
{
sspt_schedbg("Process %d is not ready", pcb->ID);
continue;
}
foreach (auto tcb in pcb->Threads)
{
if (InvalidTCB(tcb))
{
sspt_schedbg("Invalid thread %#lx", tcb);
continue;
}
if (tcb->Status != TaskStatus::Ready)
{
sspt_schedbg("Thread %d is not ready", tcb->ID);
continue;
}
CurrentCPU->CurrentProcess = pcb;
CurrentCPU->CurrentThread = tcb;
sspt_schedbg("[proc 0 -> end -> first thd] Scheduling thread %d parent of %s->%d (Procs %d)", tcb->ID, tcb->Parent->Name, pcb->Threads.size(), ListProcess.size());
return true;
}
}
return false;
}
SafeFunction __no_instrument_function void Task::UpdateProcessStatus()
{
foreach (auto pcb in ListProcess)
{
if (InvalidPCB(pcb))
continue;
if (pcb->Status == TaskStatus::Terminated ||
pcb->Status == TaskStatus::Stopped)
continue;
bool AllThreadsSleeping = true;
foreach (auto tcb in pcb->Threads)
{
if (tcb->Status != TaskStatus::Sleeping)
{
AllThreadsSleeping = false;
break;
}
}
if (AllThreadsSleeping)
pcb->Status = TaskStatus::Sleeping;
else if (pcb->Status == TaskStatus::Sleeping)
pcb->Status = TaskStatus::Ready;
}
}
SafeFunction __no_instrument_function void Task::WakeUpThreads(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
foreach (auto pcb in ListProcess)
{
if (InvalidPCB(pcb))
continue;
if (pcb->Status == TaskStatus::Terminated ||
pcb->Status == TaskStatus::Stopped)
continue;
foreach (auto tcb in pcb->Threads)
{
if (InvalidTCB(tcb))
continue;
if (tcb->Status != TaskStatus::Sleeping)
continue;
/* Check if the thread is ready to wake up. */
if (tcb->Info.SleepUntil < TimeManager->GetCounter())
{
if (pcb->Status == TaskStatus::Sleeping)
pcb->Status = TaskStatus::Ready;
tcb->Status = TaskStatus::Ready;
tcb->Info.SleepUntil = 0;
wut_schedbg("Thread \"%s\"(%d) woke up.", tcb->Name, tcb->ID);
}
else
{
wut_schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)", tcb->Name, tcb->ID, tcb->Info.SleepUntil, TimeManager->GetCounter());
}
}
}
}
SafeFunction __no_instrument_function void Task::Schedule(CPU::x64::TrapFrame *Frame)
{
SmartCriticalSection(SchedulerLock);
if (StopScheduler)
{
warn("Scheduler stopped.");
return;
}
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); /* Restore kernel page table for safety reasons. */
CPUData *CurrentCPU = GetCurrentCPU();
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
schedbg("%d: %ld%%", CurrentCPU->ID, GetUsage(CurrentCPU->ID));
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
int SuccessSource = 0;
static int sanity;
const char *Statuses[] = {
"FF0000", /* Unknown */
"AAFF00", /* Ready */
"00AA00", /* Running */
"FFAA00", /* Sleeping */
"FFAA00", /* Waiting */
"FF0088", /* Stopped */
"FF0000", /* Terminated */
};
const char *StatusesSign[] = {
"Unknown",
"Ready",
"Run",
"Sleep",
"Wait",
"Stop",
"Terminated",
};
const char *SuccessSourceStrings[] = {
"Unknown",
"GetNextAvailableThread",
"GetNextAvailableProcess",
"SchedulerSearchProcessThread",
};
uint32_t tmpX, tmpY;
#endif
#ifdef DEBUG_SCHEDULER
{
schedbg("================================================================");
schedbg("Status: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
size_t ds;
asmv("mov %%ds, %0"
: "=r"(ds));
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
schedbg("================================================================");
}
#endif
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess) || InvalidTCB(CurrentCPU->CurrentThread)))
{
schedbg("Invalid process or thread. Finding a new one.");
if (this->FindNewProcess(CurrentCPU))
goto Success;
else
goto Idle;
}
else
{
CurrentCPU->CurrentThread->Registers = *Frame;
CPU::x64::fxsave(CurrentCPU->CurrentThread->FPU);
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
if (CurrentCPU->CurrentProcess->Status == TaskStatus::Running)
CurrentCPU->CurrentProcess->Status = TaskStatus::Ready;
if (CurrentCPU->CurrentThread->Status == TaskStatus::Running)
CurrentCPU->CurrentThread->Status = TaskStatus::Ready;
this->UpdateProcessStatus();
schedbg("Passed UpdateProcessStatus");
this->WakeUpThreads(CurrentCPU);
schedbg("Passed WakeUpThreads");
if (this->GetNextAvailableThread(CurrentCPU))
{
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
SuccessSource = 1;
#endif
goto Success;
}
schedbg("Passed GetNextAvailableThread");
if (this->GetNextAvailableProcess(CurrentCPU))
{
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
SuccessSource = 2;
#endif
goto Success;
}
schedbg("Passed GetNextAvailableProcess");
this->SchedulerCleanupProcesses();
schedbg("Passed SchedulerCleanupProcesses");
if (SchedulerSearchProcessThread(CurrentCPU))
{
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
SuccessSource = 3;
#endif
schedbg("Passed SchedulerSearchProcessThread");
goto Success;
}
else
{
schedbg("SchedulerSearchProcessThread failed. Going idle.");
goto Idle;
}
}
/* [this]->RealEnd */
warn("Unwanted reach!");
TaskingScheduler_OneShot(100);
goto RealEnd;
/* Idle-->Success */
Idle:
CurrentCPU->CurrentProcess = IdleProcess;
CurrentCPU->CurrentThread = IdleThread;
/* Success-->End */
Success:
schedbg("Process \"%s\"(%d) Thread \"%s\"(%d) is now running on CPU %d",
CurrentCPU->CurrentProcess->Name, CurrentCPU->CurrentProcess->ID,
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID);
CurrentCPU->CurrentProcess->Status = TaskStatus::Running;
CurrentCPU->CurrentThread->Status = TaskStatus::Running;
*Frame = CurrentCPU->CurrentThread->Registers;
for (size_t i = 0; i < sizeof(CurrentCPU->CurrentThread->IPHistory) / sizeof(CurrentCPU->CurrentThread->IPHistory[0]); i++)
CurrentCPU->CurrentThread->IPHistory[i + 1] = CurrentCPU->CurrentThread->IPHistory[i];
CurrentCPU->CurrentThread->IPHistory[0] = Frame->rip;
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
/* Not sure if this is needed, but it's better to be safe than sorry. */
asmv("movq %cr3, %rax");
asmv("movq %rax, %cr3");
CPU::x64::fxrstor(CurrentCPU->CurrentThread->FPU);
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
for (int i = 0; i < 340; i++)
for (int j = 0; j < 200; j++)
Display->SetPixel(i, j, 0x222222, 0);
Display->GetBufferCursor(0, &tmpX, &tmpY);
Display->SetBufferCursor(0, 0, 0);
foreach (auto var in ListProcess)
{
int Status = var->Status;
printf("\e%s-> \eAABBCC%s \e00AAAA%s\n",
Statuses[Status], var->Name, StatusesSign[Status]);
foreach (auto var2 in var->Threads)
{
Status = var2->Status;
printf(" \e%s-> \eAABBCC%s \e00AAAA%s\n\eAABBCC",
Statuses[Status], var2->Name, StatusesSign[Status]);
}
}
printf("Sanity: %d\nSched. Source: %s", sanity++, SuccessSourceStrings[SuccessSource]);
if (sanity > 1000)
sanity = 0;
Display->SetBufferCursor(0, tmpX, tmpY);
Display->SetBuffer(0);
for (int i = 0; i < 50000; i++)
inb(0x80);
#endif
switch (CurrentCPU->CurrentProcess->Security.TrustLevel)
{
case TaskTrustLevel::System:
case TaskTrustLevel::Kernel:
// wrmsr(MSR_SHADOW_GS_BASE, (uint64_t)CurrentCPU->CurrentThread);
break;
case TaskTrustLevel::User:
// wrmsr(MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->gs);
break;
default:
error("Unknown trust level %d.", CurrentCPU->CurrentProcess->Security.TrustLevel);
break;
}
/* End-->RealEnd */
// End:
/* TODO: This is not accurate. */
if (CurrentCPU->CurrentProcess->Security.TrustLevel == TaskTrustLevel::User)
UpdateUserTime(&CurrentCPU->CurrentProcess->Info);
else
UpdateKernelTime(&CurrentCPU->CurrentProcess->Info);
if (CurrentCPU->CurrentThread->Security.TrustLevel == TaskTrustLevel::User)
UpdateUserTime(&CurrentCPU->CurrentThread->Info);
else
UpdateKernelTime(&CurrentCPU->CurrentThread->Info);
UpdateUsage(&CurrentCPU->CurrentProcess->Info, CurrentCPU->ID);
UpdateUsage(&CurrentCPU->CurrentThread->Info, CurrentCPU->ID);
TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority);
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID,
CurrentCPU->CurrentThread->Registers.rip,
CurrentCPU->CurrentThread->Registers.rbp,
CurrentCPU->CurrentThread->Registers.rsp);
schedbg("================================================================");
schedbg("Technical Informations on Thread %s[%ld]:", CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID);
uint64_t ds;
asmv("mov %%ds, %0"
: "=r"(ds));
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
schedbg("================================================================");
/* RealEnd->[Function Exit] */
RealEnd:
__sync_synchronize(); /* TODO: Is this really needed? */
}
SafeFunction __no_instrument_function void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame) { this->Schedule(Frame); }
#elif defined(__i386__)
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::SchedulerCleanupProcesses()
{
fixme("unimplemented");
}
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::Schedule(void *Frame)
{
fixme("unimplemented");
}
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
#elif defined(__aarch64__)
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::SchedulerCleanupProcesses()
{
fixme("unimplemented");
}
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::Schedule(void *Frame)
{
fixme("unimplemented");
}
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
#endif
}

View File

@ -6,64 +6,131 @@
namespace Tasking
{
struct TokenData
{
Token token;
enum TokenTrustLevel TrustLevel;
uint64_t OwnerID;
bool Process;
};
Vector<TokenData> Tokens;
Token Security::CreateToken()
{
uint64_t ret = Random::rand64();
uint64_t ret = 0;
Retry:
ret = Random::rand64();
foreach (auto t in Tokens)
if (t.token == ret)
goto Retry;
Tokens.push_back({ret, UnknownTrustLevel, 0, false});
debug("Created token %#lx", ret);
return ret;
}
bool Security::TrustToken(Token token,
TokenTrustLevel TrustLevel)
bool Security::TrustToken(Token token, TTL TrustLevel)
{
enum TokenTrustLevel Level = static_cast<enum TokenTrustLevel>(TrustLevel);
foreach (auto var in Tokens)
foreach (auto &t in Tokens)
{
if (var.token == token)
if (t.token == token)
{
var.TrustLevel = Level;
debug("Trusted token %#lx", token);
t.TrustLevel = TrustLevel;
debug("Trusted token %#lx to level %d", token, t.TrustLevel);
return true;
}
}
debug("Failed to trust token %#lx", token);
warn("Failed to trust token %#lx", token);
return false;
}
bool Security::UntrustToken(Token token)
{
fixme("UntrustToken->false");
UNUSED(token);
foreach (auto &t in Tokens)
{
if (t.token == token)
{
t.TrustLevel = Untrusted;
debug("Untrusted token %#lx", token);
return true;
}
}
warn("Failed to untrust token %#lx", token);
return false;
}
bool Security::AddTrustLevel(Token token, TTL TrustLevel)
{
foreach (auto &t in Tokens)
{
if (t.token == token)
{
t.TrustLevel |= TrustLevel;
debug("Added trust level %d to token %#lx", t.TrustLevel, token);
return true;
}
}
warn("Failed to add trust level %d to token %#lx", TrustLevel, token);
return false;
}
bool Security::RemoveTrustLevel(Token token, TTL TrustLevel)
{
foreach (auto &t in Tokens)
{
if (t.token == token)
{
t.TrustLevel &= ~TrustLevel;
debug("Removed trust level %d from token %#lx", t.TrustLevel, token);
return true;
}
}
warn("Failed to remove trust level %d from token %#lx", TrustLevel, token);
return false;
}
bool Security::DestroyToken(Token token)
{
fixme("DestroyToken->false");
fixme("DestroyToken->true");
UNUSED(token);
return true;
}
bool Security::IsTokenTrusted(Token token, TTL TrustLevel)
{
foreach (auto t in Tokens)
if (t.token == token)
{
if (t.TrustLevel == TrustLevel)
return true;
else
return false;
}
warn("Failed to check trust level of token %#lx", token);
return false;
}
Security::Security()
bool Security::IsTokenTrusted(Token token, int TrustLevel)
{
trace("Initializing Tasking Security");
foreach (auto t in Tokens)
if (t.token == token)
{
if (t.TrustLevel & TrustLevel)
return true;
else
return false;
}
warn("Failed to check trust level of token %#lx", token);
return false;
}
int Security::GetTokenTrustLevel(Token token)
{
foreach (auto t in Tokens)
if (t.token == token)
return t.TrustLevel;
warn("Failed to get trust level of token %#lx", token);
return UnknownTrustLevel;
}
Security::Security() {}
Security::~Security()
{
trace("Destroying Tasking Security");
for (size_t i = 0; i < Tokens.size(); i++)
Tokens.remove(i);
}

View File

@ -17,37 +17,25 @@
#elif defined(__aarch64__)
#endif
// #define DEBUG_SCHEDULER 1
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
// #define DEBUG_TASKING 1
#ifdef DEBUG_SCHEDULER
#define schedbg(m, ...) \
#ifdef DEBUG_TASKING
#define tskdbg(m, ...) \
debug(m, ##__VA_ARGS__); \
__sync_synchronize()
#else
#define schedbg(m, ...)
#define tskdbg(m, ...)
#endif
NewLock(TaskingLock);
NewLock(SchedulerLock);
namespace Tasking
{
extern "C" SafeFunction __no_instrument_function void OneShot(int TimeSlice)
{
if (TimeSlice == 0)
TimeSlice = 10;
#if defined(__amd64__)
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x64::IRQ16, TimeSlice);
#elif defined(__i386__)
#elif defined(__aarch64__)
#endif
}
void Task::Schedule()
{
if (!StopScheduler)
OneShot(100);
TaskingScheduler_OneShot(100);
// APIC::InterruptCommandRegisterLow icr;
// icr.Vector = CPU::x64::IRQ16;
// icr.Level = APIC::APICLevel::Assert;
@ -71,9 +59,11 @@ namespace Tasking
{
if (!pcb)
return true;
if (pcb >= (PCB *)(UINTPTR_MAX - 0x1000))
if (pcb >= (PCB *)(UINTPTR_MAX - 0x1000)) /* Uninitialized pointers may have uintptr_t max value instead of nullptr. */
return true;
if (!Memory::Virtual().Check((void *)pcb))
if (pcb < (PCB *)(0x1000)) /* In this section of the memory is reserved by the kernel. */
return true;
if (!Memory::Virtual().Check((void *)pcb)) /* Check if it's mapped. */
return true;
return false;
}
@ -82,9 +72,11 @@ namespace Tasking
{
if (!tcb)
return true;
if (tcb >= (TCB *)(UINTPTR_MAX - 0x1000))
if (tcb >= (TCB *)(UINTPTR_MAX - 0x1000)) /* Uninitialized pointers may have uintptr_t max value instead of nullptr. */
return true;
if (!Memory::Virtual().Check((void *)tcb))
if (tcb < (TCB *)(0x1000)) /* In this section of the memory is reserved by the kernel. */
return true;
if (!Memory::Virtual().Check((void *)tcb)) /* Check if it's mapped. */
return true;
return false;
}
@ -126,11 +118,27 @@ namespace Tasking
{
trace("Process \"%s\"(%d) removed from the list", Process->Name, Process->ID);
// Free memory
delete ListProcess[i]->IPCHandles;
delete ListProcess[i]->IPC;
delete ListProcess[i]->ELFSymbolTable;
SecurityManager.DestroyToken(ListProcess[i]->Security.UniqueToken);
if (ListProcess[i]->Security.TrustLevel == TaskTrustLevel::User)
KernelAllocator.FreePages((void *)ListProcess[i]->PageTable, TO_PAGES(PAGE_SIZE));
// Remove the process from parent's children list
if (ListProcess[i]->Parent)
for (size_t j = 0; j < ListProcess[i]->Parent->Children.size(); j++)
{
if (ListProcess[i]->Parent->Children[j] == ListProcess[i])
{
ListProcess[i]->Parent->Children.remove(j);
break;
}
}
// Delete process directory
vfs->Delete(ListProcess[i]->ProcessDirectory, true);
// Free memory
delete ListProcess[i];
// Remove from the list
ListProcess.remove(i);
@ -182,579 +190,6 @@ namespace Tasking
}
}
#if defined(__amd64__)
SafeFunction __no_instrument_function bool Task::FindNewProcess(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
schedbg("%d processes", ListProcess.size());
#ifdef DEBUG_SCHEDULER
foreach (auto var in ListProcess)
{
schedbg("Process %d %s", var->ID, var->Name);
}
#endif
// Find a new process to execute.
foreach (PCB *pcb in ListProcess)
{
if (unlikely(InvalidPCB(pcb)))
continue;
// Check process status.
switch (pcb->Status)
{
case TaskStatus::Ready:
schedbg("Ready process (%s)%d", pcb->Name, pcb->ID);
break;
default:
schedbg("Process \"%s\"(%d) status %d", pcb->Name, pcb->ID, pcb->Status);
RemoveProcess(pcb);
continue;
}
// Get first available thread from the list.
foreach (TCB *tcb in pcb->Threads)
{
if (unlikely(InvalidTCB(tcb)))
continue;
if (tcb->Status != TaskStatus::Ready)
continue;
// Set process and thread as the current one's.
CurrentCPU->CurrentProcess = pcb;
CurrentCPU->CurrentThread = tcb;
// Success!
return true;
}
}
schedbg("No process to run.");
// No process found. Idling...
return false;
}
SafeFunction __no_instrument_function bool Task::GetNextAvailableThread(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
for (size_t i = 0; i < CurrentCPU->CurrentProcess->Threads.size(); i++)
{
// Loop until we find the current thread from the process thread list.
if (CurrentCPU->CurrentProcess->Threads[i] == CurrentCPU->CurrentThread)
{
// Check if the next thread is valid. If not, we search until we find, but if we reach the end of the list, we go to the next process.
size_t TempIndex = i;
RetryAnotherThread:
TCB *thread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
if (unlikely(InvalidTCB(thread)))
{
if (TempIndex > CurrentCPU->CurrentProcess->Threads.size())
break;
TempIndex++;
goto RetryAnotherThread;
}
schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)", CurrentCPU->CurrentProcess->Threads[i]->Name, CurrentCPU->CurrentProcess->Threads[i]->ID, thread->Name, thread->ID);
// Check if the thread is ready to be executed.
if (thread->Status != TaskStatus::Ready)
{
schedbg("Thread %d is not ready", thread->ID);
goto RetryAnotherThread;
}
// Everything is fine, we can set the new thread as the current one.
CurrentCPU->CurrentThread = thread;
schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d", thread->ID, thread->Parent->Name, CurrentCPU->CurrentProcess->Threads.size(), ListProcess.size());
// Yay! We found a new thread to execute.
return true;
}
}
return false;
}
SafeFunction __no_instrument_function bool Task::GetNextAvailableProcess(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
for (size_t i = 0; i < ListProcess.size(); i++)
{
// Loop until we find the current process from the process list.
if (ListProcess[i] == CurrentCPU->CurrentProcess)
{
// Check if the next process is valid. If not, we search until we find.
size_t TempIndex = i;
RetryAnotherProcess:
PCB *pcb = ListProcess[TempIndex + 1];
if (unlikely(InvalidPCB(pcb)))
{
if (TempIndex > ListProcess.size())
{
schedbg("Exceeded the process list.");
break;
}
TempIndex++;
schedbg("Invalid process %#lx", pcb);
goto RetryAnotherProcess;
}
else
{
schedbg("Found process %d", pcb->ID);
}
if (pcb->Status != TaskStatus::Ready)
{
schedbg("Process %d is not ready", pcb->ID);
TempIndex++;
goto RetryAnotherProcess;
}
// Everything good, now search for a thread.
for (size_t j = 0; j < pcb->Threads.size(); j++)
{
TCB *tcb = pcb->Threads[j];
if (unlikely(InvalidTCB(tcb)))
{
schedbg("Invalid thread %#lx", tcb);
continue;
}
if (tcb->Status != TaskStatus::Ready)
{
schedbg("Thread %d is not ready", tcb->ID);
continue;
}
// Success! We set as the current one and restore the stuff.
CurrentCPU->CurrentProcess = pcb;
CurrentCPU->CurrentThread = tcb;
schedbg("[cur proc+1 -> first thd] Scheduling thread %d %s->%d (Total Procs %d)", tcb->ID, tcb->Name, pcb->Threads.size(), ListProcess.size());
return true;
}
}
}
schedbg("No process to run.");
return false;
}
SafeFunction __no_instrument_function void Task::SchedulerCleanupProcesses()
{
foreach (PCB *pcb in ListProcess)
{
if (unlikely(InvalidPCB(pcb)))
continue;
RemoveProcess(pcb);
}
}
SafeFunction __no_instrument_function bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
foreach (PCB *pcb in ListProcess)
{
if (unlikely(InvalidPCB(pcb)))
continue;
if (pcb->Status != TaskStatus::Ready)
continue;
// Now do the thread search!
foreach (TCB *tcb in pcb->Threads)
{
if (unlikely(InvalidTCB(tcb)))
continue;
if (tcb->Status != TaskStatus::Ready)
continue;
// \o/ We found a new thread to execute.
CurrentCPU->CurrentProcess = pcb;
CurrentCPU->CurrentThread = tcb;
schedbg("[proc 0 -> end -> first thd] Scheduling thread %d parent of %s->%d (Procs %d)", tcb->ID, tcb->Parent->Name, pcb->Threads.size(), ListProcess.size());
return true;
}
}
return false;
}
SafeFunction __no_instrument_function void Task::WakeUpThreads(void *CPUDataPointer)
{
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
// Loop through all the processes.
foreach (PCB *pcb in ListProcess)
{
if (unlikely(InvalidPCB(pcb)))
continue;
// Check process status.
if (pcb->Status == TaskStatus::Terminated)
continue;
// Loop through all the threads.
foreach (TCB *tcb in pcb->Threads)
{
if (unlikely(InvalidTCB(tcb)))
continue;
// Check if the thread is sleeping.
if (tcb->Status != TaskStatus::Sleeping || pcb->Status == TaskStatus::Terminated)
continue;
// Check if the thread is ready to wake up.
if (tcb->Info.SleepUntil < TimeManager->GetCounter())
{
tcb->Status = TaskStatus::Ready;
if (tcb->Parent->Threads.size() == 1 && tcb->Parent->Status == TaskStatus::Sleeping)
tcb->Parent->Status = TaskStatus::Ready;
tcb->Info.SleepUntil = 0;
schedbg("Thread \"%s\"(%d) woke up.", tcb->Name, tcb->ID);
}
else
{
schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)", tcb->Name, tcb->ID, tcb->Info.SleepUntil, TimeManager->GetCounter());
}
}
}
}
SafeFunction __no_instrument_function void Task::Schedule(CPU::x64::TrapFrame *Frame)
{
SmartCriticalSection(SchedulerLock);
if (StopScheduler)
{
warn("Scheduler stopped.");
return;
}
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); // Restore kernel page table for safety reasons.
CPUData *CurrentCPU = GetCurrentCPU();
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
schedbg("%d: %ld%%", CurrentCPU->ID, GetUsage(CurrentCPU->ID));
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
int SuccessSource = 0;
#endif
#ifdef DEBUG_SCHEDULER
{
schedbg("================================================================");
schedbg("Status: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
size_t ds;
asmv("mov %%ds, %0"
: "=r"(ds));
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
schedbg("================================================================");
}
#endif
// Null or invalid process/thread? Let's find a new one to execute.
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess) || InvalidTCB(CurrentCPU->CurrentThread)))
{
schedbg("Invalid process or thread. Finding a new one.");
if (this->FindNewProcess(CurrentCPU))
goto Success;
else
goto Idle;
}
else
{
// Save current process and thread registries, gs, fs, fpu, etc...
CurrentCPU->CurrentThread->Registers = *Frame;
CPU::x64::fxsave(CurrentCPU->CurrentThread->FPU);
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
// Set the process & thread as ready if they are running.
if (CurrentCPU->CurrentProcess->Status == TaskStatus::Running)
CurrentCPU->CurrentProcess->Status = TaskStatus::Ready;
if (CurrentCPU->CurrentThread->Status == TaskStatus::Running)
CurrentCPU->CurrentThread->Status = TaskStatus::Ready;
// Loop through all threads and find which one is ready.
this->WakeUpThreads(CurrentCPU);
schedbg("Passed WakeUpThreads");
// Get next available thread from the list.
if (this->GetNextAvailableThread(CurrentCPU))
{
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
SuccessSource = 1;
#endif
goto Success;
}
schedbg("Passed GetNextAvailableThread");
// If we didn't find a thread to execute, we search for a new process.
if (this->GetNextAvailableProcess(CurrentCPU))
{
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
SuccessSource = 2;
#endif
goto Success;
}
schedbg("Passed GetNextAvailableProcess");
// Before checking from the beginning, we remove everything that is terminated.
this->SchedulerCleanupProcesses();
schedbg("Passed SchedulerCleanupProcesses");
// If we didn't find anything, we check from the start of the list. This is the last chance to find something or we go idle.
if (SchedulerSearchProcessThread(CurrentCPU))
{
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
SuccessSource = 3;
#endif
schedbg("Passed SchedulerSearchProcessThread");
goto Success;
}
else
{
schedbg("SchedulerSearchProcessThread failed. Going idle.");
goto Idle;
}
}
goto UnwantedReach; // This should never happen.
Idle:
{
CurrentCPU->CurrentProcess = IdleProcess;
CurrentCPU->CurrentThread = IdleThread;
goto Success;
}
Success:
{
schedbg("Process \"%s\"(%d) Thread \"%s\"(%d) is now running on CPU %d",
CurrentCPU->CurrentProcess->Name, CurrentCPU->CurrentProcess->ID,
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID);
CurrentCPU->CurrentProcess->Status = TaskStatus::Running;
CurrentCPU->CurrentThread->Status = TaskStatus::Running;
*Frame = CurrentCPU->CurrentThread->Registers;
// FIXME: Untested
for (int i = 0; i < 128; i++)
{
if (CurrentCPU->CurrentThread->IPHistory[i] == 0)
{
CurrentCPU->CurrentThread->IPHistory[i] = Frame->rip;
break;
}
if (i == 127)
{
for (int j = 0; j < 127; j++)
CurrentCPU->CurrentThread->IPHistory[j] = CurrentCPU->CurrentThread->IPHistory[j + 1];
CurrentCPU->CurrentThread->IPHistory[127] = Frame->rip;
}
}
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
// Not sure if this is needed, but it's better to be safe than sorry.
asmv("movq %cr3, %rax");
asmv("movq %rax, %cr3");
CPU::x64::fxrstor(CurrentCPU->CurrentThread->FPU);
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
static int sanity;
const char *Statuses[] = {
"FF0000", // Unknown
"AAFF00", // Ready
"00AA00", // Running
"FFAA00", // Sleeping
"FFAA00", // Waiting
"FF0088", // Stopped
"FF0000", // Terminated
};
const char *StatusesSign[] = {
"U", // Unknown
"R", // Ready
"r", // Running
"S", // Sleeping
"W", // Waiting
"s", // Stopped
"T", // Terminated
};
const char *SuccessSourceStrings[] = {
"Unknown",
"GetNextAvailableThread",
"GetNextAvailableProcess",
"SchedulerSearchProcessThread",
};
for (int i = 0; i < 340; i++)
for (int j = 0; j < 200; j++)
Display->SetPixel(i, j, 0x222222, 0);
uint32_t tmpX, tmpY;
Display->GetBufferCursor(0, &tmpX, &tmpY);
Display->SetBufferCursor(0, 0, 0);
foreach (auto var in ListProcess)
{
int Status = var->Status;
printf("\e%s-> \eAABBCC%s\eCCCCCC[%d] \e00AAAA%s\n",
Statuses[Status], var->Name, Status, StatusesSign[Status]);
foreach (auto var2 in var->Threads)
{
Status = var2->Status;
printf(" \e%s-> \eAABBCC%s\eCCCCCC[%d] \e00AAAA%s\n\eAABBCC",
Statuses[Status], var2->Name, Status, StatusesSign[Status]);
}
}
printf("%d - SOURCE: %s", sanity++, SuccessSourceStrings[SuccessSource]);
if (sanity > 1000)
sanity = 0;
Display->SetBufferCursor(0, tmpX, tmpY);
Display->SetBuffer(0);
for (int i = 0; i < 50000; i++)
inb(0x80);
#endif
switch (CurrentCPU->CurrentProcess->Security.TrustLevel)
{
case TaskTrustLevel::System:
case TaskTrustLevel::Idle:
case TaskTrustLevel::Kernel:
// wrmsr(MSR_SHADOW_GS_BASE, (uint64_t)CurrentCPU->CurrentThread);
break;
case TaskTrustLevel::User:
// wrmsr(MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->gs);
break;
default:
error("Unknown trust level %d.", CurrentCPU->CurrentProcess->Security.TrustLevel);
break;
}
goto End;
}
UnwantedReach:
{
warn("Unwanted reach!");
OneShot(100);
goto RealEnd;
}
End:
{
// TODO: This is not accurate.
if (CurrentCPU->CurrentProcess->Security.TrustLevel == TaskTrustLevel::User)
UpdateUserTime(&CurrentCPU->CurrentProcess->Info);
else
UpdateKernelTime(&CurrentCPU->CurrentProcess->Info);
if (CurrentCPU->CurrentThread->Security.TrustLevel == TaskTrustLevel::User)
UpdateUserTime(&CurrentCPU->CurrentThread->Info);
else
UpdateKernelTime(&CurrentCPU->CurrentThread->Info);
UpdateUsage(&CurrentCPU->CurrentProcess->Info, CurrentCPU->ID);
UpdateUsage(&CurrentCPU->CurrentThread->Info, CurrentCPU->ID);
OneShot(CurrentCPU->CurrentThread->Info.Priority);
}
{
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID,
CurrentCPU->CurrentThread->Registers.rip,
CurrentCPU->CurrentThread->Registers.rbp,
CurrentCPU->CurrentThread->Registers.rsp);
}
{
schedbg("================================================================");
schedbg("Technical Informations on Thread %s[%ld]:", CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID);
uint64_t ds;
asmv("mov %%ds, %0"
: "=r"(ds));
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
Frame->ss, Frame->cs, ds);
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
schedbg("================================================================");
}
RealEnd:
{
__sync_synchronize(); // TODO: Is this really needed?
}
}
SafeFunction __no_instrument_function void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame) { this->Schedule(Frame); }
#elif defined(__i386__)
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::SchedulerCleanupProcesses()
{
fixme("unimplemented");
}
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::Schedule(void *Frame)
{
fixme("unimplemented");
}
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
#elif defined(__aarch64__)
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::SchedulerCleanupProcesses()
{
fixme("unimplemented");
}
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
{
fixme("unimplemented");
}
SafeFunction void Task::Schedule(void *Frame)
{
fixme("unimplemented");
}
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
#endif
void ThreadDoExit()
{
// TODO: How I can lock the scheduler without causing a deadlock?
@ -789,6 +224,28 @@ namespace Tasking
CPU::Halt();
}
void Task::WaitForProcessStatus(PCB *pcb, TaskStatus status)
{
if (!pcb)
return;
if (pcb->Status == TaskStatus::UnknownStatus)
return;
debug("Waiting for process \"%s\"(%d) to reach status: %d", pcb->Name, pcb->ID, status);
while (pcb->Status != status)
CPU::Halt();
}
void Task::WaitForThreadStatus(TCB *tcb, TaskStatus status)
{
if (!tcb)
return;
if (tcb->Status == TaskStatus::UnknownStatus)
return;
debug("Waiting for thread \"%s\"(%d) to reach status: %d", tcb->Name, tcb->ID, status);
while (tcb->Status != status)
CPU::Halt();
}
void Task::Sleep(uint64_t Milliseconds)
{
SmartCriticalSection(TaskingLock);
@ -797,11 +254,11 @@ namespace Tasking
if (thread->Parent->Threads.size() == 1)
thread->Parent->Status = TaskStatus::Sleeping;
thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds);
schedbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil);
// OneShot(1);
tskdbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil);
// TaskingScheduler_OneShot(1);
// IRQ16
TaskingLock.Unlock();
asmv("int $0x30");
asmv("int $0x30"); /* This will trigger the IRQ16 instantly so we won't execute the next instruction */
}
void Task::SignalShutdown()
@ -811,11 +268,59 @@ namespace Tasking
// This should hang until all processes are terminated
}
void Task::RevertProcessCreation(PCB *Process)
{
for (size_t i = 0; i < ListProcess.size(); i++)
{
if (ListProcess[i] == Process)
{
SecurityManager.DestroyToken(Process->Security.UniqueToken);
if (Process->Security.TrustLevel == TaskTrustLevel::User)
KernelAllocator.FreePages((void *)Process->PageTable, TO_PAGES(PAGE_SIZE));
if (Process->Parent)
for (size_t j = 0; j < Process->Parent->Children.size(); j++)
{
if (Process->Parent->Children[j] == Process)
{
Process->Parent->Children.remove(j);
break;
}
}
delete Process->IPC;
delete Process->ELFSymbolTable;
delete Process;
ListProcess.remove(i);
NextPID--;
break;
}
}
}
void Task::RevertThreadCreation(TCB *Thread)
{
for (size_t j = 0; j < Thread->Parent->Threads.size(); j++)
{
if (Thread->Parent->Threads[j] == Thread)
{
Thread->Parent->Threads.remove(j);
break;
}
}
delete Thread->Stack;
delete Thread->Memory;
SecurityManager.DestroyToken(Thread->Security.UniqueToken);
delete Thread;
NextTID--;
}
TCB *Task::CreateThread(PCB *Parent,
IP EntryPoint,
const char **argv,
const char **envp,
Vector<AuxiliaryVector> &auxv,
const Vector<AuxiliaryVector> &auxv,
IPOffset Offset,
TaskArchitecture Architecture,
TaskCompatibility Compatibility)
@ -848,10 +353,13 @@ namespace Tasking
Thread->Offset = Offset;
Thread->ExitCode = 0xdead;
Thread->Status = TaskStatus::Ready;
Thread->Memory = new Memory::MemMgr(Parent->PageTable);
Thread->Memory = new Memory::MemMgr(Parent->PageTable, Parent->memDirectory);
Thread->FPU = (CPU::x64::FXState *)Thread->Memory->RequestPages(TO_PAGES(sizeof(CPU::x64::FXState)));
memset(Thread->FPU, 0, FROM_PAGES(TO_PAGES(sizeof(CPU::x64::FXState))));
Thread->Security.TrustLevel = Parent->Security.TrustLevel;
Thread->Security.UniqueToken = SecurityManager.CreateToken();
// TODO: Is really a good idea to use the FPU in kernel mode?
Thread->FPU->mxcsr = 0b0001111110000000;
Thread->FPU->mxcsrmask = 0b1111111110111111;
@ -881,12 +389,11 @@ namespace Tasking
case TaskTrustLevel::System:
warn("Trust level not supported.");
[[fallthrough]];
case TaskTrustLevel::Idle:
case TaskTrustLevel::Kernel:
{
Thread->Stack = new Memory::StackGuard(false, Parent->PageTable);
#if defined(__amd64__)
SecurityManager.TrustToken(Thread->Security.UniqueToken, TokenTrustLevel::TrustedByKernel);
SecurityManager.TrustToken(Thread->Security.UniqueToken, TTL::TrustedByKernel);
Thread->GSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_GS_BASE);
Thread->FSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_FS_BASE);
Thread->Registers.cs = GDT_KERNEL_CODE;
@ -905,7 +412,7 @@ namespace Tasking
{
Thread->Stack = new Memory::StackGuard(true, Parent->PageTable);
#if defined(__amd64__)
SecurityManager.TrustToken(Thread->Security.UniqueToken, TokenTrustLevel::Untrusted);
SecurityManager.TrustToken(Thread->Security.UniqueToken, TTL::Untrusted);
Thread->GSBase = 0;
Thread->FSBase = 0;
Thread->Registers.cs = GDT_USER_CODE;
@ -981,8 +488,13 @@ namespace Tasking
Stack64--;
*Stack64 = AT_NULL;
// auxv_array is initialized with auxv elements. If the array is empty then we add a null terminator
Vector<AuxiliaryVector> auxv_array = auxv;
if (auxv_array.size() == 0)
auxv_array.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
// Store auxillary vector
foreach (AuxiliaryVector var in auxv)
foreach (AuxiliaryVector var in auxv_array)
{
// Subtract the size of the auxillary vector
Stack64 -= sizeof(Elf64_auxv_t) / sizeof(uintptr_t);
@ -1052,7 +564,7 @@ namespace Tasking
#elif defined(__i386__)
#elif defined(__aarch64__)
#endif
#ifdef DEBUG_SCHEDULER
#ifdef DEBUG_TASKING
DumpData(Thread->Name, Thread->Stack, STACK_SIZE);
#endif
break;
@ -1067,9 +579,6 @@ namespace Tasking
}
}
Thread->Security.TrustLevel = Parent->Security.TrustLevel;
// Thread->Security.UniqueToken = SecurityManager.CreateToken();
Thread->Info = {};
Thread->Info.SpawnTime = CPU::Counter();
Thread->Info.Year = 0;
@ -1083,7 +592,7 @@ namespace Tasking
Thread->Info.Usage[i] = 0;
Thread->Info.Affinity[i] = true;
}
Thread->Info.Priority = 10;
Thread->Info.Priority = TaskPriority::Normal;
Thread->Info.Architecture = Architecture;
Thread->Info.Compatibility = Compatibility;
@ -1128,19 +637,22 @@ namespace Tasking
Process->Status = TaskStatus::Ready;
Process->Security.TrustLevel = TrustLevel;
// Process->Security.UniqueToken = SecurityManager.CreateToken();
Process->Security.UniqueToken = SecurityManager.CreateToken();
Process->IPCHandles = new HashMap<InterProcessCommunication::IPCPort, uintptr_t>;
char ProcFSName[16];
sprintf(ProcFSName, "%ld", Process->ID);
Process->ProcessDirectory = vfs->Create(ProcFSName, VirtualFileSystem::NodeFlags::DIRECTORY, ProcFS);
Process->memDirectory = vfs->Create("mem", VirtualFileSystem::NodeFlags::DIRECTORY, Process->ProcessDirectory);
Process->IPC = new InterProcessCommunication::IPC((void *)Process);
switch (TrustLevel)
{
case TaskTrustLevel::System:
warn("Trust level not supported.");
[[fallthrough]];
case TaskTrustLevel::Idle:
case TaskTrustLevel::Kernel:
{
SecurityManager.TrustToken(Process->Security.UniqueToken, TokenTrustLevel::TrustedByKernel);
SecurityManager.TrustToken(Process->Security.UniqueToken, TTL::TrustedByKernel);
#if defined(__amd64__)
if (!DoNotCreatePageTable)
Process->PageTable = (Memory::PageTable4 *)CPU::x64::readcr3().raw;
@ -1151,7 +663,7 @@ namespace Tasking
}
case TaskTrustLevel::User:
{
SecurityManager.TrustToken(Process->Security.UniqueToken, TokenTrustLevel::Untrusted);
SecurityManager.TrustToken(Process->Security.UniqueToken, TTL::Untrusted);
#if defined(__amd64__)
if (!DoNotCreatePageTable)
{
@ -1187,7 +699,7 @@ namespace Tasking
Process->Info.Usage[i] = 0;
Process->Info.Affinity[i] = true;
}
Process->Info.Priority = 10;
Process->Info.Priority = TaskPriority::Normal;
debug("Process page table: %#lx", Process->PageTable);
debug("Created process \"%s\"(%d) in process \"%s\"(%d)",
@ -1229,8 +741,7 @@ namespace Tasking
TaskArchitecture Arch = TaskArchitecture::ARM64;
#endif
PCB *kproc = CreateProcess(nullptr, "Kernel", TaskTrustLevel::Kernel);
Vector<AuxiliaryVector> auxv;
TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, auxv, 0, Arch);
TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, Vector<AuxiliaryVector>(), 0, Arch);
kthrd->Rename("Main Thread");
debug("Created Kernel Process: %s and Thread: %s", kproc->Name, kthrd->Name);
TaskingLock.Lock(__FUNCTION__);
@ -1277,15 +788,14 @@ namespace Tasking
}
TaskingLock.Unlock();
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskTrustLevel::Idle);
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskTrustLevel::Kernel);
for (int i = 0; i < SMP::CPUCores; i++)
{
Vector<AuxiliaryVector> auxv;
IdleThread = CreateThread(IdleProcess, reinterpret_cast<uintptr_t>(IdleProcessLoop), nullptr, nullptr, auxv);
IdleThread = CreateThread(IdleProcess, reinterpret_cast<uintptr_t>(IdleProcessLoop));
char IdleName[16];
sprintf(IdleName, "Idle Thread %d", i);
IdleThread->Rename(IdleName);
IdleThread->SetPriority(1);
IdleThread->SetPriority(Idle);
break;
}
debug("Tasking Started");
@ -1310,23 +820,21 @@ namespace Tasking
{
SmartCriticalSection(TaskingLock);
trace("Stopping tasking");
foreach (auto Process in ListProcess)
foreach (PCB *Process in ListProcess)
{
for (auto &Thread : Process->Threads)
{
foreach (TCB *Thread in Process->Threads)
Thread->Status = TaskStatus::Terminated;
}
Process->Status = TaskStatus::Terminated;
}
TaskingLock.Unlock();
SchedulerLock.Unlock();
while (ListProcess.size() > 0)
{
trace("Waiting for %d processes to terminate", ListProcess.size());
int NotTerminated = 0;
foreach (auto Process in ListProcess)
foreach (PCB *Process in ListProcess)
{
debug("Process %s(%d) is still running (or waiting to be removed status %#lx)", Process->Name, Process->ID, Process->Status);
if (Process->Status == TaskStatus::Terminated)
@ -1335,7 +843,7 @@ namespace Tasking
}
if (NotTerminated == 0)
break;
OneShot(100);
TaskingScheduler_OneShot(100);
}
trace("Tasking stopped");

View File

@ -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

View File

@ -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);

View File

@ -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]

View File

@ -3,6 +3,7 @@
#include <types.h>
#include <filesystem.hpp>
#include <task.hpp>
#include <elf.h>
@ -21,9 +22,10 @@ namespace Execute
enum ExStatus
{
OK,
Unknown,
OK,
Unsupported,
GenericError,
InvalidFile,
InvalidFileFormat,
InvalidFileHeader,
@ -39,21 +41,78 @@ namespace Execute
Tasking::TCB *Thread;
};
struct SharedLibraries
{
char Identifier[256];
uint64_t Timeout;
long RefCount;
void *Address;
void *MemoryImage;
size_t Length;
};
struct ELFBaseLoad
{
bool Success;
SpawnData sd;
Tasking::IP InstructionPointer;
/* This should be deleted after copying the allocated pages to the thread
Intended to be used only inside BaseLoad.cpp */
Memory::MemMgr *TmpMem;
/* Same as above, for BaseLoad.cpp only */
Vector<AuxiliaryVector> auxv;
};
BinaryType GetBinaryType(void *Image);
BinaryType GetBinaryType(char *Path);
SpawnData Spawn(char *Path, const char **argv, const char **envp);
void *ELFLoadRel(Elf64_Ehdr *Header);
void ELFLoadExec(void *BaseImage,
size_t Length,
Elf64_Ehdr *ELFHeader,
Memory::Virtual &pva,
SpawnData *ret,
char *Path,
Tasking::PCB *Process,
const char **argv,
const char **envp,
Tasking::TaskArchitecture Arch,
Tasking::TaskCompatibility Comp);
ELFBaseLoad ELFLoad(char *Path, const char **argv, const char **envp,
Tasking::TaskCompatibility Compatibility = Tasking::TaskCompatibility::Native);
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header);
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index);
char *GetELFStringTable(Elf64_Ehdr *Header);
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset);
void *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name);
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index);
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag);
/**
* @brief Create a ELF Memory Image
*
* @param mem The memory manager to use
* @param pV Memory::Virtual object to use
* @param ElfFile ELF file loaded in memory (FULL FILE)
* @param Length Length of @p ElfFile
* @return void* The Memory Image
*/
void *ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length);
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &pV, const char *Interpreter);
ELFBaseLoad ELFLoadRel(void *ElfFile,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process);
ELFBaseLoad ELFLoadExec(void *ElfFile,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process);
ELFBaseLoad ELFLoadDyn(void *ElfFile,
VirtualFileSystem::File *ExFile,
Tasking::PCB *Process);
void StartExecuteService();
SharedLibraries *AddLibrary(char *Identifier,
void *ElfImage,
size_t Length,
const Memory::Virtual &pV = Memory::Virtual());
void SearchLibrary(char *Identifier);
}
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__

View File

@ -3,90 +3,75 @@
#include <types.h>
#include <smartptr.hpp>
#include <vector.hpp>
// show debug messages
// #define DEBUG_FILESYSTEM 1
#ifdef DEBUG_FILESYSTEM
#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__)
#else
#define vfsdbg(m, ...)
#endif
namespace FileSystem
namespace VirtualFileSystem
{
#define FILENAME_LENGTH 256
struct FileSystemNode;
struct Node;
typedef size_t (*OperationMount)(const char *, unsigned long, const void *);
typedef size_t (*OperationUmount)(int);
typedef size_t (*OperationRead)(FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer);
typedef size_t (*OperationWrite)(FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer);
typedef void (*OperationOpen)(FileSystemNode *Node, uint8_t Mode, uint8_t Flags);
typedef void (*OperationClose)(FileSystemNode *Node);
typedef size_t (*OperationRead)(Node *node, size_t Offset, size_t Size, uint8_t *Buffer);
typedef size_t (*OperationWrite)(Node *node, size_t Offset, size_t Size, uint8_t *Buffer);
typedef void (*OperationOpen)(Node *node, uint8_t Mode, uint8_t Flags);
typedef void (*OperationClose)(Node *node);
typedef size_t (*OperationSync)(void);
typedef void (*OperationCreate)(FileSystemNode *Node, char *Name, uint16_t NameLength);
typedef void (*OperationMkdir)(FileSystemNode *Node, char *Name, uint16_t NameLength);
typedef void (*OperationCreate)(Node *node, char *Name, uint16_t NameLength);
typedef void (*OperationMkdir)(Node *node, char *Name, uint16_t NameLength);
#define MountFSFunction(name) size_t name(const char *unknown0, unsigned long unknown1, const uint8_t *unknown2)
#define UMountFSFunction(name) size_t name(int unknown0)
#define ReadFSFunction(name) size_t name(FileSystem::FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer)
#define WriteFSFunction(name) size_t name(FileSystem::FileSystemNode *Node, size_t Offset, size_t Size, uint8_t *Buffer)
#define OpenFSFunction(name) void name(FileSystem::FileSystemNode *Node, uint8_t Mode, uint8_t Flags)
#define CloseFSFunction(name) void name(FileSystem::FileSystemNode *Node)
#define ReadFSFunction(name) size_t name(VirtualFileSystem::Node *node, size_t Offset, size_t Size, uint8_t *Buffer)
#define WriteFSFunction(name) size_t name(VirtualFileSystem::Node *node, size_t Offset, size_t Size, uint8_t *Buffer)
#define OpenFSFunction(name) void name(VirtualFileSystem::Node *node, uint8_t Mode, uint8_t Flags)
#define CloseFSFunction(name) void name(VirtualFileSystem::Node *node)
#define SyncFSFunction(name) size_t name(void)
#define CreateFSFunction(name) void name(FileSystem::FileSystemNode *Node, char *Name, uint16_t NameLength)
#define MkdirFSFunction(name) void name(FileSystem::FileSystemNode *Node, char *Name, uint16_t NameLength)
#define CreateFSFunction(name) void name(VirtualFileSystem::Node *node, char *Name, uint16_t NameLength)
#define MkdirFSFunction(name) void name(VirtualFileSystem::Node *node, char *Name, uint16_t NameLength)
enum FileStatus
{
OK = 0,
NOT_FOUND = 1,
ACCESS_DENIED = 2,
INVALID_NAME = 3,
INVALID_PARAMETER = 4,
INVALID_HANDLE = 5,
INVALID_PATH = 6,
INVALID_FILE = 7,
INVALID_DEVICE = 8,
NOT_EMPTY = 9,
NOT_SUPPORTED = 10,
INVALID_DRIVE = 11,
VOLUME_IN_USE = 12,
TIMEOUT = 13,
NO_MORE_FILES = 14,
END_OF_FILE = 15,
FILE_EXISTS = 16,
PIPE_BUSY = 17,
PIPE_DISCONNECTED = 18,
MORE_DATA = 19,
NO_DATA = 20,
PIPE_NOT_CONNECTED = 21,
MORE_ENTRIES = 22,
DIRECTORY_NOT_EMPTY = 23,
NOT_A_DIRECTORY = 24,
FILE_IS_A_DIRECTORY = 25,
DIRECTORY_NOT_ROOT = 26,
DIRECTORY_NOT_EMPTY_2 = 27,
END_OF_MEDIA = 28,
NO_MEDIA = 29,
UNRECOGNIZED_MEDIA = 30,
SECTOR_NOT_FOUND = 31
OK,
NotFound,
NotEmpty,
NotSupported,
AccessDenied,
Timeout,
SectorNotFound,
PartiallyCompleted,
InvalidName,
InvalidParameter,
InvalidHandle,
InvalidPath,
InvalidDevice,
InvalidOperator,
InvalidNode,
FileExists,
FileIsADirectory,
FileIsInvalid,
DirectoryNotEmpty,
NotADirectory,
UnknownFileStatusError
};
enum NodeFlags
{
FS_ERROR = 0x0,
FS_FILE = 0x01,
FS_DIRECTORY = 0x02,
FS_CHARDEVICE = 0x03,
FS_BLOCKDEVICE = 0x04,
FS_PIPE = 0x05,
FS_SYMLINK = 0x06,
FS_MOUNTPOINT = 0x08
NODE_FLAG_ERROR = 0x0,
FILE = 0x01,
DIRECTORY = 0x02,
CHARDEVICE = 0x03,
BLOCKDEVICE = 0x04,
PIPE = 0x05,
SYMLINK = 0x06,
MOUNTPOINT = 0x08
};
struct FileSystemOperations
@ -102,62 +87,67 @@ namespace FileSystem
OperationMkdir MakeDirectory = nullptr;
};
struct FileSystemNode
struct Node
{
char Name[FILENAME_LENGTH];
uint64_t IndexNode = 0;
uint64_t Mask = 0;
uint64_t Mode = 0;
int Flags = NodeFlags::FS_ERROR;
NodeFlags Flags = NodeFlags::NODE_FLAG_ERROR;
uint64_t UserIdentifier = 0, GroupIdentifier = 0;
uintptr_t Address = 0;
size_t Length = 0;
FileSystemNode *Parent = nullptr;
Node *Parent = nullptr;
FileSystemOperations *Operator = nullptr;
/* For root node:
0 - root "/"
1 - etc
...
*/
Vector<FileSystemNode *> Children;
Vector<Node *> Children;
};
struct FILE
struct File
{
const char *Name;
char Name[FILENAME_LENGTH];
FileStatus Status;
FileSystemNode *Node;
Node *node;
};
/* Manage / etc.. */
class Virtual
{
private:
FileSystemNode *FileSystemRoot = nullptr;
Node *FileSystemRoot = nullptr;
public:
FileSystemNode *GetRootNode() { return FileSystemRoot; }
FILE *ConvertNodeToFILE(FileSystemNode *Node)
{
FILE *File = new FILE;
File->Name = Node->Name;
File->Status = FileStatus::OK;
File->Node = Node;
return File;
}
char *GetPathFromNode(FileSystemNode *Node);
FileSystemNode *GetNodeFromPath(FileSystemNode *Parent, const char *Path);
char *NormalizePath(FileSystemNode *Parent, const char *Path);
shared_ptr<char> GetPathFromNode(Node *node);
Node *GetNodeFromPath(const char *Path, Node *Parent = nullptr);
shared_ptr<File> ConvertNodeToFILE(Node *node);
FileStatus FileExists(FileSystemNode *Parent, const char *Path);
FILE *Mount(FileSystemOperations *Operator, const char *Path);
FileStatus Unmount(FILE *File);
FILE *Open(const char *Path, FileSystemNode *Parent = nullptr);
size_t Read(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size);
size_t Write(FILE *File, size_t Offset, uint8_t *Buffer, size_t Size);
FileStatus Close(FILE *File);
FileSystemNode *CreateRoot(FileSystemOperations *Operator, const char *RootName);
FileSystemNode *Create(FileSystemNode *Parent, const char *Path);
Node *GetParent(const char *Path, Node *Parent);
Node *GetRootNode() { return FileSystemRoot; }
Node *AddNewChild(const char *Name, Node *Parent);
Node *GetChild(const char *Name, Node *Parent);
FileStatus RemoveChild(const char *Name, Node *Parent);
shared_ptr<char> NormalizePath(const char *Path, Node *Parent = nullptr);
bool PathExists(const char *Path, Node *Parent = nullptr);
Node *CreateRoot(const char *RootName, FileSystemOperations *Operator);
Node *Create(const char *Path, NodeFlags Flag, Node *Parent = nullptr);
FileStatus Delete(const char *Path, bool Recursive = false, Node *Parent = nullptr);
FileStatus Delete(Node *Path, bool Recursive = false, Node *Parent = nullptr);
shared_ptr<File> Mount(const char *Path, FileSystemOperations *Operator);
FileStatus Unmount(shared_ptr<File> File);
size_t Read(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size);
size_t Write(shared_ptr<File> File, size_t Offset, uint8_t *Buffer, size_t Size);
shared_ptr<File> Open(const char *Path, Node *Parent = nullptr);
FileStatus Close(shared_ptr<File> File);
Virtual();
~Virtual();

View File

@ -5,7 +5,7 @@
#include <filesystem.hpp>
namespace FileSystem
namespace VirtualFileSystem
{
class EXT2
{

View File

@ -5,7 +5,7 @@
#include <filesystem.hpp>
namespace FileSystem
namespace VirtualFileSystem
{
class FAT
{

View File

@ -5,7 +5,7 @@
#include <filesystem.hpp>
namespace FileSystem
namespace VirtualFileSystem
{
class Initrd
{

View File

@ -5,13 +5,13 @@
#include <filesystem.hpp>
namespace FileSystem
namespace VirtualFileSystem
{
/* Manage /system/dev */
class Device
{
public:
FileSystemNode *AddFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Node *AddFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Device();
~Device();
};
@ -20,7 +20,7 @@ namespace FileSystem
class Mount
{
public:
FileSystemNode *MountFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name);
Node *MountFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name);
void DetectAndMountFS(void *drive);
Mount();
~Mount();
@ -38,7 +38,7 @@ namespace FileSystem
class Driver
{
public:
FileSystemNode *AddDriver(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Node *AddDriver(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Driver();
~Driver();
};
@ -47,7 +47,7 @@ namespace FileSystem
class Network
{
public:
FileSystemNode *AddNetworkCard(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Node *AddNetworkCard(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Network();
~Network();
};

View File

@ -5,7 +5,7 @@
#include <filesystem.hpp>
namespace FileSystem
namespace VirtualFileSystem
{
class USTAR
{

View File

@ -1,5 +1,7 @@
#pragma once
#define HASHMAP_ERROR -0x8A50
template <typename K, typename V>
class HashNode
{
@ -33,6 +35,15 @@ public:
DummyNode = new HashNode<K, V>(-1, -1);
}
~HashMap()
{
for (int i = 0; i < HashMapCapacity; i++)
if (Nodes[i] != nullptr)
delete Nodes[i];
delete[] Nodes;
delete DummyNode;
}
int HashCode(K Key) { return Key % HashMapCapacity; }
void AddNode(K Key, V Value)
@ -67,7 +78,7 @@ public:
Index++;
Index %= HashMapCapacity;
}
return 0xdeadbeef;
return HASHMAP_ERROR;
}
V Get(int Key)
@ -78,14 +89,14 @@ public:
while (Nodes[Index] != nullptr)
{
if (Iterate++ > HashMapCapacity)
return 0xdeadbeef;
return HASHMAP_ERROR;
if (Nodes[Index]->Key == (K)Key)
return Nodes[Index]->Value;
Index++;
Index %= HashMapCapacity;
}
return 0xdeadbeef;
return HASHMAP_ERROR;
}
int Size() { return HashMapSize; }

View File

@ -2,75 +2,72 @@
#define __FENNIX_KERNEL_IPC_H__
#include <types.h>
#include <filesystem.hpp>
#include <vector.hpp>
#include <memory.hpp>
#include <lock.hpp>
namespace InterProcessCommunication
{
typedef int IPCPort;
typedef int IPCID;
enum IPCOperationType
enum IPCType
{
IPCOperationNone,
IPCOperationWrite,
IPCOperationRead
IPCNone,
IPCMessagePassing,
IPCPort,
IPCSharedMemory,
IPCPipe,
IPCSocket
};
enum IPCErrorCode
{
IPCUnknown,
IPCError = -1,
IPCSuccess,
IPCNotListening,
IPCTimeout,
IPCInvalidPort,
IPCPortInUse,
IPCPortNotRegistered,
IPCAlreadyAllocated,
IPCNotAllocated,
IPCIDInUse,
IPCIDNotRegistered,
IPCIDNotFound
};
typedef struct
struct IPCHandle
{
int ID;
IPCID ID;
long Length;
uint8_t *Buffer;
bool Listening;
IPCOperationType Operation;
VirtualFileSystem::Node *Node;
IPCErrorCode Error;
LockClass Lock;
} IPCHandle;
typedef struct
{
int ID;
long Length;
IPCOperationType Operation;
IPCErrorCode Error;
uint8_t *Buffer;
// Reserved
IPCHandle *HandleBuffer;
} __attribute__((packed)) IPCSyscallHandle;
struct IPCError
{
uint64_t ErrorCode;
};
class IPC
{
private:
NewLock(IPCLock);
IPCID NextID = 0;
Vector<IPCHandle *> Handles;
Memory::MemMgr *mem;
VirtualFileSystem::Node *IPCNode;
void *Process;
public:
IPC();
IPC(void *Process);
~IPC();
IPCHandle *RegisterHandle(IPCPort Port);
IPCError Listen(IPCPort Port);
IPCHandle *Wait(IPCPort Port);
IPCError Read(unsigned long /* Tasking::UPID */ ID, IPCPort Port, uint8_t *&Buffer, long &Size);
IPCError Write(unsigned long /* Tasking::UPID */ ID, IPCPort Port, uint8_t *Buffer, long Size);
IPCHandle *Create(IPCType Type, char UniqueToken[16]);
IPCErrorCode Destroy(IPCID ID);
IPCErrorCode Read(IPCID ID, uint8_t *Buffer, long Size);
IPCErrorCode Write(IPCID ID, uint8_t *Buffer, long Size);
IPCErrorCode Listen(IPCID ID);
IPCHandle *Wait(IPCID ID);
IPCErrorCode Allocate(IPCID ID, long Size);
IPCErrorCode Deallocate(IPCID ID);
};
}
extern InterProcessCommunication::IPC *ipc;
#endif // !__FENNIX_KERNEL_IPC_H__

View File

@ -2,6 +2,7 @@
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#ifdef __cplusplus
#include <filesystem.hpp>
#include <boot/binfo.h>
#include <bitmap.hpp>
#include <vector.hpp>
@ -634,28 +635,32 @@ namespace Memory
class MemMgr
{
private:
Bitmap PageBitmap;
PageTable4 *PageTable;
public:
struct AllocatedPages
{
void *Address;
size_t PageCount;
};
Vector<AllocatedPages> AllocatedPagesList;
public:
Vector<AllocatedPages> GetAllocatedPagesList() { return AllocatedPagesList; }
uint64_t GetAllocatedMemorySize();
bool Add(void *Address, size_t Count);
void *RequestPages(size_t Count);
void *RequestPages(size_t Count, bool User = false);
void FreePages(void *Address, size_t Count);
MemMgr(PageTable4 *PageTable = nullptr);
void DetachAddress(void *Address);
MemMgr(PageTable4 *PageTable = nullptr, VirtualFileSystem::Node *Directory = nullptr);
~MemMgr();
private:
Bitmap PageBitmap;
PageTable4 *PageTable;
VirtualFileSystem::Node *Directory;
Vector<AllocatedPages> AllocatedPagesList;
};
}

View File

@ -29,31 +29,31 @@
template <class T>
class smart_ptr
{
T *RealPointer;
T *m_RealPointer;
public:
explicit smart_ptr(T *p = nullptr)
explicit smart_ptr(T *Pointer = nullptr)
{
spdbg("Smart pointer created (%#lx)", RealPointer);
RealPointer = p;
spdbg("Smart pointer created (%#lx)", m_RealPointer);
m_RealPointer = Pointer;
}
~smart_ptr()
{
spdbg("Smart pointer deleted (%#lx)", RealPointer);
delete (RealPointer);
spdbg("Smart pointer deleted (%#lx)", m_RealPointer);
delete (m_RealPointer);
}
T &operator*()
{
spdbg("Smart pointer dereferenced (%#lx)", RealPointer);
return *RealPointer;
spdbg("Smart pointer dereferenced (%#lx)", m_RealPointer);
return *m_RealPointer;
}
T *operator->()
{
spdbg("Smart pointer dereferenced (%#lx)", RealPointer);
return RealPointer;
spdbg("Smart pointer dereferenced (%#lx)", m_RealPointer);
return m_RealPointer;
}
};
@ -67,6 +67,11 @@ class unique_ptr
{
};
template <class T>
class weak_ptr
{
};
template <typename T>
class shared_ptr
{
@ -74,81 +79,190 @@ private:
class Counter
{
private:
unsigned int RefCount{};
unsigned int m_RefCount{};
public:
Counter() : RefCount(0){};
Counter() : m_RefCount(0) { spdbg("Counter %#lx created", this); };
Counter(const Counter &) = delete;
Counter &operator=(const Counter &) = delete;
~Counter() {}
void Reset() { RefCount = 0; }
unsigned int Get() { return RefCount; }
void operator++() { RefCount++; }
void operator++(int) { RefCount++; }
void operator--() { RefCount--; }
void operator--(int) { RefCount--; }
~Counter() { spdbg("Counter %#lx deleted", this); }
void Reset()
{
m_RefCount = 0;
spdbg("Counter reset");
}
unsigned int Get()
{
return m_RefCount;
spdbg("Counter returned");
}
void operator++()
{
m_RefCount++;
spdbg("Counter incremented");
}
void operator++(int)
{
m_RefCount++;
spdbg("Counter incremented");
}
void operator--()
{
m_RefCount--;
spdbg("Counter decremented");
}
void operator--(int)
{
m_RefCount--;
spdbg("Counter decremented");
}
};
Counter *ReferenceCounter;
T *RealPointer;
Counter *m_ReferenceCounter;
T *m_RealPointer;
public:
explicit shared_ptr(T *Pointer = nullptr)
{
spdbg("Shared pointer created (%#lx)", RealPointer);
RealPointer = Pointer;
ReferenceCounter = new Counter();
m_RealPointer = Pointer;
m_ReferenceCounter = new Counter();
spdbg("[%#lx] Shared pointer created (ptr=%#lx, ref=%#lx)", this, Pointer, m_ReferenceCounter);
if (Pointer)
(*ReferenceCounter)++;
(*m_ReferenceCounter)++;
}
shared_ptr(shared_ptr<T> &SPtr)
{
spdbg("Shared pointer copied (%#lx)", RealPointer);
RealPointer = SPtr.RealPointer;
ReferenceCounter = SPtr.ReferenceCounter;
(*ReferenceCounter)++;
spdbg("[%#lx] Shared pointer copied (ptr=%#lx, ref=%#lx)", this, SPtr.m_RealPointer, SPtr.m_ReferenceCounter);
m_RealPointer = SPtr.m_RealPointer;
m_ReferenceCounter = SPtr.m_ReferenceCounter;
(*m_ReferenceCounter)++;
}
~shared_ptr()
{
spdbg("Shared pointer deleted (%#lx)", RealPointer);
(*ReferenceCounter)--;
if (ReferenceCounter->Get() == 0)
spdbg("[%#lx] Shared pointer destructor called", this);
(*m_ReferenceCounter)--;
if (m_ReferenceCounter->Get() == 0)
{
delete ReferenceCounter;
delete RealPointer;
spdbg("[%#lx] Shared pointer deleted (ptr=%#lx, ref=%#lx)", this, m_RealPointer, m_ReferenceCounter);
delete m_ReferenceCounter;
delete m_RealPointer;
}
}
unsigned int GetCount()
{
spdbg("Shared pointer count (%#lx)", RealPointer);
return ReferenceCounter->Get();
spdbg("[%#lx] Shared pointer count (%d)", this, m_ReferenceCounter->Get());
return m_ReferenceCounter->Get();
}
T *Get()
{
spdbg("Shared pointer get (%#lx)", RealPointer);
return RealPointer;
spdbg("[%#lx] Shared pointer get (%#lx)", this, m_RealPointer);
return m_RealPointer;
}
T &operator*()
{
spdbg("Shared pointer dereference (%#lx)", RealPointer);
return *RealPointer;
spdbg("[%#lx] Shared pointer dereference (ptr*=%#lx)", this, *m_RealPointer);
return *m_RealPointer;
}
T *operator->()
{
spdbg("Shared pointer dereference (%#lx)", RealPointer);
return RealPointer;
spdbg("[%#lx] Shared pointer dereference (ptr->%#lx)", this, m_RealPointer);
return m_RealPointer;
}
void reset(T *Pointer = nullptr)
{
if (m_RealPointer == Pointer)
return;
spdbg("[%#lx] Shared pointer reset (ptr=%#lx, ref=%#lx)", this, Pointer, m_ReferenceCounter);
(*m_ReferenceCounter)--;
if (m_ReferenceCounter->Get() == 0)
{
delete m_ReferenceCounter;
delete m_RealPointer;
}
m_RealPointer = Pointer;
m_ReferenceCounter = new Counter();
if (Pointer)
(*m_ReferenceCounter)++;
}
void reset()
{
spdbg("[%#lx] Shared pointer reset (ptr=%#lx, ref=%#lx)", this, m_RealPointer, m_ReferenceCounter);
if (m_ReferenceCounter->Get() == 1)
{
delete m_RealPointer;
delete m_ReferenceCounter;
}
else
{
(*m_ReferenceCounter)--;
}
m_RealPointer = nullptr;
m_ReferenceCounter = nullptr;
}
void swap(shared_ptr<T> &Other)
{
spdbg("[%#lx] Shared pointer swap (ptr=%#lx, ref=%#lx <=> ptr=%#lx, ref=%#lx)",
this, m_RealPointer, m_ReferenceCounter, Other.m_RealPointer, Other.m_ReferenceCounter);
T *tempRealPointer = m_RealPointer;
Counter *tempReferenceCounter = m_ReferenceCounter;
m_RealPointer = Other.m_RealPointer;
m_ReferenceCounter = Other.m_ReferenceCounter;
Other.m_RealPointer = tempRealPointer;
Other.m_ReferenceCounter = tempReferenceCounter;
}
};
template <class T>
class weak_ptr
template <typename T>
struct remove_reference
{
typedef T type;
};
template <typename T>
struct remove_reference<T &>
{
typedef T type;
};
template <typename T>
struct remove_reference<T &&>
{
typedef T type;
};
template <typename T>
using remove_reference_t = typename remove_reference<T>::type;
template <typename T>
T &&forward(remove_reference_t<T> &t)
{
return static_cast<T &&>(t);
};
template <typename T>
T &&forward(remove_reference_t<T> &&t)
{
return static_cast<T &&>(t);
};
template <typename T, typename... Args>
shared_ptr<T> make_shared(Args &&...args)
{
return shared_ptr<T>(new T(forward<Args>(args)...));
};
#endif // !__FENNIX_KERNEL_SMART_POINTER_H__

6
include/stddef.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef __FENNIX_KERNEL_STDDEF_STUB_H__
#define __FENNIX_KERNEL_STDDEF_STUB_H__
#include <types.h>
#endif // !__FENNIX_KERNEL_STDDEF_STUB_H__

View File

@ -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);
};
}

View File

@ -3,8 +3,8 @@
#include <types.h>
#include <filesystem.hpp>
#include <interrupts.hpp>
#include <hashmap.hpp>
#include <symbols.hpp>
#include <vector.hpp>
#include <memory.hpp>
@ -25,7 +25,7 @@ namespace Tasking
UnknownArchitecture,
x32,
x64,
ARM,
ARM32,
ARM64
};
@ -42,7 +42,6 @@ namespace Tasking
UnknownElevation,
Kernel,
System,
Idle,
User
};
@ -57,6 +56,16 @@ namespace Tasking
Terminated
};
enum TaskPriority
{
UnknownPriority = 0,
Idle = 1,
Low = 25,
Normal = 50,
High = 75,
Critical = 100
};
struct TaskSecurity
{
TaskTrustLevel TrustLevel;
@ -76,7 +85,7 @@ namespace Tasking
uint64_t Year, Month, Day, Hour, Minute, Second;
uint64_t Usage[256]; // MAX_CPU
bool Affinity[256]; // MAX_CPU
int Priority;
TaskPriority Priority;
TaskArchitecture Architecture;
TaskCompatibility Compatibility;
};
@ -123,7 +132,7 @@ namespace Tasking
}
}
void SetPriority(int priority)
void SetPriority(TaskPriority priority)
{
CriticalSection cs;
trace("Setting priority of thread %s to %d", Name, priority);
@ -165,27 +174,46 @@ namespace Tasking
TaskInfo Info;
Vector<TCB *> Threads;
Vector<PCB *> Children;
HashMap<InterProcessCommunication::IPCPort, uintptr_t> *IPCHandles;
InterProcessCommunication::IPC *IPC;
Memory::PageTable4 *PageTable;
SymbolResolver::Symbols *ELFSymbolTable;
VirtualFileSystem::Node *ProcessDirectory;
VirtualFileSystem::Node *memDirectory;
};
enum TokenTrustLevel
/** @brief Token Trust Level */
enum TTL
{
UnknownTrustLevel,
Untrusted,
Trusted,
TrustedByKernel
UnknownTrustLevel = 0b0001,
Untrusted = 0b0010,
Trusted = 0b0100,
TrustedByKernel = 0b1000,
FullTrust = Trusted | TrustedByKernel
};
class Security
{
private:
struct TokenData
{
Token token;
int TrustLevel;
uint64_t OwnerID;
bool Process;
};
Vector<TokenData> Tokens;
public:
Token CreateToken();
bool TrustToken(Token token,
TokenTrustLevel TrustLevel);
bool TrustToken(Token token, TTL TrustLevel);
bool AddTrustLevel(Token token, TTL TrustLevel);
bool RemoveTrustLevel(Token token, TTL TrustLevel);
bool UntrustToken(Token token);
bool DestroyToken(Token token);
bool IsTokenTrusted(Token token, TTL TrustLevel);
bool IsTokenTrusted(Token token, int TrustLevel);
int GetTokenTrustLevel(Token token);
Security();
~Security();
};
@ -194,7 +222,6 @@ namespace Tasking
{
private:
Security SecurityManager;
InterProcessCommunication::IPC *IPCManager = nullptr;
UPID NextPID = 0;
UTID NextTID = 0;
@ -217,6 +244,7 @@ namespace Tasking
bool GetNextAvailableProcess(void *CPUDataPointer);
void SchedulerCleanupProcesses();
bool SchedulerSearchProcessThread(void *CPUDataPointer);
void UpdateProcessStatus();
void WakeUpThreads(void *CPUDataPointer);
#if defined(__amd64__)
@ -232,16 +260,13 @@ namespace Tasking
bool StopScheduler = false;
public:
void InitIPC()
{
static int once = 0;
if (!once++)
this->IPCManager = new InterProcessCommunication::IPC();
}
Vector<PCB *> GetProcessList() { return ListProcess; }
Security *GetSecurityManager() { return &SecurityManager; }
void Panic() { StopScheduler = true; }
void Schedule();
void SignalShutdown();
void RevertProcessCreation(PCB *Process);
void RevertThreadCreation(TCB *Thread);
long GetUsage(int Core)
{
if (IdleProcess)
@ -279,6 +304,9 @@ namespace Tasking
/** @brief Wait for thread to terminate */
void WaitForThread(TCB *tcb);
void WaitForProcessStatus(PCB *pcb, TaskStatus Status);
void WaitForThreadStatus(TCB *tcb, TaskStatus Status);
/**
* @brief Sleep for a given amount of milliseconds
*
@ -294,9 +322,9 @@ namespace Tasking
TCB *CreateThread(PCB *Parent,
IP EntryPoint,
const char **argv,
const char **envp,
Vector<AuxiliaryVector> &auxv,
const char **argv = nullptr,
const char **envp = nullptr,
const Vector<AuxiliaryVector> &auxv = Vector<AuxiliaryVector>(),
IPOffset Offset = 0,
TaskArchitecture Architecture = TaskArchitecture::x64,
TaskCompatibility Compatibility = TaskCompatibility::Native);
@ -306,4 +334,6 @@ namespace Tasking
};
}
extern "C" void TaskingScheduler_OneShot(int TimeSlice);
#endif // !__FENNIX_KERNEL_TASKING_H__

57
ipc.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef __FENNIX_KERNEL_IPC_SYSCALLS_H__
#define __FENNIX_KERNEL_IPC_SYSCALLS_H__
enum IPCCommand
{
IPC_NULL,
IPC_CREATE,
IPC_READ,
IPC_WRITE,
IPC_DELETE,
IPC_GET,
IPC_SET,
IPC_GET_COUNT,
IPC_GET_SIZE,
IPC_GET_FLAGS,
IPC_SET_FLAGS,
IPC_GET_OWNER,
IPC_SET_OWNER,
IPC_GET_GROUP,
IPC_SET_GROUP,
IPC_GET_MODE,
IPC_SET_MODE,
IPC_GET_NAME,
IPC_SET_NAME,
IPC_GET_TYPE,
IPC_SET_TYPE,
IPC_GET_ID,
IPC_SET_ID,
IPC_GET_INDEX,
IPC_SET_INDEX,
};
enum IPCType
{
IPC_TYPE_None,
IPC_TYPE_MessagePassing,
IPC_TYPE_Port,
IPC_TYPE_SharedMemory,
IPC_TYPE_Pipe,
IPC_TYPE_Socket
};
enum IPCErrorCode
{
IPC_E_CODE_Error = -1,
IPC_E_CODE_Success,
IPC_E_CODE_NotListening,
IPC_E_CODE_Timeout,
IPC_E_CODE_InvalidPort,
IPC_E_CODE_AlreadyAllocated,
IPC_E_CODE_NotAllocated,
IPC_E_CODE_IDInUse,
IPC_E_CODE_IDNotRegistered,
IPC_E_CODE_IDNotFound
};
#endif // !__FENNIX_KERNEL_IPC_SYSCALLS_H__

View File

@ -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, ...);

View File

@ -1,40 +1,189 @@
#ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__
#define __FENNIX_KERNEL_SYSCALLS_LIST_H__
#include <types.h>
#include <stddef.h>
/**
* @enum NativeSyscalls
* Enumeration of all the native syscalls available in the kernel
*/
enum NativeSyscalls
{
/** @brief Exit the process.
* @fn int Exit(int Code)
* This syscall is used to exit the current process with the provided exit code.
*/
_Exit = 0,
/** @brief Print a message to the kernel console
* @fn int Print(char Char, int Index)
* This syscall is used to print a message to the kernel console.
*/
_Print,
/** @brief Request pages of memory
* @fn uintptr_t RequestPages(size_t Count)
* This syscall is used to request a specific number of pages of memory from the kernel.
*/
_RequestPages,
/** @brief Free pages of memory
* @fn int FreePages(uintptr_t Address, size_t Count)
* This syscall is used to free a specific number of pages of memory that were previously requested.
*/
_FreePages,
/** @brief Detach memory address
* @fn int DetachAddress(uintptr_t Address)
* This syscall is used to detach a specific memory address from the current process.
*/
_DetachAddress,
/** @brief Kernel Control
* @fn uintptr_t KernelCTL(enum KCtl Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
* This syscall is used to control certain aspects of the kernel or get information about it.
*/
_KernelCTL,
/**
* @brief Creates/Reads/Writes/Deletes an IPC Pipe/Shared Memory/Message Queue/etc.
* @fn int IPC(enum IPCCommand Command, enum IPCType Type, int ID, int Flags, void *Buffer, size_t Size)
* This syscall is used to create, read, write or delete an IPC Pipe/Shared Memory/Message Queue/etc.
*/
_IPC,
/** @brief Open a file
* @fn
* This syscall is used to open a file with the provided path and flags.
*/
_FileOpen,
/** @brief Close a file
* @fn
* This syscall is used to close a file that was previously opened.
*/
_FileClose,
/** @brief Read from a file
* @fn
* This syscall is used to read a specific number of bytes from a file at a specific offset.
*/
_FileRead,
/** @brief Write to a file
* @fn
* This syscall is used to write a specific number of bytes to a file at a specific offset.
*/
_FileWrite,
/** @brief Seek in a file
* @fn
* This syscall is used to change the current offset in a file.
*/
_FileSeek,
/** @brief Get file status
* @fn
* This syscall is used to retrieve information about a file such as its size, permissions, etc.
*/
_FileStatus,
/** @brief Wait for a process or a thread
* @fn
* This syscall is used to wait for a specific process or thread to terminate. It returns the exit code of the process or thread.
*/
_Wait,
/** @brief Kill a process or a thread
* @fn
* This syscall is used to send a termination signal to a specific process or thread
*/
_Kill,
/** @brief Spawn a new process
* @fn
* This syscall is used to create a new process with the provided path and arguments.
*/
_Spawn,
/** @brief Spawn a new thread
* @fn
* This syscall is used to create a new thread within the current process with the provided function and arguments.
*/
_SpawnThread,
/** @brief Get thread list of a process
* @fn
* This syscall is used to retrieve a list of all the threads within a specific process.
*/
_GetThreadListOfProcess,
/** @brief Get current process
* @fn
* This syscall is used to retrieve information about the current process.
*/
_GetCurrentProcess,
/** @brief Get current thread
* @fn
* This syscall is used to retrieve information about the current thread.
*/
_GetCurrentThread,
/** @brief Get process by PID
* @fn
* This syscall is used to retrieve information about a specific process by its PID.
*/
_GetProcessByPID,
/** @brief Get thread by TID
* @fn
* This syscall is used to retrieve information about a specific thread by its TID.
*/
_GetThreadByTID,
/** @brief Kill a process
* @fn
* This syscall is used to send a termination signal to a specific process.
*/
_KillProcess,
/** @brief Kill a thread
* @fn
* This syscall is used to send a termination signal to a specific thread.
*/
_KillThread,
/** @brief Reserved syscall */
_SysReservedCreateProcess,
/** @brief Reserved syscall */
_SysReservedCreateThread,
};
/**
* @enum SyscallsErrorCodes
* Enumeration of all the error codes that can be returned by a syscall
*/
enum SyscallsErrorCodes
{
/**
* @brief Access denied
* This error code is returned when the current thread does not have the required permissions to perform the requested operation.
*/
SYSCALL_ACCESS_DENIED = -0xDEADACC,
/**
* @brief Invalid argument
* This error code is returned when an invalid argument is passed to a syscall.
*/
SYSCALL_INVALID_ARGUMENT = -0xBADAEE,
/**
* @brief Invalid syscall
* This error code is returned when an invalid syscall number is passed to the syscall handler.
*/
SYSCALL_INVALID_SYSCALL = -0xBAD55CA,
/**
* @brief Internal error
* This error code is returned when an internal error occurs in the syscall handler.
*/
SYSCALL_INTERNAL_ERROR = -0xBADBAD5,
/**
* @brief Not implemented
* This error code is returned when a syscall is not implemented.
*/
SYSCALL_NOT_IMPLEMENTED = -0xBAD5EED,
/**
* @brief Generic error
* This error code is returned when a syscall fails for an unknown reason.
*/
SYSCALL_ERROR = -1,
/**
* @brief Success
* This error code is returned when a syscall succeeds.
*/
SYSCALL_OK = 0,
};
static inline long syscall0(long syscall)
{
unsigned long ret;