#include #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 *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 get_input_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::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)); 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, &get_input_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 = 19; } 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); }