summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--applications/goldman/makefile2
-rw-r--r--applications/goldman/source/main.cpp79
-rw-r--r--applications/init/source/main.cpp22
-rw-r--r--documentation/compositor.txt2
-rw-r--r--documentation/euler/heap.txt32
-rw-r--r--documentation/kernel-interfaces/syscalls.txt25
-rw-r--r--documentation/kernel/panics.txt1
-rw-r--r--euler/include/algorithm12
-rw-r--r--euler/include/cctype3
-rw-r--r--euler/include/cstdio22
-rw-r--r--euler/include/cstring11
-rw-r--r--euler/include/euler/heap.hpp10
-rw-r--r--euler/include/euler/start_process.hpp30
-rw-r--r--euler/include/euler/stream.hpp47
-rw-r--r--euler/include/euler/syscall.hpp234
-rw-r--r--euler/include/std/allocator.hpp30
-rw-r--r--euler/include/std/string.hpp80
-rw-r--r--euler/include/std/vector.hpp191
-rw-r--r--euler/include/string13
-rw-r--r--euler/include/type_traits23
-rw-r--r--euler/include/utility12
-rw-r--r--euler/include/vector61
-rw-r--r--euler/makefile14
-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
-rw-r--r--kernel/include/hilbert/kernel/application.hpp13
-rw-r--r--kernel/include/hilbert/kernel/panic.hpp2
-rw-r--r--kernel/include/hilbert/kernel/utility.hpp4
-rw-r--r--kernel/makefile3
-rw-r--r--kernel/source/application.asm1
-rw-r--r--kernel/source/application.cpp10
-rw-r--r--kernel/source/syscall.cpp47
-rw-r--r--libraries/daguerre/include/daguerre.hpp209
-rw-r--r--libraries/daguerre/include/daguerre/fixed-font.hpp57
-rw-r--r--libraries/daguerre/include/daguerre/framebuffer.hpp9
-rw-r--r--libraries/daguerre/include/daguerre/general.hpp59
-rw-r--r--libraries/daguerre/include/daguerre/image.hpp118
-rw-r--r--libraries/daguerre/include/daguerre/impl/fixed-font.hpp59
-rw-r--r--libraries/daguerre/include/daguerre/impl/image.hpp217
-rw-r--r--libraries/daguerre/include/daguerre/ppm.hpp20
-rw-r--r--libraries/daguerre/include/daguerre/psf.hpp20
-rw-r--r--libraries/daguerre/makefile2
-rw-r--r--libraries/daguerre/source/daguerre.cpp110
-rw-r--r--libraries/daguerre/source/framebuffer.cpp12
-rw-r--r--libraries/daguerre/source/ppm.cpp60
-rw-r--r--libraries/daguerre/source/psf.cpp51
-rw-r--r--makefile49
-rw-r--r--patches/gcc-memory.patch2
-rw-r--r--patches/mintsuki-stddef.patch14
-rw-r--r--qemu.gdb1
-rw-r--r--readme.txt15
l---------skeleton/assets/background.ppm1
74 files changed, 2345 insertions, 1301 deletions
diff --git a/applications/goldman/makefile b/applications/goldman/makefile
index 5b93fe4..56f633d 100644
--- a/applications/goldman/makefile
+++ b/applications/goldman/makefile
@@ -6,7 +6,7 @@ build/%.cpp.o: source/%.cpp
$(HILBERT_CC) -c $^ -o $@
build/goldman.elf: $(SOURCES:%=build/%.o)
- $(HILBERT_CC) $^ -o $@
+ $(HILBERT_CC) $^ -ldaguerre -o $@
clean:
rm -rf build
diff --git a/applications/goldman/source/main.cpp b/applications/goldman/source/main.cpp
index 28ed00a..d74eaad 100644
--- a/applications/goldman/source/main.cpp
+++ b/applications/goldman/source/main.cpp
@@ -1,4 +1,79 @@
+#include <daguerre/framebuffer.hpp>
+#include <daguerre/ppm.hpp>
+
+daguerre::hilbert_color trans_color;
+
+void convert_pointer(
+ daguerre::hilbert_color &dest, const daguerre::hilbert_color &src) {
+ if (src != trans_color)
+ dest = src;
+}
+
int main(int, char **) {
- while (1)
- ;
+
+ trans_color = euler::syscall::encode_color(0xff, 0x00, 0xff);
+
+ daguerre::image<daguerre::hilbert_color> framebuffer =
+ daguerre::get_hilbert_framebuffer();
+
+ int fw = framebuffer.width;
+ int fh = framebuffer.height;
+
+ daguerre::image<daguerre::hilbert_color> double_buffer(fw, fh);
+
+ std::optional<daguerre::image<daguerre::hilbert_color>>
+ background_original = daguerre::try_load_ppm("/assets/background.ppm");
+
+ daguerre::image<daguerre::hilbert_color> background;
+
+ if (background_original.has_value())
+ background = background_original->stretch(fw, fh);
+ else {
+ background = daguerre::image<daguerre::hilbert_color>(fw, fh);
+ background.fill(euler::syscall::encode_color(0, 0, 0));
+ }
+
+ std::optional<daguerre::image<daguerre::hilbert_color>>
+ pointer_original = daguerre::try_load_ppm("/assets/pointer.ppm");
+
+ if (!pointer_original.has_value())
+ //TODO
+ while (1)
+ ;
+
+ daguerre::image<daguerre::hilbert_color>
+ pointer = std::move(*pointer_original);
+
+ int mouse_x = fw / 2;
+ int mouse_y = fh / 2;
+
+ while (true) {
+
+ double_buffer.copy_from(background, 0, 0);
+ double_buffer.convert_from(pointer, mouse_x, mouse_y, 0, 0,
+ std::min(pointer. width, double_buffer. width - mouse_x),
+ std::min(pointer.height, double_buffer.height - mouse_y),
+ &convert_pointer);
+
+ framebuffer.copy_from(double_buffer, 0, 0);
+
+ auto result = euler::syscall::get_input_packet();
+ if (std::holds_alternative<euler::syscall::mouse_packet>(result)) {
+ const auto &packet = std::get<euler::syscall::mouse_packet>(result);
+ mouse_x += packet.x_changed;
+ mouse_y += packet.y_changed;
+ if (mouse_x < 0)
+ mouse_x = 0;
+ else if (mouse_x >= fw)
+ mouse_x = fw - 1;
+ if (mouse_y < 0)
+ mouse_y = 0;
+ else if (mouse_y >= fh)
+ mouse_y = fh - 1;
+ }
+
+ }
+
+ return 0;
+
}
diff --git a/applications/init/source/main.cpp b/applications/init/source/main.cpp
index 5dfa81a..ca137a4 100644
--- a/applications/init/source/main.cpp
+++ b/applications/init/source/main.cpp
@@ -1,19 +1,11 @@
-#include <euler/start_process.hpp>
+#include <euler/syscall.hpp>
-int main(int, char **) {
-
- __euler_process_handle dummy;
-
- euler::start_process wm_process("/bin/compositor");
- wm_process.add_env_variable("ARGC", "1");
- wm_process.add_env_variable("ARGV0", "/bin/compositor");
- wm_process.start(dummy);
-
- euler::start_process hello_process("/bin/hello");
- hello_process.add_env_variable("ARGC", "1");
- hello_process.add_env_variable("ARGV0", "/bin/hello");
- hello_process.start(dummy);
+//this does not keep track of the processes or whether they have started
+//successfully, nor does it set their argc, argv, stdin, stdout, or stderr.
+int main(int, char **) {
+ euler::syscall::process_handle dummy;
+ euler::syscall::start_process("/bin/compositor", {}, {}, dummy);
+ euler::syscall::start_process("/bin/hello", {}, {}, dummy);
return 0;
-
}
diff --git a/documentation/compositor.txt b/documentation/compositor.txt
index 7442d51..4d8e70f 100644
--- a/documentation/compositor.txt
+++ b/documentation/compositor.txt
@@ -13,7 +13,7 @@ data types:
color:
opaque dword (result of encode color system call).
- from c++, use __euler_encode_color in euler/syscall.hpp.
+ from c++, use euler::syscall::encode_color in euler/syscall.hpp.
color rectangle:
multiple hilbert colors, top to bottom by row, left to right within row
diff --git a/documentation/euler/heap.txt b/documentation/euler/heap.txt
deleted file mode 100644
index de1deec..0000000
--- a/documentation/euler/heap.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-this file documents dynamic memory allocation and deallocation in userspace.
-the unused areas of a process's usable mapped memory are divided into "chunks"
-with a start and a length, satisfying the following properties:
- a) the length of a chunk is a positive power of 2
- b) the start of a chunk is a multiple of its length
- c) let s be a power of 2 and k be an integer. there are never two chunks with
- length s and starts s * (2 * k) and s * (2 * k + 1). if ever an operation
- would result in two such chunks, they are combined into one chunk with
- length 2 * s and start 2 * s * k.
-
-a "chunk info page" is divided into 512 64-bit integers describing up to 255
-chunks and a pointer to another chunk info page. for each n from 0 to 254:
- if the (2 * n)'th integer (where the first integer is the 0th one) is 0:
- the (2 * n + 1)'th integer is unused.
- if the (2 * n)'th integer is not 0:
- the (2 * n)'th integer describes the length of a chunk
- the (2 * n + 1)'th integer describes the start of the same chunk
-the 510th integer is a pointer to the next chunk info page, and the 511th
-integer is never used.
-
-when a program calls new or malloc with needed size s, we find a free chunk of
-length at least s + 8. we then remove that chunk from the list of free chunks,
-and add back in whatever is left after the first s + 8 bytes, if anything.
-in the first 8 bytes of the original chunk, we store the value s + 8. the
-remainder of the orginal chunk is returned to the program.
-
-during that process, if there isn't a chunk with the needed size, one or more
-new pages are requested from the kernel to create such a chunk.
-
-when a program calls delete or free with pointer ptr, we read the integer in
-the 8 bytes starting at ptr - 8 into a variable s. we then add the region
-starting at ptr - 8 with length s to the free memory.
diff --git a/documentation/kernel-interfaces/syscalls.txt b/documentation/kernel-interfaces/syscalls.txt
index ca93b56..399eb19 100644
--- a/documentation/kernel-interfaces/syscalls.txt
+++ b/documentation/kernel-interfaces/syscalls.txt
@@ -20,6 +20,7 @@ stream result:
12 = other end closed
13 = already exists
14 = not sized
+ 15 = not readable
encode color:
rax in: 0
@@ -173,3 +174,27 @@ get other end process handle:
rdi in: stream handle
rax out: stream result
rdi out: process handle (if rax = success)
+
+start thread:
+ rax in: 20
+ rdi in: entry point
+ rsi in: argument
+ at entry, rsp is set to the top of a new stack, rdi is set
+ to the argument, and the other registers are undefined.
+
+clear socket read queue:
+ rax in: 21
+ rdi in: stream handle
+ rax out: number of bytes cleared (0 on bad handle or not a socket)
+
+get environment variable length:
+ rax in: 22
+ rdi in: pointer to variable name
+ rsi in: variable name length
+ rax out: variable value length, or -1 if unset
+
+get environment variable value:
+ rax in: 23
+ rdi in: pointer to variable name
+ rsi in: variable name length
+ rdx in: pointer to buffer for variable value
diff --git a/documentation/kernel/panics.txt b/documentation/kernel/panics.txt
index e1b6ec1..5c09490 100644
--- a/documentation/kernel/panics.txt
+++ b/documentation/kernel/panics.txt
@@ -3,6 +3,7 @@ panic. the following are the defined colors so far:
#48a6ed - failed to get root node of initfs
#5f8860 - no initfs module was given
#7e874d - failed to look up /bin/init
+ #8077a6 - pure virtual function called (i think this should never happen?)
#9af5e6 - an unimplemented path in the kernel
#ba40bb - cpu exception occurred
#c39db3 - failed to parse /bin/init
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;
+
+ }
+
+}
diff --git a/kernel/include/hilbert/kernel/application.hpp b/kernel/include/hilbert/kernel/application.hpp
index 56c2a15..a4b59ff 100644
--- a/kernel/include/hilbert/kernel/application.hpp
+++ b/kernel/include/hilbert/kernel/application.hpp
@@ -22,7 +22,8 @@ namespace hilbert::kernel::application {
socket_listener_closed,
other_end_closed,
already_exists,
- not_sized
+ not_sized,
+ not_readable
};
struct [[gnu::packed]] cpu_state {
@@ -57,10 +58,10 @@ namespace hilbert::kernel::application {
class process;
class thread;
- class file_stream;
- class socket;
- class socket_stream_end;
- class socket_listener;
+ struct file_stream;
+ struct socket;
+ struct socket_stream_end;
+ struct socket_listener;
struct generic_stream_ptr {
bool is_socket;
@@ -93,7 +94,7 @@ namespace hilbert::kernel::application {
//saves running thread state, and switches to new task. when the thread is
//resumed, returns to caller.
- extern "C" void yield();
+ extern "C" void yield(cpu_state &save_state_into);
extern "C" [[noreturn]] void resume_next_thread();
diff --git a/kernel/include/hilbert/kernel/panic.hpp b/kernel/include/hilbert/kernel/panic.hpp
index 0478142..3aadddb 100644
--- a/kernel/include/hilbert/kernel/panic.hpp
+++ b/kernel/include/hilbert/kernel/panic.hpp
@@ -1,5 +1,5 @@
#pragma once
namespace hilbert::kernel {
- [[noreturn]] void panic(uint32_t code);
+ extern "C" [[noreturn]] void panic(uint32_t code);
}
diff --git a/kernel/include/hilbert/kernel/utility.hpp b/kernel/include/hilbert/kernel/utility.hpp
index 0247fee..b7f1a1b 100644
--- a/kernel/include/hilbert/kernel/utility.hpp
+++ b/kernel/include/hilbert/kernel/utility.hpp
@@ -381,6 +381,10 @@ namespace hilbert::kernel::utility {
count = written;
}
+ void clear() {
+ count = 0;
+ }
+
};
template <class t>
diff --git a/kernel/makefile b/kernel/makefile
index 9ec5be6..6d32537 100644
--- a/kernel/makefile
+++ b/kernel/makefile
@@ -10,7 +10,8 @@ build/%.asm.o: source/%.asm
build/%.cpp.o: source/%.cpp
@mkdir -p $(@D)
- $(HILBERT_CC) -c -ffreestanding -mcmodel=kernel -I ${LIMINE_DIR} $^ -o $@
+ $(HILBERT_CC) -c -ffreestanding -fno-exceptions -fno-rtti \
+ -mcmodel=kernel -I ${LIMINE_DIR} -I ${MINTSUKI_HEADERS_DIR} $^ -o $@
build/kernel.elf: $(SOURCES:%=build/%.o)
$(HILBERT_LD) -T link.ld $^ -o $@
diff --git a/kernel/source/application.asm b/kernel/source/application.asm
index 632822f..fb19826 100644
--- a/kernel/source/application.asm
+++ b/kernel/source/application.asm
@@ -140,6 +140,7 @@ extern copy_syscall_stack
;returns: pointer to copy
extern resume_next_thread
+extern running_thread
global yield
yield:
diff --git a/kernel/source/application.cpp b/kernel/source/application.cpp
index 0c3fd36..8070019 100644
--- a/kernel/source/application.cpp
+++ b/kernel/source/application.cpp
@@ -239,7 +239,7 @@ namespace hilbert::kernel::application {
void thread::wait_for_socket_stream(socket_stream_end *the_socket_stream) {
waiting_for_socket_stream = the_socket_stream;
the_socket_stream->waiting_to_read.insert(this);
- yield();
+ yield(saved_state);
waiting_for_socket_stream = 0;
}
@@ -247,7 +247,7 @@ namespace hilbert::kernel::application {
socket_listener *the_socket_listener) {
waiting_to_accept_from = the_socket_listener;
the_socket_listener->waiting_to_accept.insert(this);
- yield();
+ yield(saved_state);
waiting_to_accept_from = 0;
return new_socket_stream_id;
}
@@ -256,15 +256,15 @@ namespace hilbert::kernel::application {
socket_listener *the_socket_listener) {
waiting_to_connect_to = the_socket_listener;
the_socket_listener->waiting_to_connect.insert(this);
- yield();
+ yield(saved_state);
waiting_to_connect_to = 0;
return new_socket_stream_id;
}
void thread::wait_for_input() {
- waiting_for_input = false;
+ waiting_for_input = true;
input::waiting_for_input->insert(this);
- yield();
+ yield(saved_state);
waiting_for_input = false;
}
diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp
index 6b0f13f..f2a6801 100644
--- a/kernel/source/syscall.cpp
+++ b/kernel/source/syscall.cpp
@@ -700,10 +700,44 @@ namespace hilbert::kernel::syscall {
}
- typedef void (*syscall_handler)(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
+ void start_thread_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
+
+ uint64_t entry_point = rdi;
+ uint64_t argument = rsi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *p = application::running_thread->owner;
+ auto *t = new application::thread(p, entry_point);
+ t->saved_state.rdi = argument;
+ p->add_thread(t);
+ application::paused_threads->insert(t);
+
+ }
+
+ void clear_socket_read_queue_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto stream = application::running_thread->owner->get_stream(handle);
+
+ if (stream.is_null() || !stream.is_socket) {
+ rax = 0;
+ return;
+ }
+
+ auto &queue = stream.as_socket_stream->read_queue;
+
+ rax = queue.count;
+ queue.clear();
+
+ }
+
+ void (*handlers[])(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) = {
- syscall_handler handlers[] = {
&encode_color_syscall,
&get_framebuffer_syscall,
&open_file_syscall,
@@ -723,10 +757,13 @@ namespace hilbert::kernel::syscall {
&start_process_syscall,
&end_this_process_syscall,
&set_stream_length_syscall,
- &get_other_end_process_handle_syscall
+ &get_other_end_process_handle_syscall,
+ &start_thread_syscall,
+ &clear_socket_read_queue_syscall
+
};
- static constexpr int max_syscall_number = 19;
+ static constexpr int max_syscall_number = 20;
}
diff --git a/libraries/daguerre/include/daguerre.hpp b/libraries/daguerre/include/daguerre.hpp
deleted file mode 100644
index 9468826..0000000
--- a/libraries/daguerre/include/daguerre.hpp
+++ /dev/null
@@ -1,209 +0,0 @@
-#pragma once
-
-#include <algorithm>
-#include <stdint.h>
-#include <cstring>
-#include <cstdio>
-
-namespace daguerre {
-
- typedef uint32_t hilbert_color;
-
- struct rgb24 {
- uint8_t r;
- uint8_t g;
- uint8_t b;
- };
-
- template <class color_t>
- static inline void default_overlay(color_t &dest, const color_t &src) {
- dest = src;
- }
-
- static inline void default_overlay(hilbert_color &dest, const rgb24 &src) {
- dest = __euler_encode_color(src.r, src.g, src.b);
- }
-
- static inline void default_overlay(rgb24 &dest, const bool &src) {
- dest.r = src ? 255 : 0;
- dest.g = src ? 255 : 0;
- dest.b = src ? 255 : 0;
- }
-
- template <class color_t>
- class image {
-
- public:
- bool delete_buffer_on_destruct;
- color_t *buffer;
- unsigned width;
- unsigned height;
- unsigned pitch;//in sizeof(color_t)
-
- image()
- : delete_buffer_on_destruct(false), buffer(0), width(0), height(0),
- pitch(0) {}
-
- image(unsigned width, unsigned height)
- : delete_buffer_on_destruct(true), buffer(new color_t[width * height]),
- width(width), height(height), pitch(width) {}
-
- image(
- color_t *buffer, unsigned width, unsigned height, unsigned pitch,
- bool delete_buffer_on_destruct)
- : delete_buffer_on_destruct(delete_buffer_on_destruct), buffer(buffer),
- width(width), height(height), pitch(pitch) {}
-
- ~image() {
- if (delete_buffer_on_destruct && buffer)
- delete[] buffer;
- }
-
- template <class other_color_t,
- void overlay(color_t &, const other_color_t &) = default_overlay>
- image(const image<other_color_t> &other)
- : delete_buffer_on_destruct(true),
- buffer(new color_t[other.width * other.height]), width(other.width),
- height(other.height), pitch(other.width) {
- overlay_from<other_color_t, overlay>(other, 0, 0, 0, 0, width, height);
- }
-
- image(image<color_t> &&other)
- : delete_buffer_on_destruct(other.delete_buffer_on_destruct),
- buffer(other.buffer), width(other.width), height(other.height),
- pitch(other.pitch) {
- other.buffer = 0;
- }
-
- template <class other_color_t,
- void overlay(color_t &, const other_color_t &) = default_overlay>
- image<color_t> &operator =(const image<other_color_t> &other) {
- if (delete_buffer_on_destruct && buffer)
- delete[] buffer;
- delete_buffer_on_destruct = true;
- width = other.width;
- height = other.height;
- pitch = width;
- buffer = new color_t[width * height];
- overlay_from<other_color_t, overlay>(other, 0, 0, 0, 0, width, height);
- return *this;
- }
-
- image<color_t> &operator =(image<color_t> &&other) {
- if (delete_buffer_on_destruct && buffer)
- delete[] buffer;
- delete_buffer_on_destruct = other.delete_buffer_on_destruct;
- buffer = other.buffer;
- width = other.width;
- height = other.height;
- pitch = other.pitch;
- other.buffer = 0;
- return *this;
- }
-
- color_t get(unsigned x, unsigned y) const {
- return buffer[y * pitch + x];
- }
-
- void set(unsigned x, unsigned y, const color_t &c) {
- buffer[y * pitch + x] = c;
- }
-
- void copy_from(
- const image<color_t> &other, unsigned to_x, unsigned to_y,
- unsigned from_x, unsigned from_y, unsigned width, unsigned height) {
-
- color_t *to_start = buffer + pitch * to_y + to_x;
- const color_t *from_start = other.buffer + other.pitch * from_y + from_x;
-
- for (unsigned y = 0; y < height; ++y)
- std::memcpy(
- to_start + pitch * y, from_start + other.pitch * y,
- width * sizeof(color_t));
-
- }
-
- template <class other_color_t,
- void overlay(color_t &, const other_color_t &) = default_overlay>
- void overlay_from(
- const image<other_color_t> &other, unsigned to_x, unsigned to_y,
- unsigned from_x, unsigned from_y, unsigned width, unsigned height) {
-
- color_t *to_start = buffer + pitch * to_y + to_x;
- const other_color_t *from_start =
- other.buffer + other.pitch * from_y + from_x;
-
- for (unsigned y = 0; y < height; ++y)
- for (unsigned x = 0; x < width; ++x)
- overlay(to_start[pitch * y + x], from_start[other.pitch * y + x]);
-
- }
-
- };
-
- template <class color_t>
- void swap(image<color_t> &a, image<color_t> &b) {
- std::swap(a.delete_buffer_on_destruct, b.delete_buffer_on_destruct);
- std::swap(a.buffer, b.buffer);
- std::swap(a.width, b.width);
- std::swap(a.height, b.height);
- std::swap(a.pitch, b.pitch);
- }
-
- image<hilbert_color> get_hilbert_framebuffer();
-
- bool try_load_ppm(std::FILE *input, image<rgb24> &into);
-
- static inline bool try_load_ppm(const char *path, image<rgb24> &into) {
- std::FILE *f = std::fopen(path, "r");
- if (!f)
- return false;
- bool success = try_load_ppm(f, into);
- std::fclose(f);
- return success;
- }
-
- //TODO: unicode
- template <class color_t>
- class fixed_bitmap_font {
-
- public:
- unsigned width;
- unsigned height;
- image<color_t> glyphs[128];
-
- template <class target_color_t,
- void overlay(target_color_t &dest, const color_t &src) = default_overlay>
- void overlay_text(
- image<target_color_t> &target, unsigned x,
- unsigned y, const char *text) const {
-
- while (1) {
- uint8_t ch = (uint8_t)*text;
- if (ch == 0)
- return;
- if (ch < 128) {
- target.template overlay_from<color_t, overlay>(
- glyphs[ch], x, y, 0, 0, width, height);
- x += width;
- }
- ++text;
- }
-
- }
-
- };
-
- bool try_load_psf(std::FILE *input, fixed_bitmap_font<bool> &into);
-
- static inline bool try_load_psf(
- const char *path, fixed_bitmap_font<bool> &into) {
- std::FILE *f = std::fopen(path, "r");
- if (!f)
- return false;
- bool success = try_load_psf(f, into);
- std::fclose(f);
- return success;
- }
-
-}
diff --git a/libraries/daguerre/include/daguerre/fixed-font.hpp b/libraries/daguerre/include/daguerre/fixed-font.hpp
new file mode 100644
index 0000000..471163a
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/fixed-font.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <daguerre/general.hpp>
+
+//TODO: support more than just ascii
+
+namespace daguerre {
+
+ //forward declare since these depend on each other
+ template <class color_t>
+ class image;
+
+ template <class color_t>
+ class fixed_font {
+
+ public:
+ int glyph_width;
+ int glyph_height;
+ image<color_t> glyphs[128];
+
+ //initializes every glyph to an empty image
+ fixed_font();
+
+ //initializes each glyph to have the right dimensions and
+ //a valid buffer, but does nothing to their contents.
+ fixed_font(int glyph_width, int glyph_height);
+
+ //moves the other font's glyphs here, then
+ //sets the other font to have empty images.
+ fixed_font(fixed_font<color_t> &&other);
+
+ //moves the other font's glyphs here, then
+ //sets the other font to have empty images.
+ fixed_font<color_t> &operator =(fixed_font<color_t> &&other);
+
+ //use one of the two constructors below instead
+ fixed_font(const fixed_font<color_t> &other) = delete;
+
+ //copies the other font's images here, passing them through conversion.
+ template <class other_color_t>
+ fixed_font(const fixed_font<other_color_t> &other,
+ converter_t<color_t, other_color_t> *conversion = &default_conversion);
+
+ //directly calls memcpy on the images' buffers. the second argument
+ //does nothing except distinguish this from the other copy constructor.
+ fixed_font(const fixed_font<color_t> &other, bool);
+
+ //use copy constructor and move assignment instead
+ fixed_font<color_t> &operator =(const fixed_font<color_t> &other) = delete;
+
+ ~fixed_font() = default;
+
+ };
+
+}
+
+#include <daguerre/impl/fixed-font.hpp>
diff --git a/libraries/daguerre/include/daguerre/framebuffer.hpp b/libraries/daguerre/include/daguerre/framebuffer.hpp
new file mode 100644
index 0000000..c9a5226
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/framebuffer.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <daguerre/image.hpp>
+
+namespace daguerre {
+
+ image<hilbert_color> get_hilbert_framebuffer();
+
+}
diff --git a/libraries/daguerre/include/daguerre/general.hpp b/libraries/daguerre/include/daguerre/general.hpp
new file mode 100644
index 0000000..78c6919
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/general.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <euler/syscall.hpp>
+#include <stdint.h>
+
+namespace daguerre {
+
+ typedef euler::syscall::encoded_color hilbert_color;
+
+ struct rgb24 {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ };
+
+ template <class dest_t, class src_t>
+ using converter_t = void (dest_t &, const src_t &);
+
+ //copies src to dest
+ template <class color_t>
+ static inline void default_conversion(color_t &dest, const color_t &src) {
+ dest = src;
+ }
+
+ //encodes src and copies that to dest
+ static inline void default_conversion(hilbert_color &dest, const rgb24 &src) {
+ dest = euler::syscall::encode_color(src.r, src.g, src.b);
+ }
+
+ template <class dest_t, class src_t, class param_t>
+ using param_converter_t = void (dest_t &, const src_t &, const param_t &);
+
+ //if src is true, copies param to dest.
+ //if src is false, does nothing.
+ template <class color_t>
+ static inline void default_conversion(
+ color_t &dest, const bool &src, const color_t &param) {
+ if (src)
+ dest = param;
+ }
+
+ //intersects [to, to + length) with [min, max) at stores the result in
+ //[to, to + length). if anything was removed from either end, the same
+ //amount is removed from the same end(s) of [from, from + length)
+ static inline void make_safe(
+ int &to, int &from, int &length, int min, int max) {
+
+ if (to < min) {
+ from += min - to;
+ length -= min - to;
+ to = min;
+ }
+
+ if (to + length > max)
+ length = max - to;
+
+ }
+
+}
diff --git a/libraries/daguerre/include/daguerre/image.hpp b/libraries/daguerre/include/daguerre/image.hpp
new file mode 100644
index 0000000..4c44dd0
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/image.hpp
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <daguerre/general.hpp>
+
+namespace daguerre {
+
+ //forward declare since these depend on each other
+ template <class color_t>
+ class fixed_font;
+
+ template <class color_t>
+ class image {
+
+ public:
+ bool delete_buffer_on_destruct;
+ int width;
+ int height;
+ color_t *buffer;
+ int buffer_pitch;//in sizeof(color_t)
+
+ //makes empty image
+ image();
+
+ //make image with specified dimensions, contents uninitialized
+ image(int width, int height);
+
+ //make image with specified dimensions and buffer
+ image(
+ int width, int height, color_t *buffer,
+ int buffer_pitch, bool delete_buffer_on_destruct);
+
+ //moves the other image's data here, and
+ //then sets the other image to an empty one.
+ image(image<color_t> &&other);
+
+ //moves the other image's data here, and
+ //then sets the other image to an empty one.
+ image<color_t> &operator =(image<color_t> &&other);
+
+ //use one of the two constructors below instead
+ image(const image<color_t> &other) = delete;
+
+ //copies the other image's data here, passing it through conversion
+ template <class other_color_t>
+ image(const image<other_color_t> &other,
+ converter_t<color_t, other_color_t> *conversion = &default_conversion);
+
+ //directly calls memcpy on the buffer. the second argument does
+ //nothing except distinguish this from the other copy constructor.
+ image(const image<color_t> &other, bool);
+
+ //use copy constructor and move assignment instead
+ image<color_t> &operator =(const image<color_t> &other) = delete;
+
+ ~image();
+
+ void fill(const color_t &color);
+
+ //does not check bounds
+ color_t &at(int x, int y);
+
+ //does not check bounds
+ const color_t &at(int x, int y) const;
+
+ image<color_t> stretch(int new_width, int new_height);
+
+ //copies the region here via memcpy. does not check bounds.
+ void copy_from(
+ const image<color_t> &other, int to_x, int to_y,
+ int from_x, int from_y, int width, int height);
+
+ //copies the entire image here via memcpy. does not check bounds.
+ void copy_from(const image<color_t> &other, int to_x, int to_y);
+
+ //copies the region here through conversion. does not check bounds.
+ template <class other_color_t>
+ void convert_from(
+ const image<other_color_t> &other, int to_x, int to_y,
+ int from_x, int from_y, int width, int height,
+ converter_t<color_t, other_color_t> *conversion = &default_conversion);
+
+ //copies the entire image here through conversion. does not check bounds.
+ template <class other_color_t>
+ void convert_from(
+ const image<other_color_t> &other, int to_x, int to_y,
+ converter_t<color_t, other_color_t> *conversion = &default_conversion);
+
+ //copies the region here through conversion. does not check bounds.
+ template <class other_color_t, class param_t>
+ void convert_from(
+ const param_t &param, const image<other_color_t> &other, int to_x,
+ int to_y, int from_x, int from_y, int width, int height,
+ param_converter_t<color_t, other_color_t, param_t> *conversion =
+ &default_conversion);
+
+ //copies the entire image here through conversion. does not check bounds.
+ template <class other_color_t, class param_t>
+ void convert_from(const param_t &param,
+ const image<other_color_t> &other, int to_x, int to_y,
+ param_converter_t<color_t, other_color_t, param_t> *conversion =
+ &default_conversion);
+
+ //does not check bounds or wrap text
+ template <class font_color_t, class param_t>
+ void render_text(
+ const fixed_font<font_color_t> &font,
+ const param_t &pararm, int x, int y, const char *text,
+ param_converter_t<color_t, font_color_t, param_t> *conversion =
+ &default_conversion);
+
+ };
+
+ template <class color_t>
+ void swap(image<color_t> &a, image<color_t> &b);
+
+}
+
+#include <daguerre/impl/image.hpp>
diff --git a/libraries/daguerre/include/daguerre/impl/fixed-font.hpp b/libraries/daguerre/include/daguerre/impl/fixed-font.hpp
new file mode 100644
index 0000000..dbff798
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/impl/fixed-font.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+//this file should only be included from <daguerre/fixed-font.hpp>
+
+#include <daguerre/image.hpp>
+#include <utility>
+
+namespace daguerre {
+
+ template<class color_t>
+ fixed_font<color_t>::fixed_font() : glyph_width(0), glyph_height(0) {}
+
+ template <class color_t>
+ fixed_font<color_t>::fixed_font(int glyph_width, int glyph_height)
+ : glyph_width(glyph_width), glyph_height(glyph_height) {
+ for (int i = 0; i < 128; ++i)
+ glyphs[i] = image<color_t>(glyph_width, glyph_height);
+ }
+
+ template <class color_t>
+ fixed_font<color_t>::fixed_font(fixed_font<color_t> &&other)
+ : glyph_width(other.glyph_width), glyph_height(other.glyph_height) {
+ for (int i = 0; 0 < 128; ++i)
+ glyphs[i] = std::move(other.glyphs[i]);
+ other.glyph_width = 0;
+ other.glyph_height = 0;
+ }
+
+ template <class color_t>
+ fixed_font<color_t> &fixed_font<color_t>::operator =(
+ fixed_font<color_t> &&other) {
+ glyph_width = other.glyph_width;
+ glyph_height = other.glyph_height;
+ for (int i = 0; 0 < 128; ++i)
+ glyphs[i] = std::move(other.glyphs[i]);
+ other.glyph_width = 0;
+ other.glyph_height = 0;
+ }
+
+ template <class color_t>
+ template <class other_color_t>
+ fixed_font<color_t>::fixed_font(
+ const fixed_font<other_color_t> &other,
+ converter_t<color_t, other_color_t> *conversion)
+ : glyph_width(other.glyph_width), glyph_height(other.glyph_height) {
+ for (int i = 0; i < 128; ++i)
+ glyphs[i] = image<color_t>(other.glyphs[i], conversion);
+ }
+
+ template <class color_t>
+ fixed_font<color_t>::fixed_font(const fixed_font<color_t> &other, bool)
+ : glyph_width(other.glyph_width), glyph_height(other.glyph_height) {
+ for (int i = 0; i < 128; ++i)
+ glyphs[i] = image<color_t>(other.glyphs[i], true);
+ }
+
+}
+
+#include <daguerre/image.hpp>
diff --git a/libraries/daguerre/include/daguerre/impl/image.hpp b/libraries/daguerre/include/daguerre/impl/image.hpp
new file mode 100644
index 0000000..1264879
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/impl/image.hpp
@@ -0,0 +1,217 @@
+#pragma once
+
+//this file should only be included from <daguerre/image.hpp>
+
+#include <daguerre/fixed-font.hpp>
+#include <algorithm>
+#include <cstring>
+
+namespace daguerre {
+
+ template <class color_t>
+ image<color_t>::image()
+ : delete_buffer_on_destruct(false), width(0),
+ height(0), buffer(0), buffer_pitch(0) {}
+
+ template <class color_t>
+ image<color_t>::image(int width, int height)
+ : delete_buffer_on_destruct(true), width(width), height(height),
+ buffer(new color_t[width * height]), buffer_pitch(width) {}
+
+ template <class color_t>
+ image<color_t>::image(
+ int width, int height, color_t *buffer,
+ int buffer_pitch, bool delete_buffer_on_destruct)
+ : delete_buffer_on_destruct(delete_buffer_on_destruct), width(width),
+ height(height), buffer(buffer), buffer_pitch(buffer_pitch) {}
+
+ template <class color_t>
+ image<color_t>::image(image<color_t> &&other)
+ : delete_buffer_on_destruct(other.delete_buffer_on_destruct),
+ width(other.width), height(other.height), buffer(other.buffer),
+ buffer_pitch(other.buffer_pitch) {
+
+ other.width = 0;
+ other.height = 0;
+ other.buffer = 0;
+
+ }
+
+ template<class color_t>
+ image<color_t> &image<color_t>::operator =(image<color_t> &&other) {
+
+ if (delete_buffer_on_destruct && buffer)
+ delete[] buffer;
+
+ delete_buffer_on_destruct = other.delete_buffer_on_destruct;
+ width = other.width;
+ height = other.height;
+ buffer = other.buffer;
+ buffer_pitch = other.buffer_pitch;
+
+ other.width = 0;
+ other.height = 0;
+ other.buffer = 0;
+
+ return *this;
+
+ }
+
+ template <class color_t>
+ template <class other_color_t>
+ image<color_t>::image(const image<other_color_t> &other,
+ converter_t<color_t, other_color_t> *conversion)
+ : delete_buffer_on_destruct(true), width(other.width),
+ height(other.height), buffer(new color_t[other.width * other.height]),
+ buffer_pitch(other.width) {
+
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ conversion(
+ buffer[y * buffer_pitch + x],
+ other.buffer[y * other.buffer_pitch + x]);
+
+ }
+
+ template <class color_t>
+ image<color_t>::image(const image<color_t> &other, bool)
+ : delete_buffer_on_destruct(true), width(width), height(other.height),
+ buffer(new color_t[other.width * other.height]),
+ buffer_pitch(other.width) {
+
+ if (buffer_pitch == other.buffer_pitch)
+ memcpy(buffer, other.buffer, (height - 1) * buffer_pitch + width);
+
+ else
+ for (int y = 0; y < height; ++y)
+ memcpy(buffer + y * buffer_pitch,
+ other.buffer + y * other.buffer_pitch,
+ sizeof(color_t) * width);
+
+ }
+
+ template <class color_t>
+ image<color_t>::~image() {
+ if (delete_buffer_on_destruct && buffer)
+ delete[] buffer;
+ }
+
+ template <class color_t>
+ void image<color_t>::fill(const color_t &color) {
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ buffer[y * buffer_pitch + x] = color;
+ }
+
+ template <class color_t>
+ color_t &image<color_t>::at(int x, int y) {
+ return buffer[y * buffer_pitch + x];
+ }
+
+ template <class color_t>
+ const color_t &image<color_t>::at(int x, int y) const {
+ return buffer[y * buffer_pitch + x];
+ }
+
+ template <class color_t>
+ image<color_t> image<color_t>::stretch(int new_width, int new_height) {
+ image<color_t> im(new_width, new_height);
+ for (int y = 0; y < new_height; ++y)
+ for (int x = 0; x < new_width; ++x)
+ im.at(x, y) = at(x * width / new_width, y * height / new_height);
+ return im;
+ }
+
+ template <class color_t>
+ void image<color_t>::copy_from(
+ const image<color_t> &other, int to_x, int to_y,
+ int from_x, int from_y, int width, int height) {
+
+ color_t *to = buffer + to_y * buffer_pitch + to_x;
+ const color_t *from = other.buffer + from_y * other.buffer_pitch + from_x;
+
+ for (int y = 0; y < height; ++y)
+ memcpy(
+ to + y * buffer_pitch,
+ from + y * other.buffer_pitch,
+ width * sizeof(color_t));
+
+ }
+
+ template <class color_t>
+ void image<color_t>::copy_from(
+ const image<color_t> &other, int to_x, int to_y) {
+ copy_from(other, to_x, to_y, 0, 0, other.width, other.height);
+ }
+
+ template <class color_t>
+ template <class other_color_t>
+ void image<color_t>::convert_from(
+ const image<other_color_t> &other, int to_x, int to_y,
+ int from_x, int from_y, int width, int height,
+ converter_t<color_t, other_color_t> *conversion) {
+
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ conversion(at(to_x + x, to_y + y), other.at(from_x + x, from_y + y));
+
+ }
+
+ template <class color_t>
+ template <class other_color_t>
+ void image<color_t>::convert_from(
+ const image<other_color_t> &other, int to_x, int to_y,
+ converter_t<color_t, other_color_t> *conversion) {
+ convert_from(other, to_x, to_y, 0, 0, other.width, other.y, conversion);
+ }
+
+ template <class color_t>
+ template <class other_color_t, class param_t>
+ void image<color_t>::convert_from(
+ const param_t &param, const image<other_color_t> &other, int to_x,
+ int to_y, int from_x, int from_y, int width, int height,
+ param_converter_t<color_t, other_color_t, param_t> *conversion) {
+
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ conversion(
+ at(to_x + x, to_y + y), other.at(from_x + x, from_y + y), param);
+
+ }
+
+ template <class color_t>
+ template <class other_color_t, class param_t>
+ void image<color_t>::convert_from(
+ const param_t &param, const image<other_color_t> &other, int to_x,
+ int to_y, param_converter_t<color_t, other_color_t, param_t> *conversion) {
+ convert_from(
+ param, other, to_x, to_y, 0, 0, other.width, other.y, conversion);
+ }
+
+ template <class color_t>
+ template <class font_color_t, class param_t>
+ void image<color_t>::render_text(
+ const fixed_font<font_color_t> &font,
+ const param_t &param, int x, int y, const char *text,
+ param_converter_t<color_t, font_color_t, param_t> *conversion) {
+
+ while (*text) {
+ int ch = *text;
+ if (ch >= 0 && ch < 128)
+ convert_from(param, font.glyphs[ch], x, y, conversion);
+ ++text;
+ x += font.glyph_width;
+ }
+
+ }
+
+ template <class color_t>
+ void swap(image<color_t> &a, image<color_t> &b) {
+ std::swap(a.delete_buffer_on_destruct, b.delete_buffer_on_destruct);
+ std::swap(a.width, b.width);
+ std::swap(a.height, b.height);
+ std::swap(a.buffer, b.buffer);
+ std::swap(a.buffer_pitch, b.buffer_pitch);
+ }
+
+}
diff --git a/libraries/daguerre/include/daguerre/ppm.hpp b/libraries/daguerre/include/daguerre/ppm.hpp
new file mode 100644
index 0000000..5249c98
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/ppm.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <daguerre/image.hpp>
+#include <optional>
+#include <cstdio>
+
+namespace daguerre {
+
+ std::optional<image<rgb24>> try_load_ppm(FILE *input);
+
+ static inline std::optional<image<rgb24>> try_load_ppm(const char *path) {
+ FILE *f = fopen(path, "r");
+ if (!f)
+ return {};
+ auto result = try_load_ppm(f);
+ fclose(f);
+ return result;
+ }
+
+}
diff --git a/libraries/daguerre/include/daguerre/psf.hpp b/libraries/daguerre/include/daguerre/psf.hpp
new file mode 100644
index 0000000..e38cdc4
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/psf.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <daguerre/fixed-font.hpp>
+#include <optional>
+#include <cstdio>
+
+namespace daguerre {
+
+ std::optional<fixed_font<bool>> try_load_psf(FILE *input);
+
+ static inline std::optional<fixed_font<bool>> try_load_psf(const char *path) {
+ FILE *f = fopen(path, "r");
+ if (!f)
+ return {};
+ auto result = try_load_psf(f);
+ fclose(f);
+ return result;
+ }
+
+}
diff --git a/libraries/daguerre/makefile b/libraries/daguerre/makefile
index 3505d35..f428193 100644
--- a/libraries/daguerre/makefile
+++ b/libraries/daguerre/makefile
@@ -1,5 +1,5 @@
SOURCES = \
- daguerre.cpp
+ framebuffer.cpp ppm.cpp psf.cpp
build/%.cpp.o: source/%.cpp
@mkdir -p $(@D)
diff --git a/libraries/daguerre/source/daguerre.cpp b/libraries/daguerre/source/daguerre.cpp
deleted file mode 100644
index 2f7fe4d..0000000
--- a/libraries/daguerre/source/daguerre.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include <daguerre.hpp>
-
-namespace daguerre {
-
- image<hilbert_color> get_hilbert_framebuffer() {
- uint32_t width, height, pitch;
- hilbert_color *ptr = __euler_get_framebuffer(width, height, pitch);
- return image<hilbert_color>(ptr, width, height, pitch, false);
- }
-
- //TODO: make this more robust
- unsigned read_text_int(std::FILE *input) {
- unsigned n = 0;
- char ch;
- std::fread(&ch, 1, 1, input);
- if (ch == '#') {
- do
- std::fread(&ch, 1, 1, input);
- while (ch != '\n');
- std::fread(&ch, 1, 1, input);
- }
- do {
- n = n * 10 + ch - '0';
- std::fread(&ch, 1, 1, input);
- } while (ch >= '0' && ch <= '9');
- return n;
- }
-
- //only supports p6 format
- bool try_load_ppm(std::FILE *input, image<rgb24> &into) {
-
- char header[3];
- if (std::fread(header, 1, 3, input) != 3)
- return false;
-
- if (header[0] != 'P' || header[1] != '6' || header[2] != '\n')
- return false;
-
- unsigned width = read_text_int(input);
- unsigned height = read_text_int(input);
- unsigned max = read_text_int(input);
-
- into = image<rgb24>(width, height);
-
- for (unsigned y = 0; y < height; ++y)
- for (unsigned x = 0; x < width; ++x) {
- if (std::fread(&into.buffer[y * width + x].r, 1, 1, input) != 1)
- return false;
- if (std::fread(&into.buffer[y * width + x].g, 1, 1, input) != 1)
- return false;
- if (std::fread(&into.buffer[y * width + x].b, 1, 1, input) != 1)
- return false;
- }
-
- if (max != 255)
- for (unsigned v = 0; v < width * height; ++v) {
- into.buffer[v].r = ((uint16_t)into.buffer[v].r * 255) / max;
- into.buffer[v].g = ((uint16_t)into.buffer[v].g * 255) / max;
- into.buffer[v].b = ((uint16_t)into.buffer[v].b * 255) / max;
- }
-
- return true;
-
- }
-
- //assumes the font is in psf2 format, and has a unicode table
- bool try_load_psf(std::FILE *input, fixed_bitmap_font<bool> &into) {
-
- uint32_t header[8];
- if (std::fread(header, 4, 8, input) != 8)
- return false;
-
- const uint32_t glyphs_start = header[2];
- const uint32_t glyph_count = header[4];
- const uint32_t glyph_length = header[5];
- into.height = header[6];
- into.width = header[7];
-
- const uint32_t unicode_start = glyphs_start + glyph_count * glyph_length;
- std::fseek(input, unicode_start, SEEK_SET);
-
- uint32_t indices[128];
-
- for (uint32_t index = 0; index < glyph_count; ++index) {
- uint8_t ch;
- std::fread(&ch, 1, 1, input);
- if (ch < 128)
- indices[ch] = index;
- do
- std::fread(&ch, 1, 1, input);
- while (ch != 0xff);
- }
-
- for (uint8_t ch = 0; ch < 128; ++ch) {
- std::fseek(input, glyphs_start + glyph_length * indices[ch], SEEK_SET);
- into.glyphs[ch] = image<bool>(into.width, into.height);
- for (unsigned h = 0; h < into.height; ++h)
- for (unsigned wb = 0; wb < into.width; wb += 8) {
- uint8_t byte;
- std::fread(&byte, 1, 1, input);
- for (unsigned x = 0; x < 8 && wb + x < into.width; ++x)
- into.glyphs[ch].set(wb + x, h, (byte >> (7 - x)) & 1);
- }
- }
-
- return true;
-
- }
-
-}
diff --git a/libraries/daguerre/source/framebuffer.cpp b/libraries/daguerre/source/framebuffer.cpp
new file mode 100644
index 0000000..d4282ad
--- /dev/null
+++ b/libraries/daguerre/source/framebuffer.cpp
@@ -0,0 +1,12 @@
+#include <daguerre/framebuffer.hpp>
+
+namespace daguerre {
+
+ image<hilbert_color> get_hilbert_framebuffer() {
+ hilbert_color *ptr;
+ uint32_t width, height, pitch;
+ euler::syscall::get_framebuffer(ptr, width, height, pitch);
+ return image<hilbert_color>(width, height, ptr, pitch, false);
+ }
+
+}
diff --git a/libraries/daguerre/source/ppm.cpp b/libraries/daguerre/source/ppm.cpp
new file mode 100644
index 0000000..a4a7e27
--- /dev/null
+++ b/libraries/daguerre/source/ppm.cpp
@@ -0,0 +1,60 @@
+#include <daguerre/ppm.hpp>
+
+namespace daguerre {
+
+ //TODO: make this more robust
+ static unsigned read_text_int(FILE *input) {
+ unsigned n = 0;
+ char ch;
+ fread(&ch, 1, 1, input);
+ if (ch == '#') {
+ do
+ fread(&ch, 1, 1, input);
+ while (ch != '\n');
+ fread(&ch, 1, 1, input);
+ }
+ do {
+ n = n * 10 + ch - '0';
+ fread(&ch, 1, 1, input);
+ } while (ch >= '0' && ch <= '9');
+ return n;
+ }
+
+ //TODO: this only supports p6 format, and assumes max < 256
+ std::optional<image<rgb24>> try_load_ppm(FILE *input) {
+
+ char header[3];
+ if (fread(header, 1, 3, input) != 3)
+ return {};
+
+ if (header[0] != 'P' || header[1] != '6' || header[2] != '\n')
+ return {};
+
+ unsigned width = read_text_int(input);
+ unsigned height = read_text_int(input);
+ unsigned max = read_text_int(input);
+
+ image<rgb24> im(width, height);
+
+ for (unsigned y = 0; y < height; ++y)
+ for (unsigned x = 0; x < width; ++x) {
+ if (fread(&im.buffer[y * width + x].r, 1, 1, input) != 1)
+ return {};
+ if (fread(&im.buffer[y * width + x].g, 1, 1, input) != 1)
+ return {};
+ if (fread(&im.buffer[y * width + x].b, 1, 1, input) != 1)
+ return {};
+ }
+
+ if (max != 255)
+ for (unsigned v = 0; v < width * height; ++v) {
+ im.buffer[v].r = ((uint16_t)im.buffer[v].r * 255) / max;
+ im.buffer[v].g = ((uint16_t)im.buffer[v].g * 255) / max;
+ im.buffer[v].b = ((uint16_t)im.buffer[v].b * 255) / max;
+ }
+
+ return im;
+
+ }
+
+}
diff --git a/libraries/daguerre/source/psf.cpp b/libraries/daguerre/source/psf.cpp
new file mode 100644
index 0000000..81f722a
--- /dev/null
+++ b/libraries/daguerre/source/psf.cpp
@@ -0,0 +1,51 @@
+#include <daguerre/psf.hpp>
+
+namespace daguerre {
+
+ //TODO: this assumes the font is in psf2 format, and has a unicode table
+ std::optional<fixed_font<bool>> try_load_psf(FILE *input) {
+
+ uint32_t header[8];
+ if (fread(header, 4, 8, input) != 8)
+ return {};
+
+ const uint32_t glyphs_start = header[2];
+ const uint32_t glyph_count = header[4];
+ const uint32_t glyph_length = header[5];
+ const uint32_t height = header[6];
+ const uint32_t width = header[7];
+
+ fixed_font<bool> font(width, height);
+
+ const uint32_t unicode_start = glyphs_start + glyph_count * glyph_length;
+ fseek(input, unicode_start, SEEK_SET);
+
+ uint32_t indices[128];
+
+ for (uint32_t index = 0; index < glyph_count; ++index) {
+ uint8_t ch;
+ fread(&ch, 1, 1, input);
+ if (ch < 128)
+ indices[ch] = index;
+ do
+ if (fread(&ch, 1, 1, input) != 1)
+ return {};
+ while (ch != 0xff);
+ }
+
+ for (uint8_t ch = 0; ch < 128; ++ch) {
+ fseek(input, glyphs_start + glyph_length * indices[ch], SEEK_SET);
+ for (unsigned h = 0; h < height; ++h)
+ for (unsigned wb = 0; wb < width; wb += 8) {
+ uint8_t byte;
+ fread(&byte, 1, 1, input);
+ for (unsigned x = 0; x < 8 && wb + x < width; ++x)
+ font.glyphs[ch].at(wb + x, h) = (byte >> (7 - x)) & 1;
+ }
+ }
+
+ return font;
+
+ }
+
+}
diff --git a/makefile b/makefile
index 17747e3..711bb03 100644
--- a/makefile
+++ b/makefile
@@ -1,29 +1,32 @@
LIMINE_DIR = $(abspath dependencies/limine)
+MINTSUKI_HEADERS_DIR = $(abspath dependencies/mintsuki-headers)
TOOLCHAIN_DIR = $(abspath toolchain)
+EXTRA_CC_ARGS = -Wall -Wextra -Og -ggdb -fno-exceptions
+
HILBERT_NASM = nasm -f elf64
-HILBERT_CC = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-c++ -std=c++17 -Wall \
- -Wextra -O3 -ggdb -static -fno-exceptions -fno-rtti -mno-sse -I include \
- -I $(abspath dependencies/mintsuki-headers) -I $(abspath euler/include) \
- -I $(abspath libraries/daguerre/include)
+HILBERT_CC = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-c++ -std=c++20 \
+ ${EXTRA_CC_ARGS} -static -mno-sse -I include -I $(abspath euler/include) \
+ -I $(abspath libraries/daguerre/include) -I ${MINTSUKI_HEADERS_DIR}
HILBERT_AR = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ar
HILBERT_LD = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ld -z noexecstack
.EXPORT_ALL_VARIABLES:
-LIB_DIR = toolchain/usr/x86_64-elf/lib/
+LIB_DIR = ${TOOLCHAIN_DIR}/usr/x86_64-elf/lib
LIMINE_DEP = dependencies/.limine-done
MINTSUKI_HEADERS_DEP = dependencies/.mintsuki-headers-done
BINUTILS_DEP = toolchain/.binutils-done
GCC_DEP = toolchain/.gcc-done
LIBGCC_DEP = toolchain/.libgcc-done
+LIBSTDCPP_DEP = toolchain/.libstdcpp-done
EULER_DEP = toolchain/.euler-done
DAGUERRE_DEP = toolchain/.daguerre-done
-APP_DEPS = ${GCC_DEP} ${LIBGCC_DEP} ${EULER_DEP} ${MINTSUKI_HEADERS_DEP}
-LIBRARY_DEPS = ${GCC_DEP} ${MINTSUKI_HEADERS_DEP}
+APP_DEPS = ${GCC_DEP} ${LIBGCC_DEP} ${LIBSTDCPP_DEP} ${EULER_DEP}
+LIBRARY_DEPS = ${GCC_DEP} ${LIBSTDCPP_DEP}
.PHONY: default run clean clean-dependencies
@@ -53,7 +56,10 @@ ${LIMINE_DEP}:
${MINTSUKI_HEADERS_DEP}:
mkdir -p dependencies
- test -e dependencies/mintsuki-headers || git clone --depth 1 https://github.com/mintsuki/freestanding-headers dependencies/mintsuki-headers
+ test -e dependencies/mintsuki-headers || git clone --depth 1 https://github.com/osdev0/freestanding-headers dependencies/mintsuki-headers
+ cd dependencies/mintsuki-headers && git fetch --depth=1 origin dd3abd2d7147efc4170dff478d3b7730bed14147
+ cd dependencies/mintsuki-headers && git checkout dd3abd2d7147efc4170dff478d3b7730bed14147
+ patch dependencies/mintsuki-headers/stddef.h patches/mintsuki-stddef.patch
touch $@
${BINUTILS_DEP}:
@@ -71,8 +77,10 @@ ${GCC_DEP}: ${BINUTILS_DEP}
test -e dependencies/gcc || git clone --depth 1 -b releases/gcc-14.1.0 https://gcc.gnu.org/git/gcc dependencies/gcc
mkdir -p dependencies/gcc/build
cd dependencies/gcc/build && ../configure --disable-fixed-point \
- --disable-gcov --disable-multilib --disable-shared --enable-languages=c++ \
- --target=x86_64-elf --prefix=${TOOLCHAIN_DIR}/usr --without-headers
+ --disable-gcov --disable-multilib --disable-shared \
+ --disable-hosted-libstdcxx \
+ --enable-languages=c++ --target=x86_64-elf --enable-cstdio=stdio_pure \
+ --prefix=${TOOLCHAIN_DIR}/usr --without-headers --enable-cxx-flags=-mno-sse
+make -C dependencies/gcc/build all-gcc
+make -C dependencies/gcc/build install-gcc
touch $@
@@ -82,17 +90,22 @@ ${LIBGCC_DEP}: ${GCC_DEP}
+make -C dependencies/gcc/build install-target-libgcc
touch $@
-${EULER_DEP}: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP}
- +make -C euler build/crt0.o build/libc.a build/libg.a build/libm.a \
- build/libstdc++.a
- mkdir -p toolchain/usr/x86_64-elf/lib
- cp euler/build/crt0.o euler/build/libc.a euler/build/libg.a \
- euler/build/libm.a euler/build/libstdc++.a ${LIB_DIR}
+${LIBSTDCPP_DEP}: ${GCC_DEP}
+ +make -C dependencies/gcc/build all-target-libstdc++-v3
+ +make -C dependencies/gcc/build install-target-libstdc++-v3
+ patch toolchain/usr/x86_64-elf/include/c++/14.1.0/memory patches/gcc-memory.patch
+ touch $@
+
+${EULER_DEP}: ${LIBRARY_DEPS}
+ +make -C euler build/crt0.o build/libc.a build/libg.a build/libm.a
+ mkdir -p ${LIB_DIR}
+ cp euler/build/crt0.o euler/build/libc.a \
+ euler/build/libg.a euler/build/libm.a ${LIB_DIR}/
touch $@
${DAGUERRE_DEP}: ${LIBRARY_DEPS}
+make -C libraries/daguerre build/libdaguerre.a
- cp libraries/daguerre/build/libdaguerre.a ${LIB_DIR}
+ cp libraries/daguerre/build/libdaguerre.a ${LIB_DIR}/
touch $@
kernel/build/kernel.elf: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP} ${LIMINE_DEP}
@@ -101,7 +114,7 @@ kernel/build/kernel.elf: ${GCC_DEP} ${MINTSUKI_HEADERS_DEP} ${LIMINE_DEP}
applications/init/build/init.elf: ${APP_DEPS}
+make -C applications/init build/init.elf
-applications/goldman/build/goldman.elf: ${APP_DEPS}
+applications/goldman/build/goldman.elf: ${APP_DEPS} ${DAGUERRE_DEP}
+make -C applications/goldman build/goldman.elf
build/initfs.tgz: applications/init/build/init.elf \
diff --git a/patches/gcc-memory.patch b/patches/gcc-memory.patch
new file mode 100644
index 0000000..9cdc9e2
--- /dev/null
+++ b/patches/gcc-memory.patch
@@ -0,0 +1,2 @@
+67a68
+> #include <std/allocator.hpp>
diff --git a/patches/mintsuki-stddef.patch b/patches/mintsuki-stddef.patch
new file mode 100644
index 0000000..4f98cc2
--- /dev/null
+++ b/patches/mintsuki-stddef.patch
@@ -0,0 +1,14 @@
+diff --git a/stddef.h b/stddef.h
+index 376eb75..fb1e99d 100644
+--- a/stddef.h
++++ b/stddef.h
+@@ -50,4 +50,9 @@ typedef decltype(nullptr) nullptr_t;
+ # define unreachable() __builtin_unreachable()
+ #endif
+
++typedef struct {
++ long long ll __attribute__((__aligned__(__alignof__(long long))));
++ long double ld __attribute__((__aligned__(__alignof__(long double))));
++} max_align_t;
++
+ #endif
diff --git a/qemu.gdb b/qemu.gdb
index 65c24a6..21d8389 100644
--- a/qemu.gdb
+++ b/qemu.gdb
@@ -1,5 +1,6 @@
target remote | qemu-system-x86_64 -gdb stdio -cdrom build/disk.iso -boot d
symbol-file kernel/build/kernel.elf
+add-symbol-file applications/goldman/build/goldman.elf
set disassembly-flavor intel
set print asm-demangle on
layout src
diff --git a/readme.txt b/readme.txt
index 5a5884b..331d767 100644
--- a/readme.txt
+++ b/readme.txt
@@ -22,6 +22,8 @@ acknowledgements (any under "dependencies" are downloaded during build):
dependencies/gcc/COPYING3 (gnu gpl v3)
dependencies/gcc/COPYING.RUNTIME (gcc runtime library exception v3.1)
homepage: https://gcc.gnu.org/
+ i patch the output <memory> header file from libstdc++ with
+ patches/gcc-memory.patch to include my std::allocator implementation.
- dependencies/limine (limine bootloader v7.5.1)
copyright 2019 - 2024 mintsuki and contributors
@@ -31,7 +33,11 @@ acknowledgements (any under "dependencies" are downloaded during build):
- dependencies/minstuki-headers
copyright 2022 - 2024 mintsuki and contributors
license: dependencies/mintsuki-headers/LICENSE (bsd zero-clause)
- homepage: https://github.com/mintsuki/freestanding-headers/
+ homepage: https://github.com/osdev0/freestanding-headers/
+ i patch the <stddef.h> header file with patches/minstuki-stddef.patch
+ to add a max_align_t type to make libstdc++ happy. i use the commit
+ dd3abd2d7147efc4170dff478d3b7730bed14147 so i don't have to worry
+ about that file changing in a future commit.
- skeleton/assets/burden.ppm
("selective focus photography snowflakes" by aaron burden)
@@ -71,8 +77,8 @@ project structure:
some descriptions of things that have not been created yet.
- euler:
- (a minimal start to) a c/c++ standard library and runtime. the plan is to
- follow the c++17 standard, and only add things as i need them.
+ (a minimal start to) a c++20 standard library, plus some hilbert
+ specific functions. this uses the freestanding part of libstdc++.
- kernel:
the kernel.
@@ -80,5 +86,8 @@ project structure:
- libraries/daguerre:
an image loading / rendering library.
+ - patches:
+ a couple patches that are applied to dependencies
+
- skeleton:
files that are copied directly to the initfs.
diff --git a/skeleton/assets/background.ppm b/skeleton/assets/background.ppm
new file mode 120000
index 0000000..f6bb84e
--- /dev/null
+++ b/skeleton/assets/background.ppm
@@ -0,0 +1 @@
+burden.ppm \ No newline at end of file