summaryrefslogtreecommitdiff
path: root/kernel/source/syscall.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/source/syscall.cpp')
-rw-r--r--kernel/source/syscall.cpp538
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);
+
+}