diff options
Diffstat (limited to 'kernel/source/syscall.cpp')
-rw-r--r-- | kernel/source/syscall.cpp | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp new file mode 100644 index 0000000..768ff0d --- /dev/null +++ b/kernel/source/syscall.cpp @@ -0,0 +1,538 @@ +#include <hilbert/kernel/application.hpp> +#include <hilbert/kernel/framebuffer.hpp> +#include <hilbert/kernel/paging.hpp> +#include <hilbert/kernel/input.hpp> +#include <hilbert/kernel/panic.hpp> +#include <hilbert/kernel/vfile.hpp> + +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 *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; + 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 *process = application::running_thread->the_process; + 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); + for (uint64_t i = 0; i < pages_needed; ++i) + process->map_page( + vaddr + i * 4096, framebuffer::paddr + i * 4096, true, false, false); + process->framebuffer_vaddr = vaddr; + } + + rax = process->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_string((const char *)rdi, rsi); + + set_zero(rax, rdi, rsi, rdx); + + vfile::canon_path cp; + vfile::vfile file; + vfile::canonize_path(path_string, cp); + + switch (vfile::lookup_path(cp, file, true)) { + + 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::does_not_exist: + + if (!(rdx & 1)) { + rax = (uint64_t)application::stream_result::does_not_exist; + return; + } + + //TODO: create the file + panic(0x9af5e6); + + case storage::fs_result::success: + + if (rdx & 2) { + rax = (uint64_t)application::stream_result::already_exists; + return; + } + + if (file.dir_entry.type != storage::file_type::regular_file) { + rax = (uint64_t)application::stream_result::not_a_regular_file; + return; + } + + 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(); + } + + 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 *p = application::running_thread->the_process; + uint64_t vaddr = p->get_free_vaddr_pages(count); + + for (uint64_t i = 0; i < count; ++i) { + uint64_t kvaddr; + uint64_t paddr; + paging::map_new_kernel_page(kvaddr, paddr); + 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); + } + + rax = vaddr; + + } + + void read_key_packet_syscall( + 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::key_queue->count > 0) { + rax = (uint64_t)input::key_queue->take(); + return; + } + while (application::save_thread_state(t->cpu)); + + t->state = application::thread_state::waiting; + application::threads_waiting_for_input->insert(t); + application::resume_next(); + + } + + 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); + 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); + } + + void create_socket_listener_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 id_string((const char *)rdi, 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; + } + + 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)); + + } + + void stop_socket_listener_syscall( + 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; + } + + } + + void accept_socket_connection_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 *p = t->the_process; + + if (!p->socket_listeners.has_id(handle)) { + rax = (uint64_t)application::stream_result::socket_id_not_in_use; + 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); + rax = (uint64_t)application::stream_result::success; + rdi = handle; + return; + } + + 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_accepted)); + } + else { + if (sl->waiting_to_accept_connection.count == 0 && + sl->waiting_to_connect.count == 0) + delete sl; + 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 + ) { + + if (!is_range_owned_by_application(rdi, rdi + rsi)) { + set_zero(rax, rdi, rsi, rdx); + return; + } + + utility::string id_string((const char *)rdi, rsi); + set_zero(rax, rdi, rsi, rdx); + + 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; + } + + 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; + } + + t->state = application::thread_state::waiting; + sl->waiting_to_connect.insert(t); + application::resume_next(); + + } + + 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 + ) { + + 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; + } + + } + + void seek_stream_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + unsigned handle = (unsigned)rdi; + uint8_t origin = (uint8_t)rsi; + int64_t offset = (int64_t)rdx; + set_zero(rax, rdi, rsi, rdx); + + if (origin >= 3) + return; + + auto *p = application::running_thread->the_process; + + if (!p->open_streams.has_id(handle)) { + rax = (uint64_t)application::stream_result::bad_handle; + return; + } + + rax = (uint64_t)p->open_streams.get(handle) + ->seek((application::seek_origin)origin, offset); + + } + + void read_from_stream_syscall( + 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; + set_zero(rax, rdi, rsi, rdx); + + if (!is_range_owned_by_application(buffer, buffer + count)) + return; + + auto *p = application::running_thread->the_process; + + if (!p->open_streams.has_id(handle)) { + rax = (uint64_t)application::stream_result::bad_handle; + return; + } + + rax = (uint64_t)p->open_streams.get(handle)->read(count, (void *)buffer); + + } + + void write_to_stream_syscall( + 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; + set_zero(rax, rdi, rsi, rdx); + + if (!is_range_owned_by_application(buffer, buffer + count)) + return; + + auto *p = application::running_thread->the_process; + + if (!p->open_streams.has_id(handle)) { + rax = (uint64_t)application::stream_result::bad_handle; + return; + } + + rax = (uint64_t)p->open_streams.get(handle) + ->write(count, (const void *)buffer); + + } + + void get_stream_length_syscall( + 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)) { + rax = (uint64_t)application::stream_result::bad_handle; + return; + } + + rax = (uint64_t)p->open_streams.get(handle)->get_length(rdi); + + } + + 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); + } + + 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(); + } + + void set_stream_length_syscall( + 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; + + if (!p->open_streams.has_id(handle)) { + rax = (uint64_t)application::stream_result::bad_handle; + return; + } + + rax = (uint64_t)p->open_streams.get(handle)->set_length(new_length); + + } + + 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, + &end_this_thread_syscall, + &get_new_pages_syscall, + &read_key_packet_syscall, + &create_private_socket_syscall, + &create_socket_listener_syscall, + &stop_socket_listener_syscall, + &accept_socket_connection_syscall, + &connect_to_socket_syscall, + &close_stream_syscall, + &seek_stream_syscall, + &read_from_stream_syscall, + &write_to_stream_syscall, + &get_stream_length_syscall, + &start_process_syscall, + &end_this_process_syscall, + &set_stream_length_syscall + }; + + static constexpr int max_syscall_number = 18; + +} + +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); + +} |