diff options
Diffstat (limited to 'kernel/source/load-app.cpp')
-rw-r--r-- | kernel/source/load-app.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/kernel/source/load-app.cpp b/kernel/source/load-app.cpp new file mode 100644 index 0000000..b4ffe03 --- /dev/null +++ b/kernel/source/load-app.cpp @@ -0,0 +1,153 @@ +#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; + + } + +} |