This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
hilbert-os/kernel/source/syscall.cpp

547 lines
15 KiB
C++

#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 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);
}