547 lines
15 KiB
C++
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);
|
|
|
|
}
|