258 lines
6.4 KiB
C++
258 lines
6.4 KiB
C++
#include <hilbert/kernel/application.hpp>
|
|
#include <hilbert/kernel/framebuffer.hpp>
|
|
#include <hilbert/kernel/paging.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 *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)) {
|
|
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;
|
|
|
|
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);
|
|
|
|
}
|