#include #include #include #include #include namespace hilbert::kernel::syscall { 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 }; 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 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, true)) { 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 (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(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); } void read_key_packet_syscall( uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx ) { set_zero(rax, rdi, rsi, rdx); asm ("cli"); while (input::key_queue->count == 0) asm ("sti\nhlt\ncli"); rax = (uint64_t)input::key_queue->take(); asm ("sti"); } 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, &read_key_packet_syscall }; static constexpr int max_syscall_number = 8; } using namespace hilbert::kernel::syscall; extern "C" void do_syscall( 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); else set_zero(rax, rdi, rsi, rdx); }