mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 07:19:20 +00:00
Update file loading
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
#include <exec.hpp>
|
||||
|
||||
#include <msexec.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
#include "../Fex.hpp"
|
||||
|
||||
@ -15,14 +17,47 @@ namespace Execute
|
||||
if (ExFile->Node->Flags == FileSystem::NodeFlags::FS_FILE)
|
||||
{
|
||||
Fex *FexHdr = (Fex *)ExFile->Node->Address;
|
||||
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ExFile->Node->Address;
|
||||
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)ExFile->Node->Address;
|
||||
if (FexHdr->Magic[0] == 'F' && FexHdr->Magic[1] == 'E' && FexHdr->Magic[2] == 'X' && FexHdr->Magic[3] == '\0')
|
||||
{
|
||||
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
|
||||
{
|
||||
trace("%s - Fex", Path);
|
||||
Type = BinaryType::BinTypeFex;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
|
||||
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
|
||||
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
|
||||
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
|
||||
{
|
||||
trace("%s - ELF", Path);
|
||||
Type = BinaryType::BinTypeELF;
|
||||
goto Exit;
|
||||
}
|
||||
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
|
||||
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)ExFile->Node->Address) + MZHeader->e_lfanew);
|
||||
if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
|
||||
{
|
||||
trace("%s - NE", Path);
|
||||
Type = BinaryType::BinTypeNE;
|
||||
}
|
||||
else if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
trace("%s - PE", Path);
|
||||
Type = BinaryType::BinTypePE;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("%s - MZ", Path);
|
||||
Type = BinaryType::BinTypeMZ;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
@ -33,4 +68,166 @@ namespace Execute
|
||||
vfs->Close(ExFile);
|
||||
return Type;
|
||||
}
|
||||
|
||||
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
|
||||
|
||||
static inline Elf64_Shdr *GetElfSheader(Elf64_Ehdr *Header) { return (Elf64_Shdr *)((uint64_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, uint64_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 (uint64_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
|
||||
{
|
||||
Symbol = (Elf64_Sym *)((uint64_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
|
||||
String = (char *)((uint64_t)Header + StringTable->sh_offset + Symbol->st_name);
|
||||
if (strcmp(String, Name) == 0)
|
||||
return (void *)Symbol->st_value;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static uint64_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 (uint64_t)Target;
|
||||
}
|
||||
else if (Symbol->st_shndx == SHN_ABS)
|
||||
return Symbol->st_value;
|
||||
else
|
||||
{
|
||||
Elf64_Shdr *Target = GetElfSection(Header, Symbol->st_shndx);
|
||||
return (uint64_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 (uint64_t i = 0; i < TO_PAGES(Section->sh_size); i++)
|
||||
pva.Map((void *)((uint64_t)Buffer + (i * PAGE_SIZE)), (void *)((uint64_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 (uint64_t i = 0; i < Header->e_shnum; i++)
|
||||
{
|
||||
Elf64_Shdr *Section = &shdr[i];
|
||||
if (Section->sh_type == SHT_REL)
|
||||
{
|
||||
for (uint64_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++)
|
||||
{
|
||||
Elf64_Rel *RelTable = &((Elf64_Rel *)((uint64_t)Header + Section->sh_offset))[Index];
|
||||
Elf64_Shdr *Target = GetElfSection(Header, Section->sh_info);
|
||||
|
||||
uint64_t *RelAddress = (uint64_t *)(((uint64_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, (uint64_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;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <msexec.h>
|
||||
#include <cwalk.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
#include "../Fex.hpp"
|
||||
@ -27,40 +29,151 @@ namespace Execute
|
||||
case BinaryType::BinTypeFex:
|
||||
{
|
||||
Fex *FexHdr = (Fex *)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)
|
||||
{
|
||||
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 *)((uint64_t)BaseImage + (i * PAGE_SIZE)), (void *)((uint64_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)FexHdr->Pointer,
|
||||
Arg0, Arg1,
|
||||
(IPOffset)BaseImage,
|
||||
TaskArchitecture::x64,
|
||||
TaskCompatibility::Native);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
goto Exit;
|
||||
}
|
||||
ret.Status = ExStatus::InvalidFileHeader;
|
||||
goto Exit;
|
||||
}
|
||||
case BinaryType::BinTypeELF:
|
||||
{
|
||||
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 *)((uint64_t)BaseImage + (i * PAGE_SIZE)), (void *)((uint64_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)
|
||||
{
|
||||
trace("Executable");
|
||||
Elf64_Phdr *pheader = (Elf64_Phdr *)(((char *)BaseImage) + ELFHeader->e_phoff);
|
||||
void *Address = nullptr;
|
||||
for (int i = 0; i < ELFHeader->e_phnum; i++, pheader++)
|
||||
{
|
||||
const char *BaseName;
|
||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), BaseName, TaskTrustLevel::User);
|
||||
if (pheader->p_type != PT_LOAD)
|
||||
continue;
|
||||
Address = (void *)((uint64_t)pheader->p_vaddr + pheader->p_memsz);
|
||||
}
|
||||
void *Offset = KernelAllocator.RequestPages(TO_PAGES((uint64_t)Address));
|
||||
|
||||
void *BaseImage = KernelAllocator.RequestPages(TO_PAGES(ExFile->Node->Length));
|
||||
memcpy(BaseImage, (void *)ExFile->Node->Address, ExFile->Node->Length);
|
||||
for (uint64_t i = 0; i < TO_PAGES((uint64_t)Address); i++)
|
||||
pva.Map((void *)((uint64_t)Offset + (i * PAGE_SIZE)), (void *)((uint64_t)Offset + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
/*
|
||||
For some reason I can't map BaseImage.
|
||||
Neither can I in the Tasking->CreateThread function.
|
||||
Very strange.
|
||||
*/
|
||||
pheader = (Elf64_Phdr *)(((char *)BaseImage) + ELFHeader->e_phoff);
|
||||
for (int i = 0; i < ELFHeader->e_phnum; i++, pheader++)
|
||||
{
|
||||
if (pheader->p_type != PT_LOAD)
|
||||
continue;
|
||||
void *dst = (void *)((uint64_t)pheader->p_vaddr + (uint64_t)Offset);
|
||||
memset(dst, 0, pheader->p_memsz);
|
||||
memcpy(dst, ((char *)BaseImage) + pheader->p_offset, pheader->p_filesz);
|
||||
}
|
||||
|
||||
Memory::Virtual pva = Memory::Virtual(Process->PageTable);
|
||||
|
||||
for (uint64_t i = 0; i < TO_PAGES(ExFile->Node->Length); i++)
|
||||
pva.Map((void *)((uint64_t)BaseImage + (i * PAGE_SIZE)), (void *)((uint64_t)BaseImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
|
||||
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)FexHdr->Pointer,
|
||||
Arg0, Arg1,
|
||||
(IPOffset)BaseImage,
|
||||
TaskArchitecture::x64,
|
||||
TaskCompatibility::Native);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)ELFHeader->e_entry,
|
||||
Arg0, Arg1,
|
||||
(IPOffset)Offset,
|
||||
Arch,
|
||||
Comp);
|
||||
ret.Process = Process;
|
||||
ret.Thread = Thread;
|
||||
ret.Status = ExStatus::OK;
|
||||
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;
|
||||
}
|
||||
TCB *Thread = TaskManager->CreateThread(Process,
|
||||
(IP)EP,
|
||||
Arg0, Arg1,
|
||||
(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;
|
||||
goto Exit;
|
||||
}
|
||||
@ -83,6 +196,9 @@ namespace Execute
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (ret.Status != ExStatus::OK)
|
||||
if (ret.Process)
|
||||
ret.Process->Status = TaskStatus::Terminated;
|
||||
vfs->Close(ExFile);
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user