summaryrefslogtreecommitdiff
path: root/kernel/source/load-app.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/source/load-app.cpp')
-rw-r--r--kernel/source/load-app.cpp153
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;
+
+ }
+
+}