This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
hilbert-os/kernel/source/load-app.cpp

153 lines
4.3 KiB
C++

#include <hilbert/kernel/load-app.hpp>
#include <hilbert/kernel/paging.hpp>
namespace hilbert::kernel {
struct elf_header {
uint8_t fixed[24];
uint64_t entry_point;
uint64_t program_header_offset;
uint64_t section_header_offset;
uint32_t flags;
uint16_t elf_header_length;
uint16_t program_header_pitch;
uint16_t program_header_count;
};
struct program_header {
uint32_t type;
uint32_t flags;
uint64_t foffset;
uint64_t vaddr;
uint64_t paddr;
uint64_t flength;
uint64_t vlength;
};
struct load_info {
uint64_t vaddr;
uint64_t vpages_start;
uint64_t vpages_count;
uint64_t foffset;
uint64_t flength;
bool writable;
bool executable;
};
static uint8_t expected_fixed_header[24] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00
};
load_app_result load_app(
vfile::vfile &file, app_memory &into, uint64_t &entry_out) {
if (file.dir_entry.type != storage::file_type::regular_file)
return load_app_result::not_app;
if (file.dir_entry.length < sizeof(elf_header))
return load_app_result::not_app;
elf_header eh;
if (file.read_file(0, sizeof(elf_header), &eh)
!= storage::fs_result::success)
return load_app_result::io_error;
for (int i = 0; i < 24; ++i)
if (eh.fixed[i] != expected_fixed_header[i])
return load_app_result::not_app;
if (eh.entry_point < 0x1000 || eh.entry_point >= 0x4000000000)
return load_app_result::not_app;
utility::vector<load_info> load_infos;
for (int i = 0; i < eh.program_header_count; ++i) {
uint64_t offset = eh.program_header_offset + eh.program_header_pitch * i;
if (offset + sizeof(program_header) > file.dir_entry.length)
return load_app_result::not_app;
program_header ph;
if (file.read_file(offset, sizeof(program_header), &ph)
!= storage::fs_result::success)
return load_app_result::io_error;
if (ph.type == 1) {
uint64_t vpages_start = (ph.vaddr / 4096) * 4096;
uint64_t vpages_end = ((ph.vaddr + ph.vlength - 1) / 4096 + 1) * 4096;
if (vpages_start < 0x1000 || vpages_end >= 0x4000000000 ||
ph.foffset + ph.flength > file.dir_entry.length)
return load_app_result::not_app;
load_infos.add_end((load_info){
.vaddr = ph.vaddr,
.vpages_start = vpages_start,
.vpages_count = (vpages_end - vpages_start) / 4096,
.foffset = ph.foffset,
.flength = ph.flength,
.writable = (ph.flags & 2) != 0,
.executable = (ph.flags & 4) != 0 });
}
}
for (unsigned i = 0; i < load_infos.count; ++i) {
const auto &li = load_infos.buffer[i];
for (uint64_t pi = 0; pi < li.vpages_count; ++pi) {
uint64_t page_user_vaddr = li.vpages_start + pi * 4096;
uint64_t page_kernel_vaddr;
uint64_t page_paddr;
paging::map_new_kernel_page(page_kernel_vaddr, page_paddr);
uint8_t *ptr = (uint8_t *)page_kernel_vaddr;
int bytes_left = 4096;
int64_t foffset = page_user_vaddr - li.vaddr;
if (foffset < 0) {
int to_skip = -foffset;
for (int i = 0; i < to_skip; ++i)
ptr[i] = 0;
ptr += to_skip;
bytes_left -= to_skip;
foffset = 0;
}
int64_t left_in_file = li.flength - foffset;
if (left_in_file > 0) {
int to_read = left_in_file < bytes_left ? left_in_file : bytes_left;
if (file.read_file(li.foffset + foffset, to_read, ptr) !=
storage::fs_result::success) {
paging::unmap_kernel_page((uint64_t)page_kernel_vaddr);
paging::free_pram_page(page_paddr);
return load_app_result::io_error;
}
ptr += to_read;
bytes_left -= to_read;
}
if (bytes_left > 0)
for (int i = 0; i < bytes_left; ++i)
ptr[i] = 0;
paging::unmap_kernel_page((uint64_t)page_kernel_vaddr);
into.map_page(
page_user_vaddr, page_paddr, li.writable, li.executable, true);
}
}
entry_out = eh.entry_point;
return load_app_result::success;
}
}