summaryrefslogtreecommitdiff
path: root/libraries
diff options
context:
space:
mode:
Diffstat (limited to 'libraries')
-rw-r--r--libraries/daguerre/include/daguerre/image.hpp155
-rw-r--r--libraries/daguerre/ppm.cpp52
-rw-r--r--libraries/euler/allocator.cpp147
-rw-r--r--libraries/euler/cassert.cpp16
-rw-r--r--libraries/euler/cctype.cpp11
-rw-r--r--libraries/euler/cstdio.cpp102
-rw-r--r--libraries/euler/entry.cpp19
-rw-r--r--libraries/euler/include/cassert13
-rw-r--r--libraries/euler/include/cctype7
l---------libraries/euler/include/cstddef1
l---------libraries/euler/include/cstdint1
-rw-r--r--libraries/euler/include/cstdio19
-rw-r--r--libraries/euler/include/cstring14
-rw-r--r--libraries/euler/include/euler/syscall.hpp48
-rw-r--r--libraries/euler/syscall.asm82
15 files changed, 687 insertions, 0 deletions
diff --git a/libraries/daguerre/include/daguerre/image.hpp b/libraries/daguerre/include/daguerre/image.hpp
new file mode 100644
index 0000000..6129306
--- /dev/null
+++ b/libraries/daguerre/include/daguerre/image.hpp
@@ -0,0 +1,155 @@
+#pragma once
+
+#include <euler/syscall.hpp>
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+
+namespace daguerre {
+
+ struct color24 {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ };
+
+ using hilbert_color = euler::syscall::encoded_color;
+
+ static inline hilbert_color to_hilbert_color(const color24 &c) {
+ return _syscall_encode_color(c.r, c.g, c.b);
+ }
+
+ template <class pixel_type = color24>
+ class image {
+
+ pixel_type *buffer;
+ unsigned width;
+ unsigned height;
+ unsigned pitch; //in pixels
+
+ bool buffer_owned;
+
+ public:
+ image() : buffer(0) {}
+
+ image(pixel_type *buffer, unsigned width,
+ unsigned height, unsigned pitch, bool buffer_owned
+ ) : buffer(buffer), width(width), height(height),
+ pitch(pitch), buffer_owned(buffer_owned) {}
+
+ image(unsigned width, unsigned height)
+ : buffer(new pixel_type[width * height]), width(width),
+ height(height), pitch(width), buffer_owned(true) {}
+
+ image(const image<pixel_type> &other) = delete;
+
+ image(image<pixel_type> &&other)
+ : buffer(other.buffer), width(other.width), height(other.height),
+ pitch(other.pitch), buffer_owned(other.buffer_owned) {
+ other.buffer = 0;
+ }
+
+ ~image() {
+ if (buffer && buffer_owned)
+ delete[] buffer;
+ }
+
+ image &operator =(const image<pixel_type> &other) = delete;
+
+ image &operator =(image<pixel_type> &&other) {
+ if (buffer && buffer_owned)
+ delete[] buffer;
+ buffer = other.buffer;
+ width = other.width;
+ height = other.height;
+ pitch = other.pitch;
+ buffer_owned = other.buffer_owned;
+ other.buffer = 0;
+ return *this;
+ }
+
+ pixel_type &get(unsigned x, unsigned y) {
+ return buffer[y * pitch + x];
+ }
+
+ const pixel_type &get(unsigned x, unsigned y) const {
+ return buffer[y * pitch + x];
+ }
+
+ pixel_type *get_buffer() {
+ return buffer;
+ }
+
+ const pixel_type *get_buffer() const {
+ return buffer;
+ }
+
+ unsigned get_width() const {
+ return width;
+ }
+
+ unsigned get_height() const {
+ return height;
+ }
+
+ unsigned get_pitch() const {
+ return pitch;
+ }
+
+ };
+
+ template <class pixel_type>
+ void default_converter(const pixel_type &i, pixel_type &o) {
+ o = i;
+ }
+
+ static inline void default_converter(const color24 &i, hilbert_color &o) {
+ o = to_hilbert_color(i);
+ }
+
+ //copies a rectangle of size width x height from source to destination. the
+ //rectangle starts in source at (source_x, source_y), and in destination at
+ //(destination_x, destination_y). every pixel is passed through the converter
+ //template argument.
+ template <
+ class source_pixel_type, class destination_pixel_type,
+ void (*converter)(const source_pixel_type &, destination_pixel_type &) =
+ &default_converter>
+ void copy_image(const image<source_pixel_type> &source,
+ image<destination_pixel_type> &destination, unsigned source_x,
+ unsigned source_y, unsigned destination_x, unsigned destination_y,
+ unsigned width, unsigned height
+ ) {
+
+ assert(source_x + width <= source.get_width());
+ assert(source_y + height <= source.get_height());
+ assert(destination_x + width <= destination.get_width());
+ assert(destination_y + height <= destination.get_height());
+
+ unsigned source_pitch = source.get_pitch();
+ unsigned destination_pitch = destination.get_pitch();
+
+ const source_pixel_type *source_buffer =
+ &source.get_buffer()[source_y * source_pitch + source_x];
+ destination_pixel_type *destination_buffer = &destination.get_buffer()[
+ destination_y * destination_pitch + destination_x];
+
+ for (unsigned y = 0; y < height; ++y)
+ for (unsigned x = 0; x < width; ++x)
+ converter(source_buffer[y * source_pitch + x],
+ destination_buffer[y * destination_pitch + x]);
+
+ }
+
+ static inline image<hilbert_color> get_hilbert_framebuffer() {
+ hilbert_color *ptr;
+ uint32_t width;
+ uint32_t height;
+ uint32_t pitch;
+ _syscall_get_framebuffer(ptr, width, height, pitch);
+ return image<hilbert_color>(ptr, width, height, pitch, false);
+ }
+
+ bool try_load_ppm(std::FILE *from, image<color24> &into);
+
+}
diff --git a/libraries/daguerre/ppm.cpp b/libraries/daguerre/ppm.cpp
new file mode 100644
index 0000000..e909503
--- /dev/null
+++ b/libraries/daguerre/ppm.cpp
@@ -0,0 +1,52 @@
+#include <daguerre/image.hpp>
+#include <cctype>
+
+namespace daguerre {
+
+ static unsigned read_int(std::FILE *from) {
+ unsigned out = 0;
+ int ch;
+ do
+ ch = std::fgetc(from);
+ while (std::isspace(ch));
+ while (true) {
+ if (ch == EOF)
+ return out;
+ if (ch < '0' || ch > '9') {
+ std::ungetc(ch, from);
+ return out;
+ }
+ out = out * 10 + (ch - '0');
+ ch = std::fgetc(from);
+ }
+ }
+
+ bool try_load_ppm(std::FILE *from, image<color24> &into) {
+
+ if (std::fgetc(from) != 'P' || std::fgetc(from) != '6' ||
+ std::fgetc(from) != '\n')
+ return false;
+
+ unsigned width = read_int(from);
+ unsigned height = read_int(from);
+ unsigned max = read_int(from);
+ std::fgetc(from);//newline
+
+ if (max != 255)
+ return false;
+
+ into = image<color24>(width, height);
+ color24 *buffer = into.get_buffer();
+
+ for (unsigned y = 0; y < height; ++y)
+ for (unsigned x = 0; x < width; ++x) {
+ buffer[y * width + x].r = std::fgetc(from);
+ buffer[y * width + x].g = std::fgetc(from);
+ buffer[y * width + x].b = std::fgetc(from);
+ }
+
+ return true;
+
+ }
+
+}
diff --git a/libraries/euler/allocator.cpp b/libraries/euler/allocator.cpp
new file mode 100644
index 0000000..5242df1
--- /dev/null
+++ b/libraries/euler/allocator.cpp
@@ -0,0 +1,147 @@
+#include <euler/syscall.hpp>
+
+//i guess we could figure out which parts of the pages the kernel allocated to
+//load the application were not actually needed and add those to the memory
+//that is available to be allocated, but whatever.
+
+namespace euler::allocator {
+
+ struct block_info {
+ //vaddr, divisible by size
+ uint64_t start;
+ //power of 2, 0 for unused
+ uint64_t size;
+ };
+
+ struct block_info_page {
+ block_info infos[255];
+ block_info_page *next;
+ };
+
+ static_assert(sizeof(block_info_page) == 4088);
+
+ static block_info_page *first_bi_page = 0;
+
+ static block_info *try_find_block(uint64_t start, uint64_t size) {
+ for (block_info_page *bip = first_bi_page; bip; bip = bip->next)
+ for (int i = 0; i < 255; ++i)
+ if (bip->infos[i].start == start && bip->infos[i].size == size)
+ return bip->infos + i;
+ return 0;
+ }
+
+ static block_info *add_block(uint64_t start, uint64_t size) {
+ for (block_info_page *bip = first_bi_page; bip; bip = bip->next)
+ for (int i = 0; i < 255; ++i)
+ if (bip->infos[i].size == 0) {
+ bip->infos[i].start = start;
+ bip->infos[i].size = size;
+ return bip->infos + i;
+ }
+ block_info_page *new_bip = (block_info_page *)_syscall_get_new_pages(1);
+ new_bip->infos[0].start = start;
+ new_bip->infos[0].size = size;
+ for (int i = 1; i < 255; ++i)
+ new_bip->infos[i].size = 0;
+ new_bip->next = first_bi_page;
+ first_bi_page = new_bip;
+ return new_bip->infos;
+ }
+
+ static block_info *find_minimal_block(uint64_t minimum_length) {
+ block_info *minimal_so_far = 0;
+ uint64_t length_so_far = UINT64_MAX;
+ for (block_info_page *bip = first_bi_page; bip; bip = bip->next)
+ for (int i = 0; i < 255; ++i)
+ if (bip->infos[i].size == minimum_length)
+ return bip->infos + i;
+ else if (
+ bip->infos[i].size > minimum_length &&
+ bip->infos[i].size < length_so_far
+ ) {
+ minimal_so_far = bip->infos + i;
+ length_so_far = bip->infos[i].size;
+ }
+ if (minimal_so_far != 0)
+ return minimal_so_far;
+ uint64_t pages_needed = (minimum_length - 1) / 4096 + 1;
+ void *block_start = _syscall_get_new_pages(pages_needed);
+ return add_block((uint64_t)block_start, pages_needed * 4096);
+ }
+
+ static void deallocate_aligned(uint64_t start, uint64_t length) {
+ block_info *buddy = try_find_block(start ^ length, length);
+ if (buddy) {
+ buddy->size = 0;
+ deallocate_aligned(start & ~length, length * 2);
+ return;
+ }
+ add_block(start, length);
+ }
+
+ static void deallocate(void *start, uint64_t length) {
+ uint64_t at = (uint64_t)start;
+ uint64_t left = length;
+ uint64_t i;
+ for (i = 1; i <= left; i *= 2)
+ if (at & i) {
+ deallocate_aligned(at, i);
+ at += i;
+ left -= i;
+ }
+ for (i /= 2; left > 0; i /= 2)
+ if (i <= left) {
+ deallocate_aligned(at, i);
+ at += i;
+ left -= i;
+ }
+ }
+
+ [[nodiscard]] static void *allocate(uint64_t length) {
+ block_info *bi = find_minimal_block(length);
+ void *to_return = (void *)bi->start;
+ void *new_start = (void *)(bi->start + length);
+ uint64_t new_length = bi->size - length;
+ bi->size = 0;
+ deallocate(new_start, new_length);
+ return to_return;
+ }
+
+ static void deallocate_with_length(void *start) {
+ uint64_t real_start = (uint64_t)start - 8;
+ deallocate((void *)real_start, *(uint64_t *)real_start);
+ }
+
+ [[nodiscard]] static void *allocate_with_length(uint64_t length) {
+ uint64_t *real_start = (uint64_t *)allocate(length + 8);
+ *real_start = length + 8;
+ return real_start + 1;
+ }
+
+}
+
+using namespace euler::allocator;
+
+void operator delete[](void *start) {
+ deallocate_with_length(start);
+}
+
+void operator delete(void *start) {
+ deallocate_with_length(start);
+}
+
+void operator delete[](void *start, uint64_t) {
+ deallocate_with_length(start);
+}
+
+void operator delete(void *start, uint64_t) {
+ deallocate_with_length(start);
+}
+
+void *operator new[](uint64_t size) {
+ return allocate_with_length(size);
+}
+
+void *operator new(uint64_t size) {
+ return allocate_with_length(size);
+}
diff --git a/libraries/euler/cassert.cpp b/libraries/euler/cassert.cpp
new file mode 100644
index 0000000..e811b38
--- /dev/null
+++ b/libraries/euler/cassert.cpp
@@ -0,0 +1,16 @@
+#include <cassert>
+
+namespace euler {
+
+ [[noreturn]] void assert_failed(
+ const char *, const char *, int, const char *
+ ) {
+ //TODO: print error and abort
+ //we could just exit right now but i want to keep us in
+ //the application so we can get a stack trace in gdb.
+ while (1)
+ ;
+ }
+
+
+}
diff --git a/libraries/euler/cctype.cpp b/libraries/euler/cctype.cpp
new file mode 100644
index 0000000..98234bb
--- /dev/null
+++ b/libraries/euler/cctype.cpp
@@ -0,0 +1,11 @@
+#include <cctype>
+
+namespace std {
+
+ int isspace(int ch) {
+ return
+ ch == ' ' || ch == '\n' || ch == '\t' ||
+ ch == '\r' || ch == '\v' || ch == '\f';
+ }
+
+}
diff --git a/libraries/euler/cstdio.cpp b/libraries/euler/cstdio.cpp
new file mode 100644
index 0000000..367e7e0
--- /dev/null
+++ b/libraries/euler/cstdio.cpp
@@ -0,0 +1,102 @@
+#include <euler/syscall.hpp>
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+
+namespace euler {
+
+ //read-only with no error bits for now
+ struct file_t {
+
+ syscall::file_handle handle;
+
+ //TODO: variable size buffer? maybe a multiple of block size for device?
+ char buffer[1024];
+ //in bytes, aligned to buffer size; 1 for no buffer loaded
+ uint64_t buffer_start;
+
+ bool is_offset_in_buffer() {
+ return
+ buffer_start != 1 && offset >= buffer_start &&
+ offset < buffer_start + 1024;
+ }
+
+ syscall::file_result ensure_offset_in_buffer() {
+ if (is_offset_in_buffer())
+ return syscall::file_result::success;
+ uint64_t new_buffer_start = (offset / 1024) * 1024;
+ uint64_t new_buffer_end = new_buffer_start + 1024;
+ if (length < new_buffer_end)
+ new_buffer_end = length;
+ syscall::file_result result = _syscall_read_from_file(
+ handle, new_buffer_start, new_buffer_end - new_buffer_start, buffer);
+ if (result == syscall::file_result::success)
+ buffer_start = new_buffer_start;
+ return result;
+ }
+
+ uint64_t offset;
+ uint64_t length;
+
+ };
+
+}
+
+namespace std {
+
+ FILE *fopen(const char *path, const char *mode) {
+
+ assert(mode[0] == 'r' && mode[1] == '\0');
+
+ euler::syscall::file_handle handle;
+ euler::syscall::file_result result =
+ _syscall_open_file(path, strlen(path), handle);
+ if (result != euler::syscall::file_result::success)
+ return 0;
+
+ uint64_t length;
+ result = _syscall_get_file_length(handle, length);
+ if (result != euler::syscall::file_result::success) {
+ _syscall_close_file(handle);
+ return 0;
+ }
+
+ return new FILE {
+ .handle = handle,
+ .buffer = {},
+ .buffer_start = 1,
+ .offset = 0,
+ .length = length
+ };
+
+ }
+
+ int fclose(FILE *file) {
+ _syscall_close_file(file->handle);
+ delete file;
+ return 0;
+ }
+
+ int fgetc(FILE *from) {
+ if (from->offset >= from->length)
+ return EOF;
+ assert(
+ from->ensure_offset_in_buffer() == euler::syscall::file_result::success);
+ char ch = from->buffer[from->offset - from->buffer_start];
+ ++from->offset;
+ return ch;
+ }
+
+ int ungetc(int ch, FILE *from) {
+ if (ch == EOF || from->offset == 0)
+ return EOF;
+ --from->offset;
+ if (!from->is_offset_in_buffer()) {
+ ++from->offset;
+ return EOF;
+ }
+ from->buffer[from->offset - from->buffer_start] = ch;
+ return ch;
+ }
+
+}
diff --git a/libraries/euler/entry.cpp b/libraries/euler/entry.cpp
new file mode 100644
index 0000000..0bbffda
--- /dev/null
+++ b/libraries/euler/entry.cpp
@@ -0,0 +1,19 @@
+#include <euler/syscall.hpp>
+
+int main(int argc, char **argv);
+
+extern "C" [[noreturn]] void _entry() {
+
+ //TODO: static constructors
+
+ //TODO: get command line via system call and populate argc and argv.
+ int argc = 0;
+ char **argv = 0;
+
+ int result = main(argc, argv);
+
+ //TODO: static destructors
+
+ _syscall_end_this_process(result);
+
+}
diff --git a/libraries/euler/include/cassert b/libraries/euler/include/cassert
new file mode 100644
index 0000000..bc716a0
--- /dev/null
+++ b/libraries/euler/include/cassert
@@ -0,0 +1,13 @@
+#pragma once
+
+namespace euler {
+ [[noreturn]] void assert_failed(
+ const char *file, const char *function, int line, const char *condition);
+}
+
+#ifdef NDEBUG
+#define assert(condition) ((void)0)
+#else
+#define assert(condition) ((condition) ? ((void)0) : \
+ euler::assert_failed(__FILE__, __func__, __LINE__, #condition))
+#endif
diff --git a/libraries/euler/include/cctype b/libraries/euler/include/cctype
new file mode 100644
index 0000000..087b191
--- /dev/null
+++ b/libraries/euler/include/cctype
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace std {
+
+ int isspace(int ch);
+
+}
diff --git a/libraries/euler/include/cstddef b/libraries/euler/include/cstddef
new file mode 120000
index 0000000..9eac9b6
--- /dev/null
+++ b/libraries/euler/include/cstddef
@@ -0,0 +1 @@
+../../../mintsuki-freestanding-headers/stddef.h \ No newline at end of file
diff --git a/libraries/euler/include/cstdint b/libraries/euler/include/cstdint
new file mode 120000
index 0000000..b087235
--- /dev/null
+++ b/libraries/euler/include/cstdint
@@ -0,0 +1 @@
+../../../mintsuki-freestanding-headers/stdint.h \ No newline at end of file
diff --git a/libraries/euler/include/cstdio b/libraries/euler/include/cstdio
new file mode 100644
index 0000000..3bb293b
--- /dev/null
+++ b/libraries/euler/include/cstdio
@@ -0,0 +1,19 @@
+#pragma once
+
+#define EOF (-1)
+
+namespace euler {
+ struct file_t;
+}
+
+namespace std {
+
+ typedef euler::file_t FILE;
+
+ FILE *fopen(const char *path, const char *mode);
+ int fclose(FILE *file);
+
+ int fgetc(FILE *from);
+ int ungetc(int ch, FILE *from);
+
+}
diff --git a/libraries/euler/include/cstring b/libraries/euler/include/cstring
new file mode 100644
index 0000000..65d00dc
--- /dev/null
+++ b/libraries/euler/include/cstring
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <cstddef>
+
+namespace std {
+
+ static inline size_t strlen(const char *str) {
+ size_t i = 0;
+ while (str[i])
+ ++i;
+ return i;
+ }
+
+}
diff --git a/libraries/euler/include/euler/syscall.hpp b/libraries/euler/include/euler/syscall.hpp
new file mode 100644
index 0000000..781d444
--- /dev/null
+++ b/libraries/euler/include/euler/syscall.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <cstdint>
+
+namespace euler::syscall {
+
+ typedef uint32_t encoded_color;
+ typedef int32_t exit_code;
+ typedef uint64_t file_handle;
+
+ enum [[nodiscard]] file_result : uint64_t {
+ success,
+ bad_file_handle,
+ device_error,
+ file_system_corrupt,
+ out_of_bounds,
+ does_not_exist,
+ directory
+ };
+
+}
+
+extern "C" {
+
+ euler::syscall::encoded_color _syscall_encode_color(
+ uint8_t red, uint8_t green, uint8_t blue);
+
+ void _syscall_get_framebuffer(
+ euler::syscall::encoded_color *&ptr_out, uint32_t &width_out,
+ uint32_t &height_out, uint32_t &pitch_out);
+
+ euler::syscall::file_result _syscall_open_file(
+ const char *path, uint64_t path_length, euler::syscall::file_handle &out);
+
+ euler::syscall::file_result _syscall_get_file_length(
+ euler::syscall::file_handle file, uint64_t &out);
+
+ euler::syscall::file_result _syscall_read_from_file(
+ euler::syscall::file_handle file,
+ uint64_t start_offset, uint64_t length, void *into);
+
+ [[noreturn]] void _syscall_end_this_process(euler::syscall::exit_code code);
+
+ [[nodiscard]] void *_syscall_get_new_pages(uint64_t count);
+
+ void _syscall_close_file(euler::syscall::file_handle file);
+
+}
diff --git a/libraries/euler/syscall.asm b/libraries/euler/syscall.asm
new file mode 100644
index 0000000..f7fe735
--- /dev/null
+++ b/libraries/euler/syscall.asm
@@ -0,0 +1,82 @@
+bits 64
+
+section .text
+
+global _syscall_encode_color
+_syscall_encode_color:
+ xor rax, rax
+ and edi, 0xff
+ and dx, 0xff
+ shl si, 8
+ shl edx, 16
+ or di, si
+ or edi, edx
+ syscall
+ ret
+
+global _syscall_get_framebuffer
+_syscall_get_framebuffer:
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ mov rax, 1
+ syscall
+ pop rcx
+ mov qword [rcx], rax
+ pop rcx
+ mov dword [rcx], edi
+ pop rcx
+ shr rdi, 32
+ mov dword [rcx], edi
+ pop rcx
+ mov dword [rcx], esi
+ ret
+
+global _syscall_open_file
+_syscall_open_file:
+ mov rax, 2
+ push rdx
+ syscall
+ pop rdx
+ mov qword [rdx], rdi
+ ret
+
+global _syscall_get_file_length
+_syscall_get_file_length:
+ mov rax, 3
+ push rsi
+ syscall
+ pop rsi
+ mov qword [rsi], rdi
+ ret
+
+global _syscall_read_from_file
+_syscall_read_from_file:
+ mov rax, 4
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ mov rdi, rsp
+ syscall
+ add rsp, 32
+ ret
+
+global _syscall_end_this_process
+_syscall_end_this_process:
+ mov rax, 5
+ syscall
+ ;does not return
+
+global _syscall_get_new_pages
+_syscall_get_new_pages:
+ mov rax, 6
+ syscall
+ ret
+
+global _syscall_close_file
+_syscall_close_file:
+ mov rax, 7
+ syscall
+ ret