From 9af5588c30c4126a2800aae1afcb0de2c373dc6c Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Mon, 20 May 2024 17:40:47 -0400 Subject: rewrite application stuff in the kernel to support multitasking --- kernel/source/app-memory.cpp | 189 ++++++++++++ kernel/source/application.asm | 11 +- kernel/source/application.cpp | 680 +++++++++++++---------------------------- kernel/source/entry.cpp | 31 +- kernel/source/input.cpp | 15 +- kernel/source/interrupts.cpp | 4 +- kernel/source/load-app.cpp | 153 ++++++++++ kernel/source/paging.cpp | 10 +- kernel/source/syscall.cpp | 682 +++++++++++++++++++++++++++--------------- kernel/source/vfile.cpp | 4 +- 10 files changed, 1027 insertions(+), 752 deletions(-) create mode 100644 kernel/source/app-memory.cpp create mode 100644 kernel/source/load-app.cpp (limited to 'kernel/source') diff --git a/kernel/source/app-memory.cpp b/kernel/source/app-memory.cpp new file mode 100644 index 0000000..cca1359 --- /dev/null +++ b/kernel/source/app-memory.cpp @@ -0,0 +1,189 @@ +#include +#include +#include + +namespace hilbert::kernel { + + app_memory::app_memory() { + + uint64_t p3_paddr; + paging::map_new_kernel_page(p3, p3_paddr); + paging::map_new_kernel_page(p4, p4_paddr); + + for (int i = 0; i < 512; ++i) { + p4[i] = 0; + p3[i] = 0; + p2s[i] = 0; + p1s[i] = 0; + pram_pages_to_free_on_exit[i] = 0; + } + + p4[0] = paging::encode_pte(p3_paddr, true, true, true); + p4[511] = paging::kernel_p4e; + + } + + app_memory::~app_memory() { + + //first we see if the p2s exist + for (int p3i = 0; p3i < 512; ++p3i) + if (p3[p3i]) { + + //now we see if the p1s under this p2 exist + for (int p2i = 0; p2i < 512; ++p2i) + if (p2s[p3i][p2i]) { + + //we see if the pages under this p1 need to be freed + for (int p1i = 0; p1i < 512; ++p1i) + if (pram_pages_to_free_on_exit[p3i][p2i][p1i]) + paging::free_pram_page( + paging::pte_to_paddr(p1s[p3i][p2i][p1i])); + + //we free the p1 and the pram list + paging::free_pram_page(paging::pte_to_paddr(p2s[p3i][p2i])); + paging::unmap_kernel_page((uint64_t)p1s[p3i][p2i]); + delete[] pram_pages_to_free_on_exit[p3i][p2i]; + + } + + //free the p2, the p1 list, and the pram list list + paging::free_pram_page(paging::pte_to_paddr(p3[p3i])); + paging::unmap_kernel_page((uint64_t)p2s[p3i]); + delete[] p1s[p3i]; + delete[] pram_pages_to_free_on_exit[p3i]; + + } + + //finally, we free the p3 and the p4 + paging::free_pram_page(paging::pte_to_paddr(p4[0])); + paging::unmap_kernel_page((uint64_t)p3); + paging::free_pram_page(p4_paddr); + paging::unmap_kernel_page((uint64_t)p4); + + } + + void app_memory::map_page(uint64_t vaddr, uint64_t paddr, + bool write, bool execute, bool free_pram_on_exit) { + + int p1i = (vaddr >> 12) & 511; + int p2i = (vaddr >> 21) & 511; + int p3i = (vaddr >> 30) & 511; + + if (p2s[p3i] == 0) { + uint64_t new_p2_paddr; + paging::map_new_kernel_page(p2s[p3i], new_p2_paddr); + p1s[p3i] = new v_page_table[512]; + pram_pages_to_free_on_exit[p3i] = new bool *[512]; + for (int i = 0; i < 512; ++i) { + p2s[p3i][i] = 0; + p1s[p3i][i] = 0; + pram_pages_to_free_on_exit[p3i][i] = 0; + } + p3[p3i] = paging::encode_pte(new_p2_paddr, true, true, true); + } + + if (p1s[p3i][p2i] == 0) { + uint64_t new_p1_paddr; + paging::map_new_kernel_page(p1s[p3i][p2i], new_p1_paddr); + pram_pages_to_free_on_exit[p3i][p2i] = new bool[512]; + for (int i = 0; i < 512; ++i) { + p1s[p3i][p2i][i] = 0; + pram_pages_to_free_on_exit[p3i][p2i][i] = false; + } + p2s[p3i][p2i] = paging::encode_pte(new_p1_paddr, true, true, true); + } + + p1s[p3i][p2i][p1i] = paging::encode_pte(paddr, true, write, execute); + pram_pages_to_free_on_exit[p3i][p2i][p1i] = free_pram_on_exit; + + } + + void app_memory::unmap_page(uint64_t vaddr) { + int p1i = (vaddr >> 12) & 511; + int p2i = (vaddr >> 21) & 511; + int p3i = (vaddr >> 30) & 511; + if (pram_pages_to_free_on_exit[p3i][p2i][p1i]) { + pram_pages_to_free_on_exit[p3i][p2i][p1i] = false; + paging::free_pram_page(paging::pte_to_paddr(p1s[p3i][p2i][p1i])); + } + p1s[p3i][p2i][p1i] = 0; + } + + bool app_memory::valid_to_read( + uint64_t vaddr_start, uint64_t vaddr_end, bool and_write) const { + if (vaddr_start > vaddr_end || vaddr_end > 0x8000000000) + return false; + vaddr_start = (vaddr_start / 4096) * 4096; + vaddr_end = (((vaddr_end - 1) / 4096) + 1) * 4096; + for (uint64_t vaddr = vaddr_start; vaddr < vaddr_end; ++vaddr) { + int p1i = (vaddr >> 12) & 511; + int p2i = (vaddr >> 21) & 511; + int p3i = (vaddr >> 30) & 511; + if (!p1s[p3i] || !p1s[p3i][p2i] || !(and_write + ? (p1s[p3i][p2i][p1i] & 0x1) : p1s[p3i][p2i][p1i])) + return false; + } + return true; + } + + uint64_t app_memory::get_free_vaddr_pages(uint64_t count) { + uint64_t vaddr = 0x1000; + uint64_t run = 0; + while (true) { + if (run == count) + return vaddr; + if (vaddr + (run + 1) * 4096 > 0x4000000000) + //TODO: handle out of virtual memory + panic(0x9af5e6); + if (valid_to_read(vaddr + run * 4096, vaddr + (run + 1) * 4096, false)) { + vaddr += (run + 1) * 4096; + run = 0; + } + else + ++run; + } + } + + uint64_t app_memory::map_new_stack() { + for (uint64_t base_vaddr = 0x4000000000; + base_vaddr < 0x8000000000; base_vaddr += 0x1000000) + if (!valid_to_read(base_vaddr + 4096, base_vaddr + 8192, false)) { + + for (uint64_t vaddr = base_vaddr + 4096; + vaddr < base_vaddr + 0x1000000; vaddr += 4096) { + + uint8_t *kvaddr; + uint64_t paddr; + paging::map_new_kernel_page(kvaddr, paddr); + for (int i = 0; i < 4096; ++i) + kvaddr[i] = 0; + paging::unmap_kernel_page(kvaddr); + map_page(vaddr, paddr, true, false, true); + + } + return base_vaddr + 0x1000000; + + } + //TODO: handle out of stacks + panic(0x9af5e6); + + } + + void app_memory::unmap_stack(uint64_t top) { + for (uint64_t vaddr = top - 0xfff000; vaddr < top; vaddr += 4096) + unmap_page(vaddr); + } + + uint64_t app_memory::count_mapped_vram_pages() const { + uint64_t count = 0; + for (int p3i = 0; p3i < 512; ++p3i) + if (p3[p3i]) + for (int p2i = 0; p2i < 512; ++p2i) + if (p2s[p3i][p2i]) + for (int p1i = 0; p1i < 512; ++p1i) + if (p1s[p3i][p2i][p1i]) + ++count; + return count; + } + +} diff --git a/kernel/source/application.asm b/kernel/source/application.asm index ed8b190..632822f 100644 --- a/kernel/source/application.asm +++ b/kernel/source/application.asm @@ -137,9 +137,12 @@ resume_thread: extern copy_syscall_stack ;rdi = bottom +;returns: pointer to copy -global save_thread_state -save_thread_state: +extern resume_next_thread + +global yield +yield: ;rdi = pointer to cpu state structure ;only saving registers that need to be preserved by this function @@ -163,9 +166,7 @@ save_thread_state: mov qword [rdi + 152], rax ;kernel_stack_copy mov byte [rdi + 160], 0x01 ;in_syscall - xor al, al - ret + jmp resume_next_thread .resume_to: - mov al, 0x01 ret diff --git a/kernel/source/application.cpp b/kernel/source/application.cpp index c3ce2f1..0c3fd36 100644 --- a/kernel/source/application.cpp +++ b/kernel/source/application.cpp @@ -1,550 +1,282 @@ #include -#include -#include - -//TODO - scheduling. +#include +#include namespace hilbert::kernel::application { - process::process() : framebuffer_vaddr(0) { - - uint64_t p4_vaddr; - paging::map_new_kernel_page(p4_vaddr, p4_paddr); - p4 = (uint64_t *)p4_vaddr; - - uint64_t p3_paddr; - uint64_t p3_vaddr; - paging::map_new_kernel_page(p3_vaddr, p3_paddr); - p3 = (uint64_t *)p3_vaddr; - - for (int i = 1; i < 511; ++i) - p4[i] = 0; - p4[0] = paging::encode_pte(p3_paddr, true, true, true); - p4[511] = paging::kernel_p4e; - - for (int i = 0; i < 512; ++i) { - p3[i] = 0; - p2s[i] = 0; - p1s[i] = 0; - p1es_to_free_on_exit[i] = 0; - } + //returns pointer to copy + extern "C" void *copy_syscall_stack(const uint8_t *bottom) { + uint64_t len = 0xfffffffffffff000 - (uint64_t)bottom; + uint8_t *buffer = new uint8_t[len]; + for (uint64_t i = 0; i < len; ++i) + buffer[i] = bottom[i]; + return buffer; + } + extern "C" void restore_syscall_stack(uint8_t *from, uint8_t *to) { + uint64_t len = 0xfffffffffffff000 - (uint64_t)to; + for (uint64_t i = 0; i < len; ++i) + to[i] = from[i]; + delete[] from; } - void process::map_page(uint64_t vaddr, uint64_t paddr, - bool write, bool execute, bool free_pram_on_exit - ) { - - uint64_t i = ((vaddr / 4096) / 512) / 512; - uint64_t j = ((vaddr / 4096) / 512) % 512; - uint64_t k = (vaddr / 4096) % 512; - - if (p2s[i] == 0) { - uint64_t p2_paddr; - uint64_t p2_vaddr; - paging::map_new_kernel_page(p2_vaddr, p2_paddr); - p3[i] = paging::encode_pte(p2_paddr, true, true, true); - p2s[i] = (uint64_t *)p2_vaddr; - p1s[i] = new uint64_t *[512]; - p1es_to_free_on_exit[i] = new bool *[512]; - for (int u = 0; u < 512; ++u) { - p2s[i][u] = 0; - p1s[i][u] = 0; - p1es_to_free_on_exit[i][u] = 0; - } - } + utility::id_allocator *all_processes; + utility::queue *paused_threads; + thread *running_thread; - if (p2s[i][j] == 0) { - uint64_t p1_paddr; - uint64_t p1_vaddr; - paging::map_new_kernel_page(p1_vaddr, p1_paddr); - p2s[i][j] = paging::encode_pte(p1_paddr, true, true, true); - p1s[i][j] = (uint64_t *)p1_vaddr; - p1es_to_free_on_exit[i][j] = new bool[512]; - for (int u = 0; u < 512; ++u) { - p1s[i][j][u] = 0; - p1es_to_free_on_exit[i][j][u] = false; - } - } + struct socket_listener_registration { + socket_listener *listener; + utility::string id; + }; - p1s[i][j][k] = paging::encode_pte(paddr, true, write, execute); - p1es_to_free_on_exit[i][j][k] = free_pram_on_exit; + utility::list *all_running_socket_listeners; - } + extern "C" void init_applications_asm(); - bool process::is_page_owned(uint64_t vaddr) { - uint64_t i = ((vaddr / 4096) / 512) / 512; - uint64_t j = ((vaddr / 4096) / 512) % 512; - uint64_t k = (vaddr / 4096) % 512; - return - i < 512 && p1s[i] != 0 && p1s[i][j] != 0 && - p1s[i][j][k] != 0 && p1es_to_free_on_exit[i][j][k]; + void init_applications() { + all_processes = new utility::id_allocator(); + paused_threads = new utility::queue(); + running_thread = 0; + all_running_socket_listeners = + new utility::list(); + init_applications_asm(); } - uint64_t process::get_free_vaddr_pages(uint64_t count) { - uint64_t start = 0x200000 / 4096; - uint64_t length = 0; - while (start + length <= 0x8000000000 / 4096) { - if (length == count) - return start * 4096; - int i = ((start + length) / 512) / 512; - int j = ((start + length) / 512) % 512; - int k = (start + length) % 512; - if (p1s[i] == 0 || p1s[i][j] == 0 || p1s[i][j][k] == 0) - ++length; - else { - start += length + 1; - length = 0; - } - } - //TODO: handle out of memory - return 0; + uint64_t add_process(process *p) { + return p->id = all_processes->add_new(utility::move(p)); } - uint64_t process::count_mapped_vram_pages() { - uint64_t count = 0; - for (int i = 0; i < 512; ++i) - if (p1s[i] != 0) - for (int j = 0; j < 512; ++j) - if (p1s[i][j] != 0) - for (int k = 0; k < 512; ++k) - if (p1s[i][j][k] != 0) - ++count; - return count; + socket_listener *try_register_socket_listener(const utility::string &id) { + for (auto *n = all_running_socket_listeners->first; n; n = n->next) + if (n->value.id == id) + return 0; + socket_listener *sl = new socket_listener(); + all_running_socket_listeners->insert_end({.listener = sl, .id = id}); + return sl; } - utility::id_allocator *processes; - utility::queue *paused_threads; - utility::queue *threads_waiting_for_input; - thread *running_thread; - utility::list *all_socket_listeners; - - 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::success) \ - return stream_result::io_error; \ + socket_listener *try_get_socket_listener(const utility::string &id) { + for (auto *n = all_running_socket_listeners->first; n; n = n->next) + if (n->value.id == id) + return n->value.listener; + return 0; } -#define TRY_MAR(expr) \ - { \ - storage::fs_result _result = expr; \ - if (_result != storage::fs_result::success) { \ - delete process_out; \ - return stream_result::io_error; \ - } \ + void remove_socket_listener(socket_listener *sl) { + for (auto *n = all_running_socket_listeners->first; n; n = n->next) + if (n->value.listener == sl) { + all_running_socket_listeners->remove(n); + delete sl; + return; + } } - struct load_info { - uint64_t foffset; - uint64_t fsize; - uint64_t vaddr; - uint64_t voffset; - uint64_t vpages; - bool writable; - bool executable; - }; - - storage::fs_result map_and_read( - const vfile::vfile &file, process *process, uint64_t vaddr, uint64_t faddr, - uint64_t len, bool writable, bool executable - ) { - - uint64_t page_vaddr = vaddr & ~4095; - int at_start = vaddr & 4095; - int at_end = 4096 - len - at_start; - - uint64_t page_paddr = paging::take_pram_page(); - process->map_page(page_vaddr, page_paddr, writable, executable, true); - uint64_t page_kvaddr = paging::find_unmapped_vram_region(1); - paging::map_kernel_page(page_paddr, page_kvaddr, true, false); - - storage::fs_result result = storage::fs_result::success; - - if (at_start) { - uint8_t *blank = (uint8_t *)page_kvaddr; - for (int i = 0; i < at_start; ++i) - blank[i] = 0; - } - - if (len != 0) - result = file.read_file(faddr, len, (void *)(page_kvaddr + at_start)); - - if (at_end) { - uint8_t *blank = (uint8_t *)(page_kvaddr + at_start + len); - for (int i = 0; i < at_end; ++i) - blank[i] = 0; - } - - paging::unmap_kernel_page(page_kvaddr); - return result; + //cpu argument not on stack. + extern "C" [[noreturn]] void resume_thread(const cpu_state &cpu); + extern "C" [[noreturn]] void resume_next_thread() { + running_thread = 0; + while (paused_threads->count == 0) + asm volatile ("sti\nhlt\ncli"); + thread *t = paused_threads->take(); + running_thread = t; + resume_thread(t->saved_state); } - stream_result create_application( - const vfile::vfile &file, process *&process_out, thread *&thread_out - ) { - - uint8_t magic[16]; - if (file.dir_entry.type != storage::file_type::regular_file) - return stream_result::not_a_regular_file; - if (file.dir_entry.length < 64) - return stream_result::not_an_executable; - READ(0, 8, magic) - READ(16, 8, magic + 8) - for (int i = 0; i < 16; ++i) - if (magic[i] != correct_magic[i]) - return stream_result::not_an_executable; - - 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 stream_result::not_an_executable; - - utility::vector 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 voffset; - 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) - - voffset = vaddr % 4096; - vaddr -= voffset; - - if (vsize == 0) - continue; - - if (file.dir_entry.length < foffset + fsize) - return stream_result::not_an_executable; - if (fsize > vsize) - return stream_result::not_an_executable; - - if (vaddr < 0x200000) - return stream_result::not_an_executable; - - uint64_t vpages = (voffset + vsize - 1) / 4096 + 1; - - if (vaddr + vpages * 4096 > 0x8000000000) - return stream_result::not_an_executable; - - load_info info = { - .foffset = foffset, - .fsize = fsize, - .vaddr = vaddr, - .voffset = voffset, - .vpages = vpages, - .writable = (flags & 2) == 2, - .executable = (flags & 1) == 1 - }; - load_infos.add_end(info); + process::process(app_memory *memory) : memory(memory) {} - } + process::~process() { + delete memory; //:p + } - process_out = new process(); - - for (unsigned i = 0; i < load_infos.count; ++i) { - const auto &info = load_infos.buffer[i]; - - uint64_t vaddr = info.vaddr + info.voffset; - uint64_t faddr = info.foffset; - uint64_t v_remaining = info.vpages * 4096 - info.voffset; - uint64_t f_remaining = info.fsize; - - if (info.voffset != 0) { - int to_read = info.fsize < 4096 - info.voffset - ? info.fsize : 4096 - info.voffset; - if (to_read > 0) { - TRY_MAR(map_and_read(file, process_out, vaddr, faddr, to_read, - info.writable, info.executable)) - vaddr += to_read; - faddr += to_read; - v_remaining -= to_read; - f_remaining -= to_read; - } - } + void process::add_environment_variable( + utility::string &&name, utility::string &&value) { + environment_variables.insert_end({.a = name, .b = value}); + } - while (f_remaining > 0) { - int to_read = f_remaining < 4096 ? f_remaining : 4096; - TRY_MAR(map_and_read(file, process_out, vaddr, faddr, to_read, - info.writable, info.executable)) - vaddr += to_read; - faddr += to_read; - v_remaining -= to_read; - f_remaining -= to_read; - } + void process::add_thread(thread *t) { + threads.insert_end(t); + } - if (vaddr & 4095) { - v_remaining -= 4096 - (vaddr & 4095); - vaddr += 4096 - (vaddr & 4095); - } + void process::notify_thread_ended(thread *t, int exit_code) { + threads.remove_first_of(t); + if (threads.first == 0) + on_end_process(exit_code); + } - while (v_remaining > 0) { - map_and_read( - file, process_out, vaddr, 0, 0, info.writable, info.executable); - vaddr += 4096; - v_remaining -= 4096; - } + void process::on_end_process(int exit_code) { + while (threads.first) { + threads.first->value->on_end_thread(); + delete threads.first->value; + threads.remove(threads.first); } - for (uint64_t vaddr = 0x1000; vaddr < 0x1ff000; vaddr += 4096) { - uint64_t paddr = paging::take_pram_page(); - uint64_t kvaddr = paging::find_unmapped_vram_region(1); - paging::map_kernel_page(paddr, kvaddr, true, false); - uint8_t *p = (uint8_t *)kvaddr; - for (int i = 0; i < 4096; ++i) - p[i] = 0; - paging::unmap_kernel_page(kvaddr); - process_out->map_page(vaddr, paddr, true, false, true); - } + //TODO: destroy file streams + //TODO: destroy socket streams + //TODO: destroy socket listeners - thread_out = new thread(); - process_out->threads.insert_end(thread_out); - thread_out->the_process = process_out; - - thread_out->state = thread_state::paused; - - thread_out->cpu.rax = 0; - thread_out->cpu.rbx = 0; - thread_out->cpu.rcx = 0; - thread_out->cpu.rdx = 0; - thread_out->cpu.rdi = 0; - thread_out->cpu.rsi = 0; - thread_out->cpu.rbp = 0; - thread_out->cpu.rsp = 0x1ff000; - thread_out->cpu.r8 = 0; - thread_out->cpu.r9 = 0; - thread_out->cpu.r10 = 0; - thread_out->cpu.r11 = 0; - thread_out->cpu.r12 = 0; - thread_out->cpu.r13 = 0; - thread_out->cpu.r14 = 0; - thread_out->cpu.r15 = 0; - - thread_out->cpu.rflags = 0x200; - thread_out->cpu.rip = entry_point; - thread_out->cpu.cr3 = process_out->p4_paddr; - thread_out->cpu.in_syscall = false; - - return stream_result::success; + this->exit_code = exit_code; } - extern "C" void init_applications_asm(); - - void init_applications() { - processes = new utility::id_allocator(); - paused_threads = new utility::queue(); - threads_waiting_for_input = new utility::queue(); - all_socket_listeners = new utility::list(); - init_applications_asm(); + bool process::has_ended() const { + return threads.first == 0; } - //only called from non-interruptable contexts. - //cpu argument not on stack. - extern "C" [[noreturn]] void resume_thread(const cpu_state &cpu); - - extern "C" void *copy_syscall_stack(uint8_t *rsp) { - uint64_t size = 0xfffffffffffff000 - (uint64_t)rsp; - uint8_t *buffer = new uint8_t[size]; - for (uint64_t i = 0; i < size; ++i) - buffer[i] = rsp[i]; - return buffer; + unsigned process::add_file_stream(file_stream *stream) { + return open_streams.add_new({ + .is_socket = false, .as_file_stream = stream }); } - extern "C" void restore_syscall_stack(const uint8_t *from, uint8_t *rsp) { - uint64_t size = 0xfffffffffffff000 - (uint64_t)rsp; - for (uint64_t i = 0; i < size; ++i) - rsp[i] = from[i]; - delete[] from; + unsigned process::add_socket_stream(socket_stream_end *stream) { + return open_streams.add_new({ + .is_socket = true, .as_socket_stream = stream }); } - thread::~thread() { - for (auto *p = the_process->threads.first; p; p = p->next) - if (p->value == this) { - the_process->threads.remove(p); - break; - } - if (the_process->threads.first == 0) { - the_process->exit_code = exit_code; - the_process->cleanup(); - } - if (state != thread_state::running) - panic(0x9af5e6); + unsigned process::add_socket_listener(socket_listener *sl) { + return running_socket_listeners.add_new(utility::move(sl)); } - [[noreturn]] void resume_next() { - while (paused_threads->count == 0) - asm volatile ("sti\nhlt\ncli"); - auto *t = paused_threads->take(); - running_thread = t; - t->state = thread_state::running; - resume_thread(t->cpu); + generic_stream_ptr process::get_stream(unsigned handle) { + if (open_streams.has_id(handle)) + return open_streams.get(handle); + return null_gsp; } - void process::end_process(unsigned exit_code) { - while (threads.first != 0) - delete threads.first->value; - this->exit_code = exit_code; - cleanup(); + generic_stream_ptr process::take_stream(unsigned handle) { + auto ptr = open_streams.get(handle); + open_streams.remove_id(handle); + return ptr; } - void process::cleanup() { - //TODO - panic(0x9af5e6); + void process::add_stream_with_handle( + unsigned handle, generic_stream_ptr ptr) { + open_streams.add_id(new generic_stream_ptr(ptr), handle); } - socket_stream::socket_stream(socket *sock, bool are_we_b) - : sock(sock), are_we_b(are_we_b), - our_threads_waiting_to_read(are_we_b - ? sock->process_b_threads_waiting_to_read - : sock->process_a_threads_waiting_to_read), - their_threads_waiting_to_read(are_we_b - ? sock->process_a_threads_waiting_to_read - : sock->process_b_threads_waiting_to_read), - them_to_us(are_we_b ? sock->a_to_b : sock->b_to_a), - us_to_them(are_we_b ? sock->b_to_a : sock->a_to_b), - them_closed(are_we_b ? sock->a_closed : sock->b_closed), - us_closed(are_we_b ? sock->b_closed : sock->a_closed) {} - - stream_result socket_stream::seek(seek_origin, int64_t) { - return stream_result::not_seekable; + socket_listener *process::get_socket_listener(unsigned handle) { + if (running_socket_listeners.has_id(handle)) + return running_socket_listeners.get(handle); + return 0; } - stream_result socket_stream::read(uint64_t count, void *into) { - uint8_t *buffer = (uint8_t *)into; - for (uint64_t i = 0; i < count; ++i) { - while (them_to_us.count == 0) { - if (them_closed) - return stream_result::other_end_closed; - if (!save_thread_state(running_thread->cpu)) { - running_thread->state = thread_state::waiting; - our_threads_waiting_to_read.insert(running_thread); - resume_next(); - } - } - buffer[i] = them_to_us.take(); + socket_listener *process::take_socket_listener(unsigned handle) { + if (running_socket_listeners.has_id(handle)) { + socket_listener *listener = running_socket_listeners.get(handle); + running_socket_listeners.remove_id(handle); + return listener; } - return stream_result::success; + return 0; } - stream_result socket_stream::write(uint64_t count, const void *from) { - if (them_closed) - return stream_result::other_end_closed; - const uint8_t *buffer = (const uint8_t *)from; - for (uint64_t i = 0; i < count; ++i) { - if (their_threads_waiting_to_read.count > 0) { - auto *ot = their_threads_waiting_to_read.take(); - ot->state = thread_state::paused; - paused_threads->insert(ot); + void process::close_stream(unsigned handle) { + + if (!open_streams.has_id(handle)) + return; + auto ptr = open_streams.get(handle); + open_streams.remove_id(handle); + + if (ptr.is_socket) { + auto stream = ptr.as_socket_stream; + + if (stream->is_other_side_open) { + stream->other_end->is_other_side_open = false; + auto &q = stream->other_end->waiting_to_read; + while (q.count > 0) + paused_threads->insert(q.take()); } - us_to_them.insert(buffer[i]); + + else + delete stream->the_socket; + + delete stream; } - return stream_result::success; + } - stream_result socket_stream::get_length(uint64_t &) { - return stream_result::not_sized; + thread::thread(process *owner, uint64_t entry) + : stack_top(owner->memory->map_new_stack()), waiting_for_socket_stream(0), + waiting_to_accept_from(0), waiting_to_connect_to(0), + waiting_for_input(false), owner(owner) { + + saved_state.rax = 0; + saved_state.rbx = 0; + saved_state.rcx = 0; + saved_state.rdx = 0; + saved_state.rdi = 0; + saved_state.rsi = 0; + saved_state.rbp = 0; + saved_state.rsp = stack_top; + saved_state.r8 = 0; + saved_state.r9 = 0; + saved_state.r10 = 0; + saved_state.r11 = 0; + saved_state.r12 = 0; + saved_state.r13 = 0; + saved_state.r14 = 0; + saved_state.r15 = 0; + + saved_state.rflags = 0x200; + saved_state.rip = entry; + saved_state.cr3 = owner->memory->p4_paddr; + saved_state.in_syscall = false; + } - stream_result socket_stream::set_length(uint64_t) { - return stream_result::not_sized; + void thread::on_end_thread() { + owner->memory->unmap_stack(stack_top); + if (waiting_for_socket_stream) + waiting_for_socket_stream->waiting_to_read.remove(this); + else if (waiting_to_accept_from) + waiting_to_accept_from->waiting_to_accept.remove(this); + else if (waiting_to_connect_to) + waiting_to_connect_to->waiting_to_connect.remove(this); + else if (waiting_for_input) + input::waiting_for_input->remove(this); } - socket_stream::~socket_stream() { - if (our_threads_waiting_to_read.count > 0) - panic(0x9af5e6); - if (them_closed) - delete sock; - else { - us_closed = true; - while (their_threads_waiting_to_read.count > 0) { - auto *t = their_threads_waiting_to_read.take(); - t->state = thread_state::paused; - paused_threads->insert(t); - } - } + void thread::wait_for_socket_stream(socket_stream_end *the_socket_stream) { + waiting_for_socket_stream = the_socket_stream; + the_socket_stream->waiting_to_read.insert(this); + yield(); + waiting_for_socket_stream = 0; } - vfile_stream::vfile_stream(vfile::vfile &&file) - : file(utility::move(file)), offset(0) {} - - stream_result vfile_stream::seek(seek_origin origin, int64_t offset) { - uint64_t start_at = {}; - switch (origin) { - case seek_origin::beginning: - start_at = 0; - break; - case seek_origin::end: - start_at = file.dir_entry.length; - break; - case seek_origin::current_position: - start_at = this->offset; - break; - } - if (offset < 0 && (uint64_t)-offset > start_at) - return stream_result::out_of_bounds; - if (offset + start_at > file.dir_entry.length) - return stream_result::out_of_bounds; - this->offset = start_at + offset; - return stream_result::success; + utility::maybe thread::wait_to_accept_from( + socket_listener *the_socket_listener) { + waiting_to_accept_from = the_socket_listener; + the_socket_listener->waiting_to_accept.insert(this); + yield(); + waiting_to_accept_from = 0; + return new_socket_stream_id; } - stream_result vfile_stream::read(uint64_t count, void *into) { - if (offset + count > file.dir_entry.length) - return stream_result::out_of_bounds; - if (file.read_file(offset, count, into) != storage::fs_result::success) - return stream_result::io_error; - offset += count; - return stream_result::success; + utility::maybe thread::wait_to_connect_to( + socket_listener *the_socket_listener) { + waiting_to_connect_to = the_socket_listener; + the_socket_listener->waiting_to_connect.insert(this); + yield(); + waiting_to_connect_to = 0; + return new_socket_stream_id; } - stream_result vfile_stream::write(uint64_t count, const void *from) { - if (offset + count > file.dir_entry.length) - return stream_result::out_of_bounds; - (void)from; - panic(0x9af5e6); + void thread::wait_for_input() { + waiting_for_input = false; + input::waiting_for_input->insert(this); + yield(); + waiting_for_input = false; } - stream_result vfile_stream::get_length(uint64_t &out) { - out = file.dir_entry.length; - return stream_result::success; + void thread::notify_no_socket_stream() { + new_socket_stream_id.has_value = false; + paused_threads->insert(this); } - stream_result vfile_stream::set_length(uint64_t to) { - (void)to; - panic(0x9af5e6); + void thread::notify_new_socket_stream(unsigned id) { + new_socket_stream_id.has_value = true; + new_socket_stream_id.value = id; + paused_threads->insert(this); } } diff --git a/kernel/source/entry.cpp b/kernel/source/entry.cpp index 5db3515..2389bb1 100644 --- a/kernel/source/entry.cpp +++ b/kernel/source/entry.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -201,25 +202,29 @@ extern "C" [[noreturn]] void entry() { vfile::canonize_path(init_path_string, init_path); vfile::vfile init_file; - if (vfile::lookup_path(init_path, init_file, true) != + if (vfile::look_up_path(init_path, init_file, true) != storage::fs_result::success) panic(0x7e874d); - application::process *init_process; - application::thread *init_thread; - if (application::create_application(init_file, init_process, init_thread) != - application::stream_result::success) + app_memory *init_memory = new app_memory(); + uint64_t init_entry_point; + load_app_result load_init_result = + load_app(init_file, *init_memory, init_entry_point); + + if (load_init_result != load_app_result::success) panic(0xc39db3); - init_process->environment.add_end({ - .a = utility::string("ARGC", 4), - .b = utility::string("1", 1)}); - init_process->environment.add_end({ - .a = utility::string("ARGV0", 5), - .b = utility::string("/bin/init", 9)}); + application::process *init_process = new application::process(init_memory); + init_process->add_environment_variable( + utility::string("ARGC", 4), utility::string("1", 1)); + init_process->add_environment_variable( + utility::string("ARGV0", 5), utility::string("/bin/init", 9)); + application::add_process(init_process); - init_thread->state = application::thread_state::paused; + application::thread *init_thread = + new application::thread(init_process, init_entry_point); + init_process->add_thread(init_thread); application::paused_threads->insert(init_thread); - application::resume_next(); + application::resume_next_thread(); } diff --git a/kernel/source/input.cpp b/kernel/source/input.cpp index 921ae7b..4f12e6e 100644 --- a/kernel/source/input.cpp +++ b/kernel/source/input.cpp @@ -6,17 +6,16 @@ namespace hilbert::kernel::input { utility::queue *input_queue; + utility::queue *waiting_for_input; - void init_input() { - input_queue = new utility::queue(); + void notify_waiting() { + if (waiting_for_input->count > 0) + application::paused_threads->insert(waiting_for_input->take()); } - void got_input() { - if (application::threads_waiting_for_input->count > 0) { - auto *t = application::threads_waiting_for_input->take(); - t->state = application::thread_state::paused; - application::paused_threads->insert(t); - } + void init_input() { + input_queue = new utility::queue(); + waiting_for_input = new utility::queue(); } } diff --git a/kernel/source/interrupts.cpp b/kernel/source/interrupts.cpp index 4046021..41d632c 100644 --- a/kernel/source/interrupts.cpp +++ b/kernel/source/interrupts.cpp @@ -93,7 +93,7 @@ static void got_key(uint32_t key) { input::input_queue->insert({ .keyboard = current_flags | key, .is_mouse = false}); - input::got_input(); + input::notify_waiting(); if (key == (input::BREAK | 0x77)) current_flags ^= input::NUM_LOCK; @@ -229,6 +229,6 @@ extern "C" void on_mouse_interrupt(uint8_t byte) { else input::input_queue->insert(packet); - input::got_input(); + input::notify_waiting(); } 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 +#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; + + } + +} diff --git a/kernel/source/paging.cpp b/kernel/source/paging.cpp index d8869fc..66d9bc7 100644 --- a/kernel/source/paging.cpp +++ b/kernel/source/paging.cpp @@ -38,11 +38,6 @@ namespace hilbert::kernel::paging { uint64_t kernel_p4e; - uint64_t encode_pte(uint64_t addr, bool user, bool write, bool execute) { - return (addr & 0x0000ffffffffffff) | (execute ? 0 : (1ULL << 63)) - | (user << 2) | (write << 1) | 1; - } - void init_kernel_page_tables(uint64_t kernel_offset) { __kernel_p4_paddr = (uint64_t)kernel_p4 - kernel_offset; for (int i = 0; i < 511; ++i) @@ -87,6 +82,11 @@ namespace hilbert::kernel::paging { return 0; } + void free_pram_page(uint64_t paddr) { + uint64_t page_i = paddr / 4096; + pram_usage_bitmap[page_i / 64] &= ~(1ULL << (page_i % 64)); + } + void map_kernel_stacks() { for (uint64_t vaddr = syscall_stack_bottom; vaddr < syscall_stack_top; vaddr += 4096) diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp index 5d9714c..6b0f13f 100644 --- a/kernel/source/syscall.cpp +++ b/kernel/source/syscall.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -17,16 +18,6 @@ namespace hilbert::kernel::syscall { file_result_directory }; - bool is_range_owned_by_application(uint64_t start, uint64_t end) { - auto *process = application::running_thread->the_process; - uint64_t pstart = (start / 4096) * 4096; - uint64_t pend = ((end - 1) / 4096 + 1) * 4096; - for (uint64_t p = pstart; p < pend; p += 4096) - if (!process->is_page_owned(p)) - return false; - return true; - } - void set_zero(uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { rax = 0; rdi = 0; @@ -35,26 +26,26 @@ namespace hilbert::kernel::syscall { } void encode_color_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + rax = (uint64_t)framebuffer::encode_color( rdi & 0xff, (rdi >> 8) & 0xff, (rdi >> 16) & 0xff); rdi = 0; rsi = 0; rdx = 0; + } void get_framebuffer_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { - auto *process = application::running_thread->the_process; + auto *process = application::running_thread->owner; if (process->framebuffer_vaddr == 0) { uint64_t pages_needed = (framebuffer::dword_pitch * framebuffer::height * 4 - 1) / 4096 + 1; - uint64_t vaddr = process->get_free_vaddr_pages(pages_needed); + uint64_t vaddr = process->memory->get_free_vaddr_pages(pages_needed); for (uint64_t i = 0; i < pages_needed; ++i) - process->map_page( + process->memory->map_page( vaddr + i * 4096, framebuffer::paddr + i * 4096, true, false, false); process->framebuffer_vaddr = vaddr; } @@ -69,23 +60,26 @@ namespace hilbert::kernel::syscall { } void open_file_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { - - if (!is_range_owned_by_application(rdi, rdi + rsi)) { - set_zero(rax, rdi, rsi, rdx); - return; - } + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { - utility::string path_string((const char *)rdi, rsi); + const char *path = (const char *)rdi; + uint64_t path_length = rsi; + bool allow_creation = rdx & 1; + bool only_allow_creation = rdx & 2; set_zero(rax, rdi, rsi, rdx); + auto *process = application::running_thread->owner; + if (!process->memory->valid_to_read(path, path + path_length, false)) + return; + + utility::string path_string(path, path_length); + vfile::canon_path cp; vfile::vfile file; vfile::canonize_path(path_string, cp); - switch (vfile::lookup_path(cp, file, true)) { + switch (vfile::look_up_path(cp, file, true)) { case storage::fs_result::device_error: case storage::fs_result::fs_corrupt: @@ -95,7 +89,7 @@ namespace hilbert::kernel::syscall { case storage::fs_result::does_not_exist: - if (!(rdx & 1)) { + if (!allow_creation) { rax = (uint64_t)application::stream_result::does_not_exist; return; } @@ -105,7 +99,7 @@ namespace hilbert::kernel::syscall { case storage::fs_result::success: - if (rdx & 2) { + if (only_allow_creation) { rax = (uint64_t)application::stream_result::already_exists; return; } @@ -115,33 +109,33 @@ namespace hilbert::kernel::syscall { return; } + rdi = process->add_file_stream(new application::file_stream { + .the_file = utility::move(file), .offset = 0 }); rax = (uint64_t)application::stream_result::success; - rdi = application::running_thread->the_process->open_streams.add_new( - new application::vfile_stream(utility::move(file))); - - return; } } void end_this_thread_syscall( - uint64_t &, uint64_t &rdi, uint64_t &, uint64_t & - ) { - application::running_thread->exit_code = (int)(uint32_t)rdi; - delete application::running_thread; - application::resume_next(); + uint64_t &, uint64_t &rdi, uint64_t &, uint64_t &) { + + int exit_code = (int)(uint32_t)rdi; + auto *t = application::running_thread; + t->on_end_thread(); + t->owner->notify_thread_ended(t, exit_code); + delete t; + application::resume_next_thread(); } void get_new_pages_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { uint64_t count = rdi; set_zero(rax, rdi, rsi, rdx); - auto *p = application::running_thread->the_process; - uint64_t vaddr = p->get_free_vaddr_pages(count); + auto *p = application::running_thread->owner; + uint64_t vaddr = p->memory->get_free_vaddr_pages(count); for (uint64_t i = 0; i < count; ++i) { uint64_t kvaddr; @@ -150,7 +144,7 @@ namespace hilbert::kernel::syscall { for (int i = 0; i < 4096; ++i) ((uint8_t *)kvaddr)[i] = 0; paging::unmap_kernel_page((uint64_t)kvaddr); - p->map_page(vaddr + i * 4096, paddr, true, false, true); + p->memory->map_page(vaddr + i * 4096, paddr, true, false, true); } rax = vaddr; @@ -158,229 +152,213 @@ namespace hilbert::kernel::syscall { } void get_input_packet_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { set_zero(rax, rdi, rsi, rdx); - auto *t = application::running_thread; - do - if (input::input_queue->count > 0) { - input::input_packet packet = input::input_queue->take(); - if (packet.is_mouse) { - rax = packet.mouse.buttons | 0x80; - rdi = (uint16_t)packet.mouse.x_change; - rsi = (uint16_t)packet.mouse.y_change; - } - else { - rax = 0; - rdi = packet.keyboard; - } - return; - } - while (application::save_thread_state(t->cpu)); + while (input::input_queue->count == 0) + application::running_thread->wait_for_input(); - t->state = application::thread_state::waiting; - application::threads_waiting_for_input->insert(t); - application::resume_next(); + input::input_packet packet = input::input_queue->take(); + if (packet.is_mouse) { + rax = packet.mouse.buttons | 0x80; + rdi = (uint16_t)packet.mouse.x_change; + rsi = (uint16_t)packet.mouse.y_change; + } + else { + rax = 0; + rdi = packet.keyboard; + } + + } + + void create_socket( + application::process *p1, application::process *p2, + application::socket_stream_end *&se1_out, + application::socket_stream_end *&se2_out) { + + application::socket *s = new application::socket(); + se1_out = new application::socket_stream_end { + .the_socket = s, .read_queue = s->queue_1, .write_queue = s->queue_2, + .waiting_to_read = utility::queue(), + .is_other_side_open = true, .other_process = p2, .other_end = 0 }; + se2_out = new application::socket_stream_end { + .the_socket = s, .read_queue = s->queue_2, .write_queue = s->queue_2, + .waiting_to_read = utility::queue(), + .is_other_side_open = true, .other_process = p1, .other_end = se1_out }; + se1_out->other_end = se2_out; } void create_private_socket_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { - auto *s = new application::socket; - auto *ss1 = new application::socket_stream(s, false); - auto *ss2 = new application::socket_stream(s, true); + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + set_zero(rax, rdi, rsi, rdx); - auto *p = application::running_thread->the_process; - rax = (uint64_t)p->open_streams.add_new(ss1); - rdi = (uint64_t)p->open_streams.add_new(ss2); + + auto *p = application::running_thread->owner; + + application::socket_stream_end *se1, *se2; + create_socket(p, p, se1, se2); + + rax = p->add_socket_stream(se1); + rdi = p->add_socket_stream(se2); + } void create_socket_listener_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { - if (!is_range_owned_by_application(rdi, rdi + rsi)) { - set_zero(rax, rdi, rsi, rdx); - return; - } + auto *p = application::running_thread->owner; - utility::string id_string((const char *)rdi, rsi); + const char *id = (const char *)rdi; + uint64_t id_length = rsi; set_zero(rax, rdi, rsi, rdx); - for (auto *p = application::all_socket_listeners->first; p; p = p->next) - if (p->value->id == id_string) { - rax = (uint64_t)application::stream_result::socket_id_already_used; - return; - } + if (!p->memory->valid_to_read(id, id + id_length, false)) + return; - auto *sl = new application::socket_listener(); - sl->id = utility::move(id_string); - sl->is_listening = true; - rax = (uint64_t)application::stream_result::success; - rdi = (uint64_t)application::running_thread->the_process - ->socket_listeners.add_new(utility::move(sl)); + auto *sl = + application::try_register_socket_listener( + utility::string(id, id_length)); + + if (sl) { + rdx = p->add_socket_listener(sl); + rax = (uint64_t)application::stream_result::success; + } + + else + rax = (uint64_t)application::stream_result::socket_id_already_in_use; } void stop_socket_listener_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; set_zero(rax, rdi, rsi, rdx); - auto *p = application::running_thread->the_process; - - if (p->socket_listeners.has_id(handle)) { - auto *sl = p->socket_listeners.get(handle); - p->socket_listeners.remove_id(handle); - if (sl->waiting_to_accept_connection.count > 0 || - sl->waiting_to_connect.count > 0) { - sl->is_listening = false; - while (sl->waiting_to_accept_connection.count > 0) { - auto *t = sl->waiting_to_accept_connection.take(); - t->state = application::thread_state::paused; - application::paused_threads->insert(t); - } - while (sl->waiting_to_connect.count > 0) { - auto *t = sl->waiting_to_connect.take(); - t->state = application::thread_state::paused; - application::paused_threads->insert(t); - } - } - else - delete sl; - } + + auto *sl = + application::running_thread->owner->take_socket_listener(handle); + + if (!sl) + return; + + while (sl->waiting_to_accept.count > 0) + sl->waiting_to_accept.take()->notify_no_socket_stream(); + while (sl->waiting_to_connect.count > 0) + sl->waiting_to_connect.take()->notify_no_socket_stream(); + + application::remove_socket_listener(sl); } void accept_socket_connection_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; set_zero(rax, rdi, rsi, rdx); + auto *t = application::running_thread; - auto *p = t->the_process; + auto *sl = t->owner->get_socket_listener(handle); - if (!p->socket_listeners.has_id(handle)) { - rax = (uint64_t)application::stream_result::socket_id_not_in_use; + if (!sl) { + rax = (uint64_t)application::stream_result::bad_handle; return; } - auto *sl = p->socket_listeners.get(handle); - if (sl->waiting_to_connect.count > 0) { + auto *ot = sl->waiting_to_connect.take(); - auto *sock = new application::socket(); - application::stream *s1 = new application::socket_stream(sock, false); - application::stream *s2 = new application::socket_stream(sock, true); - unsigned handle = p->open_streams.add_new(utility::move(s1)); - ot->just_connected_to = s2; - ot->state = application::thread_state::paused; - application::paused_threads->insert(ot); + + application::socket_stream_end *our_end, *their_end; + create_socket(t->owner, ot->owner, our_end, their_end); + + unsigned our_handle = t->owner->add_socket_stream(our_end); + unsigned their_handle = ot->owner->add_socket_stream(their_end); + + ot->notify_new_socket_stream(their_handle); + rax = (uint64_t)application::stream_result::success; - rdi = handle; - return; + rdi = our_handle; + } - if (application::save_thread_state(t->cpu)) { - if (sl->is_listening) { + else { + + auto result = t->wait_to_accept_from(sl); + if (result.has_value) { rax = (uint64_t)application::stream_result::success; - rdi = p->open_streams.add_new(utility::move(t->just_accepted)); + rdi = result.value; } - else { - if (sl->waiting_to_accept_connection.count == 0 && - sl->waiting_to_connect.count == 0) - delete sl; + else rax = (uint64_t)application::stream_result::socket_listener_closed; - } - return; - } - t->state = application::thread_state::waiting; - sl->waiting_to_accept_connection.insert(t); - application::resume_next(); + } } void connect_to_socket_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + + const char *id = (const char *)rdi; + uint64_t id_length = rsi; + set_zero(rax, rdi, rsi, rdx); - if (!is_range_owned_by_application(rdi, rdi + rsi)) { - set_zero(rax, rdi, rsi, rdx); + auto *t = application::running_thread; + + if (!t->owner->memory->valid_to_read(id, id + id_length, false)) + return; + + utility::string id_string(id, id_length); + auto *sl = application::try_get_socket_listener(id_string); + + if (!sl) { + rax = (uint64_t)application::stream_result::socket_id_not_in_use; return; } - utility::string id_string((const char *)rdi, rsi); - set_zero(rax, rdi, rsi, rdx); + if (sl->waiting_to_accept.count > 0) { - for (auto *i = application::all_socket_listeners->first; i; i = i->next) - if (i->value->id == id_string) { - auto *sl = i->value; - auto *t = application::running_thread; - auto *p = t->the_process; - - if (sl->waiting_to_accept_connection.count > 0) { - auto *ot = sl->waiting_to_accept_connection.take(); - auto *sock = new application::socket(); - auto *s1 = new application::socket_stream(sock, false); - auto *s2 = new application::socket_stream(sock, true); - unsigned handle = p->open_streams.add_new(utility::move(s1)); - ot->just_accepted = s2; - ot->state = application::thread_state::paused; - application::paused_threads->insert(ot); - rax = (uint64_t)application::stream_result::success; - rdi = handle; - return; - } + auto *ot = sl->waiting_to_accept.take(); - if (application::save_thread_state(t->cpu)) { - if (sl->is_listening) { - rax = (uint64_t)application::stream_result::success; - rdi = p->open_streams.add_new(utility::move(t->just_connected_to)); - } - else { - if (sl->waiting_to_accept_connection.count == 0 && - sl->waiting_to_connect.count == 0) - delete sl; - rax = (uint64_t)application::stream_result::socket_id_not_in_use; - } - return; - } + application::socket_stream_end *our_end, *their_end; + create_socket(t->owner, ot->owner, our_end, their_end); + + unsigned our_handle = t->owner->add_socket_stream(our_end); + unsigned their_handle = ot->owner->add_socket_stream(their_end); + + ot->notify_new_socket_stream(their_handle); - t->state = application::thread_state::waiting; - sl->waiting_to_connect.insert(t); - application::resume_next(); + rax = (uint64_t)application::stream_result::success; + rdi = our_handle; + + } + else { + + auto result = t->wait_to_connect_to(sl); + if (result.has_value) { + rax = (uint64_t)application::stream_result::success; + rdi = result.value; } + else + rax = (uint64_t)application::stream_result::socket_listener_closed; - rax = (uint64_t)application::stream_result::socket_id_not_in_use; + } } void close_stream_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; set_zero(rax, rdi, rsi, rdx); - auto *p = application::running_thread->the_process; - - if (p->open_streams.has_id(handle)) { - application::stream *s = p->open_streams.get(handle); - p->open_streams.remove_id(handle); - delete s; - } + application::running_thread->owner->close_stream(handle); } void seek_stream_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; uint8_t origin = (uint8_t)rsi; @@ -390,117 +368,335 @@ namespace hilbert::kernel::syscall { if (origin >= 3) return; - auto *p = application::running_thread->the_process; + auto stream = application::running_thread->owner->get_stream(handle); - if (!p->open_streams.has_id(handle)) { + if (stream.is_null()) { rax = (uint64_t)application::stream_result::bad_handle; return; } - rax = (uint64_t)p->open_streams.get(handle) - ->seek((application::seek_origin)origin, offset); + if (stream.is_socket) { + rax = (uint64_t)application::stream_result::not_seekable; + return; + } + + auto *fs = stream.as_file_stream; + + switch (origin) { + + case 0://beginning + if (offset < 0 || (uint64_t)offset > fs->the_file.dir_entry.length) { + rax = (uint64_t)application::stream_result::out_of_bounds; + return; + } + fs->offset = offset; + rax = (uint64_t)application::stream_result::success; + return; + + case 1://end + if (offset > 0 || (uint64_t)-offset > fs->the_file.dir_entry.length) { + rax = (uint64_t)application::stream_result::out_of_bounds; + return; + } + fs->offset = fs->the_file.dir_entry.length + offset; + rax = (uint64_t)application::stream_result::success; + return; + + case 2://current position + int64_t new_offset = offset + fs->offset; + if (new_offset < 0 || (uint64_t)new_offset > fs->the_file.dir_entry.length) { + rax = (uint64_t)application::stream_result::out_of_bounds; + return; + } + fs->offset = (uint64_t)new_offset; + rax = (uint64_t)application::stream_result::success; + return; + + } } void read_from_stream_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; uint64_t count = (uint64_t)rsi; - uint64_t buffer = (uint64_t)rdx; + uint8_t *buffer = (uint8_t *)rdx; set_zero(rax, rdi, rsi, rdx); - if (!is_range_owned_by_application(buffer, buffer + count)) + auto *t = application::running_thread; + + if (!t->owner->memory->valid_to_read(buffer, buffer + count, true)) return; - auto *p = application::running_thread->the_process; + auto stream = t->owner->get_stream(handle); - if (!p->open_streams.has_id(handle)) { + if (stream.is_null()) { rax = (uint64_t)application::stream_result::bad_handle; return; } - rax = (uint64_t)p->open_streams.get(handle)->read(count, (void *)buffer); + if (stream.is_socket) { + auto *ss = stream.as_socket_stream; + for (uint64_t i = 0; i < count; ++i) { + while (ss->read_queue.count == 0) { + if (!ss->is_other_side_open) { + rax = (uint64_t)application::stream_result::other_end_closed; + return; + } + t->wait_for_socket_stream(ss); + } + buffer[i] = ss->read_queue.take(); + } + rax = (uint64_t)application::stream_result::success; + } + + else { + auto *fs = stream.as_file_stream; + if (fs->offset + count > fs->the_file.dir_entry.length) { + rax = (uint64_t)application::stream_result::out_of_bounds; + return; + } + auto read_result = fs->the_file.read_file(fs->offset, count, buffer); + if (read_result != storage::fs_result::success) { + rax = (uint64_t)application::stream_result::io_error; + return; + } + fs->offset += count; + rax = (uint64_t)application::stream_result::success; + } } void write_to_stream_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; uint64_t count = (uint64_t)rsi; - uint64_t buffer = (uint64_t)rdx; + const uint8_t *buffer = (uint8_t *)rdx; set_zero(rax, rdi, rsi, rdx); - if (!is_range_owned_by_application(buffer, buffer + count)) + auto *t = application::running_thread; + + if (!t->owner->memory->valid_to_read(buffer, buffer + count, false)) return; - auto *p = application::running_thread->the_process; + auto stream = t->owner->get_stream(handle); - if (!p->open_streams.has_id(handle)) { + if (stream.is_null()) { rax = (uint64_t)application::stream_result::bad_handle; return; } - rax = (uint64_t)p->open_streams.get(handle) - ->write(count, (const void *)buffer); + if (stream.is_socket) { + auto *ss = stream.as_socket_stream; + if (!ss->is_other_side_open) { + rax = (uint64_t)application::stream_result::other_end_closed; + return; + } + for (uint64_t i = 0; i < count; ++i) + ss->write_queue.insert(buffer[i]); + rax = (uint64_t)application::stream_result::success; + } + + else { + //TODO: write to file + panic(0x9af5e6); + } } void get_stream_length_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; set_zero(rax, rdi, rsi, rdx); - auto *p = application::running_thread->the_process; + auto *t = application::running_thread; - if (!p->open_streams.has_id(handle)) { + auto stream = t->owner->get_stream(handle); + + if (stream.is_null()) rax = (uint64_t)application::stream_result::bad_handle; - return; - } - rax = (uint64_t)p->open_streams.get(handle)->get_length(rdi); + else if (stream.is_socket) + rax = (uint64_t)application::stream_result::not_sized; + + else { + rdi = stream.as_file_stream->the_file.dir_entry.length; + rax = (uint64_t)application::stream_result::success; + } } + struct env_var_spec { + uint64_t name_len; + const char *name; + uint64_t value_len; + const char *value; + }; + + struct gstream_spec { + uint64_t parent_handle; + uint64_t child_handle; + }; + + struct psi_spec { + uint64_t path_len; + const char *path; + uint64_t env_var_count; + const env_var_spec *env_vars; + uint64_t gstream_count; + const gstream_spec *gstreams; + }; + void start_process_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { - //TODO - (void)rax; - (void)rdi; - (void)rsi; - (void)rdx; - panic(0x9af5e6); + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + + const psi_spec *psi = (const psi_spec *)rdi; + set_zero(rax, rdi, rsi, rdx); + + auto *owner = application::running_thread->owner; + + if (!owner->memory->valid_to_read(psi, psi + 1, false) || + !owner->memory->valid_to_read( + psi->path, psi->path + psi->path_len, false) || + !owner->memory->valid_to_read( + psi->env_vars, psi->env_vars + psi->env_var_count, false) || + !owner->memory->valid_to_read( + psi->gstreams, psi->gstreams + psi->gstream_count, false)) + return; + + for (uint64_t i = 0; i < psi->env_var_count; ++i) + if (!owner->memory->valid_to_read(psi->env_vars[i].name, + psi->env_vars[i].name + psi->env_vars[i].name_len, false) || + !owner->memory->valid_to_read(psi->env_vars[i].value, + psi->env_vars[i].value + psi->env_vars[i].value_len, false)) + return; + + for (uint64_t i = 0; i < psi->gstream_count; ++i) { + auto owner_stream = owner->get_stream(psi->gstreams[i].parent_handle); + if (owner_stream.is_null() || (owner_stream.is_socket && + owner_stream.as_socket_stream->waiting_to_read.count != 0) || + psi->gstreams[i].child_handle >= 65536) + return; + } + + utility::string path_string(psi->path, psi->path_len); + vfile::canon_path cpath; + vfile::canonize_path(path_string, cpath); + + vfile::vfile file; + auto lookup_result = vfile::look_up_path(cpath, file, true); + switch (lookup_result) { + case storage::fs_result::does_not_exist: + rax = (uint64_t)application::stream_result::does_not_exist; + return; + case storage::fs_result::device_error: + case storage::fs_result::fs_corrupt: + rax = (uint64_t)application::stream_result::io_error; + return; + case storage::fs_result::success: + break; + } + + app_memory *memory = new app_memory(); + uint64_t entry_point; + load_app_result load_result = load_app(file, *memory, entry_point); + + switch (load_result) { + case load_app_result::io_error: + rax = (uint64_t)application::stream_result::io_error; + delete memory; + return; + case load_app_result::not_app: + rax = (uint64_t)application::stream_result::not_an_executable; + delete memory; + return; + case load_app_result::success: + break; + } + + application::process *p = new application::process(memory); + + for (uint64_t i = 0; i < psi->env_var_count; ++i) + p->add_environment_variable( + utility::string(psi->env_vars[i].name, psi->env_vars[i].name_len), + utility::string(psi->env_vars[i].value, psi->env_vars[i].value_len)); + + for (uint64_t i = 0; i < psi->gstream_count; ++i) { + auto s = owner->take_stream(psi->gstreams[i].parent_handle); + if (s.is_socket && s.as_socket_stream->is_other_side_open) + s.as_socket_stream->other_end->other_process = p; + p->add_stream_with_handle(psi->gstreams[i].child_handle, s); + } + + rax = (uint64_t)application::stream_result::success; + rdi = application::add_process(p); + application::thread *t = new application::thread(p, entry_point); + p->add_thread(t); + application::paused_threads->insert(t); + } void end_this_process_syscall( - uint64_t &, uint64_t &rdi, uint64_t &, uint64_t & - ) { - application::running_thread->the_process->end_process((unsigned)rdi); - application::resume_next(); + uint64_t &, uint64_t &rdi, uint64_t &, uint64_t &) { + + int exit_code = (int32_t)(uint32_t)rdi; + auto *p = application::running_thread->owner; + p->on_end_process(exit_code); + application::resume_next_thread(); + } void set_stream_length_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx - ) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { unsigned handle = (unsigned)rdi; - uint64_t new_length = rsi; set_zero(rax, rdi, rsi, rdx); - auto *p = application::running_thread->the_process; + auto *t = application::running_thread; - if (!p->open_streams.has_id(handle)) { + auto stream = t->owner->get_stream(handle); + + if (stream.is_null()) rax = (uint64_t)application::stream_result::bad_handle; - return; + + else if (stream.is_socket) + rax = (uint64_t)application::stream_result::not_sized; + + else { + //TODO + panic(0x9af5e6); } - rax = (uint64_t)p->open_streams.get(handle)->set_length(new_length); + } + + void get_other_end_process_handle_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + + unsigned handle = (unsigned)rdi; + set_zero(rax, rdi, rsi, rdx); + + auto *t = application::running_thread; + + auto stream = t->owner->get_stream(handle); + + if (stream.is_null()) + rax = (uint64_t)application::stream_result::bad_handle; + + else if (!stream.is_socket) + rax = (uint64_t)application::stream_result::other_end_closed; + + else { + auto s = stream.as_socket_stream; + if (!s->is_other_side_open) + rax = (uint64_t)application::stream_result::other_end_closed; + else { + rax = (uint64_t)application::stream_result::success; + rdi = (uint64_t)s->other_process->id; + } + } } @@ -526,7 +722,8 @@ namespace hilbert::kernel::syscall { &get_stream_length_syscall, &start_process_syscall, &end_this_process_syscall, - &set_stream_length_syscall + &set_stream_length_syscall, + &get_other_end_process_handle_syscall }; static constexpr int max_syscall_number = 19; @@ -536,8 +733,7 @@ namespace hilbert::kernel::syscall { using namespace hilbert::kernel::syscall; extern "C" void do_syscall( - uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx -) { + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { if (rax <= max_syscall_number && handlers[rax] != 0) handlers[rax](rax, rdi, rsi, rdx); diff --git a/kernel/source/vfile.cpp b/kernel/source/vfile.cpp index 89c95e6..92e1a71 100644 --- a/kernel/source/vfile.cpp +++ b/kernel/source/vfile.cpp @@ -94,7 +94,7 @@ namespace hilbert::kernel::vfile { full_path.rel(target_path); vfile next; - RET_NOT_SUC(lookup_path(full_path, next, false)) + RET_NOT_SUC(look_up_path(full_path, next, false)) next.path = path; return next.follow_symlinks(out); @@ -175,7 +175,7 @@ namespace hilbert::kernel::vfile { kernel::vfile::root = new vfile(root); } - storage::fs_result lookup_path( + storage::fs_result look_up_path( const canon_path &path, vfile &out, bool follow_final_symlink ) { -- cgit v1.2.3