diff options
Diffstat (limited to 'euler')
40 files changed, 1427 insertions, 891 deletions
diff --git a/euler/include/algorithm b/euler/include/algorithm deleted file mode 100644 index 08702f9..0000000 --- a/euler/include/algorithm +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -namespace std { - - template <class t> - void swap(t &a, t &b) { - t tmp = a; - a = b; - b = tmp; - } - -} diff --git a/euler/include/cctype b/euler/include/cctype new file mode 100644 index 0000000..2afc53d --- /dev/null +++ b/euler/include/cctype @@ -0,0 +1,3 @@ +#pragma once + +extern "C" int isspace(int ch); diff --git a/euler/include/cstdio b/euler/include/cstdio index 75472c1..0dc42d0 100644 --- a/euler/include/cstdio +++ b/euler/include/cstdio @@ -1,20 +1,16 @@ #pragma once #include <euler/stream.hpp> -#include <stddef.h> +#include <cstddef> -namespace std { +typedef euler::stream FILE; - typedef euler::stream FILE; +extern "C" FILE *fopen(const char *filename, const char *mode); +extern "C" void fclose(FILE *stream); - FILE *fopen(const char *filename, const char *mode); - int fclose(FILE *stream); +#define SEEK_CUR 2 +#define SEEK_END 1 +#define SEEK_SET 0 - int fseek(FILE *stream, long offset, int origin); - #define SEEK_SET 0 - #define SEEK_CUR 2 - #define SEEK_END 1 - - size_t fread(void *buffer, size_t size, size_t count, FILE *stream); - -} +extern "C" int fseek(FILE *stream, long offset, int origin); +extern "C" size_t fread(void *buffer, size_t size, size_t count, FILE *stream); diff --git a/euler/include/cstring b/euler/include/cstring index 45bc94e..cba5eb2 100644 --- a/euler/include/cstring +++ b/euler/include/cstring @@ -1,8 +1,9 @@ #pragma once -#include <stddef.h> +#include <cstddef> -namespace std { - size_t strlen(const char *str); - void *memcpy(void *dest, const void *src, size_t count); -} +extern "C" void *memset(void *dest, int ch, size_t count); +extern "C" void *memcpy(void *dest, const void *src, size_t count); + +extern "C" int strcmp(const char *lhs, const char *rhs); +extern "C" size_t strlen(const char *str); diff --git a/euler/include/euler/heap.hpp b/euler/include/euler/heap.hpp index e2a4852..ce94eef 100644 --- a/euler/include/euler/heap.hpp +++ b/euler/include/euler/heap.hpp @@ -1,8 +1,10 @@ #pragma once -#include <stdint.h> +#include <cstddef> + +namespace euler::heap { + + void *get_block(size_t length); + void return_block(void *start, size_t length); -namespace euler { - void *alloc(uint64_t bytes); - void dealloc(void *start, uint64_t bytes); } diff --git a/euler/include/euler/start_process.hpp b/euler/include/euler/start_process.hpp deleted file mode 100644 index 00ebbab..0000000 --- a/euler/include/euler/start_process.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <euler/syscall.hpp> -#include <vector> - -namespace euler { - - struct start_process { - - private: - const char *path; - uint64_t path_len; - std::vector<__euler_env_var_spec> env_var_specs; - std::vector<__euler_gift_stream_spec> gift_stream_specs; - - public: - //path needs to stay valid through any call to start - start_process(const char *path); - - //name and value need to stay valid through any call to start - void add_env_variable(const char *name, const char *value); - - void gift_stream( - __euler_stream_handle to_gifter, __euler_stream_handle to_giftee); - - __euler_stream_result start(__euler_process_handle &handle_out); - - }; - -} diff --git a/euler/include/euler/stream.hpp b/euler/include/euler/stream.hpp index a364ec4..741d863 100644 --- a/euler/include/euler/stream.hpp +++ b/euler/include/euler/stream.hpp @@ -7,41 +7,42 @@ namespace euler { class stream { public: - virtual ~stream(); - virtual bool try_read(void *into, uint64_t bytes) = 0; - virtual bool try_seek(__euler_seek_from from, int64_t offset) = 0; + virtual ~stream() {} - }; + virtual syscall::stream_result seek( + euler::syscall::seek_from from, int64_t offset) = 0; - class file_stream : public stream { + virtual std::pair<uint64_t, syscall::stream_result> + read(uint64_t bytes, void *into) = 0; - private: + virtual void close() = 0; - __euler_stream_handle handle; - bool is_readable; - bool is_writable; - uint64_t length; - uint64_t offset; + }; - uint8_t *buffer; - uint64_t buffer_offset; - uint64_t buffer_size; - bool buffer_dirty; + class file_stream : public stream { - void write_buffer(); + syscall::stream_handle handle; + bool may_read; - public: + bool buffer_loaded; + uint64_t buffer_start; + uint8_t buffer[1024]; - bool good; + uint64_t length; + uint64_t position; + public: file_stream( - __euler_stream_handle handle, bool is_readable, bool is_writable, - bool clear, bool seek_to_end); + syscall::stream_handle handle, bool may_read, + uint64_t length, uint64_t position); + + virtual syscall::stream_result seek( + syscall::seek_from from, int64_t offset) override; - ~file_stream(); + virtual std::pair<uint64_t, syscall::stream_result> + read(uint64_t bytes, void *into) override; - bool try_read(void *into, uint64_t bytes) override; - bool try_seek(__euler_seek_from from, int64_t offset) override; + virtual void close() override; }; diff --git a/euler/include/euler/syscall.hpp b/euler/include/euler/syscall.hpp index 981925f..64456ae 100644 --- a/euler/include/euler/syscall.hpp +++ b/euler/include/euler/syscall.hpp @@ -1,102 +1,136 @@ #pragma once -#include <stdint.h> - -enum __euler_stream_result : uint64_t { - __EULER_SR_SUCCESS = 0, - __EULER_SR_BAD_HANDLE, - __EULER_SR_IO_ERROR, - __EULER_SR_OUT_OF_BOUNDS, - __EULER_SR_DOES_NOT_EXIST, - __EULER_SR_NOT_A_REGULAR_FILE, - __EULER_SR_NOT_AN_EXECUTABLE, - __EULER_SR_NOT_WRITABLE, - __EULER_SR_NOT_SEEKABLE, - __EULER_SR_SOCKET_ID_ALREADY_IN_USE, - __EULER_SR_SOCKET_ID_NOT_IN_USE, - __EULER_SR_SOCKET_LISTENER_CLOSED, - __EULER_SR_OTHER_END_CLOSED, - __EULER_SR_ALREADY_EXISTS, - __EULER_SR_NOT_SIZED -}; - -enum __euler_seek_from : uint8_t { - __EULER_SF_BEGINNING = 0, - __EULER_SF_END, - __EULER_SF_CURRENT_POSITION -}; - -typedef uint64_t __euler_stream_handle; -typedef uint64_t __euler_process_handle; - -extern "C" __euler_stream_result __euler_open_file( - const char *path, uint64_t path_len, __euler_stream_handle &handle_out, - bool allow_creation, bool only_allow_creation); - -extern "C" [[noreturn]] void __euler_end_this_thread(int32_t exit_code); - -extern "C" __euler_stream_result __euler_seek_stream( - __euler_stream_handle handle, __euler_seek_from from, int64_t offset); - -extern "C" __euler_stream_result __euler_set_stream_length( - __euler_stream_handle handle, uint64_t new_length); - -extern "C" void __euler_close_stream(__euler_stream_handle handle); - -extern "C" __euler_stream_result __euler_get_stream_length( - __euler_stream_handle handle, uint64_t &length_out); - -extern "C" void *__euler_get_new_pages(uint64_t count); - -extern "C" __euler_stream_result __euler_write_to_stream( - __euler_stream_handle handle, uint64_t count, const void *buffer); - -extern "C" __euler_stream_result __euler_read_from_stream( - __euler_stream_handle handle, uint64_t count, void *buffer); - -extern "C" uint32_t *__euler_get_framebuffer( - uint32_t &width_out, uint32_t &height_out, uint32_t &pitch_out); - -extern "C" uint32_t __euler_encode_color(uint8_t r, uint8_t g, uint8_t b); - -enum __euler_mouse_buttons : uint8_t { - __EULER_MB_LEFT = 1, - __EULER_MB_RIGHT = 2, - __EULER_MB_MIDDLE = 4 -}; - -enum __euler_input_packet_type : uint8_t { - __EULER_IPT_MOUSE = 1, - __EULER_IPT_KEYBOARD = 2 -}; - -extern "C" __euler_input_packet_type __euler_get_input_packet( - __euler_mouse_buttons &buttons_out, int16_t &x_change_out, - int16_t &y_change_out, uint32_t &keyboard_packet_out); - -struct [[gnu::packed]] __euler_env_var_spec { - uint64_t name_len; - const char *name; - uint64_t value_len; - const char *value; -}; - -struct [[gnu::packed]] __euler_gift_stream_spec { - __euler_stream_handle stream_handle_to_gifter; - __euler_stream_handle stream_handle_to_giftee; -}; - -struct [[gnu::packed]] __euler_process_start_info { - uint64_t file_path_length; - const char *file_path; - uint64_t env_var_count; - const __euler_env_var_spec *env_vars; - uint64_t gift_stream_count; - const __euler_gift_stream_spec *gift_streams; -}; - -extern "C" __euler_stream_result __euler_start_process( - const __euler_process_start_info &info, __euler_process_handle &handle_out); - -extern "C" __euler_stream_result __euler_get_other_end_process_handle( - __euler_stream_handle handle_in, __euler_process_handle &handle_out); +#include <optional> +#include <cstdint> +#include <utility> +#include <variant> +#include <string> +#include <vector> + +namespace euler::syscall { + + enum class stream_result : uint64_t { + success, + bad_handle, + io_error, + out_of_bounds, + does_not_exist, + not_a_regular_file, + not_an_executable, + not_writable, + not_seekable, + socket_id_already_used, + socket_id_not_in_use, + socket_listener_closed, + other_end_closed, + already_exists, + not_sized, + not_readable + }; + + enum class seek_from : uint8_t { + beginning, + end, + current_position + }; + + struct mouse_packet { + bool left_button_down; + bool right_button_down; + bool middle_button_down; + int16_t x_changed; + int16_t y_changed; + }; + + struct key_packet { + bool was_key_up_event; + bool num_lock; + bool caps_lock; + bool right_win; + bool left_win; + bool right_alt; + bool left_alt; + bool right_ctrl; + bool left_ctrl; + bool right_shift; + bool left_shift; + uint8_t key_code; + }; + + typedef uint32_t encoded_color; + typedef uint64_t stream_handle; + typedef uint64_t listener_handle; + typedef uint64_t process_handle; + + encoded_color encode_color( + uint8_t r, uint8_t g, uint8_t b); + + void get_framebuffer( + encoded_color *&buffer_out, uint32_t &width_out, + uint32_t &height_out, uint32_t &pitch_out); + + stream_result open_file( + const std::string &file_path, bool allow_creation, + bool only_allow_creation, stream_handle &handle_out); + + [[noreturn]] void end_this_thread(int32_t exit_code); + + void *get_new_pages(uint64_t n_pages); + + std::variant<mouse_packet, key_packet> get_input_packet(); + + void create_private_socket( + stream_handle &end_1_out, stream_handle &end_2_out); + + stream_result create_socket_listener( + const std::string &id, listener_handle &handle_out); + + void stop_socket_listener(listener_handle handle); + + stream_result accept_socket_connection( + listener_handle listener, stream_handle &stream_out); + + stream_result connect_to_socket( + const std::string &id, stream_handle &handle_out); + + void close_stream(stream_handle handle); + + stream_result seek_stream( + stream_handle handle, seek_from from, int64_t offset); + + stream_result read_from_stream( + stream_handle handle, uint64_t bytes, void *into); + + stream_result write_to_stream( + stream_handle handle, uint64_t bytes, const void *from); + + stream_result get_stream_length( + stream_handle handle, uint64_t &length_out); + + 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); + + [[noreturn]] void end_this_process(int32_t exit_code); + + stream_result set_stream_length( + stream_handle handle, uint64_t new_length); + + stream_result get_other_end_process_handle( + stream_handle stream, process_handle &process_out); + + //entry_point must not return + void start_thread(void (*entry_point)(uint64_t), uint64_t arg); + + //entry_point must not return + void start_thread(void (*entry_point)()); + + //return value is number of bytes cleared + uint64_t clear_socket_read_queue(stream_handle handle); + + std::optional<std::string> try_get_environment_variable( + const std::string &name); + +} diff --git a/euler/include/std/allocator.hpp b/euler/include/std/allocator.hpp new file mode 100644 index 0000000..32ba005 --- /dev/null +++ b/euler/include/std/allocator.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include <euler/heap.hpp> + +namespace std { + + template <class T> + struct allocator { + + using value_type = T; + + constexpr allocator() noexcept {} + constexpr allocator(const allocator &other) noexcept {} + + template <class U> + constexpr allocator(const allocator<U> &other) noexcept {} + + constexpr ~allocator() {} + + constexpr T *allocate(size_t n) { + return (T *)euler::heap::get_block(n * sizeof(T)); + } + + constexpr void deallocate(T *p, size_t n) { + euler::heap::return_block(p, n * sizeof(T)); + } + + }; + +} diff --git a/euler/include/std/string.hpp b/euler/include/std/string.hpp new file mode 100644 index 0000000..7ccdbc2 --- /dev/null +++ b/euler/include/std/string.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include <cstddef> +#include <vector> + +namespace std { + + class string { + + std::vector<char> characters; + + public: + constexpr string() : characters({'\0'}) {} + + constexpr string(const string &other) + : characters(other.characters) {} + + constexpr string(string &&other) noexcept + : characters(std::move(other.characters)) { + other.characters.push_back('\0'); + } + + constexpr string(const char *s) { + size_t count = 0; + while (s[count] != '\0') + ++count; + characters.resize(count + 1); + for (size_t i = 0; i <= count; ++i) + characters[i] = s[i]; + } + + constexpr ~string() {} + + constexpr string &operator =(const string &str) { + characters = str.characters; + return *this; + } + + constexpr string &operator =(string &&str) noexcept { + characters = std::move(str.characters); + str.characters.push_back('\0'); + return *this; + } + + constexpr size_t size() const noexcept { + return characters.size() - 1; + } + + constexpr void resize(size_t count) { + if (count < characters.size() - 1) { + characters.resize(count + 1); + characters[count] = '\0'; + } + else if (count > characters.size() - 1) + characters.resize(count + 1); + } + + constexpr void clear() noexcept { + resize(0); + } + + constexpr const char *data() const noexcept { + return characters.data(); + } + + constexpr char *data() noexcept { + return characters.data(); + } + + constexpr char &operator[](size_t pos) { + return characters[pos]; + } + + constexpr const char &operator[](size_t pos) const { + return characters[pos]; + } + + }; + +} diff --git a/euler/include/std/vector.hpp b/euler/include/std/vector.hpp new file mode 100644 index 0000000..a1ac21d --- /dev/null +++ b/euler/include/std/vector.hpp @@ -0,0 +1,191 @@ +#pragma once + +#include <memory> + +namespace std { + + template <class T, class Allocator = std::allocator<T>> + class vector { + + public: + using size_type = size_t; + using value_type = T; + using reference = value_type &; + using const_reference = const value_type &; + + private: + Allocator _alloc; + size_type _capacity; + size_type _size; + T *_data; + + constexpr void expand_capacity_to(size_type at_least) { + + size_type new_capacity = _capacity == 0 ? 1 : _capacity; + while (new_capacity < at_least) + new_capacity *= 2; + if (new_capacity == _capacity) + return; + + T *new_data = _alloc.allocate(new_capacity); + for (size_type i = 0; i < _size; ++i) { + std::construct_at(new_data + i, std::move(_data[i])); + std::destroy_at(_data + i); + } + if (_capacity > 0) + _alloc.deallocate(_data, _capacity); + + _capacity = new_capacity; + _data = new_data; + + } + + public: + constexpr vector() noexcept(noexcept(Allocator())) + : _alloc(), _capacity(0), _size(0), _data(0) {} + + constexpr vector(const vector &other) + : _alloc(), _capacity(other._size), _size(other._size), + _data(_alloc.allocate(_capacity)) { + for (size_type i = 0; i < _size; ++i) + std::construct_at(_data + i, other._data[i]); + } + + constexpr vector(vector &&other) noexcept + : _alloc(std::move(other._alloc)), _capacity(other._capacity), + _size(other._size), _data(other._data) { + other._capacity = 0; + other._size = 0; + } + + constexpr vector( + std::initializer_list<T> init, const Allocator &alloc = Allocator()) + : _alloc(alloc), _capacity(init.size()), + _size(init.size()), _data(_alloc.allocate(_capacity)) { + for (size_type i = 0; i < _size; ++i) + std::construct_at(_data + i, init.begin()[i]); + } + + explicit vector(size_type count) + : _alloc(), _capacity(count), _size(count), + _data(_alloc.allocate(_capacity)) { + for (size_type i = 0; i < _size; ++i) + std::construct_at(_data + i); + } + + constexpr ~vector() { + if (_capacity > 0) { + for (size_type i = 0; i < _size; ++i) + std::destroy_at(_data + i); + _alloc.deallocate(_data, _capacity); + } + } + + constexpr vector &operator =(const vector &other) { + + if (&other == this) + return *this; + + expand_capacity_to(other._size); + + for (size_type i = 0; i < _size; ++i) + std::destroy_at(_data + i); + + for (size_type i = 0; i < other._size; ++i) { + std::construct_at(_data + i, std::move(other._data[i])); + std::destroy_at(other._data + i); + } + + _size = other._size; + return *this; + + } + + constexpr vector &operator =(vector &&other) + noexcept( + std::allocator_traits<Allocator>:: + propagate_on_container_move_assignment::value || + std::allocator_traits<Allocator>:: + is_always_equal::value) { + + if (&other == this) + return *this; + + if (_capacity > 0) { + for (size_type i = 0; i < _size; ++i) + std::destroy_at(_data + i); + _alloc.deallocate(_data, _capacity); + } + + _alloc = std::move(other._alloc); + _capacity = other._capacity; + _size = other._size; + _data = other._data; + + other._capacity = 0; + other._size = 0; + + return *this; + + } + + constexpr size_type size() const noexcept { + return _size; + } + + constexpr T *data() noexcept { + return _data; + } + + constexpr const T *data() const noexcept { + return _data; + } + + constexpr reference operator[](size_type pos) { + return _data[pos]; + } + + constexpr const_reference operator[](size_type pos) const { + return _data[pos]; + } + + constexpr reference back() { + return _data[_size - 1]; + } + + constexpr const_reference back() const { + return _data[_size - 1]; + } + + constexpr void resize(size_type count) { + + if (count < _size) { + for (size_type i = count; i < _size; ++i) + std::destroy_at(_data + i); + _size = count; + } + + else if (count > _size) { + expand_capacity_to(count); + for (size_type i = _size; i < count; ++i) + std::construct_at(_data + i); + _size = count; + } + + } + + constexpr void push_back(const T &value) { + expand_capacity_to(_size + 1); + std::construct_at(_data + _size, value); + ++_size; + } + + constexpr void push_back(T &&value) { + expand_capacity_to(_size + 1); + std::construct_at(_data + _size, std::move(value)); + ++_size; + } + + }; + +} diff --git a/euler/include/string b/euler/include/string new file mode 100644 index 0000000..ce42b9e --- /dev/null +++ b/euler/include/string @@ -0,0 +1,13 @@ +#pragma once + +#include <std/string.hpp> + +namespace std { + + int stoi(const std::string &str, size_t *pos = 0, int base = 10); + + std::string to_string(int value); + + std::string operator +(std::string &&lhs, std::string &&rhs); + +} diff --git a/euler/include/type_traits b/euler/include/type_traits deleted file mode 100644 index fcea013..0000000 --- a/euler/include/type_traits +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -namespace std { - - template <class t> - struct remove_reference { - typedef t type; - }; - - template <class t> - struct remove_reference<t &> { - typedef t type; - }; - - template <class t> - struct remove_reference<t &&> { - typedef t type; - }; - - template <class t> - using remove_reference_t = typename remove_reference<t>::type; - -} diff --git a/euler/include/utility b/euler/include/utility deleted file mode 100644 index 23648c4..0000000 --- a/euler/include/utility +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include <type_traits> - -namespace std { - - template <class t> - constexpr std::remove_reference_t<t> &&move(t &&x) { - return static_cast<std::remove_reference_t<t> &&>(x); - } - -} diff --git a/euler/include/vector b/euler/include/vector index f5083ed..2184475 100644 --- a/euler/include/vector +++ b/euler/include/vector @@ -1,62 +1,3 @@ #pragma once -#include <stddef.h> -#include <utility> - -namespace std { - - template <class t> - class vector { - - t *buffer; - size_t buffer_length;//always positive - size_t count; - - public: - vector() : buffer(new t[16]), buffer_length(16), count(0) {} - - ~vector() { - delete[] buffer; - } - - t &operator[](size_t pos) { - return buffer[pos]; - } - - const t &operator[](size_t pos) const { - return buffer[pos]; - } - - t *data() { - return buffer; - } - - const t *data() const { - return buffer; - } - - size_t size() const { - return count; - } - - void reserve(size_t new_length) { - if (new_length <= buffer_length) - return; - t *new_buffer = new t[new_length]; - for (size_t i = 0; i < count; ++i) - new_buffer[i] = std::move(buffer[i]); - delete[] buffer; - buffer = new_buffer; - buffer_length = new_length; - } - - void push_back(t &&value) { - if (count == buffer_length) - reserve(count * 2); - buffer[count++] = std::move(value); - } - - //TODO - }; - -} +#include <std/vector.hpp> diff --git a/euler/makefile b/euler/makefile index 1767d75..62716f6 100644 --- a/euler/makefile +++ b/euler/makefile @@ -1,7 +1,6 @@ -LIBSTDCPP_SOURCES = euler/stream.cpp strings/strlen.cpp euler/syscall.asm \ - euler/entry.cpp io/fopen.cpp euler/gcc.asm memory/delete.cpp euler/heap.cpp \ - memory/new.cpp io/fclose.cpp io/fread.cpp strings/memcpy.cpp io/fseek.cpp \ - euler/start_process.cpp +LIBC_SOURCES = \ + entry.cpp std/string.cpp std/cstring.cpp syscall.cpp std/cstdlib.cpp \ + heap.cpp syscall.asm std/cctype.cpp std/cstdio.cpp stream.cpp clean: rm -rf build @@ -12,12 +11,12 @@ build/%.asm.o: source/%.asm build/%.cpp.o: source/%.cpp @mkdir -p $(@D) - $(HILBERT_CC) -c $^ -o $@ + $(HILBERT_CC) -ffreestanding -c $^ -o $@ build/crt0.o: build/empty.asm.o cp $^ $@ -build/libc.a: build/empty.asm.o +build/libc.a: ${LIBC_SOURCES:%=build/%.o} $(HILBERT_AR) rcs $@ $^ build/libg.a: build/empty.asm.o @@ -25,6 +24,3 @@ build/libg.a: build/empty.asm.o build/libm.a: build/empty.asm.o $(HILBERT_AR) rcs $@ $^ - -build/libstdc++.a: ${LIBSTDCPP_SOURCES:%=build/%.o} - $(HILBERT_AR) rcs $@ $^ diff --git a/euler/source/entry.cpp b/euler/source/entry.cpp new file mode 100644 index 0000000..e79209c --- /dev/null +++ b/euler/source/entry.cpp @@ -0,0 +1,28 @@ +#include <euler/syscall.hpp> +#include <cstdlib> +#include <string> + +int main(int argc, char **argv); + +extern "C" [[noreturn]] void _start() { + + auto argc_raw = euler::syscall::try_get_environment_variable("ARGC"); + int argc = argc_raw.has_value() ? std::stoi(argc_raw.value()) : 0; + + std::vector<std::string> argv; + + for (int i = 0; i < argc; ++i) { + std::string arg_name = std::string("ARGV") + std::to_string(i); + auto arg_raw = euler::syscall::try_get_environment_variable(arg_name); + argv.push_back(arg_raw.has_value() ? arg_raw.value() : ""); + } + + std::vector<char *> c_argv(argc); + for (int i = 0; i < argc; ++i) + c_argv[i] = argv[i].data(); + + int exit_code = main(argc, c_argv.data()); + + euler::syscall::end_this_process(exit_code); + +} diff --git a/euler/source/euler/entry.cpp b/euler/source/euler/entry.cpp deleted file mode 100644 index 69611b7..0000000 --- a/euler/source/euler/entry.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include <euler/syscall.hpp> - -int main(int argc, char **argv); - -extern "C" [[noreturn]] void _start() { - //TODO: call global constructors - //TODO: get argc, argv from environment - int exit_code = main(0, 0); - //TODO: call global destructors - __euler_end_this_thread(exit_code); -} diff --git a/euler/source/euler/gcc.asm b/euler/source/euler/gcc.asm deleted file mode 100644 index 6fc6fd5..0000000 --- a/euler/source/euler/gcc.asm +++ /dev/null @@ -1,53 +0,0 @@ -bits 64 - -global strlen - -section .text - -strlen: - xor rax, rax -.loop: - mov rdx, qword [rdi] - test edx, 0xff - jz .plus0 - test edx, 0xff00 - jz .plus1 - test edx, 0xff0000 - jz .plus2 - test edx, 0xff000000 - jz .plus3 - shr rdx, 32 - test edx, 0xff - jz .plus4 - test edx, 0xff00 - jz .plus5 - test edx, 0xff0000 - jz .plus6 - test edx, 0xff000000 - jz .plus7 - add rax, 8 - add rdi, 8 - jmp .loop -.plus0: - ret -.plus1: - add rax, 1 - ret -.plus2: - add rax, 2 - ret -.plus3: - add rax, 3 - ret -.plus4: - add rax, 4 - ret -.plus5: - add rax, 5 - ret -.plus6: - add rax, 6 - ret -.plus7: - add rax, 7 - ret diff --git a/euler/source/euler/heap.cpp b/euler/source/euler/heap.cpp deleted file mode 100644 index f7d407f..0000000 --- a/euler/source/euler/heap.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include <euler/syscall.hpp> -#include <euler/heap.hpp> - -namespace euler { - - static uint64_t *last_chunk_info_page = 0; - - void add_record(uint64_t start, uint64_t length) { - uint64_t dual_start = start ^ length; - for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510]) - for (int i = 0; i < 255; ++i) - if (cip[i * 2] == length && cip[i * 2 + 1] == dual_start) { - cip[i * 2] = length * 2; - cip[i * 2 + 1] &= start; - return; - } - for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510]) - for (int i = 0; i < 255; ++i) - if (cip[i * 2] == 0) { - cip[i * 2] = length; - cip[i * 2 + 1] = start; - return; - } - uint64_t *new_cip = (uint64_t *)__euler_get_new_pages(1); - new_cip[0] = length; - new_cip[1] = start; - for (int i = 1; i < 255; ++i) - new_cip[i * 2] = 0; - new_cip[510] = (uint64_t)last_chunk_info_page; - last_chunk_info_page = new_cip; - } - - void *alloc(uint64_t bytes) { - for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510]) - for (int i = 0; i < 255; ++i) - if (cip[i * 2] >= bytes) { - uint64_t start = cip[i * 2 + 1]; - uint64_t extra_length = cip[i * 2] - bytes; - cip[i * 2] = 0; - if (extra_length > 0) - dealloc((void *)(start + bytes), extra_length); - return (void *)start; - } - uint64_t pages_needed = (bytes - 1) / 4096 + 1; - uint64_t start = (uint64_t)__euler_get_new_pages(pages_needed); - if (bytes != pages_needed * 4096) - dealloc((void *)(start + bytes), pages_needed * 4096 - bytes); - return (void *)start; - } - - //this implementation is a little lazy - void dealloc(void *start, uint64_t bytes) { - uint64_t s = (uint64_t)start; - while (bytes > 0) { - uint64_t l = 1; - do - l *= 2; - while (l <= bytes && s % l == 0); - l /= 2; - add_record(s, l); - s += l; - bytes -= l; - } - } - -} diff --git a/euler/source/euler/start_process.cpp b/euler/source/euler/start_process.cpp deleted file mode 100644 index 64e16c5..0000000 --- a/euler/source/euler/start_process.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include <euler/start_process.hpp> -#include <cstring> - -namespace euler { - - start_process::start_process(const char *path) - : path(path), path_len(std::strlen(path)) {} - - void start_process::add_env_variable(const char *name, const char *value) { - env_var_specs.push_back({ - .name_len = std::strlen(name), .name = name, - .value_len = std::strlen(value), .value = value }); - } - - void start_process::gift_stream( - __euler_stream_handle to_gifter, __euler_stream_handle to_giftee) { - gift_stream_specs.push_back({ - .stream_handle_to_gifter = to_gifter, - .stream_handle_to_giftee = to_giftee }); - } - - __euler_stream_result start_process::start( - __euler_process_handle &handle_out) { - __euler_process_start_info info = { - .file_path_length = path_len, - .file_path = path, - .env_var_count = env_var_specs.size(), - .env_vars = env_var_specs.data(), - .gift_stream_count = gift_stream_specs.size(), - .gift_streams = gift_stream_specs.data(), - }; - return __euler_start_process(info, handle_out); - } - -} diff --git a/euler/source/euler/stream.cpp b/euler/source/euler/stream.cpp deleted file mode 100644 index 950f3c5..0000000 --- a/euler/source/euler/stream.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include <euler/stream.hpp> -#include <cstring> - -namespace euler { - - stream::~stream() {} - - void file_stream::write_buffer() { - if (__euler_write_to_stream(handle, buffer_size, buffer) - != __EULER_SR_SUCCESS) - good = false;//TODO: more precise error reporting - else - buffer_dirty = false; - } - - file_stream::file_stream( - __euler_stream_handle handle, bool is_readable, bool is_writable, - bool clear, bool seek_to_end) - - : handle(handle), is_readable(is_readable), is_writable(is_writable), - buffer(0), good(true) { - - if (clear) { - if (__euler_set_stream_length(handle, 0) != __EULER_SR_SUCCESS) { - good = false; - return; - } - length = 0; - } - - else if (__euler_get_stream_length(handle, length) != __EULER_SR_SUCCESS) { - good = false; - return; - } - - if (seek_to_end) { - if (__euler_seek_stream(handle, __EULER_SF_END, 0) - != __EULER_SR_SUCCESS) { - good = false; - return; - } - offset = length; - } - - else - offset = 0; - - } - - file_stream::~file_stream() { - if (buffer) { - if (buffer_dirty) - write_buffer(); - delete[] buffer; - } - __euler_close_stream(handle); - } - - bool file_stream::try_read(void *into, uint64_t bytes) { - - if (bytes == 0) - return true; - - if (offset + bytes > length) - return false; - - if (buffer) { - uint64_t start = offset > buffer_offset ? offset : buffer_offset; - uint64_t end = offset + bytes < buffer_offset + buffer_size - ? offset + bytes : buffer_offset + buffer_size; - if (end > start) { - - uint64_t real_end = offset + bytes; - - std::memcpy( - (uint8_t *)into + start - offset, buffer + start - buffer_offset, - end - start); - if (start != offset) - if (!try_read(into, start - offset)) - return false; - - if (end != real_end) { - if (!try_seek(__EULER_SF_BEGINNING, end)) - return false; - if (!try_read((uint8_t *)into + end, real_end - end)) - return false; - } - - else if (offset != real_end) - if (!try_seek(__EULER_SF_BEGINNING, real_end)) - return false; - - return true; - - } - } - - if (buffer_dirty) { - write_buffer(); - if (!good) - return false; - } - - //1024 is arbitrary - buffer_size = length - offset < 1024 ? length - offset : 1024; - - if (buffer != 0) - delete[] buffer; - - buffer = new uint8_t[buffer_size]; - buffer_dirty = false; - buffer_offset = offset; - - if (__euler_read_from_stream(handle, buffer_size, buffer) - != __EULER_SR_SUCCESS) { - delete[] buffer; - buffer = 0; - return false; - } - - uint64_t read_this_buffer = buffer_size < bytes ? buffer_size : bytes; - std::memcpy(into, buffer, read_this_buffer); - offset += read_this_buffer; - - if (read_this_buffer == bytes) - return true; - - return try_read( - (uint8_t *)into + read_this_buffer, bytes - read_this_buffer); - - } - - bool file_stream::try_seek(__euler_seek_from from, int64_t offset) { - if (__euler_seek_stream(handle, from, offset) != __EULER_SR_SUCCESS) - return false; - switch (from) { - case __EULER_SF_BEGINNING: - this->offset = offset; - return true; - case __EULER_SF_END: - this->offset = length + offset; - return true; - case __EULER_SF_CURRENT_POSITION: - this->offset += offset; - return true; - default: - return false; - } - } - -} diff --git a/euler/source/euler/syscall.asm b/euler/source/euler/syscall.asm deleted file mode 100644 index 64f08f8..0000000 --- a/euler/source/euler/syscall.asm +++ /dev/null @@ -1,144 +0,0 @@ -bits 64 - -global __euler_open_file -global __euler_close_stream -global __euler_get_new_pages -global __euler_write_to_stream -global __euler_seek_stream -global __euler_get_stream_length -global __euler_set_stream_length -global __euler_end_this_thread -global __euler_read_from_stream -global __euler_get_framebuffer -global __euler_encode_color -global __euler_get_input_packet -global __euler_start_process -global __euler_get_other_end_process_handle - -section .text - -__euler_open_file: - mov rax, 2 - push rdx - xor rdx, rdx - or rdx, r8 - shl r9, 1 - or rdx, r9 - syscall - pop rdx - mov qword [rdx], rdi - ret - -__euler_close_stream: - mov rax, 11 - syscall - ret - -__euler_get_new_pages: - mov rax, 4 - syscall - ret - -__euler_write_to_stream: - mov rax, 14 - syscall - ret - -__euler_seek_stream: - mov rax, 12 - syscall - ret - -__euler_get_stream_length: - push rsi - mov rax, 15 - syscall - pop rsi - mov qword [rsi], rdi - ret - -__euler_set_stream_length: - mov rax, 18 - syscall - ret - -__euler_end_this_thread: - mov rax, 3 - syscall - -__euler_read_from_stream: - mov rax, 13 - syscall - ret - -__euler_get_framebuffer: - push rdi - push rsi - push rdx - mov rax, 1 - syscall - pop rdx - mov dword [rdx], esi - pop rdx - pop rsi - mov dword [rsi], edi - shr rdi, 32 - mov dword [rdx], edi - ret - -__euler_encode_color: - xor ah, ah - mov al, dl - shl ax, 8 - mov al, sil - shl eax, 8 - mov al, dil - mov edi, eax - xor rax, rax - syscall - ret - -__euler_get_input_packet: - push rdi - push rsi - push rdx - push rcx - mov rax, 5 - syscall - - test al, 0x80 - jnz .mouse_packet - - pop rcx - mov dword [rcx], edi - add rsp, 24 - mov al, 2 - ret - -.mouse_packet: - add rsp, 8 - pop rdx - mov word [rdx], si - pop rdx - mov word [rdx], di - pop rdx - and al, 0x7f - mov byte [rdx], al - mov al, 1 - ret - -__euler_start_process: - push rsi - mov rax, 16 - syscall - pop rsi - mov qword [rsi], rdi - ret - -__euler_get_other_end_process_handle: - push rsi - mov rax, 19 - syscall - pop rsi - mov qword [rsi], rdi - ret diff --git a/euler/source/heap.cpp b/euler/source/heap.cpp new file mode 100644 index 0000000..dc92e5d --- /dev/null +++ b/euler/source/heap.cpp @@ -0,0 +1,155 @@ +#include <euler/syscall.hpp> +#include <euler/heap.hpp> +#include <cstdint> + +namespace euler::heap { + + struct heap_aligned_entry { + size_t start_vaddr; + size_t length; + heap_aligned_entry *prev; + heap_aligned_entry *next; + }; + + struct unused_heap_entries_page { + heap_aligned_entry *unused[510]; + unused_heap_entries_page *prev; + uint16_t unused_in_this_page; + }; + + heap_aligned_entry *first_entry = 0; + heap_aligned_entry *last_entry = 0; + unused_heap_entries_page *last_page = 0; + + void mark_entry_unused(heap_aligned_entry *entry) { + + for (unused_heap_entries_page *page = last_page; page != 0; page = page->prev) { + if (page->unused_in_this_page == 510) + continue; + for (uint16_t i = 0; i < 510; ++i) + if (page->unused[i] == 0) { + page->unused[i] = entry; + ++page->unused_in_this_page; + return; + } + } + + unused_heap_entries_page *page = (unused_heap_entries_page *)euler::syscall::get_new_pages(1); + page->prev = last_page; + last_page = page; + + page->unused_in_this_page = 1; + page->unused[0] = entry; + + for (uint16_t i = 1; i < 510; ++i) + page->unused[i] = 0; + + } + + void remove_entry(heap_aligned_entry *entry) { + + if (entry->prev) + entry->prev->next = entry->next; + else + first_entry = entry->next; + if (entry->next) + entry->next->prev = entry->prev; + else + last_entry = entry->prev; + + mark_entry_unused(entry); + + } + + heap_aligned_entry *get_new_entry() { + + for (unused_heap_entries_page *page = last_page; page != 0; page = page->prev) { + if (page->unused_in_this_page == 0) + continue; + for (uint16_t i = 0; i < 510; ++i) + if (page->unused[i] != 0) { + heap_aligned_entry *entry = page->unused[i]; + page->unused[i] = 0; + --page->unused_in_this_page; + return entry; + } + } + + heap_aligned_entry *new_entries = (heap_aligned_entry *)euler::syscall::get_new_pages(1); + + for (uint8_t i = 1; i < 128; ++i) + mark_entry_unused(new_entries + i); + + return new_entries; + + } + + void *get_block(size_t length) { + + for (heap_aligned_entry *entry = first_entry; entry != 0; entry = entry->next) { + if (entry->length == length) { + void *start = (void *)entry->start_vaddr; + remove_entry(entry); + return start; + } + if (entry->length > length) { + void *start = (void *)entry->start_vaddr; + entry->start_vaddr += length; + entry->length -= length; + return start; + } + } + + size_t pages = (length - 1) / 4096 + 1; + void *new_memory = euler::syscall::get_new_pages(pages); + if (pages * 4096 != length) + return_block((uint8_t *)new_memory + length, pages * 4096 - length); + return new_memory; + + } + + void return_block(void *start, size_t length) { + + heap_aligned_entry *after = first_entry; + while (after != 0 && after->start_vaddr < (size_t)start + length) + after = after->next; + + heap_aligned_entry *before; + if (after == 0) + before = last_entry; + else + before = after->prev; + + heap_aligned_entry *us; + + if (after && after->start_vaddr == (size_t)start + length) { + after->start_vaddr -= length; + after->length += length; + us = after; + } + + else { + us = get_new_entry(); + us->prev = before; + us->next = after; + us->start_vaddr = (size_t)start; + us->length = length; + if (before) + before->next = us; + else + first_entry = us; + if (after) + after->prev = us; + else + last_entry = us; + } + + if (before && before->start_vaddr + before->length == (size_t)start) { + us->start_vaddr -= before->length; + us->length += before->length; + remove_entry(before); + } + + } + +} diff --git a/euler/source/io/fclose.cpp b/euler/source/io/fclose.cpp deleted file mode 100644 index 6f43f85..0000000 --- a/euler/source/io/fclose.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include <cstdio> - -namespace std { - - int fclose(FILE *stream) { - delete stream; - return 0; - } - -} diff --git a/euler/source/io/fopen.cpp b/euler/source/io/fopen.cpp deleted file mode 100644 index 8d47bf0..0000000 --- a/euler/source/io/fopen.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include <stdint.h> -#include <cstring> -#include <cstdio> - -namespace std { - - FILE *fopen(const char *filename, const char *mode) { - - bool read = false; - bool write = false; - bool append = false; - bool extended = false; - bool create = false; - - for (const char *p = mode; *p; ++p) - switch (*p) { - case 'r': - read = true; - continue; - case 'w': - write = true; - continue; - case 'a': - append = true; - continue; - case '+': - extended = true; - continue; - case 'x': - create = true; - continue; - default: - continue; - } - - __euler_stream_handle handle; - __euler_stream_result res = __euler_open_file( - filename, strlen(filename), handle, write || append, create); - - if (res != __EULER_SR_SUCCESS) - return 0; - - euler::file_stream *f = new euler::file_stream(handle, read || extended, - write || extended, write && !append, append); - - if (f->good) - return f; - - delete f; - return 0; - - } - -} diff --git a/euler/source/io/fread.cpp b/euler/source/io/fread.cpp deleted file mode 100644 index e2d05b6..0000000 --- a/euler/source/io/fread.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include <cstdio> - -namespace std { - - size_t fread(void *buffer, size_t size, size_t count, FILE *stream) { - return stream->try_read(buffer, size * count) ? count : 0; - } - -} diff --git a/euler/source/io/fseek.cpp b/euler/source/io/fseek.cpp deleted file mode 100644 index 3254468..0000000 --- a/euler/source/io/fseek.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include <cstdio> - -namespace std { - - int fseek(FILE *stream, long offset, int origin) { - if (origin < 0 || origin > 2) - return 1; - return stream->try_seek((__euler_seek_from)origin, offset) ? 0 : 2; - } - -} diff --git a/euler/source/memory/delete.cpp b/euler/source/memory/delete.cpp deleted file mode 100644 index e4cc288..0000000 --- a/euler/source/memory/delete.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <euler/heap.hpp> - -void operator delete(void *ptr) { - euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8)); -} - -void operator delete(void *ptr, uint64_t) { - euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8)); -} - -void operator delete[](void *ptr) { - euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8)); -} - -void operator delete[](void *ptr, uint64_t) { - euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8)); -} diff --git a/euler/source/memory/new.cpp b/euler/source/memory/new.cpp deleted file mode 100644 index 931328f..0000000 --- a/euler/source/memory/new.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include <euler/heap.hpp> - -void *operator new(uint64_t size) { - void *ptr = euler::alloc(size + 8); - *(uint64_t *)ptr = size + 8; - return (uint8_t *)ptr + 8; -} - -void *operator new[](uint64_t size) { - void *ptr = euler::alloc(size + 8); - *(uint64_t *)ptr = size + 8; - return (uint8_t *)ptr + 8; -} diff --git a/euler/source/std/cctype.cpp b/euler/source/std/cctype.cpp new file mode 100644 index 0000000..a35d1a5 --- /dev/null +++ b/euler/source/std/cctype.cpp @@ -0,0 +1,7 @@ +#include <cctype> + +extern "C" int isspace(int ch) { + return + ch == ' ' || ch == '\f' || ch == '\n' || + ch == '\r' || ch == '\t' || ch == '\v'; +} diff --git a/euler/source/std/cstdio.cpp b/euler/source/std/cstdio.cpp new file mode 100644 index 0000000..8c12a7c --- /dev/null +++ b/euler/source/std/cstdio.cpp @@ -0,0 +1,59 @@ +#include <cstdio> + +extern "C" FILE *fopen(const char *filename, const char *mode) { + + bool r = false, w = false, a = false, p = false, x = false; + for (size_t i = 0; mode[i] != '\0'; ++i) + if (mode[i] == 'r') r = true; + else if (mode[i] == 'w') w = true; + else if (mode[i] == 'a') a = true; + else if (mode[i] == 'p') p = true; + else if (mode[i] == 'x') x = true; + + euler::syscall::stream_handle handle; + if (euler::syscall::open_file(filename, !r, x, handle) != + euler::syscall::stream_result::success) + return 0; + + if (w && euler::syscall::set_stream_length(handle, 0) != + euler::syscall::stream_result::success) + return 0; + + if (a && euler::syscall::seek_stream( + handle, euler::syscall::seek_from::end, 0) != + euler::syscall::stream_result::success) { + euler::syscall::close_stream(handle); + return 0; + } + + uint64_t length; + if (euler::syscall::get_stream_length(handle, length) != + euler::syscall::stream_result::success) { + euler::syscall::close_stream(handle); + return 0; + } + + return new euler::file_stream(handle, r || p, length, a ? length : 0); + +} + +extern "C" void fclose(FILE *stream) { + stream->close(); + delete stream; +} + +extern "C" int fseek(FILE *stream, long offset, int origin) { + + if (origin < 0 || origin > 2) + return -1; + + return (int)stream->seek((euler::syscall::seek_from)origin, offset); + +} + +extern "C" size_t fread( + void *buffer, size_t size, size_t count, FILE *stream) { + + return (stream->read(size * count, buffer).first - 1) / size + 1; + +} diff --git a/euler/source/std/cstdlib.cpp b/euler/source/std/cstdlib.cpp new file mode 100644 index 0000000..cfb4b48 --- /dev/null +++ b/euler/source/std/cstdlib.cpp @@ -0,0 +1,19 @@ +#include <euler/heap.hpp> +#include <cstdlib> + +extern "C" [[noreturn]] void abort() noexcept { + //TODO + while (1) + ; +} + +extern "C" void *malloc(size_t size) { + size_t *block = (size_t *)euler::heap::get_block(size + 8); + *block = size; + return block + 1; +} + +extern "C" void free(void *ptr) { + size_t *block = (size_t *)ptr - 1; + euler::heap::return_block(block, *block + 8); +} diff --git a/euler/source/std/cstring.cpp b/euler/source/std/cstring.cpp new file mode 100644 index 0000000..3e5a56c --- /dev/null +++ b/euler/source/std/cstring.cpp @@ -0,0 +1,36 @@ +#include <cstring> + +extern "C" void *memset(void *dest, int ch, size_t count) { + unsigned char c = static_cast<unsigned char>(ch); + unsigned char *d = (unsigned char *)dest; + for (size_t i = 0; i < count; ++i) + d[i] = c; + return dest; +} + +extern "C" void *memcpy(void *dest, const void *src, size_t count) { + unsigned char *d = (unsigned char *)dest; + const unsigned char *s = (const unsigned char *)src; + for (size_t i = 0; i < count; ++i) + d[i] = s[i]; + return dest; +} + +extern "C" int strcmp(const char *lhs, const char *rhs) { + const unsigned char *l = (const unsigned char *)lhs; + const unsigned char *r = (const unsigned char *)rhs; + while (*l == *r) { + if (*l == 0) + return 0; + ++l; + ++r; + } + return *l < *r ? -1 : 1; +} + +extern "C" size_t strlen(const char *str) { + size_t len = 0; + while (str[len] != '\0') + ++len; + return len; +} diff --git a/euler/source/std/string.cpp b/euler/source/std/string.cpp new file mode 100644 index 0000000..31c47a5 --- /dev/null +++ b/euler/source/std/string.cpp @@ -0,0 +1,86 @@ +#include <cctype> +#include <string> + +namespace std { + + int stoi(const std::string &str, size_t *pos, int base) { + //TODO: exceptions + + size_t i = 0; + while (isspace(str[i])) + ++i; + + bool is_negative = false; + if (str[i] == '-') { + is_negative = true; + ++i; + } + else if (str[i] == '+') + ++i; + + if ((base == 16 || base == 0) && str[i] == '0' && + (str[i + 1] == 'x' || str[i + 1] == 'X')) { + base = 16; + i += 2; + } + + else if ((base == 8 || base == 0) && str[i] == '0') { + base = 8; + ++i; + } + + else if (base == 0) + base = 10; + + int value = 0; + + while (true) { + char c = str[i]; + if (c >= '0' && c < '0' + base) + value = value * base + c - '0'; + else if (c >= 'a' && c < 'a' + base - 10) + value = value * base + c - 'a' + 10; + else if (c >= 'A' && c < 'A' + base - 10) + value = value * base + c - 'A' + 10; + else + break; + } + + if (pos != 0) + *pos = i; + + return is_negative ? -value : value; + + } + + std::string to_string(int value) { + + int max_place = 1; + int places = 1; + while (max_place <= value / 10) { + max_place *= 10; + ++places; + } + + std::string s; + s.resize(places); + + for (int i = 0; i < places; ++i) { + s[i] = (value / max_place) % 10 + '0'; + max_place /= 10; + } + + return s; + + } + + std::string operator +(std::string &&lhs, std::string &&rhs) { + std::string s = std::move(lhs); + s.resize(lhs.size() + rhs.size()); + for (size_t i = 0; i < rhs.size(); ++i) + s[lhs.size() + i] = rhs[i]; + rhs.clear(); + return s; + } + +} diff --git a/euler/source/stream.cpp b/euler/source/stream.cpp new file mode 100644 index 0000000..faf2907 --- /dev/null +++ b/euler/source/stream.cpp @@ -0,0 +1,106 @@ +#include <euler/stream.hpp> +#include <cstring> + +namespace euler { + + file_stream::file_stream( + syscall::stream_handle handle, bool may_read, + uint64_t length, uint64_t position) + : handle(handle), may_read(may_read), buffer_loaded(false), + length(length), position(position) {} + + syscall::stream_result file_stream::seek( + syscall::seek_from from, int64_t offset) { + + int64_t new_position = offset + + (from == syscall::seek_from::beginning ? 0 : + from == syscall::seek_from::end ? length : position); + + if (new_position < 0 || (uint64_t)new_position > length) + return syscall::stream_result::out_of_bounds; + + position = new_position; + return syscall::stream_result::success; + + } + + std::pair<uint64_t, syscall::stream_result> + file_stream::read(uint64_t bytes, void *into) { + + if (!may_read) + return {0, syscall::stream_result::not_readable}; + + uint64_t have_read = 0; + syscall::stream_result result = syscall::stream_result::success; + + uint64_t end = position + bytes; + + if (end > length) { + end = length; + result = syscall::stream_result::out_of_bounds; + } + + uint64_t block_start = (position / 1024) * 1024; + + while (position < end) { + + uint64_t length_in_this_block = + std::min(end, block_start + 1024) - position; + + if (buffer_loaded && buffer_start == block_start) + memcpy(into, buffer + position - block_start, length_in_this_block); + + else if (length_in_this_block == 1024) { + + syscall::stream_result seek_result = + syscall::seek_stream( + handle, syscall::seek_from::beginning, block_start); + if (seek_result != syscall::stream_result::success) + return {have_read, seek_result}; + + syscall::stream_result read_result = + syscall::read_from_stream(handle, 1024, into); + if (read_result != syscall::stream_result::success) + return {have_read, read_result}; + + } + + else { + + syscall::stream_result seek_result = + syscall::seek_stream( + handle, syscall::seek_from::beginning, block_start); + if (seek_result != syscall::stream_result::success) + return {have_read, seek_result}; + + uint64_t buffer_length = std::min(1024UL, length - block_start); + + syscall::stream_result read_result = + syscall::read_from_stream(handle, buffer_length, buffer); + if (read_result != syscall::stream_result::success) { + buffer_loaded = false; + return {have_read, read_result}; + } + + buffer_loaded = true; + buffer_start = block_start; + memcpy(into, buffer + position - block_start, length_in_this_block); + + } + + into = (uint8_t *)into + length_in_this_block; + have_read += length_in_this_block; + position += length_in_this_block; + block_start += 1024; + + } + + return {have_read, result}; + + } + + void file_stream::close() { + syscall::close_stream(handle); + } + +} diff --git a/euler/source/strings/memcpy.cpp b/euler/source/strings/memcpy.cpp deleted file mode 100644 index d5a1d6c..0000000 --- a/euler/source/strings/memcpy.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include <stdint.h> -#include <cstring> - -namespace std { - - void *memcpy(void *dest, const void *src, size_t count) { - uint8_t *d8 = (uint8_t *)dest; - const uint8_t *s8 = (const uint8_t *)src; - for (size_t i = 0; i < count; ++i) - d8[i] = s8[i]; - return dest; - } - -} diff --git a/euler/source/strings/strlen.cpp b/euler/source/strings/strlen.cpp deleted file mode 100644 index 7a6fe2a..0000000 --- a/euler/source/strings/strlen.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include <cstring> - -namespace std { - - size_t strlen(const char *str) { - size_t len = 0; - while (str[len]) - ++len; - return len; - } - -} diff --git a/euler/source/syscall.asm b/euler/source/syscall.asm new file mode 100644 index 0000000..d4515bb --- /dev/null +++ b/euler/source/syscall.asm @@ -0,0 +1,32 @@ +bits 64 + +section .text + +global __euler_do_syscall +__euler_do_syscall: + + push rdi + push rsi + push rdx + push rcx + + mov rax, qword [rdi] + mov rdi, qword [rsi] + mov rsi, qword [rdx] + mov rdx, qword [rcx] + + syscall + + pop rcx + mov qword [rcx], rdx + + pop rdx + mov qword [rdx], rsi + + pop rsi + mov qword [rsi], rdi + + pop rdi + mov qword [rdi], rax + + ret diff --git a/euler/source/syscall.cpp b/euler/source/syscall.cpp new file mode 100644 index 0000000..b3ed3a8 --- /dev/null +++ b/euler/source/syscall.cpp @@ -0,0 +1,397 @@ +#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; + + } + +} |