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

View File

@ -127,7 +127,7 @@ namespace Interrupts
if (likely(Frame->InterruptNumber < CPU::x64::IRQ223 && Frame->InterruptNumber > CPU::x64::ISR0)) if (likely(Frame->InterruptNumber < CPU::x64::IRQ223 && Frame->InterruptNumber > CPU::x64::ISR0))
{ {
Handler *handler = (Handler *)RegisteredEvents->Get(Frame->InterruptNumber); Handler *handler = (Handler *)RegisteredEvents->Get(Frame->InterruptNumber);
if (likely(handler != (Handler *)0xdeadbeef)) if (likely(handler != (Handler *)HASHMAP_ERROR))
handler->OnInterruptReceived(Frame); handler->OnInterruptReceived(Frame);
else else
error("IRQ%ld is unhandled on CPU %d.", Frame->InterruptNumber - 32, Core); error("IRQ%ld is unhandled on CPU %d.", Frame->InterruptNumber - 32, Core);
@ -151,7 +151,7 @@ namespace Interrupts
Handler::Handler(int InterruptNumber) 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); warn("IRQ%d is already registered.", InterruptNumber - 32);
return; return;
@ -165,7 +165,7 @@ namespace Interrupts
Handler::~Handler() Handler::~Handler()
{ {
debug("Unregistering interrupt handler for IRQ%d.", InterruptNumber - 32); 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); warn("Node %d not found.", InterruptNumber);
} }

View File

@ -174,7 +174,7 @@ __no_instrument_function void InitializeMemoryManagement(BootInfo *Info)
#endif #endif
trace("Initializing Physical Memory Manager"); trace("Initializing Physical Memory Manager");
KernelAllocator = Physical(); // KernelAllocator = Physical(); <- Already called in the constructor
KernelAllocator.Init(Info); KernelAllocator.Init(Info);
debug("Memory Info: %lldMB / %lldMB (%lldMB reserved)", debug("Memory Info: %lldMB / %lldMB (%lldMB reserved)",
TO_MB(KernelAllocator.GetUsedMemory()), TO_MB(KernelAllocator.GetUsedMemory()),
@ -338,28 +338,34 @@ void *operator new(size_t Size)
{ {
return HeapMalloc(Size); return HeapMalloc(Size);
} }
void *operator new[](size_t Size) void *operator new[](size_t Size)
{ {
return HeapMalloc(Size); return HeapMalloc(Size);
} }
void *operator new(unsigned long Size, std::align_val_t Alignment) void *operator new(unsigned long Size, std::align_val_t Alignment)
{ {
fixme("operator new with alignment(%#lx) is not implemented", Alignment); fixme("operator new with alignment(%#lx) is not implemented", Alignment);
return HeapMalloc(Size); return HeapMalloc(Size);
} }
void operator delete(void *Pointer) void operator delete(void *Pointer)
{ {
HeapFree(Pointer); HeapFree(Pointer);
} }
void operator delete[](void *Pointer) void operator delete[](void *Pointer)
{ {
HeapFree(Pointer); HeapFree(Pointer);
} }
void operator delete(void *Pointer, long unsigned int Size) void operator delete(void *Pointer, long unsigned int Size)
{ {
HeapFree(Pointer); HeapFree(Pointer);
UNUSED(Size); UNUSED(Size);
} }
void operator delete[](void *Pointer, long unsigned int Size) void operator delete[](void *Pointer, long unsigned int Size)
{ {
HeapFree(Pointer); HeapFree(Pointer);

View File

@ -1,18 +1,62 @@
#include <memory.hpp> #include <memory.hpp>
#include <debug.h> #include <debug.h>
#include "../../kernel.h"
namespace Memory 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 MemMgr::GetAllocatedMemorySize()
{ {
uint64_t Size = 0; uint64_t Size = 0;
foreach (auto var in AllocatedPagesList) foreach (auto ap in AllocatedPagesList)
Size += var.PageCount; Size += ap.PageCount;
return FROM_PAGES(Size); return FROM_PAGES(Size);
} }
bool MemMgr::Add(void *Address, size_t Count) 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++) for (size_t i = 0; i < AllocatedPagesList.size(); i++)
{ {
if (AllocatedPagesList[i].Address == Address) if (AllocatedPagesList[i].Address == Address)
@ -20,8 +64,7 @@ namespace Memory
error("Address already exists!"); error("Address already exists!");
return false; return false;
} }
else if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
if ((uintptr_t)Address < (uintptr_t)AllocatedPagesList[i].Address)
{ {
if ((uintptr_t)Address + (Count * PAGE_SIZE) > (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}); AllocatedPagesList.push_back({Address, Count});
return true; return true;
} }
void *MemMgr::RequestPages(size_t Count) void *MemMgr::RequestPages(size_t Count, bool User)
{ {
void *Address = KernelAllocator.RequestPages(Count); void *Address = KernelAllocator.RequestPages(Count);
for (size_t i = 0; i < Count; i++) 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}); AllocatedPagesList.push_back({Address, Count});
return Address; return Address;
} }
@ -57,39 +132,80 @@ namespace Memory
for (size_t i = 0; i < AllocatedPagesList.size(); i++) for (size_t i = 0; i < AllocatedPagesList.size(); i++)
if (AllocatedPagesList[i].Address == Address) 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) 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; return;
} }
KernelAllocator.FreePages(Address, Count); KernelAllocator.FreePages(Address, Count);
for (size_t i = 0; i < Count; i++) 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).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); AllocatedPagesList.remove(i);
return; 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) if (PageTable)
this->PageTable = PageTable; this->PageTable = PageTable;
else else
this->PageTable = (PageTable4 *)CPU::x64::readcr3().raw; this->PageTable = (PageTable4 *)CPU::x64::readcr3().raw;
debug("MemMgr initialized.");
this->Directory = Directory;
debug("+ %#lx", this);
} }
MemMgr::~MemMgr() MemMgr::~MemMgr()
{ {
foreach (auto var in AllocatedPagesList) foreach (auto ap in AllocatedPagesList)
{ {
KernelAllocator.FreePages(var.Address, var.PageCount); KernelAllocator.FreePages(ap.Address, ap.PageCount);
for (size_t i = 0; i < var.PageCount; i++) for (size_t i = 0; i < ap.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); 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 namespace Execute
{ {
void ELFLoadExec(void *BaseImage, ELFBaseLoad ELFLoadExec(void *ElfFile,
size_t Length, VirtualFileSystem::File *ExFile,
Elf64_Ehdr *ELFHeader, Tasking::PCB *Process)
Memory::Virtual &pva,
SpawnData *ret,
char *Path,
Tasking::PCB *Process,
const char **argv,
const char **envp,
Tasking::TaskArchitecture Arch,
Tasking::TaskCompatibility Comp)
{ {
trace("Executable"); debug("Executable");
Elf64_Phdr *ProgramHeader = (Elf64_Phdr *)(((char *)BaseImage) + ELFHeader->e_phoff); ELFBaseLoad ELFBase = {};
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); /* 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; uintptr_t BaseAddress = UINTPTR_MAX;
uint64_t ElfAppSize = 0; 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++) 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,
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr); (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++) 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; uintptr_t SegmentEnd;
SegmentEnd = ItrProgramHeader.p_vaddr - BaseAddress + ItrProgramHeader.p_memsz; SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
ElfAppSize = MAX(ElfAppSize, SegmentEnd); 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("BaseAddress: %#lx | ElfAppSize: %#lx (%ld, %ld KB)", BaseAddress, ElfAppSize, ElfAppSize, TO_KB(ElfAppSize));
debug("Solving symbols for address: %#llx", (uintptr_t)BaseImage); /* If required, MemoryImage will be at virtual address. (unless has PIE)
Elf64_Shdr *ElfSections = (Elf64_Shdr *)((uintptr_t)BaseImage + ELFHeader->e_shoff); *
Elf64_Shdr *Dynamic = nullptr; * tl;dr this is where the code is stored. */
Elf64_Shdr *DynamicSymbol = nullptr; 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 *DynamicString = nullptr;
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr; Elf64_Shdr *StringTable = nullptr;
Elf64_Shdr *RelaPlt = nullptr;
for (Elf64_Half i = 0; i < ELFHeader->e_shnum; i++) 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) if (strcmp(DynamicStringTable, ".dynstr") == 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)
{ {
DynamicString = &ElfSections[i]; DynamicString = &ElfSections[i];
debug("Found .dynstr"); debug("Found .dynstr");
@ -119,76 +79,57 @@ namespace Execute
StringTable = &ElfSections[i]; StringTable = &ElfSections[i];
debug("Found .strtab"); 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); Vector<char *> NeededLibraries;
UNUSED(DynamicSymbol);
UNUSED(SymbolTable);
UNUSED(RelaPlt);
char *NeededLibraries[256];
uint64_t InitAddress = 0;
uint64_t FiniAddress = 0;
UNUSED(NeededLibraries);
UNUSED(InitAddress);
UNUSED(FiniAddress);
if (!DynamicString) if (!DynamicString)
DynamicString = StringTable; 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++) 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,
uintptr_t MAddr; (uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
sizeof(Elf64_Phdr));
switch (ItrProgramHeader.p_type) switch (ItrPhdr.p_type)
{ {
case PT_NULL: case PT_NULL:
fixme("PT_NULL"); fixme("PT_NULL");
break; break;
case PT_LOAD: case PT_LOAD:
{ {
debug("PT_LOAD - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx", debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr, ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align); ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
MAddr = (ItrProgramHeader.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage; uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
debug("MAddr: %#lx", MAddr); 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); memcpy((void *)MAddr, (uint8_t *)ElfFile + ItrPhdr.p_offset, ItrPhdr.p_filesz);
debug("memcpy operation: %#lx to %#lx for length %ld", (uint8_t *)BaseImage + ItrProgramHeader.p_offset, MemoryImage + MAddr, ItrProgramHeader.p_filesz); debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)ElfFile + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
break; break;
} }
case PT_DYNAMIC: case PT_DYNAMIC:
{ {
debug("PT_DYNAMIC - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx", debug("PT_DYNAMIC - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr, ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align); 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) if (Dynamic[i].d_tag == DT_NEEDED)
{
case DT_NULL:
debug("DT_NULL");
break;
case DT_NEEDED:
{ {
if (!DynamicString) if (!DynamicString)
{ {
@ -196,240 +137,71 @@ namespace Execute
break; break;
} }
debug("DT_NEEDED - Name[%ld]: %s", i, (uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr); char *ReqLib = (char *)kmalloc(256);
NeededLibraries[i] = (char *)((uintptr_t)BaseImage + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr); strcpy(ReqLib, (char *)((uintptr_t)ElfFile + DynamicString->sh_offset + Dynamic[i].d_un.d_ptr));
break; debug("DT_NEEDED - Name[%ld]: %s", i, ReqLib);
NeededLibraries.push_back(ReqLib);
} }
case DT_PLTRELSZ: else if (Dynamic[i].d_tag == DT_NULL)
{
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)
break; break;
} }
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", debug("PT_INTERP - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr, ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align); ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
char InterpreterPath[256]; memcpy((void *)InterpreterPath, (uint8_t *)ElfFile + ItrPhdr.p_offset, 256);
memcpy((void *)InterpreterPath, (uint8_t *)BaseImage + ItrProgramHeader.p_offset, 256); debug("Interpreter: %s", InterpreterPath);
fixme("Interpreter: %s", InterpreterPath);
FileSystem::FILE *InterpreterFile = vfs->Open(InterpreterPath); shared_ptr<VirtualFileSystem::File> InterpreterFile = vfs->Open(InterpreterPath);
if (InterpreterFile->Status != FileSystem::FileStatus::OK) if (InterpreterFile->Status != VirtualFileSystem::FileStatus::OK)
{
warn("Failed to open interpreter file: %s", InterpreterPath); 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; break;
} }
/* ... */ /* ... */
case PT_PHDR: case PT_PHDR:
{ {
debug("PT_PHDR - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx", debug("PT_PHDR - Offset: %#lx VirtAddr: %#lx FileSiz: %ld MemSiz: %ld Align: %#lx",
ItrProgramHeader.p_offset, ItrProgramHeader.p_vaddr, ItrPhdr.p_offset, ItrPhdr.p_vaddr,
ItrProgramHeader.p_filesz, ItrProgramHeader.p_memsz, ItrProgramHeader.p_align); ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
break; break;
} }
default: default:
{ {
warn("Unknown or unsupported program header type: %d", ItrProgramHeader.p_type); warn("Unknown or unsupported program header type: %d", ItrPhdr.p_type);
break; 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}}}); char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true);
auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)Path}}}); strcpy(aux_platform, "x86_64");
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}}});
TCB *Thread = TaskManager->CreateThread(Process, ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
(IP)ELFHeader->e_entry, ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)vfs->GetPathFromNode(ExFile->node).Get()}}});
argv, envp, auxv, ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
Arch, ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage}}});
Comp); ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ret->Process = Process; ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader->e_phnum}}});
ret->Thread = Thread; ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader->e_phentsize}}});
ret->Status = ExStatus::OK; 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() void StartExecuteService()
{ {
mem = new Memory::MemMgr; mem = new Memory::MemMgr;
return; // return;
while (true) 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); SmartLock(ExecuteServiceLock);
SharedLibraries sl; SharedLibraries sl;
@ -62,12 +62,47 @@ namespace Execute
sl.Timeout = TimeManager->CalculateTarget(600000); /* 10 minutes */ sl.Timeout = TimeManager->CalculateTarget(600000); /* 10 minutes */
sl.RefCount = 0; sl.RefCount = 0;
void *BaseLibImage = mem->RequestPages(TO_PAGES(Length)); void *LibFile = mem->RequestPages(TO_PAGES(Length), true);
memcpy(BaseLibImage, (void *)LibraryImage, Length); memcpy(LibFile, (void *)ElfImage, Length);
sl.Address = BaseLibImage;
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; 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); Libs.push_back(sl);
return &Libs[Libs.size() - 1]; return &Libs[Libs.size() - 1];
@ -77,262 +112,4 @@ namespace Execute
{ {
SmartLock(ExecuteServiceLock); 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 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 GetBinaryType(char *Path)
{ {
BinaryType Type = BinaryType::BinTypeInvalid; 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) debug("File opened: %s", Path);
{ Type = GetBinaryType((void *)ExFile->node->Address);
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;
}
} }
Exit:
vfs->Close(ExFile); vfs->Close(ExFile);
return Type; 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, .Process = nullptr,
.Thread = nullptr}; .Thread = nullptr};
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) if (ExFile->node->Flags != VirtualFileSystem::NodeFlags::FILE)
{ {
BinaryType Type = GetBinaryType(Path); ret.Status = ExStatus::InvalidFilePath;
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;
}
goto Exit; 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; ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
else else
{
ret.Status = ExStatus::InvalidFile; ret.Status = ExStatus::InvalidFile;
goto Exit;
}
Exit: Exit:
if (ret.Status != ExStatus::OK)
if (ret.Process)
ret.Process->Status = TaskStatus::Terminated;
vfs->Close(ExFile); vfs->Close(ExFile);
return ret; return ret;
} }

