diff options
Diffstat (limited to 'kernel/application.cpp')
-rw-r--r-- | kernel/application.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/kernel/application.cpp b/kernel/application.cpp new file mode 100644 index 0000000..19b1dbc --- /dev/null +++ b/kernel/application.cpp @@ -0,0 +1,266 @@ +#include <mercury/kernel/application.hpp> +#include <mercury/kernel/paging.hpp> + +//TODO - scheduling. + +namespace mercury::kernel::application { + + app_instance::app_instance() : state(app_state::paused) { + + framebuffer_vaddr = 0; + + uint64_t p3_paddr; + uint64_t p2_paddr; + + uint64_t p4_vaddr; + uint64_t p3_vaddr; + uint64_t p2_vaddr; + + paging::map_new_kernel_page(p4_vaddr, p4_paddr); + paging::map_new_kernel_page(p3_vaddr, p3_paddr); + paging::map_new_kernel_page(p2_vaddr, p2_paddr); + + p4 = (uint64_t *)p4_vaddr; + p3 = (uint64_t *)p3_vaddr; + p2 = (uint64_t *)p2_vaddr; + + for (int i = 1; i < 511; ++i) + p4[i] = 0; + p4[511] = paging::kernel_p4e; + p4[0] = paging::encode_pte(p3_paddr, true, true, true, false); + + for (int i = 1; i < 512; ++i) + p3[i] = 0; + p3[0] = paging::encode_pte(p2_paddr, true, true, true, false); + + for (int i = 0; i < 512; ++i) + p2[i] = 0; + + p2es_to_free_on_exit = new bool[512]; + + } + + app_instance::~app_instance() { + + for (int i = 1; i < 512; ++i) + if (p2[i] != 0 && p2es_to_free_on_exit[i]) { + uint64_t paddr = p2[i] & ~0x1fffffULL; + paging::mark_pram_region_free(paddr, paddr + 0x200000); + } + + delete[] p2es_to_free_on_exit; + + uint64_t p2_paddr = p3[0] & ~0x1fffffULL; + paging::unmap_kernel_page((uint64_t)p2); + paging::mark_pram_region_free(p2_paddr, p2_paddr + 4096); + + uint64_t p3_paddr = p4[0] & ~0x1fffffULL; + paging::unmap_kernel_page((uint64_t)p3); + paging::mark_pram_region_free(p3_paddr, p3_paddr + 4096); + + paging::unmap_kernel_page((uint64_t)p4); + paging::mark_pram_region_free(p4_paddr, p4_paddr + 4096); + + } + + void app_instance::map_page(uint64_t vaddr, uint64_t paddr, + bool write, bool execute, bool free_pram_on_exit + ) { + uint64_t i = vaddr / 0x200000; + p2[i] = paging::encode_pte(paddr, true, write, execute, true); + p2es_to_free_on_exit[i] = free_pram_on_exit; + } + + uint64_t app_instance::get_free_vaddr_pages(uint64_t count) { + uint64_t start = 1; + uint64_t length = 0; + while (start + length < 510) { + if (length == count) + return start * 0x200000; + if (p2[start + length] == 0) + ++length; + else { + start += length + 1; + length = 0; + } + } + //TODO: handle out of memory + return 0; + } + + void app_instance::create_stack() { + uint64_t stack_paddr = paging::take_2mib_pram_page(); + map_page(0x3fe00000, stack_paddr, true, false, true); + for (int i = 0; i < 512; ++i) { + uint64_t vaddr = paging::find_unmapped_vram_region(1); + paging::map_kernel_page(stack_paddr + 512 * i, vaddr, true, false); + for (int j = 0; j < 4096 / 8; ++j) + *(uint64_t *)(vaddr + j * 8) = 0; + paging::unmap_kernel_page(vaddr); + } + saved_regs.rsp = 0x40000000; + } + + void app_instance::set_instruction_pointer(uint64_t vaddr) { + saved_regs.rip = vaddr; + } + + uint64_t app_instance::count_mapped_vram_pages() { + uint64_t count = 0; + for (int i = 1; i < 512; ++i) + if (p2[i] != 0) + ++count; + return count; + } + + app_instance *running_app; + + static uint8_t correct_magic[16] = { + 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, + 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00 + }; + +#define READ(a, b, c) \ + { \ + storage::fs_result _result = file.read_file(a, b, c); \ + if (_result == storage::fs_result::device_error) \ + return create_app_result::device_error; \ + if (_result == storage::fs_result::fs_corrupt) \ + return create_app_result::fs_corrupt; \ + } + + struct load_info { + uint64_t foffset; + uint64_t fsize; + uint64_t vaddr; + uint64_t vpages; + bool writable; + bool executable; + }; + + create_app_result create_app(const vfile::vfile &file, app_instance *&out) { + + uint8_t magic[16]; + if (file.dir_entry.length < 64) + return create_app_result::app_corrupt; + READ(0, 8, magic) + READ(16, 8, magic + 8) + for (int i = 0; i < 16; ++i) + if (magic[i] != correct_magic[i]) + return create_app_result::app_corrupt; + + uint64_t entry_point; + uint64_t phead_start; + uint16_t phead_entry_size; + uint16_t phead_entry_count; + + READ(24, 8, &entry_point) + READ(32, 8, &phead_start) + READ(54, 2, &phead_entry_size) + READ(56, 2, &phead_entry_count) + + if (file.dir_entry.length < + phead_start + phead_entry_size * phead_entry_count) + return create_app_result::app_corrupt; + + utility::vector<load_info> load_infos; + + for (uint16_t i = 0; i < phead_entry_count; ++i) { + + uint64_t entry_start = phead_start + phead_entry_size * i; + + uint32_t seg_type; + READ(entry_start, 4, &seg_type) + if (seg_type != 1) + continue; + + uint64_t foffset; + uint64_t vaddr; + uint64_t fsize; + uint64_t vsize; + uint32_t flags; + + READ(entry_start + 8, 8, &foffset) + READ(entry_start + 16, 8, &vaddr) + READ(entry_start + 32, 8, &fsize) + READ(entry_start + 40, 8, &vsize) + READ(entry_start + 4, 4, &flags) + + if (vaddr & 0x1fffff) + return create_app_result::app_corrupt; + if (file.dir_entry.length < foffset + fsize) + return create_app_result::app_corrupt; + if (fsize > vsize) + return create_app_result::app_corrupt; + if (vaddr == 0) + return create_app_result::app_corrupt; + + uint64_t vpages = (vsize - 1) / 0x200000 + 1; + + if (vaddr + vpages * 0x200000 > ((1 << 30) - (4 << 20))) + return create_app_result::app_corrupt; + + load_info info = { + .foffset = foffset, + .fsize = fsize, + .vaddr = vaddr, + .vpages = vpages, + .writable = (flags & 2) == 2, + .executable = (flags & 1) == 1 + }; + load_infos.add_end(info); + + } + + out = new app_instance(); + + for (unsigned i = 0; i < load_infos.count; ++i) { + const auto &info = load_infos.buffer[i]; + for (uint64_t j = 0; j < info.vpages; ++j) { + uint64_t paddr = paging::take_2mib_pram_page(); + out->map_page(info.vaddr + j * 0x200000, paddr, + info.writable, info.executable, true); + for (int k = 0; k < 512; ++k) { + uint64_t offset_in_segment = j * 0x200000 + k * 4096; + uint64_t kvaddr = paging::find_unmapped_vram_region(1); + paging::map_kernel_page(paddr + k * 4096, kvaddr, true, false); + storage::fs_result result = storage::fs_result::success; + if (info.fsize > offset_in_segment) { + if (info.fsize >= offset_in_segment + 4096) + result = file.read_file( + info.foffset + offset_in_segment, 4096, (void *)kvaddr); + else { + int to_read = info.fsize - offset_in_segment; + result = file.read_file( + info.foffset + offset_in_segment, to_read, (void *)kvaddr); + uint8_t *blank = (uint8_t *)(kvaddr + to_read); + for (int i = 0; i < 4096 - to_read; ++i) + blank[i] = 0; + } + } + else { + uint8_t *blank = (uint8_t *)kvaddr; + for (int i = 0; i < 4096; ++i) + blank[i] = 0; + } + paging::unmap_kernel_page(kvaddr); + if (result == storage::fs_result::device_error) { + delete out; + return create_app_result::device_error; + } + if (result == storage::fs_result::fs_corrupt) { + delete out; + return create_app_result::fs_corrupt; + } + } + } + } + + out->create_stack(); + out->set_instruction_pointer(entry_point); + + return create_app_result::success; + + } + +} |