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