View File

@ -5,21 +5,21 @@
#include "../../kernel.h" #include "../../kernel.h"
namespace FileSystem namespace VirtualFileSystem
{ {
ReadFSFunction(USTAR_Read) ReadFSFunction(USTAR_Read)
{ {
if (!Size) if (!Size)
Size = Node->Length; Size = node->Length;
if (Offset > Node->Length) if (Offset > node->Length)
return 0; return 0;
if (Offset + Size > Node->Length) if (Offset + Size > node->Length)
Size = Node->Length - Offset; Size = node->Length - Offset;
memcpy(Buffer, (uint8_t *)(Node->Address + Offset), Size); memcpy(Buffer, (uint8_t *)(node->Address + Offset), Size);
return Size; return Size;
} }
FileSystemOperations ustar = { FileSystemOperations ustar_op = {
.Name = "ustar", .Name = "ustar",
.Read = USTAR_Read, .Read = USTAR_Read,
}; };
@ -39,9 +39,7 @@ namespace FileSystem
string2int(((FileHeader *)Address)->mode), string2int(((FileHeader *)Address)->mode),
((FileHeader *)Address)->size); ((FileHeader *)Address)->size);
vfs->CreateRoot(&ustar, "/"); vfs->CreateRoot("/", &ustar_op);
int ErrorsAllowed = 20;
for (size_t i = 0;; i++) for (size_t i = 0;; i++)
{ {
@ -52,7 +50,7 @@ namespace FileSystem
if (header->name[strlen(header->name) - 1] == '/') if (header->name[strlen(header->name) - 1] == '/')
header->name[strlen(header->name) - 1] = 0; header->name[strlen(header->name) - 1] = 0;
size_t size = getsize(header->size); size_t size = getsize(header->size);
FileSystemNode *node = nullptr; Node *node = nullptr;
// if (!isempty((char *)header->name)) // if (!isempty((char *)header->name))
// KPrint("Adding file \e88AACC%s\eCCCCCC (\e88AACC%lu \eCCCCCCbytes)", header->name, size); // KPrint("Adding file \e88AACC%s\eCCCCCC (\e88AACC%lu \eCCCCCCbytes)", header->name, size);
@ -62,10 +60,12 @@ namespace FileSystem
if (isempty((char *)header->name)) if (isempty((char *)header->name))
goto NextFileAddress; goto NextFileAddress;
node = vfs->Create(nullptr, header->name); node = vfs->Create(header->name, NodeFlags::NODE_FLAG_ERROR);
debug("Added node: %s", node->Name); debug("Added node: %s", node->Name);
if (node == nullptr) if (node == nullptr)
{ {
static int ErrorsAllowed = 20;
if (ErrorsAllowed > 0) if (ErrorsAllowed > 0)
{ {
ErrorsAllowed--; ErrorsAllowed--;
@ -73,7 +73,7 @@ namespace FileSystem
} }
else 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; break;
} }
} }
@ -90,19 +90,19 @@ namespace FileSystem
switch (header->typeflag[0]) switch (header->typeflag[0])
{ {
case REGULAR_FILE: case REGULAR_FILE:
node->Flags = NodeFlags::FS_FILE; node->Flags = NodeFlags::FILE;
break; break;
case SYMLINK: case SYMLINK:
node->Flags = NodeFlags::FS_SYMLINK; node->Flags = NodeFlags::SYMLINK;
break; break;
case DIRECTORY: case DIRECTORY:
node->Flags = NodeFlags::FS_DIRECTORY; node->Flags = NodeFlags::DIRECTORY;
break; break;
case CHARDEV: case CHARDEV:
node->Flags = NodeFlags::FS_CHARDEVICE; node->Flags = NodeFlags::CHARDEVICE;
break; break;
case BLOCKDEV: case BLOCKDEV:
node->Flags = NodeFlags::FS_BLOCKDEVICE; node->Flags = NodeFlags::BLOCKDEVICE;
break; break;
default: default:
warn("Unknown type: %d", header->typeflag[0]); warn("Unknown type: %d", header->typeflag[0]);

View File

@ -9,14 +9,23 @@
#include "../kernel.h" #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); NewLock(VFSLock);
namespace FileSystem namespace VirtualFileSystem
{ {
char *Virtual::GetPathFromNode(FileSystemNode *Node) shared_ptr<char> Virtual::GetPathFromNode(Node *node)
{ {
vfsdbg("GetPathFromNode( Node: \"%s\" )", Node->Name); vfsdbg("GetPathFromNode( Node: \"%s\" )", node->Name);
FileSystemNode *Parent = Node; Node *Parent = node;
char **Path = nullptr; char **Path = nullptr;
size_t Size = 1; size_t Size = 1;
size_t PathSize = 0; size_t PathSize = 0;
@ -25,7 +34,7 @@ namespace FileSystem
while (Parent != FileSystemRoot && Parent != nullptr) while (Parent != FileSystemRoot && Parent != nullptr)
{ {
bool Found = false; bool Found = false;
for (const auto &Children : FileSystemRoot->Children) foreach (const auto &Children in FileSystemRoot->Children)
if (Children == Parent) if (Children == Parent)
{ {
Found = true; Found = true;
@ -64,7 +73,9 @@ namespace FileSystem
} }
// Allocate a new string for the final path // 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; size_t Offset = 0;
// Concatenate the elements of the Path array into the FinalPath string // Concatenate the elements of the Path array into the FinalPath string
@ -75,443 +86,533 @@ namespace FileSystem
continue; continue;
} }
size_t ElementSize = strlen(Path[i]); size_t ElementSize = strlen(Path[i]);
memcpy(FinalPath + Offset, Path[i], ElementSize); memcpy(FinalPath.Get() + Offset, Path[i], ElementSize);
Offset += ElementSize; Offset += ElementSize;
} }
// Add a null terminator to the final path string // Add a null terminator to the final path string
FinalPath[Size - 1] = '\0'; FinalPath.Get()[Size - 1] = '\0';
// Deallocate the Path array // Deallocate the Path array
delete[] Path; delete[] Path;
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath); vfsdbg("GetPathFromNode()->\"%s\"", FinalPath.Get());
return FinalPath; 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) Node *ReturnNode = Parent;
Parent = FileSystemRoot; 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; error("Path doesn't have any segments.");
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);
return nullptr; return nullptr;
} }
else
do
{ {
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name); char *SegmentName = new char[segment.end - segment.begin + 1];
return Parent; 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); shared_ptr<File> file = make_shared<File>();
FileSystemNode *newNode = new FileSystemNode; file->Status = FileStatus::OK;
newNode->Parent = Parent; file->node = node;
strncpy(newNode->Name, Name, FILENAME_LENGTH); return file;
if (likely(Parent)) }
newNode->Operator = Parent->Operator;
else Node *Virtual::GetParent(const char *Path, Node *Parent)
newNode->Operator = nullptr; {
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); vfsdbg("AddNewChild()->\"%s\"", newNode->Name);
return newNode; 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); vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
if (likely(Parent)) if (!Parent)
foreach (auto var in Parent->Children) {
if (strcmp(var->Name, Name) == 0) vfsdbg("GetChild()->nullptr");
{ return nullptr;
vfsdbg("GetChild()->\"%s\"", var->Name); }
return var;
} foreach (auto Child in Parent->Children)
vfsdbg("GetChild()->nullptr"); if (strcmp(Child->Name, Name) == 0)
{
vfsdbg("GetChild()->\"%s\"", Child->Name);
return Child;
}
vfsdbg("GetChild()->nullptr (not found)");
return nullptr; 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); vfsdbg("RemoveChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
for (uintptr_t i = 0; i < Parent->Children.size(); i++) for (size_t i = 0; i < Parent->Children.size(); i++)
{
if (strcmp(Parent->Children[i]->Name, Name) == 0) if (strcmp(Parent->Children[i]->Name, Name) == 0)
{ {
delete Parent->Children[i];
Parent->Children.remove(i); Parent->Children.remove(i);
vfsdbg("RemoveChild()->OK"); vfsdbg("RemoveChild()->OK");
return FileStatus::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 *NormalizedPath = new char[strlen((char *)Path) + 1];
char *RelativePath = nullptr; shared_ptr<char> RelativePath;
cwk_path_normalize(Path, NormalizedPath, strlen((char *)Path) + 1); cwk_path_normalize(Path, NormalizedPath, strlen((char *)Path) + 1);
if (cwk_path_is_relative(NormalizedPath)) if (cwk_path_is_relative(NormalizedPath))
{ {
char *ParentPath = GetPathFromNode(Parent); shared_ptr<char> ParentPath = GetPathFromNode(Parent);
size_t PathSize = cwk_path_get_absolute(ParentPath, NormalizedPath, nullptr, 0); size_t PathSize = cwk_path_get_absolute(ParentPath.Get(), NormalizedPath, nullptr, 0);
RelativePath = new char[PathSize + 1]; RelativePath.reset(new char[PathSize + 1]);
cwk_path_get_absolute(ParentPath, NormalizedPath, RelativePath, PathSize + 1); cwk_path_get_absolute(ParentPath.Get(), NormalizedPath, RelativePath.Get(), PathSize + 1);
delete[] ParentPath;
} }
else else
{ {
RelativePath = new char[strlen(NormalizedPath) + 1]; RelativePath.reset(new char[strlen(NormalizedPath) + 1]);
strcpy(RelativePath, NormalizedPath); strcpy(RelativePath.Get(), NormalizedPath);
} }
delete[] NormalizedPath; delete[] NormalizedPath;
vfsdbg("NormalizePath()->\"%s\"", RelativePath); vfsdbg("NormalizePath()->\"%s\"", RelativePath.Get());
return RelativePath; 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)) if (isempty((char *)Path))
return FileStatus::INVALID_PATH; {
vfsdbg("PathExists()->PathIsEmpty");
return false;
}
if (Parent == nullptr) if (Parent == nullptr)
Parent = FileSystemRoot; Parent = FileSystemRoot;
char *NormalizedPath = NormalizePath(Parent, Path); vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
FileSystemNode *Node = GetNodeFromPath(Parent, NormalizedPath);
if (!Node) if (GetNodeFromPath(NormalizePath(Path, Parent).Get(), Parent))
{ {
vfsdbg("FileExists()->NOT_FOUND"); vfsdbg("PathExists()->OK");
return FileStatus::NOT_FOUND; return true;
}
else
{
vfsdbg("FileExists()->OK");
return FileStatus::OK;
} }
vfsdbg("PathExists()->NotFound");
return false;
} }
FileSystemNode *Virtual::Create(FileSystemNode *Parent, const char *Path) Node *Virtual::CreateRoot(const char *RootName, FileSystemOperations *Operator)
{
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)
{ {
if (Operator == nullptr) if (Operator == nullptr)
return nullptr; return nullptr;
vfsdbg("Setting root to %s", RootName); vfsdbg("Creating root %s", RootName);
FileSystemNode *newNode = new FileSystemNode; Node *newNode = new Node;
strncpy(newNode->Name, RootName, FILENAME_LENGTH); strncpy(newNode->Name, RootName, FILENAME_LENGTH);
newNode->Flags = NodeFlags::FS_DIRECTORY; newNode->Flags = NodeFlags::DIRECTORY;
newNode->Operator = Operator; newNode->Operator = Operator;
FileSystemRoot->Children.push_back(newNode); FileSystemRoot->Children.push_back(newNode);
return 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); SmartLock(VFSLock);
if (unlikely(!Operator)) if (isempty((char *)Path))
return nullptr; 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))) if (unlikely(isempty((char *)Path)))
return nullptr; {
file->Status = FileStatus::InvalidParameter;
return file;
}
vfsdbg("Mounting %s", Path); vfsdbg("Mounting %s", Path);
FILE *file = new FILE; const char *PathCopy;
cwk_path_get_basename(Path, &file->Name, 0); cwk_path_get_basename(Path, &PathCopy, 0);
strcpy(file->Name, PathCopy);
file->Status = FileStatus::OK; file->Status = FileStatus::OK;
file->Node = Create(nullptr, Path); file->node = Create(Path, NodeFlags::MOUNTPOINT);
file->Node->Operator = Operator; file->node->Operator = Operator;
file->Node->Flags = NodeFlags::FS_MOUNTPOINT;
return file; return file;
} }
FileStatus Virtual::Unmount(FILE *File) FileStatus Virtual::Unmount(shared_ptr<File> File)
{ {
SmartLock(VFSLock); SmartLock(VFSLock);
if (unlikely(File)) if (unlikely(File.Get()))
return FileStatus::INVALID_PARAMETER; return FileStatus::InvalidParameter;
vfsdbg("Unmounting %s", File->Name); fixme("Unmounting %s", File->Name);
return FileStatus::OK; 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); 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) if (strcmp(Path, ".") == 0)
{ {
FILE *file = new FILE; shared_ptr<File> file = make_shared<File>();
file->Node = Parent; file->node = Parent;
if (unlikely(!file->Node)) if (unlikely(!file->node))
file->Status = FileStatus::NOT_FOUND; file->Status = FileStatus::NotFound;
const char *basename; cwk_path_get_basename(GetPathFromNode(Parent).Get(), &basename, nullptr);
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr); strcpy(file->Name, basename);
file->Name = basename;
return file; return file;
} }
if (strcmp(Path, "..") == 0) if (strcmp(Path, "..") == 0)
{ {
if (Parent->Parent != nullptr) shared_ptr<File> file = make_shared<File>();
Parent = Parent->Parent;
FILE *file = new FILE; if (Parent->Parent != nullptr)
file->Node = Parent; file->node = Parent->Parent;
if (!file->Node)
file->Status = FileStatus::NOT_FOUND; if (!file->node)
const char *basename; file->Status = FileStatus::NotFound;
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr); cwk_path_get_basename(GetPathFromNode(Parent).Get(), &basename, nullptr);
file->Name = basename; strcpy(file->Name, basename);
return file; return file;
} }
if (Parent == nullptr) Node *CurrentParent = this->GetParent(Path, Parent);
{ shared_ptr<char> CleanPath = NormalizePath(Path, CurrentParent);
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;
}
}
}
char *CleanPath = NormalizePath(Parent, Path); shared_ptr<File> file = make_shared<File>();
FILE *file = new FILE;
FileStatus filestatus = FileStatus::OK;
filestatus = FileExists(Parent, CleanPath);
/* TODO: Check for other errors */ /* TODO: Check for other errors */
if (filestatus != FileStatus::OK) if (!PathExists(CleanPath.Get(), CurrentParent))
{ {
foreach (auto var in FileSystemRoot->Children) foreach (auto Child 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)
{ {
const char *basename; if (strcmp(Child->Name, CleanPath.Get()) == 0)
cwk_path_get_basename(GetPathFromNode(file->Node), &basename, nullptr); {
file->Name = basename; file->node = Child;
goto OpenNodeExit; 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->node = GetNodeFromPath(CleanPath.Get(), FileSystemRoot->Children[0]);
file->Status = filestatus; if (file->node)
file->Node = nullptr; {
cwk_path_get_basename(GetPathFromNode(file->node).Get(), &basename, nullptr);
strcpy(file->Name, basename);
return file;
}
} }
else else
{ {
file->Node = GetNodeFromPath(Parent, CleanPath); file->node = GetNodeFromPath(CleanPath.Get(), CurrentParent);
if (unlikely(!file->Node)) cwk_path_get_basename(CleanPath.Get(), &basename, nullptr);
file->Status = FileStatus::NOT_FOUND; strcpy(file->Name, basename);
const char *basename;
cwk_path_get_basename(CleanPath, &basename, nullptr);
file->Name = basename;
return file; return file;
} }
OpenNodeExit:
file->Status = FileStatus::NotFound;
return file; 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); SmartLock(VFSLock);
if (unlikely(!File)) if (unlikely(!File.Get()))
return 0; return FileStatus::InvalidHandle;
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;
vfsdbg("Closing %s", File->Name); vfsdbg("Closing %s", File->Name);
delete File;
return FileStatus::OK; return FileStatus::OK;
} }
Virtual::Virtual() Virtual::Virtual()
{ {
trace("Initializing virtual file system..."); trace("Initializing virtual file system...");
FileSystemRoot = new FileSystemNode; FileSystemRoot = new Node;
FileSystemRoot->Flags = NodeFlags::FS_MOUNTPOINT; FileSystemRoot->Flags = NodeFlags::MOUNTPOINT;
FileSystemRoot->Operator = nullptr; FileSystemRoot->Operator = nullptr;
FileSystemRoot->Parent = nullptr; FileSystemRoot->Parent = nullptr;
strncpy(FileSystemRoot->Name, "root", 4); strncpy(FileSystemRoot->Name, "root", 4);
@ -520,6 +621,6 @@ namespace FileSystem
Virtual::~Virtual() Virtual::~Virtual()
{ {
warn("Tried to deinitialize Virtual File System!"); trace("Destroying virtual file system...");
} }
} }

