diff options
Diffstat (limited to 'libraries')
-rw-r--r-- | libraries/daguerre/include/daguerre/image.hpp | 155 | ||||
-rw-r--r-- | libraries/daguerre/ppm.cpp | 52 | ||||
-rw-r--r-- | libraries/euler/allocator.cpp | 147 | ||||
-rw-r--r-- | libraries/euler/cassert.cpp | 16 | ||||
-rw-r--r-- | libraries/euler/cctype.cpp | 11 | ||||
-rw-r--r-- | libraries/euler/cstdio.cpp | 102 | ||||
-rw-r--r-- | libraries/euler/entry.cpp | 19 | ||||
-rw-r--r-- | libraries/euler/include/cassert | 13 | ||||
-rw-r--r-- | libraries/euler/include/cctype | 7 | ||||
l--------- | libraries/euler/include/cstddef | 1 | ||||
l--------- | libraries/euler/include/cstdint | 1 | ||||
-rw-r--r-- | libraries/euler/include/cstdio | 19 | ||||
-rw-r--r-- | libraries/euler/include/cstring | 14 | ||||
-rw-r--r-- | libraries/euler/include/euler/syscall.hpp | 48 | ||||
-rw-r--r-- | libraries/euler/syscall.asm | 82 |
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 |