summaryrefslogtreecommitdiff
path: root/euler/source
diff options
context:
space:
mode:
authorBenji Dial <benji@benjidial.net>2024-07-27 16:57:39 -0400
committerBenji Dial <benji@benjidial.net>2024-07-27 16:57:39 -0400
commitfbfc078e9f44c1c1e95c9c484f1d5650bcf631b7 (patch)
treecab539c8cbbac81d895b6f8be695f3f53bf8f4d5 /euler/source
parent9af5588c30c4126a2800aae1afcb0de2c373dc6c (diff)
downloadhilbert-os-fbfc078e9f44c1c1e95c9c484f1d5650bcf631b7.tar.gz
lots and lots of userspace stuff
Diffstat (limited to 'euler/source')
-rw-r--r--euler/source/entry.cpp28
-rw-r--r--euler/source/euler/entry.cpp11
-rw-r--r--euler/source/euler/gcc.asm53
-rw-r--r--euler/source/euler/heap.cpp66
-rw-r--r--euler/source/euler/start_process.cpp35
-rw-r--r--euler/source/euler/stream.cpp151
-rw-r--r--euler/source/euler/syscall.asm144
-rw-r--r--euler/source/heap.cpp155
-rw-r--r--euler/source/io/fclose.cpp10
-rw-r--r--euler/source/io/fopen.cpp54
-rw-r--r--euler/source/io/fread.cpp9
-rw-r--r--euler/source/io/fseek.cpp11
-rw-r--r--euler/source/memory/delete.cpp17
-rw-r--r--euler/source/memory/new.cpp13
-rw-r--r--euler/source/std/cctype.cpp7
-rw-r--r--euler/source/std/cstdio.cpp59
-rw-r--r--euler/source/std/cstdlib.cpp19
-rw-r--r--euler/source/std/cstring.cpp36
-rw-r--r--euler/source/std/string.cpp86
-rw-r--r--euler/source/stream.cpp106
-rw-r--r--euler/source/strings/memcpy.cpp14
-rw-r--r--euler/source/strings/strlen.cpp12
-rw-r--r--euler/source/syscall.asm32
-rw-r--r--euler/source/syscall.cpp397
24 files changed, 925 insertions, 600 deletions
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;
+
+ }
+
+}