Kernel: Big commit. Rewrite ELF loading code
We now load ELF files to VirtualRanges instead of using kmalloc. We have only a fixed 1 MiB kmalloc for big allocations and this allows loading files even when they don't fit in there. This caused me to rewrite the whole ELF loading process since the loaded ELF is not in memory mapped by every process. Virtual ranges allow you to zero out the memory and to copy into them from arbitary byte buffers.
This commit is contained in:
@@ -1,15 +1,54 @@
|
||||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <LibELF/ELF.h>
|
||||
#include <LibELF/Values.h>
|
||||
|
||||
#ifdef __is_kernel
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Memory/PageTableScope.h>
|
||||
#include <kernel/Process.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#define ELF_PRINT_HEADERS 0
|
||||
|
||||
#ifdef __is_kernel
|
||||
extern uint8_t g_kernel_end[];
|
||||
using namespace Kernel;
|
||||
#endif
|
||||
|
||||
namespace LibELF
|
||||
{
|
||||
|
||||
#ifdef __is_kernel
|
||||
BAN::ErrorOr<BAN::UniqPtr<ELF>> ELF::load_from_file(BAN::StringView file_path)
|
||||
{
|
||||
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(file_path, true));
|
||||
|
||||
PageTable::current().lock();
|
||||
size_t page_count = BAN::Math::div_round_up<size_t>(file.inode->size(), PAGE_SIZE);
|
||||
vaddr_t vaddr = PageTable::current().get_free_contiguous_pages(page_count, (vaddr_t)g_kernel_end);
|
||||
auto virtual_range = BAN::UniqPtr<VirtualRange>::adopt(
|
||||
VirtualRange::create(
|
||||
PageTable::current(),
|
||||
vaddr, page_count * PAGE_SIZE,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
||||
)
|
||||
);
|
||||
PageTable::current().unlock();
|
||||
|
||||
TRY(file.inode->read(0, (void*)vaddr, file.inode->size()));
|
||||
|
||||
ELF* elf_ptr = new ELF(BAN::move(virtual_range), file.inode->size());
|
||||
if (elf_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
|
||||
auto elf = BAN::UniqPtr<ELF>::adopt(elf_ptr);
|
||||
TRY(elf->load());
|
||||
|
||||
return BAN::move(elf);
|
||||
}
|
||||
#else
|
||||
BAN::ErrorOr<ELF*> ELF::load_from_file(BAN::StringView file_path)
|
||||
{
|
||||
ELF* elf = nullptr;
|
||||
@@ -39,6 +78,7 @@ namespace LibELF
|
||||
|
||||
return elf;
|
||||
}
|
||||
#endif
|
||||
|
||||
BAN::ErrorOr<void> ELF::load()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __is_kernel
|
||||
#include <kernel/Memory/VirtualRange.h>
|
||||
#endif
|
||||
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/Arch.h>
|
||||
#include "Types.h"
|
||||
@@ -11,7 +16,7 @@ namespace LibELF
|
||||
class ELF
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<ELF*> load_from_file(BAN::StringView);
|
||||
static BAN::ErrorOr<BAN::UniqPtr<ELF>> load_from_file(BAN::StringView);
|
||||
|
||||
const Elf64FileHeader& file_header64() const;
|
||||
const Elf64ProgramHeader& program_header64(size_t) const;
|
||||
@@ -47,9 +52,16 @@ namespace LibELF
|
||||
bool is_x86_64() const;
|
||||
|
||||
private:
|
||||
#ifdef __is_kernel
|
||||
ELF(BAN::UniqPtr<Kernel::VirtualRange>&& storage, size_t size)
|
||||
: m_storage(BAN::move(storage))
|
||||
, m_data((const uint8_t*)m_storage->vaddr(), size)
|
||||
{}
|
||||
#else
|
||||
ELF(BAN::Vector<uint8_t>&& data)
|
||||
: m_data(BAN::move(data))
|
||||
{}
|
||||
#endif
|
||||
BAN::ErrorOr<void> load();
|
||||
|
||||
bool parse_elf64_file_header(const Elf64FileHeader&);
|
||||
@@ -61,7 +73,12 @@ namespace LibELF
|
||||
bool parse_elf32_section_header(const Elf32SectionHeader&);
|
||||
|
||||
private:
|
||||
#ifdef __is_kernel
|
||||
BAN::UniqPtr<Kernel::VirtualRange> m_storage;
|
||||
BAN::Span<const uint8_t> m_data;
|
||||
#else
|
||||
const BAN::Vector<uint8_t> m_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user