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