Implement an ELFImage struct

This struct allows us to keep track of what memory is used by the loaded executable. For some reason, freeing this memory when the task exits triggers a kernel page fault, so I'm not doing that right now.
This commit is contained in:
apio 2022-10-07 17:54:05 +02:00
parent b2d43d66c4
commit dc389da74e
5 changed files with 56 additions and 6 deletions

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include "sys/elf/Image.h"
#include <stdint.h> #include <stdint.h>
namespace ELFLoader namespace ELFLoader
{ {
void* load_elf_from_address(uintptr_t addr); ELFImage* load_elf_from_address(uintptr_t addr);
void* load_elf_from_initrd(const char* filename); ELFImage* load_elf_from_initrd(const char* filename);
} }

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
struct ELFSection
{
uintptr_t base;
uint64_t pages;
};
struct ELFImage
{
uintptr_t entry;
uint64_t section_count;
ELFSection sections[1];
};

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "interrupts/Context.h" #include "interrupts/Context.h"
#include "sys/elf/Image.h"
struct Task struct Task
{ {
@ -30,6 +31,8 @@ struct Task
bool floating_saved = false; bool floating_saved = false;
bool is_user_task(); bool is_user_task();
ELFImage* image = nullptr;
}; };
void set_context_from_task(Task& task, Context* ctx); void set_context_from_task(Task& task, Context* ctx);

View File

@ -5,6 +5,7 @@
#include "log/Log.h" #include "log/Log.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "misc/utils.h" #include "misc/utils.h"
#include "std/stdlib.h"
#include "std/string.h" #include "std/string.h"
#include "sys/elf/ELF.h" #include "sys/elf/ELF.h"
@ -18,7 +19,7 @@ static const char* format_permissions(uint32_t flags)
return perms; return perms;
} }
void* ELFLoader::load_elf_from_initrd(const char* filename) ELFImage* ELFLoader::load_elf_from_initrd(const char* filename)
{ {
InitRD::File elf_file = InitRD::open(filename); InitRD::File elf_file = InitRD::open(filename);
if (!elf_file.addr) if (!elf_file.addr)
@ -30,7 +31,7 @@ void* ELFLoader::load_elf_from_initrd(const char* filename)
return load_elf_from_address((uintptr_t)elf_file.addr); return load_elf_from_address((uintptr_t)elf_file.addr);
} }
void* ELFLoader::load_elf_from_address(uintptr_t addr) ELFImage* ELFLoader::load_elf_from_address(uintptr_t addr)
{ {
Elf64_Ehdr* elf_ehdr = (Elf64_Ehdr*)addr; Elf64_Ehdr* elf_ehdr = (Elf64_Ehdr*)addr;
if (strncmp((const char*)elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0) if (strncmp((const char*)elf_ehdr->e_ident, ELFMAG, SELFMAG) != 0)
@ -63,6 +64,9 @@ void* ELFLoader::load_elf_from_address(uintptr_t addr)
kwarnln("ELF file has no PHDRS"); kwarnln("ELF file has no PHDRS");
return 0; return 0;
} }
ELFImage* image = (ELFImage*)kmalloc(sizeof(ELFImage) - sizeof(ELFSection));
memset(image, 0, sizeof(ELFImage) - sizeof(ELFSection));
image->entry = elf_ehdr->e_entry;
int i; int i;
Elf64_Phdr* phdr; Elf64_Phdr* phdr;
for (phdr = (Elf64_Phdr*)((uint64_t)addr + elf_ehdr->e_phoff), i = 0; i < elf_ehdr->e_phnum; for (phdr = (Elf64_Phdr*)((uint64_t)addr + elf_ehdr->e_phoff), i = 0; i < elf_ehdr->e_phnum;
@ -82,8 +86,19 @@ void* ELFLoader::load_elf_from_address(uintptr_t addr)
phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER); phdr->p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER);
memcpy(buffer, (void*)(addr + phdr->p_offset), phdr->p_filesz); memcpy(buffer, (void*)(addr + phdr->p_offset), phdr->p_filesz);
memset((void*)((uint64_t)buffer + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz); memset((void*)((uint64_t)buffer + phdr->p_filesz), 0, phdr->p_memsz - phdr->p_filesz);
image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) +
(image->section_count + 1) * sizeof(ELFSection));
ELFSection& section = image->sections[image->section_count];
section.base = (uintptr_t)buffer;
section.pages = pages;
image->section_count++;
} }
else { kdbgln("skipping non-loadable segment"); } else { kdbgln("skipping non-loadable segment"); }
} }
return (void*)elf_ehdr->e_entry; if (!image->section_count)
{
kfree(image);
return 0;
}
return image;
} }

View File

@ -117,7 +117,14 @@ void Scheduler::load_user_task(const char* filename)
Task* new_task = new Task; Task* new_task = new Task;
ASSERT(new_task); ASSERT(new_task);
new_task->id = free_tid++; new_task->id = free_tid++;
new_task->regs.rip = (uint64_t)ELFLoader::load_elf_from_initrd(filename); ELFImage* image = ELFLoader::load_elf_from_initrd(filename);
if (!image)
{
kerrorln("Failed to load %s from initrd", filename);
return;
}
new_task->regs.rip = image->entry;
new_task->image = image;
if (!new_task->regs.rip) if (!new_task->regs.rip)
{ {
kwarnln("Failed to load user task %s", filename); kwarnln("Failed to load user task %s", filename);
@ -154,6 +161,15 @@ void Scheduler::reap_task(Task* task)
kinfoln("reaping task %ld", exiting_task->id); kinfoln("reaping task %ld", exiting_task->id);
if (exiting_task->allocated_stack) if (exiting_task->allocated_stack)
MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK); MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK);
if (exiting_task->image)
{
for (uint64_t i = 0; i < exiting_task->image->section_count; i++)
{
ELFSection& section = exiting_task->image->sections[i];
kdbgln("Task was using region %lx, which used %ld pages", section.base, section.pages);
}
kfree(exiting_task->image);
}
delete exiting_task; delete exiting_task;
} }