View File

@ -11,23 +11,61 @@
#include "DAPI.hpp" #include "DAPI.hpp"
#include "Fex.hpp" #include "Fex.hpp"
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
Driver::Driver *DriverManager = nullptr; Driver::Driver *DriverManager = nullptr;
Disk::Manager *DiskManager = nullptr; Disk::Manager *DiskManager = nullptr;
NetworkInterfaceManager::NetworkInterface *NIManager = nullptr; NetworkInterfaceManager::NetworkInterface *NIManager = nullptr;
Recovery::KernelRecovery *RecoveryScreen = 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() void KernelMainThread()
{ {
TaskManager->InitIPC(); TaskManager->GetCurrentThread()->SetPriority(Tasking::Critical);
TaskManager->GetCurrentThread()->SetPriority(100);
CPU::Interrupts(CPU::Disable);
KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD); KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
KPrint("C++ Language Version (__cplusplus): %ld", __cplusplus); 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..."); KPrint("Initializing Disk Manager...");
DiskManager = new Disk::Manager; DiskManager = new Disk::Manager;
@ -49,43 +87,69 @@ void KernelMainThread()
KPrint("Starting Network Interface Manager..."); KPrint("Starting Network Interface Manager...");
NIManager->StartService(); NIManager->StartService();
KPrint("Setting up userspace..."); KPrint("Setting up userspace");
const char *envp[9] = { #ifdef DEBUG
"PATH=/system:/system/bin", TreeFS(vfs->GetRootNode(), 0);
"TERM=tty", #endif
"HOME=/",
"USER=root",
"SHELL=/system/sh",
"PWD=/",
"LANG=en_US.UTF-8",
"TZ=UTC",
nullptr};
const char *argv[4] = { const char *USpace_msg = "Setting up userspace";
Config.InitPath, for (size_t i = 0; i < strlen(USpace_msg); i++)
"--init", Display->Print(USpace_msg[i], 0);
"--critical",
nullptr}; 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) if (ret.Status != Execute::ExStatus::OK)
{ {
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, ret.Status); KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, ret.Status);
CPU::Interrupts(CPU::Enable);
goto Exit; 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); ret.Thread->SetCritical(true);
KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath); KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath);
CPU::Interrupts(CPU::Enable); CPU::Interrupts(CPU::Enable);
TaskManager->GetCurrentThread()->SetPriority(1); TaskManager->GetCurrentThread()->SetPriority(Tasking::Idle);
TaskManager->WaitForThread(ret.Thread); TaskManager->WaitForThread(ret.Thread);
KPrint("\eE85230Userspace process exited with code %d", ret.Thread->GetExitCode()); ExitCode = ret.Thread->GetExitCode();
error("Userspace process exited with code %d (%#x)", ret.Thread->GetExitCode(), 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: Exit:
KPrint("%s exited with code %d! Dropping to recovery screen...", Config.InitPath, ret.Thread->GetExitCode()); if (ExitCode != 0)
TaskManager->Sleep(1000); {
RecoveryScreen = new Recovery::KernelRecovery; 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); CPU::Halt(true);
} }
@ -93,7 +157,7 @@ void KernelShutdownThread(bool Reboot)
{ {
BeforeShutdown(); BeforeShutdown();
trace("Shutting Down/Rebooting..."); trace("%s...", Reboot ? "Rebooting" : "Shutting down");
if (Reboot) if (Reboot)
PowerManager->Reboot(); PowerManager->Reboot();
else else

View File

@ -1,6 +1,7 @@
#include "kernel.h" #include "kernel.h"
#include <boot/protocols/multiboot2.h> #include <boot/protocols/multiboot2.h>
#include <filesystem/ustar.hpp>
#include <interrupts.hpp> #include <interrupts.hpp>
#include <memory.hpp> #include <memory.hpp>
#include <convert.h> #include <convert.h>
@ -12,6 +13,7 @@
#include <io.h> #include <io.h>
#include "Core/smbios.hpp" #include "Core/smbios.hpp"
#include "Tests/t.h"
/** /**
* Fennix Kernel * Fennix Kernel
@ -29,6 +31,12 @@
* - [ ] Optimize SMP. * - [ ] Optimize SMP.
* - [ ] Support IPv6. * - [ ] Support IPv6.
* - [ ] Endianess of the network stack (currently: [HOST](LSB)<=>[NETWORK](MSB)). Not sure if this is a standard or not. * - [ ] 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: * BUGS:
* - [ ] Kernel crashes when receiving interrupts for drivers only if the system has one core and the tasking is running. * - [ ] 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: * CREDITS AND REFERENCES:
* - General: * - General:
* https://wiki.osdev.org/Main_Page * https://wiki.osdev.org/Main_Page
* *
* - Font: * - Font:
* http://www.fial.com/~scott/tamsyn-font/ * http://www.fial.com/~scott/tamsyn-font/
* *
* - CPU XCR0 structure: * - CPU XCR0 structure:
* https://wiki.osdev.org/CPU_Registers_x86#XCR0 * https://wiki.osdev.org/CPU_Registers_x86#XCR0
* *
* - CPUID 0x7: * - CPUID 0x7:
* https://en.wikipedia.org/wiki/CPUID * https://en.wikipedia.org/wiki/CPUID
* *
@ -67,6 +75,22 @@
* http://realtek.info/pdf/rtl8139cp.pdf * http://realtek.info/pdf/rtl8139cp.pdf
* https://en.wikipedia.org/wiki/IPv4 * https://en.wikipedia.org/wiki/IPv4
* https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml * 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__ #ifdef __amd64__
@ -89,6 +113,11 @@
NewLock(KernelLock); NewLock(KernelLock);
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
BootInfo *bInfo = nullptr; BootInfo *bInfo = nullptr;
Video::Display *Display = nullptr; Video::Display *Display = nullptr;
SymbolResolver::Symbols *KernelSymbolTable = nullptr; SymbolResolver::Symbols *KernelSymbolTable = nullptr;
@ -96,7 +125,7 @@ Power::Power *PowerManager = nullptr;
PCI::PCI *PCIManager = nullptr; PCI::PCI *PCIManager = nullptr;
Tasking::Task *TaskManager = nullptr; Tasking::Task *TaskManager = nullptr;
Time::time *TimeManager = nullptr; Time::time *TimeManager = nullptr;
FileSystem::Virtual *vfs = nullptr; VirtualFileSystem::Virtual *vfs = nullptr;
KernelConfig Config; KernelConfig Config;
Time::Clock BootClock; Time::Clock BootClock;
@ -110,7 +139,7 @@ EXTERNC void KPrint(const char *Format, ...)
{ {
SmartLock(KernelLock); SmartLock(KernelLock);
Time::Clock tm = Time::ReadClock(); 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_list args;
va_start(args, Format); va_start(args, Format);
vprintf(Format, args); vprintf(Format, args);
@ -236,8 +265,57 @@ EXTERNC __no_instrument_function void Main(BootInfo *Info)
else else
KPrint("SMBIOS: \eFF0000Not Found"); 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################################"); KPrint("\e058C19################################");
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
CPU::Halt(true); CPU::Halt(true);
} }
@ -254,6 +332,16 @@ EXTERNC __no_stack_protector __no_instrument_function void Entry(BootInfo *Info)
(*func)(); (*func)();
InitializeMemoryManagement(Info); 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; EnableProfiler = true;
Main(Info); Main(Info);
} }

View File

@ -310,7 +310,7 @@ EXTERNC unsigned int isdelim(char c, char *delim)
return 0; 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) EXTERNC void swap(char *x, char *y)
{ {

View File

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

View File

@ -86,7 +86,7 @@ namespace NetworkUDP
Socket *GoodSocket = nullptr; 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", netdbg("UDP->SKT[]: LP:%d | LIP:%s | RP:%d | RIP:%s | LST:%d",
b16(var.UDPSocket->LocalPort), b16(var.UDPSocket->LocalPort),

View File

@ -33,12 +33,10 @@ namespace Recovery
gui = new GraphicalUserInterface::GUI; 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); // 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->Rename("GUI Thread");
guiThread->SetPriority(100); guiThread->SetPriority(Tasking::TaskPriority::Critical);
Rect RecoveryModeWindow; Rect RecoveryModeWindow;
RecoveryModeWindow.Width = 460; RecoveryModeWindow.Width = 460;

View File

@ -1,5 +1,6 @@
#include <syscalls.hpp> #include <syscalls.hpp>
#include <memory.hpp> #include <memory.hpp>
#include <lock.hpp>
#include <debug.h> #include <debug.h>
@ -7,19 +8,54 @@
#include "../kernel.h" #include "../kernel.h"
#include "../../Userspace/libs/include/sysbase.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) 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); trace("Userspace thread %s(%lld) exited with code %#llx", TaskManager->GetCurrentThread()->Name, TaskManager->GetCurrentThread()->ID, code);
TaskManager->GetCurrentThread()->ExitCode = code; TaskManager->GetCurrentThread()->ExitCode = code;
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated; TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated;
UNUSED(Frame); UNUSED(Frame);
return 0; return SYSCALL_OK;
} }
static int sys_print(SyscallsFrame *Frame, char Char, int Index) 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 #ifdef DEBUG
Display->SetBuffer(Index); Display->SetBuffer(Index);
#endif #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) 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); 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) 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); TaskManager->GetCurrentThread()->Memory->FreePages((void *)Address, Count);
UNUSED(Frame); 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) switch (Command)
{ {
case KCTL_GET_PID: case KCTL_GET_PID:
@ -53,7 +113,7 @@ static int sys_kernelctl(SyscallsFrame *Frame, int Command, uint64_t Arg1, uint6
default: default:
{ {
warn("KernelCTL: Unknown command: %lld", Command); 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(Arg3);
UNUSED(Arg4); UNUSED(Arg4);
UNUSED(Frame); 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) static int sys_file_open(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_open: %#lx", Frame); fixme("sys_file_open: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_file_close(SyscallsFrame *Frame) static int sys_file_close(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_close: %#lx", Frame); fixme("sys_file_close: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_file_read(SyscallsFrame *Frame) static int sys_file_read(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_read: %#lx", Frame); fixme("sys_file_read: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_file_write(SyscallsFrame *Frame) static int sys_file_write(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_write: %#lx", Frame); fixme("sys_file_write: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_file_seek(SyscallsFrame *Frame) static int sys_file_seek(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_seek: %#lx", Frame); fixme("sys_file_seek: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_file_status(SyscallsFrame *Frame) static int sys_file_status(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_file_status: %#lx", Frame); fixme("sys_file_status: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_wait(SyscallsFrame *Frame) static int sys_wait(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_wait: %#lx", Frame); fixme("sys_wait: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_kill(SyscallsFrame *Frame) static int sys_kill(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_kill: %#lx", Frame); fixme("sys_kill: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_spawn(SyscallsFrame *Frame) static int sys_spawn(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_spawn: %#lx", Frame); fixme("sys_spawn: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_spawn_thread(SyscallsFrame *Frame) static int sys_spawn_thread(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_spawn_thread: %#lx", Frame); fixme("sys_spawn_thread: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_get_thread_list_of_process(SyscallsFrame *Frame) static int sys_get_thread_list_of_process(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_thread_list_of_process: %#lx", Frame); fixme("sys_get_thread_list_of_process: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_get_current_process(SyscallsFrame *Frame) static int sys_get_current_process(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_current_process: %#lx", Frame); fixme("sys_get_current_process: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_get_current_thread(SyscallsFrame *Frame) static int sys_get_current_thread(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_current_thread: %#lx", Frame); fixme("sys_get_current_thread: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_get_process_by_pid(SyscallsFrame *Frame) static int sys_get_process_by_pid(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_process_by_pid: %#lx", Frame); fixme("sys_get_process_by_pid: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_get_thread_by_tid(SyscallsFrame *Frame) static int sys_get_thread_by_tid(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_get_thread_by_tid: %#lx", Frame); fixme("sys_get_thread_by_tid: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_kill_process(SyscallsFrame *Frame) static int sys_kill_process(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_kill_process: %#lx", Frame); fixme("sys_kill_process: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_kill_thread(SyscallsFrame *Frame) static int sys_kill_thread(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_kill_thread: %#lx", Frame); fixme("sys_kill_thread: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_sys_reserved_create_process(SyscallsFrame *Frame) static int sys_sys_reserved_create_process(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_sys_reserved_create_process: %#lx", Frame); fixme("sys_sys_reserved_create_process: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static int sys_sys_reserved_create_thread(SyscallsFrame *Frame) static int sys_sys_reserved_create_thread(SyscallsFrame *Frame)
{ {
SmartTimeoutLock(SyscallsLock, 10000);
fixme("sys_sys_reserved_create_thread: %#lx", Frame); fixme("sys_sys_reserved_create_thread: %#lx", Frame);
return -1; return SYSCALL_NOT_IMPLEMENTED;
} }
static void *NativeSyscallsTable[] = { static void *NativeSyscallsTable[] = {
@ -185,8 +276,10 @@ static void *NativeSyscallsTable[] = {
[_RequestPages] = (void *)sys_request_pages, [_RequestPages] = (void *)sys_request_pages,
[_FreePages] = (void *)sys_free_pages, [_FreePages] = (void *)sys_free_pages,
[_DetachAddress] = (void *)sys_detach_address,
[_KernelCTL] = (void *)sys_kernelctl, [_KernelCTL] = (void *)sys_kernelctl,
[_IPC] = (void *)sys_ipc,
[_FileOpen] = (void *)sys_file_open, [_FileOpen] = (void *)sys_file_open,
[_FileClose] = (void *)sys_file_close, [_FileClose] = (void *)sys_file_close,
@ -217,14 +310,14 @@ uintptr_t HandleNativeSyscalls(SyscallsFrame *Frame)
if (Frame->rax > sizeof(NativeSyscallsTable)) if (Frame->rax > sizeof(NativeSyscallsTable))
{ {
fixme("Syscall %lld not implemented", Frame->rax); 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]); uintptr_t (*call)(uintptr_t, ...) = reinterpret_cast<uintptr_t (*)(uintptr_t, ...)>(NativeSyscallsTable[Frame->rax]);
if (!call) if (!call)
{ {
error("Syscall %#llx failed.", Frame->rax); 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); 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); 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 <ipc.hpp>
#include <lock.hpp>
#include <task.hpp> #include <task.hpp>
#include "../kernel.h" #include "../kernel.h"
NewLock(IPCLock);
InterProcessCommunication::IPC *ipc = nullptr;
namespace InterProcessCommunication namespace InterProcessCommunication
{ {
IPCHandle *IPC::RegisterHandle(IPCPort Port) IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16])
{ {
SmartLock(IPCLock); SmartLock(IPCLock);
if (Port == 0)
return nullptr;
Tasking::PCB *pcb = TaskManager->GetCurrentProcess(); IPCHandle *Handle = (IPCHandle *)mem->RequestPages(TO_PAGES(sizeof(IPCHandle)));
Handle->ID = NextID++;
if (pcb->IPCHandles->Get((int)Port) != 0) Handle->Node = vfs->Create(UniqueToken, VirtualFileSystem::NodeFlags::FILE, IPCNode);
return nullptr; Handle->Node->Address = (uintptr_t)mem->RequestPages(TO_PAGES(sizeof(4096)));
Handle->Node->Length = 4096;
IPCHandle *handle = new IPCHandle; Handles.push_back(Handle);
handle->ID = -1; return Handle;
handle->Buffer = nullptr;
handle->Length = 0;
handle->Operation = IPCOperationNone;
handle->Listening = 0;
handle->Error = IPCUnknown;
pcb->IPCHandles->AddNode(Port, (uintptr_t)handle);
return handle;
} }
IPCError IPC::Listen(IPCPort Port) IPCErrorCode IPC::Destroy(IPCID ID)
{ {
SmartLock(IPCLock); SmartLock(IPCLock);
if (Port == 0) for (size_t i = 0; i < Handles.size(); i++)
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++)
{ {
Tasking::PCB *pcb = Processes[i]; if (Handles[i]->ID == ID)
if (pcb->ID == ID)
{ {
if (pcb->IPCHandles->Get((int)Port) == 0) mem->FreePages(Handles[i], TO_PAGES(sizeof(IPCHandle)));
return IPCError{IPCInvalidPort}; Handles.remove(i);
return IPCSuccess;
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;
} }
} }
return IPCIDNotFound;
return IPCError{IPCIDNotFound};
} }
IPC::IPC() IPCErrorCode IPC::Read(IPCID ID, uint8_t *Buffer, long Size)
{ {
SmartLock(IPCLock); 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() 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 namespace Tasking
{ {
struct TokenData
{
Token token;
enum TokenTrustLevel TrustLevel;
uint64_t OwnerID;
bool Process;
};
Vector<TokenData> Tokens;
Token Security::CreateToken() 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}); Tokens.push_back({ret, UnknownTrustLevel, 0, false});
debug("Created token %#lx", ret); debug("Created token %#lx", ret);
return ret; return ret;
} }
bool Security::TrustToken(Token token, bool Security::TrustToken(Token token, TTL TrustLevel)
TokenTrustLevel TrustLevel)
{ {
enum TokenTrustLevel Level = static_cast<enum TokenTrustLevel>(TrustLevel); foreach (auto &t in Tokens)
foreach (auto var in Tokens)
{ {
if (var.token == token) if (t.token == token)
{ {
var.TrustLevel = Level; t.TrustLevel = TrustLevel;
debug("Trusted token %#lx", token); debug("Trusted token %#lx to level %d", token, t.TrustLevel);
return true; return true;
} }
} }
debug("Failed to trust token %#lx", token); warn("Failed to trust token %#lx", token);
return false; return false;
} }
bool Security::UntrustToken(Token token) bool Security::UntrustToken(Token token)
{ {
fixme("UntrustToken->false"); foreach (auto &t in Tokens)
UNUSED(token); {
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; return false;
} }
bool Security::DestroyToken(Token token) bool Security::DestroyToken(Token token)
{ {
fixme("DestroyToken->false"); fixme("DestroyToken->true");
UNUSED(token); 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; 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() Security::~Security()
{ {
trace("Destroying Tasking Security");
for (size_t i = 0; i < Tokens.size(); i++) for (size_t i = 0; i < Tokens.size(); i++)
Tokens.remove(i); Tokens.remove(i);
} }

View File

@ -17,37 +17,25 @@
#elif defined(__aarch64__) #elif defined(__aarch64__)
#endif #endif
// #define DEBUG_SCHEDULER 1 // #define DEBUG_TASKING 1
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
#ifdef DEBUG_SCHEDULER #ifdef DEBUG_TASKING
#define schedbg(m, ...) \ #define tskdbg(m, ...) \
debug(m, ##__VA_ARGS__); \ debug(m, ##__VA_ARGS__); \
__sync_synchronize() __sync_synchronize()
#else #else
#define schedbg(m, ...) #define tskdbg(m, ...)
#endif #endif
NewLock(TaskingLock); NewLock(TaskingLock);
NewLock(SchedulerLock);
namespace Tasking 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() void Task::Schedule()
{ {
if (!StopScheduler) if (!StopScheduler)
OneShot(100); TaskingScheduler_OneShot(100);
// APIC::InterruptCommandRegisterLow icr; // APIC::InterruptCommandRegisterLow icr;
// icr.Vector = CPU::x64::IRQ16; // icr.Vector = CPU::x64::IRQ16;
// icr.Level = APIC::APICLevel::Assert; // icr.Level = APIC::APICLevel::Assert;
@ -71,9 +59,11 @@ namespace Tasking
{ {
if (!pcb) if (!pcb)
return true; 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; 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 true;
return false; return false;
} }
@ -82,9 +72,11 @@ namespace Tasking
{ {
if (!tcb) if (!tcb)
return true; 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; 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 true;
return false; return false;
} }
@ -126,11 +118,27 @@ namespace Tasking
{ {
trace("Process \"%s\"(%d) removed from the list", Process->Name, Process->ID); trace("Process \"%s\"(%d) removed from the list", Process->Name, Process->ID);
// Free memory // Free memory
delete ListProcess[i]->IPCHandles; delete ListProcess[i]->IPC;
delete ListProcess[i]->ELFSymbolTable; delete ListProcess[i]->ELFSymbolTable;
SecurityManager.DestroyToken(ListProcess[i]->Security.UniqueToken); SecurityManager.DestroyToken(ListProcess[i]->Security.UniqueToken);
if (ListProcess[i]->Security.TrustLevel == TaskTrustLevel::User) if (ListProcess[i]->Security.TrustLevel == TaskTrustLevel::User)
KernelAllocator.FreePages((void *)ListProcess[i]->PageTable, TO_PAGES(PAGE_SIZE)); 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]; delete ListProcess[i];
// Remove from the list // Remove from the list
ListProcess.remove(i); 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() void ThreadDoExit()
{ {
// TODO: How I can lock the scheduler without causing a deadlock? // TODO: How I can lock the scheduler without causing a deadlock?
@ -789,6 +224,28 @@ namespace Tasking
CPU::Halt(); 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) void Task::Sleep(uint64_t Milliseconds)
{ {
SmartCriticalSection(TaskingLock); SmartCriticalSection(TaskingLock);
@ -797,11 +254,11 @@ namespace Tasking
if (thread->Parent->Threads.size() == 1) if (thread->Parent->Threads.size() == 1)
thread->Parent->Status = TaskStatus::Sleeping; thread->Parent->Status = TaskStatus::Sleeping;
thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds); thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds);
schedbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil); tskdbg("Thread \"%s\"(%d) is going to sleep until %llu", thread->Name, thread->ID, thread->Info.SleepUntil);
// OneShot(1); // TaskingScheduler_OneShot(1);
// IRQ16 // IRQ16
TaskingLock.Unlock(); 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() void Task::SignalShutdown()
@ -811,11 +268,59 @@ namespace Tasking
// This should hang until all processes are terminated // 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, TCB *Task::CreateThread(PCB *Parent,
IP EntryPoint, IP EntryPoint,
const char **argv, const char **argv,
const char **envp, const char **envp,
Vector<AuxiliaryVector> &auxv, const Vector<AuxiliaryVector> &auxv,
IPOffset Offset, IPOffset Offset,
TaskArchitecture Architecture, TaskArchitecture Architecture,
TaskCompatibility Compatibility) TaskCompatibility Compatibility)
@ -848,10 +353,13 @@ namespace Tasking
Thread->Offset = Offset; Thread->Offset = Offset;
Thread->ExitCode = 0xdead; Thread->ExitCode = 0xdead;
Thread->Status = TaskStatus::Ready; 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))); 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)))); 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? // TODO: Is really a good idea to use the FPU in kernel mode?
Thread->FPU->mxcsr = 0b0001111110000000; Thread->FPU->mxcsr = 0b0001111110000000;
Thread->FPU->mxcsrmask = 0b1111111110111111; Thread->FPU->mxcsrmask = 0b1111111110111111;
@ -881,12 +389,11 @@ namespace Tasking
case TaskTrustLevel::System: case TaskTrustLevel::System:
warn("Trust level not supported."); warn("Trust level not supported.");
[[fallthrough]]; [[fallthrough]];
case TaskTrustLevel::Idle:
case TaskTrustLevel::Kernel: case TaskTrustLevel::Kernel:
{ {
Thread->Stack = new Memory::StackGuard(false, Parent->PageTable); Thread->Stack = new Memory::StackGuard(false, Parent->PageTable);
#if defined(__amd64__) #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->GSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_GS_BASE);
Thread->FSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_FS_BASE); Thread->FSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_FS_BASE);
Thread->Registers.cs = GDT_KERNEL_CODE; Thread->Registers.cs = GDT_KERNEL_CODE;
@ -905,7 +412,7 @@ namespace Tasking
{ {
Thread->Stack = new Memory::StackGuard(true, Parent->PageTable); Thread->Stack = new Memory::StackGuard(true, Parent->PageTable);
#if defined(__amd64__) #if defined(__amd64__)
SecurityManager.TrustToken(Thread->Security.UniqueToken, TokenTrustLevel::Untrusted); SecurityManager.TrustToken(Thread->Security.UniqueToken, TTL::Untrusted);
Thread->GSBase = 0; Thread->GSBase = 0;
Thread->FSBase = 0; Thread->FSBase = 0;
Thread->Registers.cs = GDT_USER_CODE; Thread->Registers.cs = GDT_USER_CODE;
@ -981,8 +488,13 @@ namespace Tasking
Stack64--; Stack64--;
*Stack64 = AT_NULL; *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 // Store auxillary vector
foreach (AuxiliaryVector var in auxv) foreach (AuxiliaryVector var in auxv_array)
{ {
// Subtract the size of the auxillary vector // Subtract the size of the auxillary vector
Stack64 -= sizeof(Elf64_auxv_t) / sizeof(uintptr_t); Stack64 -= sizeof(Elf64_auxv_t) / sizeof(uintptr_t);
@ -1052,7 +564,7 @@ namespace Tasking
#elif defined(__i386__) #elif defined(__i386__)
#elif defined(__aarch64__) #elif defined(__aarch64__)
#endif #endif
#ifdef DEBUG_SCHEDULER #ifdef DEBUG_TASKING
DumpData(Thread->Name, Thread->Stack, STACK_SIZE); DumpData(Thread->Name, Thread->Stack, STACK_SIZE);
#endif #endif
break; break;
@ -1067,9 +579,6 @@ namespace Tasking
} }
} }
Thread->Security.TrustLevel = Parent->Security.TrustLevel;
// Thread->Security.UniqueToken = SecurityManager.CreateToken();
Thread->Info = {}; Thread->Info = {};
Thread->Info.SpawnTime = CPU::Counter(); Thread->Info.SpawnTime = CPU::Counter();
Thread->Info.Year = 0; Thread->Info.Year = 0;
@ -1083,7 +592,7 @@ namespace Tasking
Thread->Info.Usage[i] = 0; Thread->Info.Usage[i] = 0;
Thread->Info.Affinity[i] = true; Thread->Info.Affinity[i] = true;
} }
Thread->Info.Priority = 10; Thread->Info.Priority = TaskPriority::Normal;
Thread->Info.Architecture = Architecture; Thread->Info.Architecture = Architecture;
Thread->Info.Compatibility = Compatibility; Thread->Info.Compatibility = Compatibility;
@ -1128,19 +637,22 @@ namespace Tasking
Process->Status = TaskStatus::Ready; Process->Status = TaskStatus::Ready;
Process->Security.TrustLevel = TrustLevel; 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) switch (TrustLevel)
{ {
case TaskTrustLevel::System: case TaskTrustLevel::System:
warn("Trust level not supported."); warn("Trust level not supported.");
[[fallthrough]]; [[fallthrough]];
case TaskTrustLevel::Idle:
case TaskTrustLevel::Kernel: case TaskTrustLevel::Kernel:
{ {
SecurityManager.TrustToken(Process->Security.UniqueToken, TokenTrustLevel::TrustedByKernel); SecurityManager.TrustToken(Process->Security.UniqueToken, TTL::TrustedByKernel);
#if defined(__amd64__) #if defined(__amd64__)
if (!DoNotCreatePageTable) if (!DoNotCreatePageTable)
Process->PageTable = (Memory::PageTable4 *)CPU::x64::readcr3().raw; Process->PageTable = (Memory::PageTable4 *)CPU::x64::readcr3().raw;
@ -1151,7 +663,7 @@ namespace Tasking
} }
case TaskTrustLevel::User: case TaskTrustLevel::User:
{ {
SecurityManager.TrustToken(Process->Security.UniqueToken, TokenTrustLevel::Untrusted); SecurityManager.TrustToken(Process->Security.UniqueToken, TTL::Untrusted);
#if defined(__amd64__) #if defined(__amd64__)
if (!DoNotCreatePageTable) if (!DoNotCreatePageTable)
{ {
@ -1187,7 +699,7 @@ namespace Tasking
Process->Info.Usage[i] = 0; Process->Info.Usage[i] = 0;
Process->Info.Affinity[i] = true; Process->Info.Affinity[i] = true;
} }
Process->Info.Priority = 10; Process->Info.Priority = TaskPriority::Normal;
debug("Process page table: %#lx", Process->PageTable); debug("Process page table: %#lx", Process->PageTable);
debug("Created process \"%s\"(%d) in process \"%s\"(%d)", debug("Created process \"%s\"(%d) in process \"%s\"(%d)",
@ -1229,8 +741,7 @@ namespace Tasking
TaskArchitecture Arch = TaskArchitecture::ARM64; TaskArchitecture Arch = TaskArchitecture::ARM64;
#endif #endif
PCB *kproc = CreateProcess(nullptr, "Kernel", TaskTrustLevel::Kernel); PCB *kproc = CreateProcess(nullptr, "Kernel", TaskTrustLevel::Kernel);
Vector<AuxiliaryVector> auxv; TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, Vector<AuxiliaryVector>(), 0, Arch);
TCB *kthrd = CreateThread(kproc, EntryPoint, nullptr, nullptr, auxv, 0, Arch);
kthrd->Rename("Main Thread"); kthrd->Rename("Main Thread");
debug("Created Kernel Process: %s and Thread: %s", kproc->Name, kthrd->Name); debug("Created Kernel Process: %s and Thread: %s", kproc->Name, kthrd->Name);
TaskingLock.Lock(__FUNCTION__); TaskingLock.Lock(__FUNCTION__);
@ -1277,15 +788,14 @@ namespace Tasking
} }
TaskingLock.Unlock(); TaskingLock.Unlock();
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskTrustLevel::Idle); IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskTrustLevel::Kernel);
for (int i = 0; i < SMP::CPUCores; i++) for (int i = 0; i < SMP::CPUCores; i++)
{ {
Vector<AuxiliaryVector> auxv; IdleThread = CreateThread(IdleProcess, reinterpret_cast<uintptr_t>(IdleProcessLoop));
IdleThread = CreateThread(IdleProcess, reinterpret_cast<uintptr_t>(IdleProcessLoop), nullptr, nullptr, auxv);
char IdleName[16]; char IdleName[16];
sprintf(IdleName, "Idle Thread %d", i); sprintf(IdleName, "Idle Thread %d", i);
IdleThread->Rename(IdleName); IdleThread->Rename(IdleName);
IdleThread->SetPriority(1); IdleThread->SetPriority(Idle);
break; break;
} }
debug("Tasking Started"); debug("Tasking Started");
@ -1310,23 +820,21 @@ namespace Tasking
{ {
SmartCriticalSection(TaskingLock); SmartCriticalSection(TaskingLock);
trace("Stopping tasking"); 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; Thread->Status = TaskStatus::Terminated;
}
Process->Status = TaskStatus::Terminated; Process->Status = TaskStatus::Terminated;
} }
TaskingLock.Unlock(); TaskingLock.Unlock();
SchedulerLock.Unlock();
while (ListProcess.size() > 0) while (ListProcess.size() > 0)
{ {
trace("Waiting for %d processes to terminate", ListProcess.size()); trace("Waiting for %d processes to terminate", ListProcess.size());
int NotTerminated = 0; 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); 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) if (Process->Status == TaskStatus::Terminated)
@ -1335,7 +843,7 @@ namespace Tasking
} }
if (NotTerminated == 0) if (NotTerminated == 0)
break; break;
OneShot(100); TaskingScheduler_OneShot(100);
} }
trace("Tasking stopped"); 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]); 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 isalpha(int c);
int isupper(int c); int isupper(int c);
unsigned int isdelim(char c, char *delim); unsigned int isdelim(char c, char *delim);
int abs(int i); long abs(long i);
void swap(char *x, char *y); void swap(char *x, char *y);
char *reverse(char *Buffer, int i, int j); char *reverse(char *Buffer, int i, int j);

View File

@ -8,7 +8,7 @@
/* 32-bit ELF base types. */ /* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Addr;
typedef uint64_t Elf32_Half; typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off; typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword; typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word; typedef uint32_t Elf32_Word;
@ -153,6 +153,13 @@ struct Elf64_Dyn
} d_un; } d_un;
}; };
typedef struct
{
Elf64_Addr r_offset;
Elf64_Xword r_info;
Elf64_Sxword r_addend;
} Elf64_Rela;
enum Elf_Ident enum Elf_Ident
{ {
EI_MAG0 = 0, // 0x7F EI_MAG0 = 0, // 0x7F
@ -184,7 +191,7 @@ enum Elf_OSABI
ELFOSABI_OPENVMS = 13, ELFOSABI_OPENVMS = 13,
ELFOSABI_NSK = 14, ELFOSABI_NSK = 14,
ELFOSABI_AROS = 15, ELFOSABI_AROS = 15,
ELFOSABI_FENIXOS = 16, /* Wait... what? */ ELFOSABI_FENIXOS = 16,
ELFOSABI_CLOUDABI = 17, ELFOSABI_CLOUDABI = 17,
ELFOSABI_OPENVOS = 18, ELFOSABI_OPENVOS = 18,
ELFOSABI_C6000_ELFABI = 64, ELFOSABI_C6000_ELFABI = 64,
@ -208,7 +215,28 @@ enum RtT_Types
{ {
R_386_NONE = 0, // No relocation R_386_NONE = 0, // No relocation
R_386_32 = 1, // Symbol + Offset 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 enum StT_Bindings
@ -359,11 +387,13 @@ enum DynamicArrayTags
#define DO_64_64(S, A) ((S) + (A)) #define DO_64_64(S, A) ((S) + (A))
#define DO_64_PC32(S, A, P) ((S) + (A) - (P)) #define DO_64_PC32(S, A, P) ((S) + (A) - (P))
#define ELF32_R_SYM(INFO) ((INFO) >> 8) #define ELF32_R_SYM(i) ((i) >> 8)
#define ELF32_R_TYPE(INFO) ((uint8_t)(INFO)) #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_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(INFO) ((uint8_t)(INFO)) #define ELF64_R_TYPE(i) ((i)&0xffffffffL)
#define ELF64_R_INFO(s, t) (((s) << 32) + ((t)&0xffffffffL))
#define SHN_UNDEF 0 #define SHN_UNDEF 0
#define SHN_ABS 0xfff1 #define SHN_ABS 0xfff1
@ -374,10 +404,12 @@ enum DynamicArrayTags
#define SHF_WRITE 0x1 #define SHF_WRITE 0x1
#define SHF_ALLOC 0x2 #define SHF_ALLOC 0x2
#define EM_386 (3) // x86 Machine Type #define EM_386 0x3 // x86 Machine Type
#define EM_AMD64 (0x3E) // 64bit #define EM_X86_64 0x3E // 64bit
#define EM_AARCH64 (0xb7) // ARM64 #define EM_ARM 0x28 // ARM
#define EV_CURRENT (1) // ELF Current Version #define EM_AARCH64 0xb7 // ARM64
#define EV_CURRENT 0x1 // ELF Current Version
#define ELFMAG0 0x7F // e_ident[EI_MAG0] #define ELFMAG0 0x7F // e_ident[EI_MAG0]
#define ELFMAG1 'E' // e_ident[EI_MAG1] #define ELFMAG1 'E' // e_ident[EI_MAG1]

View File

@ -3,6 +3,7 @@
#include <types.h> #include <types.h>
#include <filesystem.hpp>
#include <task.hpp> #include <task.hpp>
#include <elf.h> #include <elf.h>
@ -21,9 +22,10 @@ namespace Execute
enum ExStatus enum ExStatus
{ {
OK,
Unknown, Unknown,
OK,
Unsupported, Unsupported,
GenericError,
InvalidFile, InvalidFile,
InvalidFileFormat, InvalidFileFormat,
InvalidFileHeader, InvalidFileHeader,
@ -39,21 +41,78 @@ namespace Execute
Tasking::TCB *Thread; 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); BinaryType GetBinaryType(char *Path);
SpawnData Spawn(char *Path, const char **argv, const char **envp); SpawnData Spawn(char *Path, const char **argv, const char **envp);
void *ELFLoadRel(Elf64_Ehdr *Header); ELFBaseLoad ELFLoad(char *Path, const char **argv, const char **envp,
void ELFLoadExec(void *BaseImage, Tasking::TaskCompatibility Compatibility = Tasking::TaskCompatibility::Native);
size_t Length,
Elf64_Ehdr *ELFHeader, Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header);
Memory::Virtual &pva, Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index);
SpawnData *ret, char *GetELFStringTable(Elf64_Ehdr *Header);
char *Path, char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset);
Tasking::PCB *Process, void *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name);
const char **argv, uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index);
const char **envp, Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag);
Tasking::TaskArchitecture Arch,
Tasking::TaskCompatibility Comp); /**
* @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__ #endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__

View File

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

View File

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

View File

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

View File

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

View File

@ -5,13 +5,13 @@
#include <filesystem.hpp> #include <filesystem.hpp>
namespace FileSystem namespace VirtualFileSystem
{ {
/* Manage /system/dev */ /* Manage /system/dev */
class Device class Device
{ {
public: 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();
~Device(); ~Device();
}; };
@ -20,7 +20,7 @@ namespace FileSystem
class Mount class Mount
{ {
public: 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); void DetectAndMountFS(void *drive);
Mount(); Mount();
~Mount(); ~Mount();
@ -38,7 +38,7 @@ namespace FileSystem
class Driver class Driver
{ {
public: 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();
~Driver(); ~Driver();
}; };
@ -47,7 +47,7 @@ namespace FileSystem
class Network class Network
{ {
public: 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();
~Network(); ~Network();
}; };

View File

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

View File

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

View File

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

View File

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

View File

@ -29,31 +29,31 @@
template <class T> template <class T>
class smart_ptr class smart_ptr
{ {
T *RealPointer; T *m_RealPointer;
public: public:
explicit smart_ptr(T *p = nullptr) explicit smart_ptr(T *Pointer = nullptr)
{ {
spdbg("Smart pointer created (%#lx)", RealPointer); spdbg("Smart pointer created (%#lx)", m_RealPointer);
RealPointer = p; m_RealPointer = Pointer;
} }
~smart_ptr() ~smart_ptr()
{ {
spdbg("Smart pointer deleted (%#lx)", RealPointer); spdbg("Smart pointer deleted (%#lx)", m_RealPointer);
delete (RealPointer); delete (m_RealPointer);
} }
T &operator*() T &operator*()
{ {
spdbg("Smart pointer dereferenced (%#lx)", RealPointer); spdbg("Smart pointer dereferenced (%#lx)", m_RealPointer);
return *RealPointer; return *m_RealPointer;
} }
T *operator->() T *operator->()
{ {
spdbg("Smart pointer dereferenced (%#lx)", RealPointer); spdbg("Smart pointer dereferenced (%#lx)", m_RealPointer);
return RealPointer; return m_RealPointer;
} }
}; };
@ -67,6 +67,11 @@ class unique_ptr
{ {
}; };
template <class T>
class weak_ptr
{
};
template <typename T> template <typename T>
class shared_ptr class shared_ptr
{ {
@ -74,81 +79,190 @@ private:
class Counter class Counter
{ {
private: private:
unsigned int RefCount{}; unsigned int m_RefCount{};
public: public:
Counter() : RefCount(0){}; Counter() : m_RefCount(0) { spdbg("Counter %#lx created", this); };
Counter(const Counter &) = delete; Counter(const Counter &) = delete;
Counter &operator=(const Counter &) = delete; Counter &operator=(const Counter &) = delete;
~Counter() {} ~Counter() { spdbg("Counter %#lx deleted", this); }
void Reset() { RefCount = 0; } void Reset()
unsigned int Get() { return RefCount; } {
void operator++() { RefCount++; } m_RefCount = 0;
void operator++(int) { RefCount++; } spdbg("Counter reset");
void operator--() { RefCount--; } }
void operator--(int) { RefCount--; }
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; Counter *m_ReferenceCounter;
T *RealPointer; T *m_RealPointer;
public: public:
explicit shared_ptr(T *Pointer = nullptr) explicit shared_ptr(T *Pointer = nullptr)
{ {
spdbg("Shared pointer created (%#lx)", RealPointer); m_RealPointer = Pointer;
RealPointer = Pointer; m_ReferenceCounter = new Counter();
ReferenceCounter = new Counter(); spdbg("[%#lx] Shared pointer created (ptr=%#lx, ref=%#lx)", this, Pointer, m_ReferenceCounter);
if (Pointer) if (Pointer)
(*ReferenceCounter)++; (*m_ReferenceCounter)++;
} }
shared_ptr(shared_ptr<T> &SPtr) shared_ptr(shared_ptr<T> &SPtr)
{ {
spdbg("Shared pointer copied (%#lx)", RealPointer); spdbg("[%#lx] Shared pointer copied (ptr=%#lx, ref=%#lx)", this, SPtr.m_RealPointer, SPtr.m_ReferenceCounter);
RealPointer = SPtr.RealPointer; m_RealPointer = SPtr.m_RealPointer;
ReferenceCounter = SPtr.ReferenceCounter; m_ReferenceCounter = SPtr.m_ReferenceCounter;
(*ReferenceCounter)++; (*m_ReferenceCounter)++;
} }
~shared_ptr() ~shared_ptr()
{ {
spdbg("Shared pointer deleted (%#lx)", RealPointer); spdbg("[%#lx] Shared pointer destructor called", this);
(*ReferenceCounter)--; (*m_ReferenceCounter)--;
if (ReferenceCounter->Get() == 0) if (m_ReferenceCounter->Get() == 0)
{ {
delete ReferenceCounter; spdbg("[%#lx] Shared pointer deleted (ptr=%#lx, ref=%#lx)", this, m_RealPointer, m_ReferenceCounter);
delete RealPointer; delete m_ReferenceCounter;
delete m_RealPointer;
} }
} }
unsigned int GetCount() unsigned int GetCount()
{ {
spdbg("Shared pointer count (%#lx)", RealPointer); spdbg("[%#lx] Shared pointer count (%d)", this, m_ReferenceCounter->Get());
return ReferenceCounter->Get(); return m_ReferenceCounter->Get();
} }
T *Get() T *Get()
{ {
spdbg("Shared pointer get (%#lx)", RealPointer); spdbg("[%#lx] Shared pointer get (%#lx)", this, m_RealPointer);
return RealPointer; return m_RealPointer;
} }
T &operator*() T &operator*()
{ {
spdbg("Shared pointer dereference (%#lx)", RealPointer); spdbg("[%#lx] Shared pointer dereference (ptr*=%#lx)", this, *m_RealPointer);
return *RealPointer; return *m_RealPointer;
} }
T *operator->() T *operator->()
{ {
spdbg("Shared pointer dereference (%#lx)", RealPointer); spdbg("[%#lx] Shared pointer dereference (ptr->%#lx)", this, m_RealPointer);
return 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> template <typename T>
class weak_ptr 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__ #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(uintptr_t ImageAddress);
~Symbols(); ~Symbols();
const char *GetSymbolFromAddress(uintptr_t Address); const char *GetSymbolFromAddress(uintptr_t Address);
void AddSymbol(uintptr_t Address, const char *Name);
}; };
} }

View File

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

View File

@ -1,40 +1,189 @@
#ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__ #ifndef __FENNIX_KERNEL_SYSCALLS_LIST_H__
#define __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 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, _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, _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, _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, _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, _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, _FileOpen,
/** @brief Close a file
* @fn
* This syscall is used to close a file that was previously opened.
*/
_FileClose, _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, _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, _FileWrite,
/** @brief Seek in a file
* @fn
* This syscall is used to change the current offset in a file.
*/
_FileSeek, _FileSeek,
/** @brief Get file status
* @fn
* This syscall is used to retrieve information about a file such as its size, permissions, etc.
*/
_FileStatus, _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, _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, _Kill,
/** @brief Spawn a new process
* @fn
* This syscall is used to create a new process with the provided path and arguments.
*/
_Spawn, _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, _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, _GetThreadListOfProcess,
/** @brief Get current process
* @fn
* This syscall is used to retrieve information about the current process.
*/
_GetCurrentProcess, _GetCurrentProcess,
/** @brief Get current thread
* @fn
* This syscall is used to retrieve information about the current thread.
*/
_GetCurrentThread, _GetCurrentThread,
/** @brief Get process by PID
* @fn
* This syscall is used to retrieve information about a specific process by its PID.
*/
_GetProcessByPID, _GetProcessByPID,
/** @brief Get thread by TID
* @fn
* This syscall is used to retrieve information about a specific thread by its TID.
*/
_GetThreadByTID, _GetThreadByTID,
/** @brief Kill a process
* @fn
* This syscall is used to send a termination signal to a specific process.
*/
_KillProcess, _KillProcess,
/** @brief Kill a thread
* @fn
* This syscall is used to send a termination signal to a specific thread.
*/
_KillThread, _KillThread,
/** @brief Reserved syscall */
_SysReservedCreateProcess, _SysReservedCreateProcess,
/** @brief Reserved syscall */
_SysReservedCreateThread, _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) static inline long syscall0(long syscall)
{ {
unsigned long ret; unsigned long ret;