mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-31 16:57:58 +00:00
Updated kernel (tl;dr: improved filesystem, tasking, loading files, etc..)
This commit is contained in:
parent
640f6a412a
commit
a592b85ce5
@ -168,27 +168,35 @@ namespace Driver
|
|||||||
Driver::Driver()
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
162
Execute/Elf/BaseLoad.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#include <exec.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <lock.hpp>
|
||||||
|
#include <msexec.h>
|
||||||
|
#include <cwalk.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <abi.h>
|
||||||
|
|
||||||
|
#include "../../kernel.h"
|
||||||
|
#include "../../Fex.hpp"
|
||||||
|
|
||||||
|
using namespace Tasking;
|
||||||
|
using VirtualFileSystem::File;
|
||||||
|
using VirtualFileSystem::FileStatus;
|
||||||
|
using VirtualFileSystem::NodeFlags;
|
||||||
|
|
||||||
|
namespace Execute
|
||||||
|
{
|
||||||
|
ELFBaseLoad ELFLoad(char *Path, const char **argv, const char **envp, Tasking::TaskCompatibility Compatibility)
|
||||||
|
{
|
||||||
|
/* We get the base name ("app.elf") */
|
||||||
|
const char *BaseName;
|
||||||
|
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||||
|
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
|
||||||
|
|
||||||
|
shared_ptr<File> ExFile = vfs->Open(Path);
|
||||||
|
|
||||||
|
if (ExFile->Status != FileStatus::OK)
|
||||||
|
{
|
||||||
|
vfs->Close(ExFile);
|
||||||
|
error("Failed to open file: %s", Path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ExFile->node->Flags != NodeFlags::FILE)
|
||||||
|
{
|
||||||
|
vfs->Close(ExFile);
|
||||||
|
error("Invalid file path: %s", Path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
else if (GetBinaryType(Path) != BinaryType::BinTypeELF)
|
||||||
|
{
|
||||||
|
vfs->Close(ExFile);
|
||||||
|
error("Invalid file type: %s", Path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ExFileSize = ExFile->node->Length;
|
||||||
|
|
||||||
|
/* Allocate elf in memory */
|
||||||
|
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize));
|
||||||
|
/* Copy the file to the allocated memory */
|
||||||
|
memcpy(ElfFile, (void *)ExFile->node->Address, ExFileSize);
|
||||||
|
debug("Image Size: %#lx - %#lx (length: %ld)", ElfFile, (uintptr_t)ElfFile + ExFileSize, ExFileSize);
|
||||||
|
|
||||||
|
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||||
|
|
||||||
|
switch (ELFHeader->e_machine)
|
||||||
|
{
|
||||||
|
case EM_386:
|
||||||
|
Arch = TaskArchitecture::x32;
|
||||||
|
break;
|
||||||
|
case EM_X86_64:
|
||||||
|
Arch = TaskArchitecture::x64;
|
||||||
|
break;
|
||||||
|
case EM_ARM:
|
||||||
|
Arch = TaskArchitecture::ARM32;
|
||||||
|
break;
|
||||||
|
case EM_AARCH64:
|
||||||
|
Arch = TaskArchitecture::ARM64;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This shouldn't be ignored
|
||||||
|
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
|
||||||
|
{
|
||||||
|
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||||
|
fixme("ELF32 LSB");
|
||||||
|
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||||
|
fixme("ELF32 MSB");
|
||||||
|
else
|
||||||
|
fixme("ELF32 Unknown");
|
||||||
|
}
|
||||||
|
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
|
||||||
|
{
|
||||||
|
if (ELFHeader->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||||
|
fixme("ELF64 LSB");
|
||||||
|
else if (ELFHeader->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||||
|
fixme("ELF64 MSB");
|
||||||
|
else
|
||||||
|
fixme("ELF64 Unknown");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fixme("Unknown ELF");
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User, ElfFile);
|
||||||
|
Memory::Virtual pV = Memory::Virtual(Process->PageTable);
|
||||||
|
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
|
||||||
|
pV.Remap((void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||||
|
|
||||||
|
// for (size_t i = 0; i < TO_PAGES(ElfLazyResolverSize); i++)
|
||||||
|
// pV.Remap((void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), (void *)((uintptr_t)ElfLazyResolver + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||||
|
|
||||||
|
/* We prepare the ELF for execution (allocate memory, etc...) */
|
||||||
|
ELFBaseLoad bl;
|
||||||
|
|
||||||
|
switch (ELFHeader->e_type)
|
||||||
|
{
|
||||||
|
case ET_REL:
|
||||||
|
bl = ELFLoadRel(ElfFile, ExFile.Get(), Process);
|
||||||
|
break;
|
||||||
|
case ET_EXEC:
|
||||||
|
bl = ELFLoadExec(ElfFile, ExFile.Get(), Process);
|
||||||
|
break;
|
||||||
|
case ET_DYN:
|
||||||
|
bl = ELFLoadDyn(ElfFile, ExFile.Get(), Process);
|
||||||
|
break;
|
||||||
|
case ET_CORE:
|
||||||
|
{
|
||||||
|
fixme("ET_CORE not implemented");
|
||||||
|
TaskManager->RevertProcessCreation(Process);
|
||||||
|
vfs->Close(ExFile);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
case ET_NONE:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
error("Unknown ELF Type: %d", ELFHeader->e_type);
|
||||||
|
vfs->Close(ExFile);
|
||||||
|
TaskManager->RevertProcessCreation(Process);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB *Thread = TaskManager->CreateThread(Process,
|
||||||
|
bl.InstructionPointer,
|
||||||
|
argv, envp, bl.auxv,
|
||||||
|
(IPOffset)0 /* ProgramHeader->p_offset */, // I guess I don't need this
|
||||||
|
Arch,
|
||||||
|
Compatibility);
|
||||||
|
|
||||||
|
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
|
||||||
|
{
|
||||||
|
Thread->Memory->Add(p.Address, p.PageCount);
|
||||||
|
bl.TmpMem->DetachAddress(p.Address);
|
||||||
|
}
|
||||||
|
delete bl.TmpMem;
|
||||||
|
|
||||||
|
bl.sd.Process = Process;
|
||||||
|
bl.sd.Thread = Thread;
|
||||||
|
bl.sd.Status = ExStatus::OK;
|
||||||
|
vfs->Close(ExFile);
|
||||||
|
return bl;
|
||||||
|
}
|
||||||
|
}
|
24
Execute/Elf/Dyn.cpp
Normal file
24
Execute/Elf/Dyn.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <exec.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <lock.hpp>
|
||||||
|
#include <msexec.h>
|
||||||
|
#include <cwalk.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <abi.h>
|
||||||
|
|
||||||
|
#include "../../kernel.h"
|
||||||
|
#include "../../Fex.hpp"
|
||||||
|
|
||||||
|
using namespace Tasking;
|
||||||
|
|
||||||
|
namespace Execute
|
||||||
|
{
|
||||||
|
ELFBaseLoad ELFLoadDyn(void *BaseImage,
|
||||||
|
VirtualFileSystem::File *ExFile,
|
||||||
|
Tasking::PCB *Process)
|
||||||
|
{
|
||||||
|
fixme("Not implemented");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
@ -14,102 +14,62 @@ using namespace Tasking;
|
|||||||
|
|
||||||
namespace Execute
|
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
284
Execute/Elf/Parse.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
#include <exec.hpp>
|
||||||
|
|
||||||
|
#include <msexec.h>
|
||||||
|
|
||||||
|
#include "../../kernel.h"
|
||||||
|
#include "../../Fex.hpp"
|
||||||
|
|
||||||
|
namespace Execute
|
||||||
|
{
|
||||||
|
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||||
|
|
||||||
|
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
|
||||||
|
{
|
||||||
|
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
|
||||||
|
{
|
||||||
|
return &GetELFSheader(Header)[Index];
|
||||||
|
}
|
||||||
|
|
||||||
|
char *GetELFStringTable(Elf64_Ehdr *Header)
|
||||||
|
{
|
||||||
|
if (Header->e_shstrndx == SHN_UNDEF)
|
||||||
|
return nullptr;
|
||||||
|
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
|
||||||
|
{
|
||||||
|
char *StringTable = GetELFStringTable(Header);
|
||||||
|
if (StringTable == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return StringTable + Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
|
||||||
|
{
|
||||||
|
Elf64_Shdr *SymbolTable = nullptr;
|
||||||
|
Elf64_Shdr *StringTable = nullptr;
|
||||||
|
Elf64_Sym *Symbol = nullptr;
|
||||||
|
char *String = nullptr;
|
||||||
|
|
||||||
|
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
|
||||||
|
{
|
||||||
|
Elf64_Shdr *shdr = GetELFSection(Header, i);
|
||||||
|
switch (shdr->sh_type)
|
||||||
|
{
|
||||||
|
case SHT_SYMTAB:
|
||||||
|
SymbolTable = shdr;
|
||||||
|
StringTable = GetELFSection(Header, shdr->sh_link);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SymbolTable == nullptr || StringTable == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
|
||||||
|
{
|
||||||
|
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||||
|
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||||
|
if (strcmp(String, Name) == 0)
|
||||||
|
return (void *)Symbol->st_value;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
|
||||||
|
{
|
||||||
|
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
|
||||||
|
return 0;
|
||||||
|
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
|
||||||
|
|
||||||
|
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
|
||||||
|
if (Index >= STEntries)
|
||||||
|
{
|
||||||
|
error("Symbol index out of range %d-%u.", Table, Index);
|
||||||
|
return 0xdead;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
|
||||||
|
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
|
||||||
|
|
||||||
|
if (Symbol->st_shndx == SHN_UNDEF)
|
||||||
|
{
|
||||||
|
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
|
||||||
|
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
|
||||||
|
|
||||||
|
void *Target = ELFLookupSymbol(Header, Name);
|
||||||
|
if (Target == nullptr)
|
||||||
|
{
|
||||||
|
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error("Undefined external symbol \"%s\".", Name);
|
||||||
|
return 0xdead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return (uintptr_t)Target;
|
||||||
|
}
|
||||||
|
else if (Symbol->st_shndx == SHN_ABS)
|
||||||
|
return Symbol->st_value;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
|
||||||
|
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicArrayTags Tag)
|
||||||
|
{
|
||||||
|
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||||
|
|
||||||
|
Elf64_Phdr ItrPhdr;
|
||||||
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||||
|
{
|
||||||
|
memcpy(&ItrPhdr, (uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
|
||||||
|
if (ItrPhdr.p_type == PT_DYNAMIC)
|
||||||
|
{
|
||||||
|
Elf64_Dyn *Dynamic = (Elf64_Dyn *)((uint8_t *)ElfFile + ItrPhdr.p_offset);
|
||||||
|
for (size_t i = 0; i < ItrPhdr.p_filesz / sizeof(Elf64_Dyn); i++)
|
||||||
|
{
|
||||||
|
if (Dynamic[i].d_tag == Tag)
|
||||||
|
{
|
||||||
|
debug("Found dynamic tag %d at %#lx [d_val: %#lx].", Tag, &Dynamic[i], Dynamic[i].d_un.d_val);
|
||||||
|
return &Dynamic[i];
|
||||||
|
}
|
||||||
|
if (Dynamic[i].d_tag == DT_NULL)
|
||||||
|
{
|
||||||
|
debug("Reached end of dynamic tag list for tag %d.", Tag);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug("Dynamic tag %d not found.", Tag);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ELFCreateMemoryImage(Memory::MemMgr *mem, Memory::Virtual &pV, void *ElfFile, size_t Length)
|
||||||
|
{
|
||||||
|
void *MemoryImage = nullptr;
|
||||||
|
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
||||||
|
|
||||||
|
/* TODO: Not sure what I am supposed to do with this.
|
||||||
|
* It is supposed to detect if it's PIC or not but I
|
||||||
|
* don't know if it's right. */
|
||||||
|
if (ELFGetDynamicTag(ElfFile, DT_TEXTREL))
|
||||||
|
{
|
||||||
|
fixme("Text relocation is not(?) tested yet!");
|
||||||
|
MemoryImage = (uint8_t *)mem->RequestPages(TO_PAGES(Length), true);
|
||||||
|
memset(MemoryImage, 0, Length);
|
||||||
|
return MemoryImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
Elf64_Phdr ItrPhdr;
|
||||||
|
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
|
||||||
|
|
||||||
|
bool FirstProgramHeader = false;
|
||||||
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||||
|
{
|
||||||
|
memcpy(&ItrPhdr,
|
||||||
|
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||||
|
sizeof(Elf64_Phdr));
|
||||||
|
|
||||||
|
if (ItrPhdr.p_type == PT_LOAD && !FirstProgramHeader)
|
||||||
|
{
|
||||||
|
FirstProgramHeaderVirtualAddress = ItrPhdr.p_vaddr;
|
||||||
|
FirstProgramHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ItrPhdr.p_type == PT_LOAD && ItrPhdr.p_vaddr == 0)
|
||||||
|
{
|
||||||
|
debug("p_vaddr is 0, allocating %ld pages for image", TO_PAGES(Length));
|
||||||
|
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
|
||||||
|
memset(MemoryImage, 0, Length);
|
||||||
|
return MemoryImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("Allocating %ld pages for image", TO_PAGES(Length));
|
||||||
|
MemoryImage = mem->RequestPages(TO_PAGES(Length));
|
||||||
|
memset(MemoryImage, 0, Length);
|
||||||
|
|
||||||
|
if (FirstProgramHeaderVirtualAddress != 0)
|
||||||
|
FirstProgramHeaderVirtualAddress &= 0xFFFFFFFFFFFFF000;
|
||||||
|
else
|
||||||
|
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < TO_PAGES(Length); i++)
|
||||||
|
{
|
||||||
|
pV.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||||
|
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddress + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
|
||||||
|
}
|
||||||
|
return MemoryImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &pV, const char *Interpreter)
|
||||||
|
{
|
||||||
|
if (GetBinaryType((char *)Interpreter) != BinaryType::BinTypeELF)
|
||||||
|
{
|
||||||
|
error("Interpreter \"%s\" is not an ELF file.", Interpreter);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No need to check if it's valid, the GetBinaryType() call above does that. */
|
||||||
|
shared_ptr<VirtualFileSystem::File> File = vfs->Open(Interpreter);
|
||||||
|
|
||||||
|
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)File->node->Address;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
const char *InterpreterType[6] = {
|
||||||
|
"ET_NONE",
|
||||||
|
"ET_REL",
|
||||||
|
"ET_EXEC",
|
||||||
|
"ET_DYN",
|
||||||
|
"ET_CORE",
|
||||||
|
"ET_LOPROC - ET_HIPROC"};
|
||||||
|
Elf64_Half IntType = ELFHeader->e_type;
|
||||||
|
if (IntType > 5)
|
||||||
|
IntType = 5;
|
||||||
|
debug("Interpreter type: %s - %#x", InterpreterType[IntType], ELFHeader->e_type);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uintptr_t BaseAddress = UINTPTR_MAX;
|
||||||
|
uint64_t ElfAppSize = 0;
|
||||||
|
|
||||||
|
Elf64_Phdr ItrPhdr;
|
||||||
|
|
||||||
|
/* Get base address */
|
||||||
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||||
|
{
|
||||||
|
memcpy(&ItrPhdr,
|
||||||
|
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||||
|
sizeof(Elf64_Phdr));
|
||||||
|
|
||||||
|
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get size */
|
||||||
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||||
|
{
|
||||||
|
memcpy(&ItrPhdr,
|
||||||
|
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||||
|
sizeof(Elf64_Phdr));
|
||||||
|
|
||||||
|
uintptr_t SegmentEnd;
|
||||||
|
SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
|
||||||
|
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryImage = ELFCreateMemoryImage(mem, pV, (void *)File->node->Address, ElfAppSize);
|
||||||
|
|
||||||
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
||||||
|
{
|
||||||
|
memcpy(&ItrPhdr,
|
||||||
|
(uint8_t *)File->node->Address + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
||||||
|
sizeof(Elf64_Phdr));
|
||||||
|
|
||||||
|
if (ItrPhdr.p_type == PT_LOAD)
|
||||||
|
{
|
||||||
|
debug("PT_LOAD - Offset: %#lx, VirtAddr: %#lx, FileSiz: %ld, MemSiz: %ld, Align: %#lx",
|
||||||
|
ItrPhdr.p_offset, ItrPhdr.p_vaddr,
|
||||||
|
ItrPhdr.p_filesz, ItrPhdr.p_memsz, ItrPhdr.p_align);
|
||||||
|
uintptr_t MAddr = (ItrPhdr.p_vaddr - BaseAddress) + (uintptr_t)MemoryImage;
|
||||||
|
fixme("Address: %#lx %s%s%s", MAddr,
|
||||||
|
(ItrPhdr.p_flags & PF_R) ? "R" : "",
|
||||||
|
(ItrPhdr.p_flags & PF_W) ? "W" : "",
|
||||||
|
(ItrPhdr.p_flags & PF_X) ? "X" : "");
|
||||||
|
|
||||||
|
memcpy((void *)MAddr, (uint8_t *)File->node->Address + ItrPhdr.p_offset, ItrPhdr.p_filesz);
|
||||||
|
debug("memcpy: %#lx => %#lx (%ld bytes)", (uint8_t *)File->node->Address + ItrPhdr.p_offset, MAddr, ItrPhdr.p_filesz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs->Close(File);
|
||||||
|
debug("Interpreter entry point: %#lx (%#lx + %#lx)", (uintptr_t)MemoryImage + ELFHeader->e_entry,
|
||||||
|
(uintptr_t)MemoryImage, ELFHeader->e_entry);
|
||||||
|
return (uintptr_t)MemoryImage + ELFHeader->e_entry;
|
||||||
|
}
|
||||||
|
}
|
93
Execute/Elf/Rel.cpp
Normal file
93
Execute/Elf/Rel.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <exec.hpp>
|
||||||
|
|
||||||
|
#include <msexec.h>
|
||||||
|
|
||||||
|
#include "../../kernel.h"
|
||||||
|
#include "../../Fex.hpp"
|
||||||
|
|
||||||
|
namespace Execute
|
||||||
|
{
|
||||||
|
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||||
|
|
||||||
|
ELFBaseLoad ELFLoadRel(void *BaseImage,
|
||||||
|
VirtualFileSystem::File *ExFile,
|
||||||
|
Tasking::PCB *Process)
|
||||||
|
{
|
||||||
|
debug("Relocatable");
|
||||||
|
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */
|
||||||
|
warn("Relocatable ELF is not fully supported yet");
|
||||||
|
/* This should be deleted after with kfree */
|
||||||
|
ELFBaseLoad ELFBase = {};
|
||||||
|
/* This should be deleted inside BaseLoad.cpp */
|
||||||
|
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
|
||||||
|
|
||||||
|
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
|
||||||
|
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
|
||||||
|
{
|
||||||
|
Elf64_Shdr *Section = &shdr[i];
|
||||||
|
if (Section->sh_type == SHT_NOBITS)
|
||||||
|
{
|
||||||
|
if (!Section->sh_size)
|
||||||
|
continue;
|
||||||
|
if (Section->sh_flags & SHF_ALLOC)
|
||||||
|
{
|
||||||
|
void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size));
|
||||||
|
memset(Buffer, 0, Section->sh_size);
|
||||||
|
|
||||||
|
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
|
||||||
|
for (size_t i = 0; i < TO_PAGES(Section->sh_size); i++)
|
||||||
|
pva.Map((void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), (void *)((uintptr_t)Buffer + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||||
|
|
||||||
|
Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage;
|
||||||
|
debug("Section %ld", Section->sh_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
|
||||||
|
{
|
||||||
|
Elf64_Shdr *Section = &shdr[i];
|
||||||
|
if (Section->sh_type == SHT_REL)
|
||||||
|
{
|
||||||
|
for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
|
||||||
|
{
|
||||||
|
Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index];
|
||||||
|
Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info);
|
||||||
|
|
||||||
|
uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset);
|
||||||
|
uint64_t SymbolValue = 0;
|
||||||
|
|
||||||
|
if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF)
|
||||||
|
{
|
||||||
|
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
|
||||||
|
if (SymbolValue == 0xdead)
|
||||||
|
{
|
||||||
|
delete ELFBase.TmpMem;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ELF64_R_TYPE(RelTable->r_info))
|
||||||
|
{
|
||||||
|
case R_386_NONE:
|
||||||
|
break;
|
||||||
|
case R_386_32:
|
||||||
|
*RelAddress = DO_64_64(SymbolValue, *RelAddress);
|
||||||
|
break;
|
||||||
|
case R_386_PC32:
|
||||||
|
*RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
|
||||||
|
delete ELFBase.TmpMem;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug("Symbol value: %#lx", SymbolValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ELFBase;
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ namespace Execute
|
|||||||
void StartExecuteService()
|
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
21
Execute/Fex/BaseLoad.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include <exec.hpp>
|
||||||
|
|
||||||
|
#include <memory.hpp>
|
||||||
|
#include <lock.hpp>
|
||||||
|
#include <msexec.h>
|
||||||
|
#include <cwalk.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <abi.h>
|
||||||
|
|
||||||
|
#include "../../kernel.h"
|
||||||
|
#include "../../Fex.hpp"
|
||||||
|
|
||||||
|
using namespace Tasking;
|
||||||
|
|
||||||
|
namespace Execute
|
||||||
|
{
|
||||||
|
void FEXLoad()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -7,227 +7,77 @@
|
|||||||
|
|
||||||
namespace Execute
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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]);
|
||||||
|
@ -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...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
126
KThread.cpp
126
KThread.cpp
@ -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
|
||||||
|
100
Kernel.cpp
100
Kernel.cpp
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
@ -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),
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
688
Tasking/Scheduler.cpp
Normal file
@ -0,0 +1,688 @@
|
|||||||
|
#include <task.hpp>
|
||||||
|
|
||||||
|
#include <dumper.hpp>
|
||||||
|
#include <convert.h>
|
||||||
|
#include <lock.hpp>
|
||||||
|
#include <printf.h>
|
||||||
|
#include <smp.hpp>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#include "../kernel.h"
|
||||||
|
|
||||||
|
#if defined(__amd64__)
|
||||||
|
#include "../Architecture/amd64/cpu/apic.hpp"
|
||||||
|
#include "../Architecture/amd64/cpu/gdt.hpp"
|
||||||
|
#elif defined(__i386__)
|
||||||
|
#include "../Architecture/i686/cpu/apic.hpp"
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NewLock(SchedulerLock);
|
||||||
|
|
||||||
|
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
|
||||||
|
|
||||||
|
// #define DEBUG_SCHEDULER 1
|
||||||
|
// #define DEBUG_GET_NEXT_AVAILABLE_PROCESS 1
|
||||||
|
// #define DEBUG_GET_NEXT_AVAILABLE_THREAD 1
|
||||||
|
// #define DEBUG_FIND_NEW_PROCESS 1
|
||||||
|
// #define DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD 1
|
||||||
|
// #define DEBUG_WAKE_UP_THREADS 1
|
||||||
|
|
||||||
|
/* Global */
|
||||||
|
#ifdef DEBUG_SCHEDULER
|
||||||
|
|
||||||
|
#define DEBUG_GET_NEXT_AVAILABLE_PROCESS 1
|
||||||
|
#define DEBUG_GET_NEXT_AVAILABLE_THREAD 1
|
||||||
|
#define DEBUG_FIND_NEW_PROCESS 1
|
||||||
|
#define DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD 1
|
||||||
|
#define DEBUG_WAKE_UP_THREADS 1
|
||||||
|
|
||||||
|
#define schedbg(m, ...) \
|
||||||
|
debug(m, ##__VA_ARGS__); \
|
||||||
|
__sync_synchronize()
|
||||||
|
#else
|
||||||
|
#define schedbg(m, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* GetNextAvailableThread */
|
||||||
|
#ifdef DEBUG_GET_NEXT_AVAILABLE_PROCESS
|
||||||
|
#define gnap_schedbg(m, ...) \
|
||||||
|
debug(m, ##__VA_ARGS__); \
|
||||||
|
__sync_synchronize()
|
||||||
|
#else
|
||||||
|
#define gnap_schedbg(m, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* GetNextAvailableProcess */
|
||||||
|
#ifdef DEBUG_GET_NEXT_AVAILABLE_THREAD
|
||||||
|
#define gnat_schedbg(m, ...) \
|
||||||
|
debug(m, ##__VA_ARGS__); \
|
||||||
|
__sync_synchronize()
|
||||||
|
#else
|
||||||
|
#define gnat_schedbg(m, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FindNewProcess */
|
||||||
|
#ifdef DEBUG_FIND_NEW_PROCESS
|
||||||
|
#define fnp_schedbg(m, ...) \
|
||||||
|
debug(m, ##__VA_ARGS__); \
|
||||||
|
__sync_synchronize()
|
||||||
|
#else
|
||||||
|
#define fnp_schedbg(m, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* SchedulerSearchProcessThread */
|
||||||
|
#ifdef DEBUG_SCHEDULER_SEARCH_PROCESS_THREAD
|
||||||
|
#define sspt_schedbg(m, ...) \
|
||||||
|
debug(m, ##__VA_ARGS__); \
|
||||||
|
__sync_synchronize()
|
||||||
|
#else
|
||||||
|
#define sspt_schedbg(m, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* WakeUpThreads */
|
||||||
|
#ifdef DEBUG_WAKE_UP_THREADS
|
||||||
|
#define wut_schedbg(m, ...) \
|
||||||
|
debug(m, ##__VA_ARGS__); \
|
||||||
|
__sync_synchronize()
|
||||||
|
#else
|
||||||
|
#define wut_schedbg(m, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" SafeFunction __no_instrument_function void TaskingScheduler_OneShot(int TimeSlice)
|
||||||
|
{
|
||||||
|
if (TimeSlice == 0)
|
||||||
|
TimeSlice = 10;
|
||||||
|
#if defined(__amd64__)
|
||||||
|
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x64::IRQ16, TimeSlice);
|
||||||
|
#elif defined(__i386__)
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Tasking
|
||||||
|
{
|
||||||
|
#if defined(__amd64__)
|
||||||
|
SafeFunction __no_instrument_function bool Task::FindNewProcess(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
fnp_schedbg("%d processes", ListProcess.size());
|
||||||
|
#ifdef DEBUG_FIND_NEW_PROCESS
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
fnp_schedbg("Process %d %s", pcb->ID, pcb->Name);
|
||||||
|
#endif
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
{
|
||||||
|
if (InvalidPCB(pcb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (pcb->Status)
|
||||||
|
{
|
||||||
|
case TaskStatus::Ready:
|
||||||
|
fnp_schedbg("Ready process (%s)%d", pcb->Name, pcb->ID);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fnp_schedbg("Process \"%s\"(%d) status %d", pcb->Name, pcb->ID, pcb->Status);
|
||||||
|
/* We don't actually remove the process. RemoveProcess
|
||||||
|
firstly checks if it's terminated, if not, it will
|
||||||
|
loop through Threads and call RemoveThread on
|
||||||
|
terminated threads. */
|
||||||
|
RemoveProcess(pcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (auto tcb in pcb->Threads)
|
||||||
|
{
|
||||||
|
if (InvalidTCB(tcb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tcb->Status != TaskStatus::Ready)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CurrentCPU->CurrentProcess = pcb;
|
||||||
|
CurrentCPU->CurrentThread = tcb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fnp_schedbg("No process to run.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < CurrentCPU->CurrentProcess->Threads.size(); i++)
|
||||||
|
{
|
||||||
|
if (CurrentCPU->CurrentProcess->Threads[i] == CurrentCPU->CurrentThread)
|
||||||
|
{
|
||||||
|
size_t TempIndex = i;
|
||||||
|
RetryAnotherThread:
|
||||||
|
TCB *thread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
|
||||||
|
if (unlikely(InvalidTCB(thread)))
|
||||||
|
{
|
||||||
|
if (TempIndex > CurrentCPU->CurrentProcess->Threads.size())
|
||||||
|
break;
|
||||||
|
TempIndex++;
|
||||||
|
gnat_schedbg("Thread %#lx is invalid", thread);
|
||||||
|
goto RetryAnotherThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnat_schedbg("\"%s\"(%d) and next thread is \"%s\"(%d)", CurrentCPU->CurrentProcess->Threads[i]->Name, CurrentCPU->CurrentProcess->Threads[i]->ID, thread->Name, thread->ID);
|
||||||
|
|
||||||
|
if (thread->Status != TaskStatus::Ready)
|
||||||
|
{
|
||||||
|
gnat_schedbg("Thread %d is not ready", thread->ID);
|
||||||
|
TempIndex++;
|
||||||
|
goto RetryAnotherThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentCPU->CurrentThread = thread;
|
||||||
|
gnat_schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d", thread->ID, thread->Parent->Name, CurrentCPU->CurrentProcess->Threads.size(), ListProcess.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gnat_schedbg("Thread %d is not the current one", CurrentCPU->CurrentProcess->Threads[i]->ID);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
|
||||||
|
bool Skip = true;
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
{
|
||||||
|
if (pcb == CurrentCPU->CurrentProcess)
|
||||||
|
{
|
||||||
|
Skip = false;
|
||||||
|
gnap_schedbg("Found current process %#lx", pcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Skip)
|
||||||
|
{
|
||||||
|
gnap_schedbg("Skipping process %#lx", pcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InvalidPCB(pcb))
|
||||||
|
{
|
||||||
|
gnap_schedbg("Invalid process %#lx", pcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcb->Status != TaskStatus::Ready)
|
||||||
|
{
|
||||||
|
gnap_schedbg("Process %d is not ready", pcb->ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (auto tcb in pcb->Threads)
|
||||||
|
{
|
||||||
|
if (InvalidTCB(tcb))
|
||||||
|
{
|
||||||
|
gnap_schedbg("Invalid thread %#lx", tcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcb->Status != TaskStatus::Ready)
|
||||||
|
{
|
||||||
|
gnap_schedbg("Thread %d is not ready", tcb->ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentCPU->CurrentProcess = pcb;
|
||||||
|
CurrentCPU->CurrentThread = tcb;
|
||||||
|
gnap_schedbg("[cur proc+1 -> first thd] Scheduling thread %d %s->%d (Total Procs %d)", tcb->ID, tcb->Name, pcb->Threads.size(), ListProcess.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gnap_schedbg("No process to run.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function void Task::SchedulerCleanupProcesses()
|
||||||
|
{
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
{
|
||||||
|
if (InvalidPCB(pcb))
|
||||||
|
continue;
|
||||||
|
RemoveProcess(pcb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
{
|
||||||
|
if (InvalidPCB(pcb))
|
||||||
|
{
|
||||||
|
sspt_schedbg("Invalid process %#lx", pcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcb->Status != TaskStatus::Ready)
|
||||||
|
{
|
||||||
|
sspt_schedbg("Process %d is not ready", pcb->ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (auto tcb in pcb->Threads)
|
||||||
|
{
|
||||||
|
if (InvalidTCB(tcb))
|
||||||
|
{
|
||||||
|
sspt_schedbg("Invalid thread %#lx", tcb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcb->Status != TaskStatus::Ready)
|
||||||
|
{
|
||||||
|
sspt_schedbg("Thread %d is not ready", tcb->ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentCPU->CurrentProcess = pcb;
|
||||||
|
CurrentCPU->CurrentThread = tcb;
|
||||||
|
sspt_schedbg("[proc 0 -> end -> first thd] Scheduling thread %d parent of %s->%d (Procs %d)", tcb->ID, tcb->Parent->Name, pcb->Threads.size(), ListProcess.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function void Task::UpdateProcessStatus()
|
||||||
|
{
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
{
|
||||||
|
if (InvalidPCB(pcb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pcb->Status == TaskStatus::Terminated ||
|
||||||
|
pcb->Status == TaskStatus::Stopped)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool AllThreadsSleeping = true;
|
||||||
|
foreach (auto tcb in pcb->Threads)
|
||||||
|
{
|
||||||
|
if (tcb->Status != TaskStatus::Sleeping)
|
||||||
|
{
|
||||||
|
AllThreadsSleeping = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AllThreadsSleeping)
|
||||||
|
pcb->Status = TaskStatus::Sleeping;
|
||||||
|
else if (pcb->Status == TaskStatus::Sleeping)
|
||||||
|
pcb->Status = TaskStatus::Ready;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function void Task::WakeUpThreads(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||||
|
foreach (auto pcb in ListProcess)
|
||||||
|
{
|
||||||
|
if (InvalidPCB(pcb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pcb->Status == TaskStatus::Terminated ||
|
||||||
|
pcb->Status == TaskStatus::Stopped)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (auto tcb in pcb->Threads)
|
||||||
|
{
|
||||||
|
if (InvalidTCB(tcb))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tcb->Status != TaskStatus::Sleeping)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check if the thread is ready to wake up. */
|
||||||
|
if (tcb->Info.SleepUntil < TimeManager->GetCounter())
|
||||||
|
{
|
||||||
|
if (pcb->Status == TaskStatus::Sleeping)
|
||||||
|
pcb->Status = TaskStatus::Ready;
|
||||||
|
tcb->Status = TaskStatus::Ready;
|
||||||
|
|
||||||
|
tcb->Info.SleepUntil = 0;
|
||||||
|
wut_schedbg("Thread \"%s\"(%d) woke up.", tcb->Name, tcb->ID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wut_schedbg("Thread \"%s\"(%d) is not ready to wake up. (SleepUntil: %d, Counter: %d)", tcb->Name, tcb->ID, tcb->Info.SleepUntil, TimeManager->GetCounter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function void Task::Schedule(CPU::x64::TrapFrame *Frame)
|
||||||
|
{
|
||||||
|
SmartCriticalSection(SchedulerLock);
|
||||||
|
if (StopScheduler)
|
||||||
|
{
|
||||||
|
warn("Scheduler stopped.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); /* Restore kernel page table for safety reasons. */
|
||||||
|
CPUData *CurrentCPU = GetCurrentCPU();
|
||||||
|
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
|
||||||
|
schedbg("%d: %ld%%", CurrentCPU->ID, GetUsage(CurrentCPU->ID));
|
||||||
|
|
||||||
|
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||||
|
int SuccessSource = 0;
|
||||||
|
static int sanity;
|
||||||
|
const char *Statuses[] = {
|
||||||
|
"FF0000", /* Unknown */
|
||||||
|
"AAFF00", /* Ready */
|
||||||
|
"00AA00", /* Running */
|
||||||
|
"FFAA00", /* Sleeping */
|
||||||
|
"FFAA00", /* Waiting */
|
||||||
|
"FF0088", /* Stopped */
|
||||||
|
"FF0000", /* Terminated */
|
||||||
|
};
|
||||||
|
const char *StatusesSign[] = {
|
||||||
|
"Unknown",
|
||||||
|
"Ready",
|
||||||
|
"Run",
|
||||||
|
"Sleep",
|
||||||
|
"Wait",
|
||||||
|
"Stop",
|
||||||
|
"Terminated",
|
||||||
|
};
|
||||||
|
const char *SuccessSourceStrings[] = {
|
||||||
|
"Unknown",
|
||||||
|
"GetNextAvailableThread",
|
||||||
|
"GetNextAvailableProcess",
|
||||||
|
"SchedulerSearchProcessThread",
|
||||||
|
};
|
||||||
|
uint32_t tmpX, tmpY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SCHEDULER
|
||||||
|
{
|
||||||
|
schedbg("================================================================");
|
||||||
|
schedbg("Status: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
|
||||||
|
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
|
||||||
|
size_t ds;
|
||||||
|
asmv("mov %%ds, %0"
|
||||||
|
: "=r"(ds));
|
||||||
|
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||||
|
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||||
|
Frame->ss, Frame->cs, ds);
|
||||||
|
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||||
|
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||||
|
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||||
|
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||||
|
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||||
|
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||||
|
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||||
|
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||||
|
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||||
|
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||||
|
schedbg("================================================================");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess) || InvalidTCB(CurrentCPU->CurrentThread)))
|
||||||
|
{
|
||||||
|
schedbg("Invalid process or thread. Finding a new one.");
|
||||||
|
if (this->FindNewProcess(CurrentCPU))
|
||||||
|
goto Success;
|
||||||
|
else
|
||||||
|
goto Idle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentCPU->CurrentThread->Registers = *Frame;
|
||||||
|
CPU::x64::fxsave(CurrentCPU->CurrentThread->FPU);
|
||||||
|
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||||
|
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
|
||||||
|
|
||||||
|
if (CurrentCPU->CurrentProcess->Status == TaskStatus::Running)
|
||||||
|
CurrentCPU->CurrentProcess->Status = TaskStatus::Ready;
|
||||||
|
if (CurrentCPU->CurrentThread->Status == TaskStatus::Running)
|
||||||
|
CurrentCPU->CurrentThread->Status = TaskStatus::Ready;
|
||||||
|
|
||||||
|
this->UpdateProcessStatus();
|
||||||
|
schedbg("Passed UpdateProcessStatus");
|
||||||
|
|
||||||
|
this->WakeUpThreads(CurrentCPU);
|
||||||
|
schedbg("Passed WakeUpThreads");
|
||||||
|
|
||||||
|
if (this->GetNextAvailableThread(CurrentCPU))
|
||||||
|
{
|
||||||
|
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||||
|
SuccessSource = 1;
|
||||||
|
#endif
|
||||||
|
goto Success;
|
||||||
|
}
|
||||||
|
schedbg("Passed GetNextAvailableThread");
|
||||||
|
|
||||||
|
if (this->GetNextAvailableProcess(CurrentCPU))
|
||||||
|
{
|
||||||
|
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||||
|
SuccessSource = 2;
|
||||||
|
#endif
|
||||||
|
goto Success;
|
||||||
|
}
|
||||||
|
schedbg("Passed GetNextAvailableProcess");
|
||||||
|
|
||||||
|
this->SchedulerCleanupProcesses();
|
||||||
|
schedbg("Passed SchedulerCleanupProcesses");
|
||||||
|
|
||||||
|
if (SchedulerSearchProcessThread(CurrentCPU))
|
||||||
|
{
|
||||||
|
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||||
|
SuccessSource = 3;
|
||||||
|
#endif
|
||||||
|
schedbg("Passed SchedulerSearchProcessThread");
|
||||||
|
goto Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
schedbg("SchedulerSearchProcessThread failed. Going idle.");
|
||||||
|
goto Idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* [this]->RealEnd */
|
||||||
|
warn("Unwanted reach!");
|
||||||
|
TaskingScheduler_OneShot(100);
|
||||||
|
goto RealEnd;
|
||||||
|
|
||||||
|
/* Idle-->Success */
|
||||||
|
Idle:
|
||||||
|
CurrentCPU->CurrentProcess = IdleProcess;
|
||||||
|
CurrentCPU->CurrentThread = IdleThread;
|
||||||
|
|
||||||
|
/* Success-->End */
|
||||||
|
Success:
|
||||||
|
schedbg("Process \"%s\"(%d) Thread \"%s\"(%d) is now running on CPU %d",
|
||||||
|
CurrentCPU->CurrentProcess->Name, CurrentCPU->CurrentProcess->ID,
|
||||||
|
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID);
|
||||||
|
|
||||||
|
CurrentCPU->CurrentProcess->Status = TaskStatus::Running;
|
||||||
|
CurrentCPU->CurrentThread->Status = TaskStatus::Running;
|
||||||
|
|
||||||
|
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(CurrentCPU->CurrentThread->IPHistory) / sizeof(CurrentCPU->CurrentThread->IPHistory[0]); i++)
|
||||||
|
CurrentCPU->CurrentThread->IPHistory[i + 1] = CurrentCPU->CurrentThread->IPHistory[i];
|
||||||
|
|
||||||
|
CurrentCPU->CurrentThread->IPHistory[0] = Frame->rip;
|
||||||
|
|
||||||
|
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
|
||||||
|
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
|
||||||
|
/* Not sure if this is needed, but it's better to be safe than sorry. */
|
||||||
|
asmv("movq %cr3, %rax");
|
||||||
|
asmv("movq %rax, %cr3");
|
||||||
|
CPU::x64::fxrstor(CurrentCPU->CurrentThread->FPU);
|
||||||
|
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
|
||||||
|
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
|
||||||
|
|
||||||
|
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||||
|
for (int i = 0; i < 340; i++)
|
||||||
|
for (int j = 0; j < 200; j++)
|
||||||
|
Display->SetPixel(i, j, 0x222222, 0);
|
||||||
|
Display->GetBufferCursor(0, &tmpX, &tmpY);
|
||||||
|
Display->SetBufferCursor(0, 0, 0);
|
||||||
|
foreach (auto var in ListProcess)
|
||||||
|
{
|
||||||
|
int Status = var->Status;
|
||||||
|
printf("\e%s-> \eAABBCC%s \e00AAAA%s\n",
|
||||||
|
Statuses[Status], var->Name, StatusesSign[Status]);
|
||||||
|
foreach (auto var2 in var->Threads)
|
||||||
|
{
|
||||||
|
Status = var2->Status;
|
||||||
|
printf(" \e%s-> \eAABBCC%s \e00AAAA%s\n\eAABBCC",
|
||||||
|
Statuses[Status], var2->Name, StatusesSign[Status]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Sanity: %d\nSched. Source: %s", sanity++, SuccessSourceStrings[SuccessSource]);
|
||||||
|
if (sanity > 1000)
|
||||||
|
sanity = 0;
|
||||||
|
Display->SetBufferCursor(0, tmpX, tmpY);
|
||||||
|
Display->SetBuffer(0);
|
||||||
|
for (int i = 0; i < 50000; i++)
|
||||||
|
inb(0x80);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (CurrentCPU->CurrentProcess->Security.TrustLevel)
|
||||||
|
{
|
||||||
|
case TaskTrustLevel::System:
|
||||||
|
case TaskTrustLevel::Kernel:
|
||||||
|
// wrmsr(MSR_SHADOW_GS_BASE, (uint64_t)CurrentCPU->CurrentThread);
|
||||||
|
break;
|
||||||
|
case TaskTrustLevel::User:
|
||||||
|
// wrmsr(MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->gs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown trust level %d.", CurrentCPU->CurrentProcess->Security.TrustLevel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End-->RealEnd */
|
||||||
|
// End:
|
||||||
|
/* TODO: This is not accurate. */
|
||||||
|
if (CurrentCPU->CurrentProcess->Security.TrustLevel == TaskTrustLevel::User)
|
||||||
|
UpdateUserTime(&CurrentCPU->CurrentProcess->Info);
|
||||||
|
else
|
||||||
|
UpdateKernelTime(&CurrentCPU->CurrentProcess->Info);
|
||||||
|
|
||||||
|
if (CurrentCPU->CurrentThread->Security.TrustLevel == TaskTrustLevel::User)
|
||||||
|
UpdateUserTime(&CurrentCPU->CurrentThread->Info);
|
||||||
|
else
|
||||||
|
UpdateKernelTime(&CurrentCPU->CurrentThread->Info);
|
||||||
|
|
||||||
|
UpdateUsage(&CurrentCPU->CurrentProcess->Info, CurrentCPU->ID);
|
||||||
|
UpdateUsage(&CurrentCPU->CurrentThread->Info, CurrentCPU->ID);
|
||||||
|
TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority);
|
||||||
|
|
||||||
|
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
||||||
|
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
|
||||||
|
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID,
|
||||||
|
CurrentCPU->CurrentThread->Registers.rip,
|
||||||
|
CurrentCPU->CurrentThread->Registers.rbp,
|
||||||
|
CurrentCPU->CurrentThread->Registers.rsp);
|
||||||
|
|
||||||
|
schedbg("================================================================");
|
||||||
|
schedbg("Technical Informations on Thread %s[%ld]:", CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID);
|
||||||
|
uint64_t ds;
|
||||||
|
asmv("mov %%ds, %0"
|
||||||
|
: "=r"(ds));
|
||||||
|
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||||
|
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||||
|
Frame->ss, Frame->cs, ds);
|
||||||
|
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||||
|
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||||
|
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||||
|
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||||
|
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||||
|
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||||
|
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||||
|
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||||
|
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||||
|
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||||
|
schedbg("================================================================");
|
||||||
|
|
||||||
|
/* RealEnd->[Function Exit] */
|
||||||
|
RealEnd:
|
||||||
|
__sync_synchronize(); /* TODO: Is this really needed? */
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction __no_instrument_function void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame) { this->Schedule(Frame); }
|
||||||
|
#elif defined(__i386__)
|
||||||
|
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction void Task::SchedulerCleanupProcesses()
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction void Task::Schedule(void *Frame)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
SafeFunction bool Task::FindNewProcess(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction bool Task::GetNextAvailableThread(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction bool Task::GetNextAvailableProcess(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction void Task::SchedulerCleanupProcesses()
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction bool Task::SchedulerSearchProcessThread(void *CPUDataPointer)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction void Task::Schedule(void *Frame)
|
||||||
|
{
|
||||||
|
fixme("unimplemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFunction void Task::OnInterruptReceived(void *Frame) { this->Schedule(Frame); }
|
||||||
|
#endif
|
||||||
|
}
|
@ -6,64 +6,131 @@
|
|||||||
|
|
||||||
namespace Tasking
|
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);
|
||||||
}
|
}
|
||||||
|
764
Tasking/Task.cpp
764
Tasking/Task.cpp
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
@ -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__
|
||||||
|
@ -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();
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <filesystem.hpp>
|
||||||
|
|
||||||
namespace FileSystem
|
namespace VirtualFileSystem
|
||||||
{
|
{
|
||||||
class EXT2
|
class EXT2
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <filesystem.hpp>
|
||||||
|
|
||||||
namespace FileSystem
|
namespace VirtualFileSystem
|
||||||
{
|
{
|
||||||
class FAT
|
class FAT
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <filesystem.hpp>
|
||||||
|
|
||||||
namespace FileSystem
|
namespace VirtualFileSystem
|
||||||
{
|
{
|
||||||
class Initrd
|
class Initrd
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <filesystem.hpp>
|
||||||
|
|
||||||
namespace FileSystem
|
namespace VirtualFileSystem
|
||||||
{
|
{
|
||||||
class USTAR
|
class USTAR
|
||||||
{
|
{
|
||||||
|
@ -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; }
|
||||||
|
@ -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__
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
6
include/stddef.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef __FENNIX_KERNEL_STDDEF_STUB_H__
|
||||||
|
#define __FENNIX_KERNEL_STDDEF_STUB_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#endif // !__FENNIX_KERNEL_STDDEF_STUB_H__
|
@ -19,6 +19,7 @@ namespace SymbolResolver
|
|||||||
Symbols(uintptr_t ImageAddress);
|
Symbols(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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
57
ipc.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef __FENNIX_KERNEL_IPC_SYSCALLS_H__
|
||||||
|
#define __FENNIX_KERNEL_IPC_SYSCALLS_H__
|
||||||
|
|
||||||
|
enum IPCCommand
|
||||||
|
{
|
||||||
|
IPC_NULL,
|
||||||
|
IPC_CREATE,
|
||||||
|
IPC_READ,
|
||||||
|
IPC_WRITE,
|
||||||
|
IPC_DELETE,
|
||||||
|
IPC_GET,
|
||||||
|
IPC_SET,
|
||||||
|
IPC_GET_COUNT,
|
||||||
|
IPC_GET_SIZE,
|
||||||
|
IPC_GET_FLAGS,
|
||||||
|
IPC_SET_FLAGS,
|
||||||
|
IPC_GET_OWNER,
|
||||||
|
IPC_SET_OWNER,
|
||||||
|
IPC_GET_GROUP,
|
||||||
|
IPC_SET_GROUP,
|
||||||
|
IPC_GET_MODE,
|
||||||
|
IPC_SET_MODE,
|
||||||
|
IPC_GET_NAME,
|
||||||
|
IPC_SET_NAME,
|
||||||
|
IPC_GET_TYPE,
|
||||||
|
IPC_SET_TYPE,
|
||||||
|
IPC_GET_ID,
|
||||||
|
IPC_SET_ID,
|
||||||
|
IPC_GET_INDEX,
|
||||||
|
IPC_SET_INDEX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IPCType
|
||||||
|
{
|
||||||
|
IPC_TYPE_None,
|
||||||
|
IPC_TYPE_MessagePassing,
|
||||||
|
IPC_TYPE_Port,
|
||||||
|
IPC_TYPE_SharedMemory,
|
||||||
|
IPC_TYPE_Pipe,
|
||||||
|
IPC_TYPE_Socket
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IPCErrorCode
|
||||||
|
{
|
||||||
|
IPC_E_CODE_Error = -1,
|
||||||
|
IPC_E_CODE_Success,
|
||||||
|
IPC_E_CODE_NotListening,
|
||||||
|
IPC_E_CODE_Timeout,
|
||||||
|
IPC_E_CODE_InvalidPort,
|
||||||
|
IPC_E_CODE_AlreadyAllocated,
|
||||||
|
IPC_E_CODE_NotAllocated,
|
||||||
|
IPC_E_CODE_IDInUse,
|
||||||
|
IPC_E_CODE_IDNotRegistered,
|
||||||
|
IPC_E_CODE_IDNotFound
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !__FENNIX_KERNEL_IPC_SYSCALLS_H__
|
7
kernel.h
7
kernel.h
@ -28,16 +28,19 @@ extern PCI::PCI *PCIManager;
|
|||||||
extern KernelConfig Config;
|
extern 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, ...);
|
||||||
|
151
syscalls.h
151
syscalls.h
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user