397 lines
9 KiB
C++
397 lines
9 KiB
C++
#include <euler/syscall.hpp>
|
|
|
|
extern "C" void __euler_do_syscall(
|
|
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
|
|
|
|
namespace euler::syscall {
|
|
|
|
encoded_color encode_color(
|
|
uint8_t r, uint8_t g, uint8_t b) {
|
|
|
|
uint64_t rax = 0;
|
|
uint64_t rdi = (uint32_t)r | ((uint32_t)g << 8) | ((uint32_t)b << 16);
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return (encoded_color)(rax & 0xffffffff);
|
|
|
|
}
|
|
|
|
void get_framebuffer(
|
|
encoded_color *&buffer_out, uint32_t &width_out,
|
|
uint32_t &height_out, uint32_t &pitch_out) {
|
|
|
|
uint64_t rax = 1;
|
|
uint64_t rdi;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
buffer_out = (encoded_color *)rax;
|
|
width_out = rdi & 0xffffffff;
|
|
height_out = rdi >> 32;
|
|
pitch_out = rsi & 0xffffffff;
|
|
|
|
}
|
|
|
|
stream_result open_file(
|
|
const std::string &file_path, bool allow_creation,
|
|
bool only_allow_creation, stream_handle &handle_out) {
|
|
|
|
uint64_t rax = 2;
|
|
uint64_t rdi = (uint64_t)file_path.data();
|
|
uint64_t rsi = file_path.size();
|
|
uint64_t rdx =
|
|
( allow_creation ? 0x1 : 0x0) |
|
|
(only_allow_creation ? 0x2 : 0x0);
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
handle_out = rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
[[noreturn]] void end_this_thread(int32_t exit_code) {
|
|
|
|
uint64_t rax = 3;
|
|
uint64_t rdi = (uint32_t)exit_code;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
__builtin_unreachable();
|
|
|
|
}
|
|
|
|
void *get_new_pages(uint64_t n_pages) {
|
|
|
|
uint64_t rax = 4;
|
|
uint64_t rdi = n_pages;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return (void *)rax;
|
|
|
|
}
|
|
|
|
std::variant<mouse_packet, key_packet> get_input_packet() {
|
|
|
|
uint64_t rax = 5;
|
|
uint64_t rdi;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
if (rax & 0x80)
|
|
return (mouse_packet){
|
|
. left_button_down = (rax & 0x01) != 0,
|
|
. right_button_down = (rax & 0x02) != 0,
|
|
.middle_button_down = (rax & 0x04) != 0,
|
|
.x_changed = (int16_t)(rdi & 0xffff),
|
|
.y_changed = (int16_t)(rsi & 0xffff)
|
|
};
|
|
|
|
return (key_packet){
|
|
.was_key_up_event = (rdi & 0x40000) != 0,
|
|
. num_lock = (rdi & 0x20000) != 0,
|
|
. caps_lock = (rdi & 0x10000) != 0,
|
|
. right_win = (rdi & 0x8000) != 0,
|
|
. left_win = (rdi & 0x4000) != 0,
|
|
. right_alt = (rdi & 0x2000) != 0,
|
|
. left_alt = (rdi & 0x1000) != 0,
|
|
. right_ctrl = (rdi & 0x800) != 0,
|
|
. left_ctrl = (rdi & 0x400) != 0,
|
|
. right_shift = (rdi & 0x200) != 0,
|
|
. left_shift = (rdi & 0x100) != 0,
|
|
. key_code = (uint8_t)(rdi & 0xff)
|
|
};
|
|
|
|
}
|
|
|
|
void create_private_socket(
|
|
stream_handle &end_1_out, stream_handle &end_2_out) {
|
|
|
|
uint64_t rax = 6;
|
|
uint64_t rdi;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
end_1_out = rax;
|
|
end_2_out = rdi;
|
|
|
|
}
|
|
|
|
stream_result create_socket_listener(
|
|
const std::string &id, listener_handle &handle_out) {
|
|
|
|
uint64_t rax = 7;
|
|
uint64_t rdi = (uint64_t)id.data();
|
|
uint64_t rsi = id.size();
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
handle_out = rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
void stop_socket_listener(listener_handle handle) {
|
|
|
|
uint64_t rax = 8;
|
|
uint64_t rdi = handle;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
}
|
|
|
|
stream_result accept_socket_connection(
|
|
listener_handle listener, stream_handle &stream_out) {
|
|
|
|
uint64_t rax = 9;
|
|
uint64_t rdi = listener;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
stream_out = rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
stream_result connect_to_socket(
|
|
const std::string &id, stream_handle &handle_out) {
|
|
|
|
uint64_t rax = 10;
|
|
uint64_t rdi = (uint64_t)id.data();
|
|
uint64_t rsi = id.size();
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
handle_out = rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
void close_stream(stream_handle handle) {
|
|
|
|
uint64_t rax = 11;
|
|
uint64_t rdi = handle;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
}
|
|
|
|
stream_result seek_stream(
|
|
stream_handle handle, seek_from from, int64_t offset) {
|
|
|
|
uint64_t rax = 12;
|
|
uint64_t rdi = (uint64_t)handle;
|
|
uint64_t rsi = (uint8_t)from;
|
|
uint64_t rdx = (uint64_t)offset;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
stream_result read_from_stream(
|
|
stream_handle handle, uint64_t bytes, void *into) {
|
|
|
|
uint64_t rax = 13;
|
|
uint64_t rdi = (uint64_t)handle;
|
|
uint64_t rsi = bytes;
|
|
uint64_t rdx = (uint64_t)into;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
stream_result write_to_stream(
|
|
stream_handle handle, uint64_t bytes, const void *from) {
|
|
|
|
uint64_t rax = 14;
|
|
uint64_t rdi = (uint64_t)handle;
|
|
uint64_t rsi = bytes;
|
|
uint64_t rdx = (uint64_t)from;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
stream_result get_stream_length(
|
|
stream_handle handle, uint64_t &length_out) {
|
|
|
|
uint64_t rax = 15;
|
|
uint64_t rdi = (uint64_t)handle;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
length_out = rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
stream_result start_process(
|
|
const std::string &file_path,
|
|
const std::vector<std::pair<std::string, std::string>> &environment_variables,
|
|
const std::vector<std::pair<stream_handle, stream_result>> &gifted_streams,
|
|
process_handle &handle_out) {
|
|
|
|
std::vector<uint64_t> ev_structs(environment_variables.size() * 4);
|
|
for (size_t i = 0; i < environment_variables.size(); ++i) {
|
|
ev_structs[i * 4] = environment_variables[i]. first.size();
|
|
ev_structs[i * 4 + 1] = (uint64_t)environment_variables[i]. first.data();
|
|
ev_structs[i * 4 + 2] = environment_variables[i].second.size();
|
|
ev_structs[i * 4 + 3] = (uint64_t)environment_variables[i].second.data();
|
|
}
|
|
|
|
std::vector<uint64_t> gs_structs(gifted_streams.size() * 2);
|
|
for (size_t i = 0; i < environment_variables.size(); ++i) {
|
|
gs_structs[i * 2] = (uint64_t)gifted_streams[i]. first;
|
|
gs_structs[i * 2 + 1] = (uint64_t)gifted_streams[i].second;
|
|
}
|
|
|
|
uint64_t psi_struct[] = {
|
|
file_path.size(), (uint64_t) file_path.data(),
|
|
environment_variables.size(), (uint64_t)ev_structs.data(),
|
|
gifted_streams.size(), (uint64_t)gs_structs.data()
|
|
};
|
|
|
|
uint64_t rax = 16;
|
|
uint64_t rdi = (uint64_t)psi_struct;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
handle_out = rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
[[noreturn]] void end_this_process(int32_t exit_code) {
|
|
|
|
uint64_t rax = 17;
|
|
uint64_t rdi = (uint32_t)exit_code;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
__builtin_unreachable();
|
|
|
|
}
|
|
|
|
stream_result set_stream_length(
|
|
stream_handle handle, uint64_t new_length) {
|
|
|
|
uint64_t rax = 18;
|
|
uint64_t rdi = (uint64_t)handle;
|
|
uint64_t rsi = new_length;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
stream_result get_other_end_process_handle(
|
|
stream_handle stream, process_handle &process_out) {
|
|
|
|
uint64_t rax = 19;
|
|
uint64_t rdi = (uint64_t)stream;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
process_out = (process_handle)rdi;
|
|
return (stream_result)rax;
|
|
|
|
}
|
|
|
|
//entry_point must not return
|
|
void start_thread(void (*entry_point)(uint64_t), uint64_t arg) {
|
|
|
|
uint64_t rax = 20;
|
|
uint64_t rdi = (uint64_t)entry_point;
|
|
uint64_t rsi = arg;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
}
|
|
|
|
//entry_point must not return
|
|
void start_thread(void (*entry_point)()) {
|
|
|
|
uint64_t rax = 20;
|
|
uint64_t rdi = (uint64_t)entry_point;
|
|
uint64_t rsi = 0;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
}
|
|
|
|
//return value is number of bytes cleared
|
|
uint64_t clear_socket_read_queue(stream_handle handle) {
|
|
|
|
uint64_t rax = 21;
|
|
uint64_t rdi = handle;
|
|
uint64_t rsi;
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
return rax;
|
|
|
|
}
|
|
|
|
//this function has a race condition if the variable is changed
|
|
//or unset by another thread between the two syscalls.
|
|
std::optional<std::string> try_get_environment_variable(
|
|
const std::string &name) {
|
|
|
|
uint64_t rax = 22;
|
|
uint64_t rdi = (uint64_t)name.data();
|
|
uint64_t rsi = name.size();
|
|
uint64_t rdx;
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
|
|
if (rax == (uint64_t)-1)
|
|
return {};
|
|
|
|
std::string s;
|
|
s.resize(rax);
|
|
|
|
rax = 23;
|
|
rdi = (uint64_t)name.data();
|
|
rsi = name.size();
|
|
rdx = (uint64_t)s.data();
|
|
|
|
__euler_do_syscall(rax, rdi, rsi, rdx);
|
|
//do i need to tell gcc that s is modified?
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|