user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
+182
-106
@@ -1,3 +1,4 @@
|
||||
// elf.c (now extracts AT_PHDR / AT_PHENT / AT_PHNUM + minor cleanups)
|
||||
#include "elf.h"
|
||||
#include "libk/stdio.h"
|
||||
#include "libk/string.h"
|
||||
@@ -8,148 +9,223 @@
|
||||
|
||||
extern uintptr_t g_hhdm_offset;
|
||||
|
||||
#define ELF_BUFFER_SIZE (1024 * 1024)
|
||||
|
||||
|
||||
|
||||
|
||||
bool ELF_Read(const char* path, void** entryPoint, struct pagemap *target_pagemap)
|
||||
bool ELF_Read(const char* path,
|
||||
void** entryPoint,
|
||||
struct pagemap *target_pagemap,
|
||||
uint64_t *out_tls_fs_base,
|
||||
uint64_t *out_phdr_va,
|
||||
uint16_t *out_phent,
|
||||
uint16_t *out_phnum)
|
||||
{
|
||||
uint32_t size;
|
||||
*out_tls_fs_base = 0;
|
||||
*out_phdr_va = 0;
|
||||
*out_phent = 0;
|
||||
*out_phnum = 0;
|
||||
|
||||
uint8_t* elf_buffer = kmalloc(ELF_BUFFER_SIZE);
|
||||
if (!elf_buffer) {
|
||||
printf("ELF: kmalloc failed\n");
|
||||
uint32_t inum = ext2_resolve_path(path);
|
||||
if (!inum) {
|
||||
printf("ELF: file not found: %s\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ── load file ─────────────────────────────────────
|
||||
if (!ext2_read_file_from_root(path, elf_buffer, &size)) {
|
||||
printf("ELF: failed to read file\n");
|
||||
kfree(elf_buffer);
|
||||
ext2_inode_t inode;
|
||||
if (!ext2_read_inode(inum, &inode)) {
|
||||
printf("ELF: failed to read inode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size < sizeof(ELFHeader)) {
|
||||
uint64_t file_size = inode.i_size;
|
||||
if (file_size < sizeof(ELFHeader)) {
|
||||
printf("ELF: file too small\n");
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t buf_pages = ALIGN_UP(file_size, PAGE_SIZE) / PAGE_SIZE;
|
||||
void* buffer_phys = pmm_allocz(buf_pages);
|
||||
if (!buffer_phys) {
|
||||
printf("ELF: failed to allocate %lu pages for file buffer\n", buf_pages);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* elf_buffer = (uint8_t*)((uintptr_t)buffer_phys + MEM_PHYS_OFFSET);
|
||||
|
||||
if (!ext2_read_file(&inode, elf_buffer)) {
|
||||
pmm_free(buffer_phys, buf_pages);
|
||||
return false;
|
||||
}
|
||||
|
||||
ELFHeader* header = (ELFHeader*)elf_buffer;
|
||||
|
||||
printf("=== ELF DEBUG ===\n");
|
||||
printf("Entry point VA = 0x%lx\n", header->ProgramEntryPosition);
|
||||
printf("PHDR offset = 0x%lx\n", header->ProgramHeaderTablePosition);
|
||||
printf("PHDR count = %u\n", header->ProgramHeaderTableEntryCount);
|
||||
printf("=== ELF DEBUG ===\n"
|
||||
"Entry=0x%lx PHDR@0x%lx count=%u type=0x%x arch=0x%x\n"
|
||||
"=== END ===\n",
|
||||
header->ProgramEntryPosition,
|
||||
header->ProgramHeaderTablePosition,
|
||||
header->ProgramHeaderTableEntryCount,
|
||||
header->Type,
|
||||
header->InstructionSet);
|
||||
|
||||
if (memcmp(header->Magic, ELF_MAGIC, 4) != 0 ||
|
||||
header->Bitness != ELF_BITNESS_64BIT ||
|
||||
header->Endianness != ELF_ENDIANNESS_LITTLE ||
|
||||
(header->Type != ELF_TYPE_EXECUTABLE && header->Type != ELF_TYPE_SHARED) ||
|
||||
header->InstructionSet != ELF_INSTRUCTION_SET_X64) {
|
||||
|
||||
|
||||
printf("=== END ELF DEBUG ===\n");
|
||||
|
||||
// ── validate ELF ──────────────────────────────────
|
||||
if (memcmp(header->Magic, ELF_MAGIC, 4) != 0) {
|
||||
printf("ELF: bad magic\n");
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->Bitness != ELF_BITNESS_64BIT) {
|
||||
printf("ELF: not 64-bit\n");
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->Endianness != ELF_ENDIANNESS_LITTLE) {
|
||||
printf("ELF: wrong endianness\n");
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->Type != ELF_TYPE_EXECUTABLE) {
|
||||
printf("ELF: not executable\n");
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header->InstructionSet != ELF_INSTRUCTION_SET_X64) {
|
||||
printf("ELF: wrong arch\n");
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
printf("ELF: unsupported/invalid header\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*entryPoint = (void*)header->ProgramEntryPosition;
|
||||
|
||||
// ── program headers ───────────────────────────────
|
||||
// ------------------------------------------------------------------
|
||||
// Parse program headers – LOAD, TLS, and PHDR
|
||||
// ------------------------------------------------------------------
|
||||
uint64_t tls_vaddr = 0, tls_filesz = 0, tls_memsz = 0, tls_align = 8;
|
||||
uint8_t* tls_src = NULL;
|
||||
uint64_t phdr_vaddr = 0;
|
||||
|
||||
uint8_t* ph_table = elf_buffer + header->ProgramHeaderTablePosition;
|
||||
uint64_t phdr_table_end = header->ProgramHeaderTablePosition +
|
||||
(uint64_t)header->ProgramHeaderTableEntryCount *
|
||||
header->ProgramHeaderTableEntrySize;
|
||||
|
||||
for (uint32_t i = 0; i < header->ProgramHeaderTableEntryCount; i++)
|
||||
{
|
||||
ELFProgramHeader* ph = (ELFProgramHeader*)(ph_table +
|
||||
i * header->ProgramHeaderTableEntrySize);
|
||||
if (phdr_table_end > file_size) {
|
||||
printf("ELF: program header table extends beyond file\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ph->Type != ELF_PROGRAM_TYPE_LOAD) {
|
||||
printf("LOAD segment: VA=0x%lx FileSz=0x%lx MemSz=0x%lx\n",
|
||||
ph->VirtualAddress, ph->FileSize, ph->MemorySize);
|
||||
for (uint32_t i = 0; i < header->ProgramHeaderTableEntryCount; i++) {
|
||||
ELFProgramHeader* ph = (ELFProgramHeader*)(ph_table + i * header->ProgramHeaderTableEntrySize);
|
||||
|
||||
// PT_PHDR
|
||||
if (ph->Type == ELF_PROGRAM_TYPE_PHDR) {
|
||||
phdr_vaddr = ph->VirtualAddress;
|
||||
printf("ELF: Found PT_PHDR VA=0x%lx\n", phdr_vaddr);
|
||||
// fall through
|
||||
}
|
||||
|
||||
// PT_TLS
|
||||
if (ph->Type == ELF_PROGRAM_TYPE_TLS) {
|
||||
tls_vaddr = ph->VirtualAddress;
|
||||
tls_filesz = ph->FileSize;
|
||||
tls_memsz = ph->MemorySize;
|
||||
tls_align = ph->Align ? ph->Align : 8;
|
||||
tls_src = elf_buffer + ph->Offset;
|
||||
|
||||
if (ph->Offset + ph->FileSize > file_size) {
|
||||
printf("ELF: PT_TLS segment data out of file bounds\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
printf("ELF: Found PT_TLS VA=0x%lx FileSz=0x%lx MemSz=0x%lx Align=0x%lx\n",
|
||||
tls_vaddr, tls_filesz, tls_memsz, tls_align);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t virt = ph->VirtualAddress;
|
||||
uint64_t offset = ph->Offset;
|
||||
uint64_t memsz = ph->MemorySize;
|
||||
uint64_t filesz = ph->FileSize;
|
||||
|
||||
if (memsz == 0)
|
||||
if (ph->Type != ELF_PROGRAM_TYPE_LOAD || ph->MemorySize == 0)
|
||||
continue;
|
||||
|
||||
// ── align to page boundary ─────────────────────
|
||||
uint64_t aligned_virt = ALIGN_DOWN(virt, PAGE_SIZE);
|
||||
uint64_t page_offset = virt & 0xFFF;
|
||||
uint64_t aligned_memsz = ALIGN_UP(memsz + page_offset, PAGE_SIZE);
|
||||
|
||||
uint64_t pages = aligned_memsz / PAGE_SIZE;
|
||||
|
||||
// Allocate physical pages
|
||||
uint64_t phys_base = (uint64_t)pmm_alloc(pages);
|
||||
if (!phys_base) {
|
||||
printf("ELF: pmm_alloc failed for %lu pages\n", pages);
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
if (ph->Offset + ph->FileSize > file_size) {
|
||||
printf("ELF: PT_LOAD segment data out of file bounds\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Map with exact permissions
|
||||
uint64_t map_flags = PAGE_USER;
|
||||
if (ph->Flags & PF_R) map_flags |= PAGE_READ;
|
||||
if (ph->Flags & PF_W) map_flags |= PAGE_WRITE;
|
||||
if (!(ph->Flags & PF_X)) map_flags |= PAGE_NO_EXECUTE;
|
||||
|
||||
uint64_t virt = ph->VirtualAddress;
|
||||
uint64_t aligned_virt = ALIGN_DOWN(virt, PAGE_SIZE);
|
||||
uint64_t page_offset = virt & (PAGE_SIZE - 1);
|
||||
uint64_t aligned_memsz = ALIGN_UP(ph->MemorySize + page_offset, PAGE_SIZE);
|
||||
uint64_t pages = aligned_memsz / PAGE_SIZE;
|
||||
|
||||
void* seg_phys = pmm_allocz(pages);
|
||||
if (!seg_phys) {
|
||||
printf("ELF: failed to allocate physical pages for LOAD segment\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// ── map each page individually using new vmm_map_page ─────
|
||||
for (uint64_t p = 0; p < pages; p++) {
|
||||
uint64_t virt_addr = aligned_virt + p * PAGE_SIZE;
|
||||
uint64_t phys_addr = phys_base + p * PAGE_SIZE;
|
||||
|
||||
bool success = vmm_map_page(
|
||||
target_pagemap,
|
||||
virt_addr,
|
||||
phys_addr,
|
||||
PAGE_READ | PAGE_WRITE | PAGE_USER, // RW + User mode
|
||||
Size4KiB
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
printf("ELF: failed to map page at 0x%lx\n", virt_addr);
|
||||
// TODO: cleanup previously mapped pages + free phys
|
||||
kfree(elf_buffer);
|
||||
return false;
|
||||
if (!vmm_map_page(target_pagemap,
|
||||
aligned_virt + p * PAGE_SIZE,
|
||||
(uintptr_t)seg_phys + p * PAGE_SIZE,
|
||||
map_flags,
|
||||
Size4KiB)) {
|
||||
pmm_free(seg_phys, pages);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// ── copy segment data ───────────────────────────────
|
||||
uint8_t* dst = (uint8_t*)(phys_base + MEM_PHYS_OFFSET); // via HHDM
|
||||
uint8_t* src = elf_buffer + offset;
|
||||
|
||||
memcpy(dst + page_offset, src, filesz);
|
||||
|
||||
// ── zero BSS section ────────────────────────────────
|
||||
if (memsz > filesz) {
|
||||
memset(dst + page_offset + filesz, 0, memsz - filesz);
|
||||
uint8_t* dst = (uint8_t*)((uintptr_t)seg_phys + MEM_PHYS_OFFSET);
|
||||
memcpy(dst + page_offset, elf_buffer + ph->Offset, ph->FileSize);
|
||||
if (ph->MemorySize > ph->FileSize) {
|
||||
memset(dst + page_offset + ph->FileSize, 0,
|
||||
ph->MemorySize - ph->FileSize);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(elf_buffer);
|
||||
|
||||
uint64_t tls_size = tls_memsz ? ALIGN_UP(tls_memsz, tls_align) : 0ULL;
|
||||
|
||||
uint64_t tcb_va = TLS_BASE_VA + PAGE_SIZE;
|
||||
uint64_t tls_va = tcb_va - tls_size;
|
||||
|
||||
uint64_t page_va = ALIGN_DOWN(tls_va, PAGE_SIZE);
|
||||
uint64_t tcb_size = sizeof(TCB);
|
||||
uint64_t block_end_va = tcb_va + tcb_size;
|
||||
uint64_t block_end_page = ALIGN_UP(block_end_va, PAGE_SIZE);
|
||||
uint64_t map_pages = ((block_end_page - page_va) / PAGE_SIZE) + 8;
|
||||
if (map_pages == 0) map_pages = 1;
|
||||
|
||||
void* tls_phys = pmm_allocz(map_pages);
|
||||
if (!tls_phys) {
|
||||
printf("ELF: failed to allocate TLS/TCB pages\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint64_t tls_map_flags = PAGE_USER | PAGE_READ | PAGE_WRITE;
|
||||
for (uint64_t p = 0; p < map_pages; p++) {
|
||||
if (!vmm_map_page(target_pagemap,
|
||||
page_va + p * PAGE_SIZE,
|
||||
(uintptr_t)tls_phys + p * PAGE_SIZE,
|
||||
tls_map_flags,
|
||||
Size4KiB)) {
|
||||
pmm_free(tls_phys, map_pages);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* base_hhdm = (uint8_t*)((uintptr_t)tls_phys + MEM_PHYS_OFFSET);
|
||||
|
||||
if (tls_size > 0) {
|
||||
uint8_t* tls_dst = base_hhdm + (tls_va - page_va);
|
||||
if (tls_filesz) memcpy(tls_dst, tls_src, tls_filesz);
|
||||
if (tls_memsz > tls_filesz)
|
||||
memset(tls_dst + tls_filesz, 0, tls_memsz - tls_filesz);
|
||||
}
|
||||
|
||||
TCB* tcb = (TCB*)(base_hhdm + (tcb_va - page_va));
|
||||
memset(tcb, 0, sizeof(TCB));
|
||||
tcb->self = (void*)tcb_va;
|
||||
tcb->tid = 1;
|
||||
|
||||
*out_tls_fs_base = tcb_va;
|
||||
|
||||
*out_phdr_va = tls_vaddr ? tls_vaddr : phdr_vaddr;
|
||||
*out_phent = header->ProgramHeaderTableEntrySize;
|
||||
*out_phnum = header->ProgramHeaderTableEntryCount;
|
||||
|
||||
printf("ELF: TLS/TCB setup complete TCB@0x%lx TLS@0x%lx FS=0x%lx\n"
|
||||
" PHDR@0x%lx PHENT=0x%x PHNUM=%u\n",
|
||||
tcb_va, tls_va, tcb_va, *out_phdr_va, *out_phent, *out_phnum);
|
||||
|
||||
pmm_free(buffer_phys, buf_pages);
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
pmm_free(buffer_phys, buf_pages);
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user