diff options
Diffstat (limited to 'euler')
-rw-r--r-- | euler/include/cstdio | 15 | ||||
-rw-r--r-- | euler/include/cstring | 8 | ||||
-rw-r--r-- | euler/include/euler/heap.hpp | 8 | ||||
-rw-r--r-- | euler/include/euler/stream.hpp | 48 | ||||
-rw-r--r-- | euler/include/euler/syscall.hpp | 61 | ||||
-rw-r--r-- | euler/makefile | 29 | ||||
-rw-r--r-- | euler/source/empty.asm | 0 | ||||
-rw-r--r-- | euler/source/euler/entry.cpp | 11 | ||||
-rw-r--r-- | euler/source/euler/gcc.asm | 53 | ||||
-rw-r--r-- | euler/source/euler/heap.cpp | 66 | ||||
-rw-r--r-- | euler/source/euler/stream.cpp | 151 | ||||
-rw-r--r-- | euler/source/euler/syscall.asm | 102 | ||||
-rw-r--r-- | euler/source/io/fclose.cpp | 10 | ||||
-rw-r--r-- | euler/source/io/fopen.cpp | 54 | ||||
-rw-r--r-- | euler/source/io/fread.cpp | 9 | ||||
-rw-r--r-- | euler/source/memory/delete.cpp | 17 | ||||
-rw-r--r-- | euler/source/memory/new.cpp | 13 | ||||
-rw-r--r-- | euler/source/strings/memcpy.cpp | 14 | ||||
-rw-r--r-- | euler/source/strings/strlen.cpp | 12 |
19 files changed, 681 insertions, 0 deletions
diff --git a/euler/include/cstdio b/euler/include/cstdio new file mode 100644 index 0000000..27073db --- /dev/null +++ b/euler/include/cstdio @@ -0,0 +1,15 @@ +#pragma once + +#include <euler/stream.hpp> +#include <stddef.h> + +namespace std { + + typedef euler::stream FILE; + + FILE *fopen(const char *filename, const char *mode); + int fclose(FILE *stream); + + size_t fread(void *buffer, size_t size, size_t count, FILE *stream); + +} diff --git a/euler/include/cstring b/euler/include/cstring new file mode 100644 index 0000000..45bc94e --- /dev/null +++ b/euler/include/cstring @@ -0,0 +1,8 @@ +#pragma once + +#include <stddef.h> + +namespace std { + size_t strlen(const char *str); + void *memcpy(void *dest, const void *src, size_t count); +} diff --git a/euler/include/euler/heap.hpp b/euler/include/euler/heap.hpp new file mode 100644 index 0000000..e2a4852 --- /dev/null +++ b/euler/include/euler/heap.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include <stdint.h> + +namespace euler { + void *alloc(uint64_t bytes); + void dealloc(void *start, uint64_t bytes); +} diff --git a/euler/include/euler/stream.hpp b/euler/include/euler/stream.hpp new file mode 100644 index 0000000..a364ec4 --- /dev/null +++ b/euler/include/euler/stream.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include <euler/syscall.hpp> + +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; + + }; + + class file_stream : public stream { + + private: + + __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; + + void write_buffer(); + + public: + + bool good; + + file_stream( + __euler_stream_handle handle, bool is_readable, bool is_writable, + bool clear, bool seek_to_end); + + ~file_stream(); + + bool try_read(void *into, uint64_t bytes) override; + bool try_seek(__euler_seek_from from, int64_t offset) override; + + }; + +} diff --git a/euler/include/euler/syscall.hpp b/euler/include/euler/syscall.hpp new file mode 100644 index 0000000..9255642 --- /dev/null +++ b/euler/include/euler/syscall.hpp @@ -0,0 +1,61 @@ +#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; + +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); + +extern "C" uint32_t __euler_read_key_packet(); diff --git a/euler/makefile b/euler/makefile new file mode 100644 index 0000000..3b8022d --- /dev/null +++ b/euler/makefile @@ -0,0 +1,29 @@ +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 + +clean: + rm -rf build + +build/%.asm.o: source/%.asm + @mkdir -p $(@D) + $(HILBERT_NASM) $^ -o $@ + +build/%.cpp.o: source/%.cpp + @mkdir -p $(@D) + $(HILBERT_CC) -c $^ -o $@ + +build/crt0.o: build/empty.asm.o + cp $^ $@ + +build/libc.a: build/empty.asm.o + $(HILBERT_AR) rcs $@ $^ + +build/libg.a: build/empty.asm.o + $(HILBERT_AR) rcs $@ $^ + +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/empty.asm b/euler/source/empty.asm new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/euler/source/empty.asm diff --git a/euler/source/euler/entry.cpp b/euler/source/euler/entry.cpp new file mode 100644 index 0000000..69611b7 --- /dev/null +++ b/euler/source/euler/entry.cpp @@ -0,0 +1,11 @@ +#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 new file mode 100644 index 0000000..6fc6fd5 --- /dev/null +++ b/euler/source/euler/gcc.asm @@ -0,0 +1,53 @@ +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 new file mode 100644 index 0000000..f7d407f --- /dev/null +++ b/euler/source/euler/heap.cpp @@ -0,0 +1,66 @@ +#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/stream.cpp b/euler/source/euler/stream.cpp new file mode 100644 index 0000000..950f3c5 --- /dev/null +++ b/euler/source/euler/stream.cpp @@ -0,0 +1,151 @@ +#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 new file mode 100644 index 0000000..34f2735 --- /dev/null +++ b/euler/source/euler/syscall.asm @@ -0,0 +1,102 @@ +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_read_key_packet + +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_read_key_packet: + mov rax, 5 + syscall + ret diff --git a/euler/source/io/fclose.cpp b/euler/source/io/fclose.cpp new file mode 100644 index 0000000..6f43f85 --- /dev/null +++ b/euler/source/io/fclose.cpp @@ -0,0 +1,10 @@ +#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 new file mode 100644 index 0000000..8d47bf0 --- /dev/null +++ b/euler/source/io/fopen.cpp @@ -0,0 +1,54 @@ +#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 new file mode 100644 index 0000000..e2d05b6 --- /dev/null +++ b/euler/source/io/fread.cpp @@ -0,0 +1,9 @@ +#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/memory/delete.cpp b/euler/source/memory/delete.cpp new file mode 100644 index 0000000..e4cc288 --- /dev/null +++ b/euler/source/memory/delete.cpp @@ -0,0 +1,17 @@ +#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 new file mode 100644 index 0000000..931328f --- /dev/null +++ b/euler/source/memory/new.cpp @@ -0,0 +1,13 @@ +#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/strings/memcpy.cpp b/euler/source/strings/memcpy.cpp new file mode 100644 index 0000000..d5a1d6c --- /dev/null +++ b/euler/source/strings/memcpy.cpp @@ -0,0 +1,14 @@ +#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 new file mode 100644 index 0000000..7a6fe2a --- /dev/null +++ b/euler/source/strings/strlen.cpp @@ -0,0 +1,12 @@ +#include <cstring> + +namespace std { + + size_t strlen(const char *str) { + size_t len = 0; + while (str[len]) + ++len; + return len; + } + +} |