diff options
Diffstat (limited to 'kernel/syscall.cpp')
-rw-r--r-- | kernel/syscall.cpp | 250 |
1 files changed, 236 insertions, 14 deletions
diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 3aa4105..3c72d23 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1,21 +1,247 @@ #include <hilbert/kernel/application.hpp> #include <hilbert/kernel/framebuffer.hpp> -#include <hilbert/kernel/syscall.hpp> #include <hilbert/kernel/paging.hpp> +#include <hilbert/kernel/vfile.hpp> namespace hilbert::kernel::syscall { - syscall_handler handlers[256]; + enum file_result : uint64_t { + file_result_success, + file_result_bad_file_handle, + file_result_device_error, + file_result_file_system_corrupt, + file_result_out_of_bounds, + file_result_does_not_exist, + file_result_directory + }; - void init_syscalls() { - for (int i = 0; i < 256; ++i) - handlers[i] = 0; + bool is_range_owned_by_application(uint64_t start, uint64_t end) { + auto *app = application::running_app; + uint64_t pstart = (start / 4096) * 4096; + uint64_t pend = ((end - 1) / 4096 + 1) * 4096; + for (uint64_t p = pstart; p < pend; p += 4096) + if (!app->is_page_owned(p)) + return false; + return true; } - void add_syscall(uint64_t rax, syscall_handler handler) { - handlers[rax] = handler; + void set_zero(uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) { + rax = 0; + rdi = 0; + rsi = 0; + rdx = 0; + } + + void encode_color_syscall( + 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 + ) { + + auto *app = application::running_app; + if (app->framebuffer_vaddr == 0) { + uint64_t pages_needed = + (framebuffer::dword_pitch * framebuffer::height * 4 - 1) / 4096 + 1; + uint64_t vaddr = app->get_free_vaddr_pages(pages_needed); + for (uint64_t i = 0; i < pages_needed; ++i) + app->map_page( + vaddr + i * 4096, framebuffer::paddr + i * 4096, true, false, false); + app->framebuffer_vaddr = vaddr; + } + + rax = app->framebuffer_vaddr; + rdi = + (uint64_t)(uint32_t)framebuffer::width | + ((uint64_t)(uint32_t)framebuffer::height << 32); + rsi = (uint32_t)framebuffer::dword_pitch; + rdx = 0; + + } + + 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; + } + + utility::string path((const char *)rdi, rsi); + vfile::canon_path cp; + vfile::canonize_path(path, cp); + + set_zero(rax, rdi, rsi, rdx); + + vfile::vfile file; + switch (vfile::lookup_path(cp, file)) { + case storage::fs_result::success: + break; + case storage::fs_result::device_error: + rax = file_result_device_error; + return; + case storage::fs_result::fs_corrupt: + rax = file_result_file_system_corrupt; + return; + case storage::fs_result::does_not_exist: + rax = file_result_does_not_exist; + return; + } + + vfile::vfile real_file; + switch (file.follow_symlinks(real_file)) { + case storage::fs_result::success: + break; + case storage::fs_result::device_error: + rax = file_result_device_error; + return; + case storage::fs_result::fs_corrupt: + rax = file_result_file_system_corrupt; + return; + case storage::fs_result::does_not_exist: + rax = file_result_does_not_exist; + return; + } + + if (real_file.dir_entry.type != storage::file_type::regular_file) { + rax = file_result_directory; + return; + } + + unsigned handler = + application::running_app->open_files.add_new(utility::move(real_file)); + rax = file_result_success; + rdi = (uint64_t)handler; + } + void get_file_length_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + auto &open_files = application::running_app->open_files; + unsigned handle = (unsigned)rdi; + + set_zero(rax, rdi, rsi, rdx); + + if (!open_files.has_id(handle)) { + rax = file_result_bad_file_handle; + return; + } + + rax = file_result_success; + rdi = open_files.get(handle).dir_entry.length; + + } + + void read_from_file_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + if (!is_range_owned_by_application(rdi, rdi + 32)) { + set_zero(rax, rdi, rsi, rdx); + return; + } + + const uint64_t *request = (const uint64_t *)rdi; + unsigned handle = (unsigned)request[0]; + uint64_t start = request[1]; + uint64_t length = request[2]; + uint64_t buffer_vaddr = request[3]; + + set_zero(rax, rdi, rsi, rdx); + + if (!is_range_owned_by_application(buffer_vaddr, buffer_vaddr + length)) + return; + + auto &open_files = application::running_app->open_files; + + if (!open_files.has_id(handle)) + rax = file_result_bad_file_handle; + + vfile::vfile &file = open_files.get(handle); + + if (start + length > file.dir_entry.length) + rax = file_result_out_of_bounds; + + switch (file.read_file(start, length, (void *)buffer_vaddr)) { + case storage::fs_result::success: + rax = file_result_success; + return; + case storage::fs_result::device_error: + rax = file_result_device_error; + return; + case storage::fs_result::fs_corrupt: + case storage::fs_result::does_not_exist: + rax = file_result_file_system_corrupt; + return; + } + + } + + [[noreturn]] void end_this_process_syscall( + uint64_t &, uint64_t &, uint64_t &, uint64_t & + ) { + + //TODO + while (1) + ; + + } + + void get_new_pages_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + uint64_t count = rdi; + set_zero(rax, rdi, rsi, rdx); + + auto *app = application::running_app; + uint64_t vaddr = app->get_free_vaddr_pages(count); + + for (uint64_t i = 0; i < count; ++i) { + uint64_t paddr = paging::take_pram_page(); + app->map_page(vaddr + i * 4096, paddr, true, false, true); + } + + rax = vaddr; + + } + + void close_file_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + unsigned handle = rdi; + set_zero(rax, rdi, rsi, rdx); + application::running_app->open_files.remove_id(handle); + + } + + typedef void (*syscall_handler)( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx); + + syscall_handler handlers[] = { + &encode_color_syscall, + &get_framebuffer_syscall, + &open_file_syscall, + &get_file_length_syscall, + &read_from_file_syscall, + &end_this_process_syscall, + &get_new_pages_syscall, + &close_file_syscall + }; + + static constexpr int max_syscall_number = 7; + } using namespace hilbert::kernel::syscall; @@ -24,13 +250,9 @@ extern "C" void do_syscall( uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx ) { - if (rax < 256 && handlers[rax] != 0) + if (rax <= max_syscall_number && handlers[rax] != 0) handlers[rax](rax, rdi, rsi, rdx); - else { - rax = 0; - rdi = 0; - rsi = 0; - rdx = 0; - } + else + set_zero(rax, rdi, rsi, rdx); } |