153 lines
4.3 KiB
C++
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;
|
|
|
|
}
|
|
|
|
}
|