#include #include 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_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; } }