From c9a1266d219a83882735a3a8304f3824e0219cdb Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Mon, 15 Jan 2024 15:44:20 -0500 Subject: redo application paging and system calls, rename mercury to hilbert --- .gitignore | 2 +- applications/init/main.cpp | 11 +- applications/link.ld | 4 +- documentation/memory.txt | 10 +- documentation/syscalls.txt | 5 - include/hilbert/kernel/application.hpp | 70 +++++++++ include/hilbert/kernel/framebuffer.hpp | 27 ++++ include/hilbert/kernel/paging.hpp | 45 ++++++ include/hilbert/kernel/storage.hpp | 104 +++++++++++++ include/hilbert/kernel/storage/bd/memory.hpp | 22 +++ include/hilbert/kernel/storage/fs/tarfs.hpp | 32 ++++ include/hilbert/kernel/syscall.hpp | 13 ++ include/hilbert/kernel/terminal.hpp | 35 +++++ include/hilbert/kernel/utility.hpp | 224 +++++++++++++++++++++++++++ include/hilbert/kernel/vfile.hpp | 67 ++++++++ include/hilbert/syscall.hpp | 24 +++ include/mercury/kernel/application.hpp | 72 --------- include/mercury/kernel/framebuffer.hpp | 29 ---- include/mercury/kernel/paging.hpp | 46 ------ include/mercury/kernel/storage.hpp | 104 ------------- include/mercury/kernel/storage/bd/memory.hpp | 22 --- include/mercury/kernel/storage/fs/tarfs.hpp | 32 ---- include/mercury/kernel/terminal.hpp | 35 ----- include/mercury/kernel/utility.hpp | 224 --------------------------- include/mercury/kernel/vfile.hpp | 67 -------- include/mercury/syscall.hpp | 26 ---- kernel/allocator.cpp | 6 +- kernel/application.cpp | 216 +++++++++++++------------- kernel/entry.cpp | 22 +-- kernel/framebuffer.cpp | 52 ++++++- kernel/interrupts.cpp | 4 +- kernel/paging.cpp | 37 ++--- kernel/storage.cpp | 4 +- kernel/storage/bd/memory.cpp | 4 +- kernel/storage/fs/tarfs.cpp | 4 +- kernel/syscall.asm | 70 ++------- kernel/syscall.cpp | 62 ++++---- kernel/terminal.cpp | 6 +- kernel/utility.cpp | 4 +- kernel/vfile.cpp | 4 +- limine.cfg | 2 +- makefile | 4 +- readme.txt | 2 +- stdlib/syscall.asm | 5 - 44 files changed, 916 insertions(+), 944 deletions(-) create mode 100644 include/hilbert/kernel/application.hpp create mode 100644 include/hilbert/kernel/framebuffer.hpp create mode 100644 include/hilbert/kernel/paging.hpp create mode 100644 include/hilbert/kernel/storage.hpp create mode 100644 include/hilbert/kernel/storage/bd/memory.hpp create mode 100644 include/hilbert/kernel/storage/fs/tarfs.hpp create mode 100644 include/hilbert/kernel/syscall.hpp create mode 100644 include/hilbert/kernel/terminal.hpp create mode 100644 include/hilbert/kernel/utility.hpp create mode 100644 include/hilbert/kernel/vfile.hpp create mode 100644 include/hilbert/syscall.hpp delete mode 100644 include/mercury/kernel/application.hpp delete mode 100644 include/mercury/kernel/framebuffer.hpp delete mode 100644 include/mercury/kernel/paging.hpp delete mode 100644 include/mercury/kernel/storage.hpp delete mode 100644 include/mercury/kernel/storage/bd/memory.hpp delete mode 100644 include/mercury/kernel/storage/fs/tarfs.hpp delete mode 100644 include/mercury/kernel/terminal.hpp delete mode 100644 include/mercury/kernel/utility.hpp delete mode 100644 include/mercury/kernel/vfile.hpp delete mode 100644 include/mercury/syscall.hpp diff --git a/.gitignore b/.gitignore index 24524ee..d35ad13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .vscode/ -include/mercury/kernel/limine.hpp +include/hilbert/kernel/limine.hpp limine obj out diff --git a/applications/init/main.cpp b/applications/init/main.cpp index e0019b5..1a39513 100644 --- a/applications/init/main.cpp +++ b/applications/init/main.cpp @@ -1,7 +1,7 @@ -#include +#include -using mercury::syscall::encoded_color; -using mercury::syscall::color; +using hilbert::syscall::encoded_color; +using hilbert::syscall::color; encoded_color *fb; uint32_t fb_width; @@ -10,7 +10,7 @@ uint32_t fb_pitch; int main(int, char **) { - mercury::syscall::get_framebuffer(fb, fb_width, fb_height, fb_pitch); + hilbert::syscall::get_framebuffer(fb, fb_width, fb_height, fb_pitch); for (uint32_t y = 0; y < fb_height; ++y) for (uint32_t x = 0; x < fb_width; ++x) { color c = { @@ -18,9 +18,8 @@ int main(int, char **) { .g = (uint8_t)(y * 255 / fb_height), .b = (uint8_t)(x * 255 / fb_width) }; - fb[y * fb_pitch + x] = mercury::syscall::encode_color(c); + fb[y * fb_pitch + x] = hilbert::syscall::encode_color(c); } - mercury::syscall::draw_framebuffer(); //*(int *)0x12345678 = 0; //fb_width = *(uint32_t *)0xffffffffc0000000; diff --git a/applications/link.ld b/applications/link.ld index eaba220..f8c09a2 100644 --- a/applications/link.ld +++ b/applications/link.ld @@ -18,13 +18,13 @@ SECTIONS { *(.text .text.*) } : rx - . = ALIGN(0x200000); + . = ALIGN(4096); .rodata : { *(.rodata .rodata.*) } : ro - . = ALIGN(0x200000); + . = ALIGN(4096); .data : { *(.data .data.*) diff --git a/documentation/memory.txt b/documentation/memory.txt index 581bd71..c000fa7 100644 --- a/documentation/memory.txt +++ b/documentation/memory.txt @@ -1,11 +1,11 @@ only the first 32GiB of physical memory are considered. this can be changed with pram_pages in paging.cpp. vram layout is as follows: -0x0000.0000.0000 - 0x0000.001f.ffff: always unmapped -0x0000.0020.0000 - 0x0000.3fbf.ffff: available to user process -0x0000.3fc0.0000 - 0x0000.3fdf.ffff: always unmapped -0x0000.3fe0.0000 - 0x0000.3fff.ffff: user stack -0x0000.4000.0000 - 0xffff.bfff.ffff: always unmapped +0x0000.0000.0000 - 0x0000.0000.0fff: always unmapped +0x0000.0000.1000 - 0x0000.001f.efff: user stack +0x0000.001f.f000 - 0x0000.001f.ffff: always unmapped +0x0000.0020.0000 - 0x007f.ffff.ffff: available to user process +0x0080.0000.0000 - 0xffff.bfff.ffff: always unmapped 0xffff.c000.0000 - 0xffff.ffdf.ffff: available to kernel 0xffff.ffe0.0000 - 0xffff.ffe0.0fff: always unmapped 0xffff.ffe0.1000 - 0xffff.ffef.efff: interrupt stack diff --git a/documentation/syscalls.txt b/documentation/syscalls.txt index cbba5e3..463f815 100644 --- a/documentation/syscalls.txt +++ b/documentation/syscalls.txt @@ -20,8 +20,3 @@ get framebuffer: esi out: pitch framebuffer is always 32 bpp. use the encode color syscall to encode colors. pitch is in dwords, not in bytes. - -draw framebuffer: - rax in: 2 - this draws changes to the framebuffer gotten by the get framebuffer - system call. (currently, the entire thing is copied, not just changes.) diff --git a/include/hilbert/kernel/application.hpp b/include/hilbert/kernel/application.hpp new file mode 100644 index 0000000..dc2c9a3 --- /dev/null +++ b/include/hilbert/kernel/application.hpp @@ -0,0 +1,70 @@ +#ifndef HILBERT_KERNEL_APPLICATION_HPP +#define HILBERT_KERNEL_APPLICATION_HPP + +#include +#include + +//TODO: end application, threading. + +namespace hilbert::kernel::application { + + enum class app_state { + running, + paused, + zombie + }; + + struct app_instance { + + app_state state; + + uint64_t *p4; + uint64_t *p3; + uint64_t *p2s[512]; + uint64_t **p1s[512]; + + bool **p1es_to_free_on_exit[512]; + + uint64_t p4_paddr; + + //set to 0 if none + uint64_t framebuffer_vaddr; + + //only valid if state is zombie + int exit_code; + + //only valid if state is paused + struct { + uint64_t rip; + uint64_t rsp; + //TODO: etc. + } saved_regs; + + app_instance(); + + //vaddr and paddr must be aligned, and vaddr must be < 0x0080.0000.0000 + void map_page(uint64_t vaddr, uint64_t paddr, + bool write, bool execute, bool free_pram_on_exit); + + //returns start of first page. + uint64_t get_free_vaddr_pages(uint64_t count); + + //in lower half + uint64_t count_mapped_vram_pages(); + + }; + + extern app_instance *running_app; + + enum class create_app_result { + success, + device_error, + app_corrupt, + fs_corrupt + }; + + create_app_result create_app(const vfile::vfile &file, app_instance *&out); + +} + +#endif diff --git a/include/hilbert/kernel/framebuffer.hpp b/include/hilbert/kernel/framebuffer.hpp new file mode 100644 index 0000000..c6725ae --- /dev/null +++ b/include/hilbert/kernel/framebuffer.hpp @@ -0,0 +1,27 @@ +#ifndef HILBERT_KERNEL_FRAMEBUFFER_HPP +#define HILBERT_KERNEL_FRAMEBUFFER_HPP + +#include + +namespace hilbert::kernel::framebuffer { + + extern int width; + extern int height; + + void init_framebuffer(uint64_t paddr, uint64_t vaddr, uint64_t width, uint64_t height, uint64_t pitch); + + typedef uint32_t color; + color encode_color(uint8_t r, uint8_t g, uint8_t b); + + void set_pixel(int x, int y, color c); + + //[from_start_x, from_end_x) x [from_start_y, from_end_y) -> [to_start_x, ...) x [to_start_y, ...) + //we assume from_start_x < from_end_x and from_start_y < from_end_y + void move_region(int from_start_x, int from_start_y, int from_end_x, int from_end_y, int to_start_x, int to_start_y); + + //[start_x, end_x) x [start_y, end_y) + void fill_region(int start_x, int start_y, int end_x, int end_y, color c); + +} + +#endif diff --git a/include/hilbert/kernel/paging.hpp b/include/hilbert/kernel/paging.hpp new file mode 100644 index 0000000..2cf6f5c --- /dev/null +++ b/include/hilbert/kernel/paging.hpp @@ -0,0 +1,45 @@ +#ifndef HILBERT_KERNEL_PAGING_HPP +#define HILBERT_KERNEL_PAGING_HPP + +#include + +//in paging.asm +extern "C" [[noreturn]] void switch_to_kernel_p4(void (*and_then_jump_to)()); + +namespace hilbert::kernel::paging { + + void mark_all_pram_used(); + void mark_all_vram_free(); + + void mark_pram_region_free(uint64_t start_addr, uint64_t end_addr); + void mark_vram_region_used(uint64_t start_addr, uint64_t end_addr); + + uint64_t find_unmapped_vram_region(uint64_t page_count); + + uint64_t encode_pte(uint64_t addr, bool user, bool write, bool execute); + + void init_kernel_page_tables(uint64_t kernel_offset); + + uint64_t take_pram_page(); + + void map_kernel_stacks(); + + void map_kernel_page( + uint64_t paddr, uint64_t vaddr, bool write, bool execute); + + void unmap_kernel_page(uint64_t vaddr); + + //maps writable and not executable + void *map_new_kernel_pages(uint64_t count); + + //maps writable and not executable + void map_new_kernel_page(uint64_t &vaddr_out, uint64_t &paddr_out); + + uint64_t get_used_vram_page_count(); + uint64_t get_free_pram_page_count(); + + extern uint64_t kernel_p4e; + +} + +#endif diff --git a/include/hilbert/kernel/storage.hpp b/include/hilbert/kernel/storage.hpp new file mode 100644 index 0000000..ea40d86 --- /dev/null +++ b/include/hilbert/kernel/storage.hpp @@ -0,0 +1,104 @@ +#ifndef HILBERT_KERNEL_STORAGE_HPP +#define HILBERT_KERNEL_STORAGE_HPP + +#include +#include + +namespace hilbert::kernel::storage { + + typedef uint64_t node_id_t; + typedef uint64_t directory_iter_t; + + enum class file_type { + regular_file, + directory, + symlink + }; + + enum class bd_result { + success, + out_of_bounds, + device_error + }; + + enum class fs_result { + success, + device_error, + fs_corrupt + }; + + struct dir_entry { + utility::string name; + node_id_t node; + file_type type; + //only used if type is regular_file. + uint64_t length; + //only used if type is symlink. + utility::string target; + }; + + class file_system_instance { + + public: + virtual ~file_system_instance() {} + + virtual fs_result get_root_node(node_id_t &out) = 0; + + //it is assumed that this is a directory. sets iter_out + //to a value that can be passed to subsequent calls + //to get_next_child with the same argument for node. + virtual fs_result get_first_child(node_id_t node, std::optional &out, directory_iter_t &iter_out) = 0; + + //it is assumed that this is a directory. sets iter_out + //to a value that can be passed to subsequent calls + //to get_next_child with the same argument for node. + virtual fs_result get_next_child(node_id_t node, std::optional &out, directory_iter_t &iter) = 0; + + //it is assumed that this is a regular file and that + //the region requested is within the bounds of the file. + virtual fs_result read_bytes_from_file(node_id_t node, uint64_t start, uint64_t count, void *into) = 0; + + }; + + class block_device { + + private: + uint8_t *block_cache; + uint64_t block_cache_i; + + //it is assumed that this block is within the bounds of the device. + bd_result load_cache_block(uint64_t i); + + protected: + //implemented in driver. it is assumed that the + //blocks are within the bounds of the device. + virtual bd_result read_blocks_no_cache(uint64_t start, uint64_t count, void *into) = 0; + + //it is assumed that this is only called once, by the driver, after + //block_size and block_count have been set, and before read_bytes or + //write_bytes can be called (e.g. in the derived class's constructor). + void allocate_block_cache(); + + public: + //set by storage component + file_system_instance *mounted_as; + //set by storage component + utility::uuid id; + + //set by driver + uint64_t block_size; + //set by driver + uint64_t block_count; + + virtual ~block_device() { + if (block_cache) + delete block_cache; + } + + bd_result read_bytes(uint64_t start, uint64_t count, void *into); + + }; + +} + +#endif diff --git a/include/hilbert/kernel/storage/bd/memory.hpp b/include/hilbert/kernel/storage/bd/memory.hpp new file mode 100644 index 0000000..7702cb3 --- /dev/null +++ b/include/hilbert/kernel/storage/bd/memory.hpp @@ -0,0 +1,22 @@ +#ifndef HILBERT_KERNEL_STORAGE_BD_MEMORY_HPP +#define HILBERT_KERNEL_STORAGE_BD_MEMORY_HPP + +#include + +namespace hilbert::kernel::storage::bd { + + class memory : public block_device { + + private: + uint8_t *buffer; + + public: + memory(void *buffer, uint64_t buffer_len); + + bd_result read_blocks_no_cache(uint64_t start, uint64_t count, void *into) override; + + }; + +} + +#endif diff --git a/include/hilbert/kernel/storage/fs/tarfs.hpp b/include/hilbert/kernel/storage/fs/tarfs.hpp new file mode 100644 index 0000000..80e6030 --- /dev/null +++ b/include/hilbert/kernel/storage/fs/tarfs.hpp @@ -0,0 +1,32 @@ +#ifndef HILBERT_KERNEL_STORAGE_FS_TARFS_HPP +#define HILBERT_KERNEL_STORAGE_FS_TARFS_HPP + +#include + +namespace hilbert::kernel::storage::fs { + + class tarfs_instance : public file_system_instance { + + private: + block_device *bd; + + fs_result next_node(node_id_t node, std::optional &out); + fs_result read_full_name(node_id_t node, utility::string &out); + //len <= 12. + fs_result read_num(uint64_t offset, unsigned len, uint64_t &out); + fs_result first_child_starting_at(node_id_t parent, node_id_t start, std::optional &out); + fs_result get_dir_entry(node_id_t node, dir_entry &entry); + + public: + tarfs_instance(block_device *bd); + + fs_result get_root_node(node_id_t &out); + fs_result get_first_child(node_id_t node, std::optional &out, directory_iter_t &iter_out); + fs_result get_next_child(node_id_t node, std::optional &out, directory_iter_t &iter); + fs_result read_bytes_from_file(node_id_t node, uint64_t start, uint64_t count, void *into); + + }; + +} + +#endif diff --git a/include/hilbert/kernel/syscall.hpp b/include/hilbert/kernel/syscall.hpp new file mode 100644 index 0000000..c83e514 --- /dev/null +++ b/include/hilbert/kernel/syscall.hpp @@ -0,0 +1,13 @@ +#include + +namespace hilbert::kernel::syscall { + + typedef void (*syscall_handler)( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx); + + void init_syscalls(); + + //assumes this rax has not been used yet and is < 256. + void add_syscall(uint64_t rax, syscall_handler handler); + +} diff --git a/include/hilbert/kernel/terminal.hpp b/include/hilbert/kernel/terminal.hpp new file mode 100644 index 0000000..78ddbe8 --- /dev/null +++ b/include/hilbert/kernel/terminal.hpp @@ -0,0 +1,35 @@ +#ifndef HILBERT_KERNEL_TERMINAL_HPP +#define HILBERT_KERNEL_TERMINAL_HPP + +#include +#include +#include +#include + +namespace hilbert::kernel::terminal { + + extern uint8_t *termfont; + extern uint64_t termfont_len; + + void init_terminal(); + + extern int width; + extern int height; + + extern int cursor_x; + extern int cursor_y; + + extern framebuffer::color bg_color; + extern framebuffer::color fg_color; + + void put_char(char ch); + void put_string(const utility::string &str); + void put_string_sz(const char *str); + + void put_int_decimal(uint64_t n, bool with_commas = true); + + void put_int_hex(uint64_t n, int digits, bool with_dots = true); + +} + +#endif diff --git a/include/hilbert/kernel/utility.hpp b/include/hilbert/kernel/utility.hpp new file mode 100644 index 0000000..930264a --- /dev/null +++ b/include/hilbert/kernel/utility.hpp @@ -0,0 +1,224 @@ +#ifndef HILBERT_KERNEL_UTILITY_HPP +#define HILBERT_KERNEL_UTILITY_HPP + +#include +#include + +namespace hilbert::kernel::utility { + + template + static inline t min(t a, t b) { + return a < b ? a : b; + } + + //includes start_i, does not include end_i + void mark_bitmap_region_zero(uint64_t *bitmap, uint64_t start_i, uint64_t end_i); + //includes start_i, does not include end_i + void mark_bitmap_region_one(uint64_t *bitmap, uint64_t start_i, uint64_t end_i); + + struct uuid { + uint8_t bytes[16]; + }; + + //if c appears in str, this returns the index of the first time it appears. + //otherwise, this returns len. + static inline unsigned find(const char *str, unsigned len, char c) { + for (unsigned i = 0; i < len; ++i) + if (str[i] == c) + return i; + return len; + } + + //if c appears in str, this returns the index of the last time it appears. + //otherwise, this returns len. + static inline unsigned find_last(const char *str, unsigned len, char c) { + for (unsigned i = len; i > 0; --i) + if (str[i - 1] == c) + return i - 1; + return len; + } + + //str1 starts with str2 + static inline bool starts_with( + const char *str1, unsigned str1_len, const char *str2, unsigned str2_len + ) { + if (str1_len < str2_len) + return false; + for (unsigned i = 0; i < str2_len; ++i) + if (str1[i] != str2[i]) + return false; + return true; + } + + template + struct list { + + struct node { + value_t value; + node *next; + node *prev; + }; + + node *first; + node *last; + + list() : first(0), last(0) {} + + ~list() { + if (first) { + for (node *n = first->next; n; n = n->next) + delete n->prev; + delete last; + } + } + + void insert_end(const value_t &value) { + node *n = new node {}; + n->value = value; + n->next = 0; + n->prev = last; + last = n; + } + + void insert_end(value_t &&value) { + node *n = new node {}; + n->value = value; + n->next = 0; + n->prev = last; + last = n; + } + + void clear() { + for (node *n = first; n; n = n->next) + delete n; + first = 0; + last = 0; + } + + //assumes there is a last. + void remove_last() { + node *new_last = last->prev; + if (new_last) + new_last->next = 0; + else + first = 0; + delete last; + last = new_last; + } + + void remove(node *n) { + if (n->prev) + n->prev->next = n->next; + else + first = n->next; + if (n->next) + n->next->prev = n->prev; + else + last = n->prev; + delete n; + } + + }; + + template + struct vector { + + value_t *buffer; + unsigned buffer_len; + unsigned count; + + vector(unsigned buffer_len = 16) + : buffer(new value_t[buffer_len]), buffer_len(buffer_len), count(0) {} + + vector(const value_t *copy_from, unsigned len) + : buffer(new value_t[len]), buffer_len(len), count(len) { + for (unsigned i = 0; i < len; ++i) + buffer[i] = copy_from[i]; + } + + vector(const vector &other) + : buffer(new value_t[other.buffer_len]), + buffer_len(other.buffer_len), count(other.count) + { + for (unsigned i = 0; i < count; ++i) + buffer[i] = other.buffer[i]; + } + + ~vector() { + if (buffer) + delete[] buffer; + } + + vector &operator =(const vector &other) { + if (buffer) + delete[] buffer; + buffer = new value_t[other.buffer_len]; + buffer_len = other.buffer_len; + count = other.count; + for (unsigned i = 0; i < other.count; ++i) + buffer[i] = other.buffer[i]; + return *this; + } + + vector &operator =(vector &&other) { + if (buffer) + delete[] buffer; + buffer = other.buffer; + buffer_len = other.buffer_len; + count = other.count; + other.buffer = 0; + return *this; + } + + bool operator ==(const vector &other) { + if (other.count != count) + return false; + for (unsigned i = 0; i < count; ++i) + if (other.buffer[i] != buffer[i]) + return false; + return true; + } + + void verify_buffer_len(unsigned target_len) { + if (buffer_len >= target_len) + return; + unsigned new_buffer_len = buffer_len; + do + new_buffer_len *= 2; + while (new_buffer_len < target_len); + value_t *new_buffer = new value_t[new_buffer_len]; + for (unsigned i = 0; i < count; ++i) + new_buffer[i] = std::move(buffer[i]); + delete[] buffer; + buffer = new_buffer; + buffer_len = new_buffer_len; + } + + void add_end(value_t &&v) { + verify_buffer_len(count + 1); + buffer[count] = std::move(v); + ++count; + } + + void add_end(const value_t &v) { + verify_buffer_len(count + 1); + buffer[count] = v; + ++count; + } + + bool starts_with(const vector &other) { + if (count < other.count) + return false; + for (unsigned i = 0; i < other.count; ++i) + if (buffer[i] != other.buffer[i]) + return false; + return true; + } + + }; + + typedef vector string; + +} + +#endif diff --git a/include/hilbert/kernel/vfile.hpp b/include/hilbert/kernel/vfile.hpp new file mode 100644 index 0000000..086b6ab --- /dev/null +++ b/include/hilbert/kernel/vfile.hpp @@ -0,0 +1,67 @@ +#ifndef HILBERT_KERNEL_VFILE_HPP +#define HILBERT_KERNEL_VFILE_HPP + +#include +#include + +//TODO: mounts points. +//maybe a two-way map between mount points and targets? one mount point per +//target and vice versa. only directories may be mount points, and only file +//system roots (which must be directories) may be targets. + +namespace hilbert::kernel::vfile { + + //a canon path contains no . or empty directory names, and + //contains no .. except for at the start of a relative path. + struct canon_path { + + bool absolute; + unsigned parent_count; + utility::vector segments; + + canon_path() : absolute(false), parent_count(0), segments(8) {} + + void parent(); + void rel(const canon_path &r); + + utility::string to_string(bool trailing_slash) const; + + }; + + void canonize_path(const utility::string &name, canon_path &out); + + struct vfile { + + //on followed symlinks, path is the source of the symlink and the + //rest of these are the target. in any case, path should be absolute. + canon_path path; + storage::block_device *bd; + storage::dir_entry dir_entry; + + //TODO: instead of passing root, use saved mount points. + storage::fs_result follow_symlinks( + const vfile &root, std::optional &out) const; + + //dir_entry.type is assumed to be directory. + storage::fs_result get_child( + std::optional &out, const utility::string &name) const; + //dir_entry.type is assumed to be directory. out must be empty on entry. + storage::fs_result get_children(utility::vector &out) const; + + //assumes file is a regular file and [start, start + length) + //is in bounds of file. start and length are in bytes. + storage::fs_result read_file( + uint64_t start, uint64_t length, void *into) const; + + }; + + //path must be absolute. follows symlinks on all but the last node. + //relative_to should be a directory to do the lookup inside; e.g., + //if relative_to is /a/b and path is c, then out becomes /a/b/c. + //TODO: instead of passing root, use saved mount points. + storage::fs_result lookup_path( + const vfile &root, const canon_path &path, std::optional &out); + +} + +#endif diff --git a/include/hilbert/syscall.hpp b/include/hilbert/syscall.hpp new file mode 100644 index 0000000..0e430d1 --- /dev/null +++ b/include/hilbert/syscall.hpp @@ -0,0 +1,24 @@ +#ifndef HILBERT_SYSCALL_HPP +#define HILBERT_SYSCALL_HPP + +#include + +namespace hilbert::syscall { + + typedef uint32_t encoded_color; + + struct [[gnu::packed]] color { + uint8_t r; + uint8_t g; + uint8_t b; + }; + + extern "C" encoded_color encode_color(color c); + + extern "C" void get_framebuffer(encoded_color *&framebuffer_out, + uint32_t &width_out, uint32_t &height_out, uint32_t &pitch_out + ); + +} + +#endif diff --git a/include/mercury/kernel/application.hpp b/include/mercury/kernel/application.hpp deleted file mode 100644 index bc4a763..0000000 --- a/include/mercury/kernel/application.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef MERCURY_KERNEL_APPLICATION_HPP -#define MERCURY_KERNEL_APPLICATION_HPP - -#include -#include - -namespace mercury::kernel::application { - - enum class app_state { - running, - paused, - zombie - }; - - struct app_instance { - - app_state state; - - uint64_t *p4; - uint64_t *p3; - uint64_t *p2; - - bool *p2es_to_free_on_exit; - - uint64_t p4_paddr; - - //set to 0 if none - uint64_t framebuffer_vaddr; - - //only valid if state is zombie - int exit_code; - - //only valid if state is paused - struct { - uint64_t rip; - uint64_t rsp; - //TODO: etc. - } saved_regs; - - app_instance(); - ~app_instance(); - - //2MiB page. vaddr and paddr must be aligned, and vaddr in valid range. - void map_page(uint64_t vaddr, uint64_t paddr, - bool write, bool execute, bool free_pram_on_exit); - - //2MiB pages. returns start of first page. - uint64_t get_free_vaddr_pages(uint64_t count); - - void create_stack(); - - void set_instruction_pointer(uint64_t vaddr); - - //2MiB pages; only lower half. - uint64_t count_mapped_vram_pages(); - - }; - - extern app_instance *running_app; - - enum class create_app_result { - success, - device_error, - app_corrupt, - fs_corrupt - }; - - create_app_result create_app(const vfile::vfile &file, app_instance *&out); - -} - -#endif diff --git a/include/mercury/kernel/framebuffer.hpp b/include/mercury/kernel/framebuffer.hpp deleted file mode 100644 index 677a42a..0000000 --- a/include/mercury/kernel/framebuffer.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MERCURY_KERNEL_FRAMEBUFFER_HPP -#define MERCURY_KERNEL_FRAMEBUFFER_HPP - -#include - -namespace mercury::kernel::framebuffer { - - extern uint32_t *vaddr; - extern int width; - extern int height; - extern int dword_pitch; - - void init_framebuffer(uint64_t vaddr, uint64_t width, uint64_t height, uint64_t pitch); - - typedef uint32_t color; - color encode_color(uint8_t r, uint8_t g, uint8_t b); - - void set_pixel(int x, int y, color c); - - //[from_start_x, from_end_x) x [from_start_y, from_end_y) -> [to_start_x, ...) x [to_start_y, ...) - //we assume from_start_x < from_end_x and from_start_y < from_end_y - void move_region(int from_start_x, int from_start_y, int from_end_x, int from_end_y, int to_start_x, int to_start_y); - - //[start_x, end_x) x [start_y, end_y) - void fill_region(int start_x, int start_y, int end_x, int end_y, color c); - -} - -#endif diff --git a/include/mercury/kernel/paging.hpp b/include/mercury/kernel/paging.hpp deleted file mode 100644 index f6d400a..0000000 --- a/include/mercury/kernel/paging.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef MERCURY_KERNEL_PAGING_HPP -#define MERCURY_KERNEL_PAGING_HPP - -#include - -//in paging.asm -extern "C" [[noreturn]] void switch_to_kernel_p4(void (*and_then_jump_to)()); - -namespace mercury::kernel::paging { - - void mark_all_pram_used(); - void mark_all_vram_free(); - - void mark_pram_region_free(uint64_t start_addr, uint64_t end_addr); - void mark_vram_region_used(uint64_t start_addr, uint64_t end_addr); - - uint64_t find_unmapped_vram_region(uint64_t page_count); - - uint64_t encode_pte( - uint64_t addr, bool user, bool write, bool execute, bool ps); - - void init_kernel_page_tables(uint64_t kernel_offset); - - void map_kernel_stacks(); - - void map_kernel_page( - uint64_t paddr, uint64_t vaddr, bool write, bool execute); - - void unmap_kernel_page(uint64_t vaddr); - - //maps writable and not executable - void *map_new_kernel_pages(uint64_t count); - - //maps writable and not executable - void map_new_kernel_page(uint64_t &vaddr_out, uint64_t &paddr_out); - - uint64_t get_used_vram_page_count(); - uint64_t get_free_pram_page_count(); - - extern uint64_t kernel_p4e; - - uint64_t take_2mib_pram_page(); - -} - -#endif diff --git a/include/mercury/kernel/storage.hpp b/include/mercury/kernel/storage.hpp deleted file mode 100644 index 61e7d3b..0000000 --- a/include/mercury/kernel/storage.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef MERCURY_KERNEL_STORAGE_HPP -#define MERCURY_KERNEL_STORAGE_HPP - -#include -#include - -namespace mercury::kernel::storage { - - typedef uint64_t node_id_t; - typedef uint64_t directory_iter_t; - - enum class file_type { - regular_file, - directory, - symlink - }; - - enum class bd_result { - success, - out_of_bounds, - device_error - }; - - enum class fs_result { - success, - device_error, - fs_corrupt - }; - - struct dir_entry { - utility::string name; - node_id_t node; - file_type type; - //only used if type is regular_file. - uint64_t length; - //only used if type is symlink. - utility::string target; - }; - - class file_system_instance { - - public: - virtual ~file_system_instance() {} - - virtual fs_result get_root_node(node_id_t &out) = 0; - - //it is assumed that this is a directory. sets iter_out - //to a value that can be passed to subsequent calls - //to get_next_child with the same argument for node. - virtual fs_result get_first_child(node_id_t node, std::optional &out, directory_iter_t &iter_out) = 0; - - //it is assumed that this is a directory. sets iter_out - //to a value that can be passed to subsequent calls - //to get_next_child with the same argument for node. - virtual fs_result get_next_child(node_id_t node, std::optional &out, directory_iter_t &iter) = 0; - - //it is assumed that this is a regular file and that - //the region requested is within the bounds of the file. - virtual fs_result read_bytes_from_file(node_id_t node, uint64_t start, uint64_t count, void *into) = 0; - - }; - - class block_device { - - private: - uint8_t *block_cache; - uint64_t block_cache_i; - - //it is assumed that this block is within the bounds of the device. - bd_result load_cache_block(uint64_t i); - - protected: - //implemented in driver. it is assumed that the - //blocks are within the bounds of the device. - virtual bd_result read_blocks_no_cache(uint64_t start, uint64_t count, void *into) = 0; - - //it is assumed that this is only called once, by the driver, after - //block_size and block_count have been set, and before read_bytes or - //write_bytes can be called (e.g. in the derived class's constructor). - void allocate_block_cache(); - - public: - //set by storage component - file_system_instance *mounted_as; - //set by storage component - utility::uuid id; - - //set by driver - uint64_t block_size; - //set by driver - uint64_t block_count; - - virtual ~block_device() { - if (block_cache) - delete block_cache; - } - - bd_result read_bytes(uint64_t start, uint64_t count, void *into); - - }; - -} - -#endif diff --git a/include/mercury/kernel/storage/bd/memory.hpp b/include/mercury/kernel/storage/bd/memory.hpp deleted file mode 100644 index e12d565..0000000 --- a/include/mercury/kernel/storage/bd/memory.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MERCURY_KERNEL_STORAGE_BD_MEMORY_HPP -#define MERCURY_KERNEL_STORAGE_BD_MEMORY_HPP - -#include - -namespace mercury::kernel::storage::bd { - - class memory : public block_device { - - private: - uint8_t *buffer; - - public: - memory(void *buffer, uint64_t buffer_len); - - bd_result read_blocks_no_cache(uint64_t start, uint64_t count, void *into) override; - - }; - -} - -#endif diff --git a/include/mercury/kernel/storage/fs/tarfs.hpp b/include/mercury/kernel/storage/fs/tarfs.hpp deleted file mode 100644 index 9e16207..0000000 --- a/include/mercury/kernel/storage/fs/tarfs.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef MERCURY_KERNEL_STORAGE_FS_TARFS_HPP -#define MERCURY_KERNEL_STORAGE_FS_TARFS_HPP - -#include - -namespace mercury::kernel::storage::fs { - - class tarfs_instance : public file_system_instance { - - private: - block_device *bd; - - fs_result next_node(node_id_t node, std::optional &out); - fs_result read_full_name(node_id_t node, utility::string &out); - //len <= 12. - fs_result read_num(uint64_t offset, unsigned len, uint64_t &out); - fs_result first_child_starting_at(node_id_t parent, node_id_t start, std::optional &out); - fs_result get_dir_entry(node_id_t node, dir_entry &entry); - - public: - tarfs_instance(block_device *bd); - - fs_result get_root_node(node_id_t &out); - fs_result get_first_child(node_id_t node, std::optional &out, directory_iter_t &iter_out); - fs_result get_next_child(node_id_t node, std::optional &out, directory_iter_t &iter); - fs_result read_bytes_from_file(node_id_t node, uint64_t start, uint64_t count, void *into); - - }; - -} - -#endif diff --git a/include/mercury/kernel/terminal.hpp b/include/mercury/kernel/terminal.hpp deleted file mode 100644 index 7b2d27a..0000000 --- a/include/mercury/kernel/terminal.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef MERCURY_KERNEL_TERMINAL_HPP -#define MERCURY_KERNEL_TERMINAL_HPP - -#include -#include -#include -#include - -namespace mercury::kernel::terminal { - - extern uint8_t *termfont; - extern uint64_t termfont_len; - - void init_terminal(); - - extern int width; - extern int height; - - extern int cursor_x; - extern int cursor_y; - - extern framebuffer::color bg_color; - extern framebuffer::color fg_color; - - void put_char(char ch); - void put_string(const utility::string &str); - void put_string_sz(const char *str); - - void put_int_decimal(uint64_t n, bool with_commas = true); - - void put_int_hex(uint64_t n, int digits, bool with_dots = true); - -} - -#endif diff --git a/include/mercury/kernel/utility.hpp b/include/mercury/kernel/utility.hpp deleted file mode 100644 index 3edd7d4..0000000 --- a/include/mercury/kernel/utility.hpp +++ /dev/null @@ -1,224 +0,0 @@ -#ifndef MERCURY_KERNEL_UTILITY_HPP -#define MERCURY_KERNEL_UTILITY_HPP - -#include -#include - -namespace mercury::kernel::utility { - - template - static inline t min(t a, t b) { - return a < b ? a : b; - } - - //includes start_i, does not include end_i - void mark_bitmap_region_zero(uint64_t *bitmap, uint64_t start_i, uint64_t end_i); - //includes start_i, does not include end_i - void mark_bitmap_region_one(uint64_t *bitmap, uint64_t start_i, uint64_t end_i); - - struct uuid { - uint8_t bytes[16]; - }; - - //if c appears in str, this returns the index of the first time it appears. - //otherwise, this returns len. - static inline unsigned find(const char *str, unsigned len, char c) { - for (unsigned i = 0; i < len; ++i) - if (str[i] == c) - return i; - return len; - } - - //if c appears in str, this returns the index of the last time it appears. - //otherwise, this returns len. - static inline unsigned find_last(const char *str, unsigned len, char c) { - for (unsigned i = len; i > 0; --i) - if (str[i - 1] == c) - return i - 1; - return len; - } - - //str1 starts with str2 - static inline bool starts_with( - const char *str1, unsigned str1_len, const char *str2, unsigned str2_len - ) { - if (str1_len < str2_len) - return false; - for (unsigned i = 0; i < str2_len; ++i) - if (str1[i] != str2[i]) - return false; - return true; - } - - template - struct list { - - struct node { - value_t value; - node *next; - node *prev; - }; - - node *first; - node *last; - - list() : first(0), last(0) {} - - ~list() { - if (first) { - for (node *n = first->next; n; n = n->next) - delete n->prev; - delete last; - } - } - - void insert_end(const value_t &value) { - node *n = new node {}; - n->value = value; - n->next = 0; - n->prev = last; - last = n; - } - - void insert_end(value_t &&value) { - node *n = new node {}; - n->value = value; - n->next = 0; - n->prev = last; - last = n; - } - - void clear() { - for (node *n = first; n; n = n->next) - delete n; - first = 0; - last = 0; - } - - //assumes there is a last. - void remove_last() { - node *new_last = last->prev; - if (new_last) - new_last->next = 0; - else - first = 0; - delete last; - last = new_last; - } - - void remove(node *n) { - if (n->prev) - n->prev->next = n->next; - else - first = n->next; - if (n->next) - n->next->prev = n->prev; - else - last = n->prev; - delete n; - } - - }; - - template - struct vector { - - value_t *buffer; - unsigned buffer_len; - unsigned count; - - vector(unsigned buffer_len = 16) - : buffer(new value_t[buffer_len]), buffer_len(buffer_len), count(0) {} - - vector(const value_t *copy_from, unsigned len) - : buffer(new value_t[len]), buffer_len(len), count(len) { - for (unsigned i = 0; i < len; ++i) - buffer[i] = copy_from[i]; - } - - vector(const vector &other) - : buffer(new value_t[other.buffer_len]), - buffer_len(other.buffer_len), count(other.count) - { - for (unsigned i = 0; i < count; ++i) - buffer[i] = other.buffer[i]; - } - - ~vector() { - if (buffer) - delete[] buffer; - } - - vector &operator =(const vector &other) { - if (buffer) - delete[] buffer; - buffer = new value_t[other.buffer_len]; - buffer_len = other.buffer_len; - count = other.count; - for (unsigned i = 0; i < other.count; ++i) - buffer[i] = other.buffer[i]; - return *this; - } - - vector &operator =(vector &&other) { - if (buffer) - delete[] buffer; - buffer = other.buffer; - buffer_len = other.buffer_len; - count = other.count; - other.buffer = 0; - return *this; - } - - bool operator ==(const vector &other) { - if (other.count != count) - return false; - for (unsigned i = 0; i < count; ++i) - if (other.buffer[i] != buffer[i]) - return false; - return true; - } - - void verify_buffer_len(unsigned target_len) { - if (buffer_len >= target_len) - return; - unsigned new_buffer_len = buffer_len; - do - new_buffer_len *= 2; - while (new_buffer_len < target_len); - value_t *new_buffer = new value_t[new_buffer_len]; - for (unsigned i = 0; i < count; ++i) - new_buffer[i] = std::move(buffer[i]); - delete[] buffer; - buffer = new_buffer; - buffer_len = new_buffer_len; - } - - void add_end(value_t &&v) { - verify_buffer_len(count + 1); - buffer[count] = std::move(v); - ++count; - } - - void add_end(const value_t &v) { - verify_buffer_len(count + 1); - buffer[count] = v; - ++count; - } - - bool starts_with(const vector &other) { - if (count < other.count) - return false; - for (unsigned i = 0; i < other.count; ++i) - if (buffer[i] != other.buffer[i]) - return false; - return true; - } - - }; - - typedef vector string; - -} - -#endif diff --git a/include/mercury/kernel/vfile.hpp b/include/mercury/kernel/vfile.hpp deleted file mode 100644 index ce72bb1..0000000 --- a/include/mercury/kernel/vfile.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef MERCURY_KERNEL_VFILE_HPP -#define MERCURY_KERNEL_VFILE_HPP - -#include -#include - -//TODO: mounts points. -//maybe a two-way map between mount points and targets? one mount point per -//target and vice versa. only directories may be mount points, and only file -//system roots (which must be directories) may be targets. - -namespace mercury::kernel::vfile { - - //a canon path contains no . or empty directory names, and - //contains no .. except for at the start of a relative path. - struct canon_path { - - bool absolute; - unsigned parent_count; - utility::vector segments; - - canon_path() : absolute(false), parent_count(0), segments(8) {} - - void parent(); - void rel(const canon_path &r); - - utility::string to_string(bool trailing_slash) const; - - }; - - void canonize_path(const utility::string &name, canon_path &out); - - struct vfile { - - //on followed symlinks, path is the source of the symlink and the - //rest of these are the target. in any case, path should be absolute. - canon_path path; - storage::block_device *bd; - storage::dir_entry dir_entry; - - //TODO: instead of passing root, use saved mount points. - storage::fs_result follow_symlinks( - const vfile &root, std::optional &out) const; - - //dir_entry.type is assumed to be directory. - storage::fs_result get_child( - std::optional &out, const utility::string &name) const; - //dir_entry.type is assumed to be directory. out must be empty on entry. - storage::fs_result get_children(utility::vector &out) const; - - //assumes file is a regular file and [start, start + length) - //is in bounds of file. start and length are in bytes. - storage::fs_result read_file( - uint64_t start, uint64_t length, void *into) const; - - }; - - //path must be absolute. follows symlinks on all but the last node. - //relative_to should be a directory to do the lookup inside; e.g., - //if relative_to is /a/b and path is c, then out becomes /a/b/c. - //TODO: instead of passing root, use saved mount points. - storage::fs_result lookup_path( - const vfile &root, const canon_path &path, std::optional &out); - -} - -#endif diff --git a/include/mercury/syscall.hpp b/include/mercury/syscall.hpp deleted file mode 100644 index f434d91..0000000 --- a/include/mercury/syscall.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef MERCURY_SYSCALL_HPP -#define MERCURY_SYSCALL_HPP - -#include - -namespace mercury::syscall { - - typedef uint32_t encoded_color; - - struct [[gnu::packed]] color { - uint8_t r; - uint8_t g; - uint8_t b; - }; - - extern "C" encoded_color encode_color(color c); - - extern "C" void get_framebuffer(encoded_color *&framebuffer_out, - uint32_t &width_out, uint32_t &height_out, uint32_t &pitch_out - ); - - extern "C" void draw_framebuffer(); - -} - -#endif diff --git a/kernel/allocator.cpp b/kernel/allocator.cpp index b04078c..807bc94 100644 --- a/kernel/allocator.cpp +++ b/kernel/allocator.cpp @@ -1,7 +1,7 @@ -#include +#include #include -namespace mercury::kernel::allocator { +namespace hilbert::kernel::allocator { struct free_entry { uint64_t start; @@ -118,7 +118,7 @@ namespace mercury::kernel::allocator { } -using namespace mercury::kernel::allocator; +using namespace hilbert::kernel::allocator; void *_new(size_t len) { if (len == 0) diff --git a/kernel/application.cpp b/kernel/application.cpp index 19b1dbc..ed8795b 100644 --- a/kernel/application.cpp +++ b/kernel/application.cpp @@ -1,83 +1,87 @@ -#include -#include +#include +#include //TODO - scheduling. -namespace mercury::kernel::application { +namespace hilbert::kernel::application { - app_instance::app_instance() : state(app_state::paused) { + app_instance::app_instance() + : state(app_state::paused), framebuffer_vaddr(0) { - framebuffer_vaddr = 0; + uint64_t p4_vaddr; + paging::map_new_kernel_page(p4_vaddr, p4_paddr); + p4 = (uint64_t *)p4_vaddr; uint64_t p3_paddr; - uint64_t p2_paddr; - - uint64_t p4_vaddr; uint64_t p3_vaddr; - uint64_t p2_vaddr; - - paging::map_new_kernel_page(p4_vaddr, p4_paddr); paging::map_new_kernel_page(p3_vaddr, p3_paddr); - paging::map_new_kernel_page(p2_vaddr, p2_paddr); - - p4 = (uint64_t *)p4_vaddr; p3 = (uint64_t *)p3_vaddr; - p2 = (uint64_t *)p2_vaddr; for (int i = 1; i < 511; ++i) p4[i] = 0; + p4[0] = paging::encode_pte(p3_paddr, true, true, true); p4[511] = paging::kernel_p4e; - p4[0] = paging::encode_pte(p3_paddr, true, true, true, false); - for (int i = 1; i < 512; ++i) + for (int i = 0; i < 512; ++i) { p3[i] = 0; - p3[0] = paging::encode_pte(p2_paddr, true, true, true, false); - - for (int i = 0; i < 512; ++i) - p2[i] = 0; - - p2es_to_free_on_exit = new bool[512]; + p2s[i] = 0; + p1s[i] = 0; + p1es_to_free_on_exit[i] = 0; + } } - app_instance::~app_instance() { + void app_instance::map_page(uint64_t vaddr, uint64_t paddr, + bool write, bool execute, bool free_pram_on_exit + ) { - for (int i = 1; i < 512; ++i) - if (p2[i] != 0 && p2es_to_free_on_exit[i]) { - uint64_t paddr = p2[i] & ~0x1fffffULL; - paging::mark_pram_region_free(paddr, paddr + 0x200000); + uint64_t i = ((vaddr / 4096) / 512) / 512; + uint64_t j = ((vaddr / 4096) / 512) % 512; + uint64_t k = (vaddr / 4096) % 512; + + if (p2s[i] == 0) { + uint64_t p2_paddr; + uint64_t p2_vaddr; + paging::map_new_kernel_page(p2_vaddr, p2_paddr); + p3[i] = paging::encode_pte(p2_paddr, true, true, true); + p2s[i] = (uint64_t *)p2_vaddr; + p1s[i] = new uint64_t *[512]; + p1es_to_free_on_exit[i] = new bool *[512]; + for (int u = 0; u < 512; ++u) { + p2s[i][u] = 0; + p1s[i][u] = 0; + p1es_to_free_on_exit[i][u] = 0; } + } - delete[] p2es_to_free_on_exit; - - uint64_t p2_paddr = p3[0] & ~0x1fffffULL; - paging::unmap_kernel_page((uint64_t)p2); - paging::mark_pram_region_free(p2_paddr, p2_paddr + 4096); - - uint64_t p3_paddr = p4[0] & ~0x1fffffULL; - paging::unmap_kernel_page((uint64_t)p3); - paging::mark_pram_region_free(p3_paddr, p3_paddr + 4096); - - paging::unmap_kernel_page((uint64_t)p4); - paging::mark_pram_region_free(p4_paddr, p4_paddr + 4096); + if (p2s[i][j] == 0) { + uint64_t p1_paddr; + uint64_t p1_vaddr; + paging::map_new_kernel_page(p1_vaddr, p1_paddr); + p2s[i][j] = paging::encode_pte(p1_paddr, true, true, true); + p1s[i][j] = (uint64_t *)p1_vaddr; + p1es_to_free_on_exit[i][j] = new bool[512]; + for (int u = 0; u < 512; ++u) { + p1s[i][j][u] = 0; + p1es_to_free_on_exit[i][j][u] = false; + } + } - } + p1s[i][j][k] = paging::encode_pte(paddr, true, write, execute); + p1es_to_free_on_exit[i][j][k] = free_pram_on_exit; - void app_instance::map_page(uint64_t vaddr, uint64_t paddr, - bool write, bool execute, bool free_pram_on_exit - ) { - uint64_t i = vaddr / 0x200000; - p2[i] = paging::encode_pte(paddr, true, write, execute, true); - p2es_to_free_on_exit[i] = free_pram_on_exit; } uint64_t app_instance::get_free_vaddr_pages(uint64_t count) { - uint64_t start = 1; + uint64_t start = 0x200000 / 4096; uint64_t length = 0; - while (start + length < 510) { + while (start + length <= 0x8000000000 / 4096) { if (length == count) - return start * 0x200000; - if (p2[start + length] == 0) + return start * 4096; + int i = ((start + length) / 512) / 512; + int j = ((start + length) / 512) % 512; + int k = (start + length) % 512; + if (p1s[i] == 0 || p1s[i][j] == 0 || p1s[i][j][k] == 0) ++length; else { start += length + 1; @@ -88,28 +92,15 @@ namespace mercury::kernel::application { return 0; } - void app_instance::create_stack() { - uint64_t stack_paddr = paging::take_2mib_pram_page(); - map_page(0x3fe00000, stack_paddr, true, false, true); - for (int i = 0; i < 512; ++i) { - uint64_t vaddr = paging::find_unmapped_vram_region(1); - paging::map_kernel_page(stack_paddr + 512 * i, vaddr, true, false); - for (int j = 0; j < 4096 / 8; ++j) - *(uint64_t *)(vaddr + j * 8) = 0; - paging::unmap_kernel_page(vaddr); - } - saved_regs.rsp = 0x40000000; - } - - void app_instance::set_instruction_pointer(uint64_t vaddr) { - saved_regs.rip = vaddr; - } - uint64_t app_instance::count_mapped_vram_pages() { uint64_t count = 0; - for (int i = 1; i < 512; ++i) - if (p2[i] != 0) - ++count; + for (int i = 0; i < 512; ++i) + if (p1s[i] != 0) + for (int j = 0; j < 512; ++j) + if (p1s[i][j] != 0) + for (int k = 0; k < 512; ++k) + if (p1s[i][j][k] != 0) + ++count; return count; } @@ -186,18 +177,19 @@ namespace mercury::kernel::application { READ(entry_start + 40, 8, &vsize) READ(entry_start + 4, 4, &flags) - if (vaddr & 0x1fffff) + if (vaddr & 4095) return create_app_result::app_corrupt; if (file.dir_entry.length < foffset + fsize) return create_app_result::app_corrupt; if (fsize > vsize) return create_app_result::app_corrupt; - if (vaddr == 0) + + if (vaddr < 0x200000) return create_app_result::app_corrupt; - uint64_t vpages = (vsize - 1) / 0x200000 + 1; + uint64_t vpages = (vsize - 1) / 4096 + 1; - if (vaddr + vpages * 0x200000 > ((1 << 30) - (4 << 20))) + if (vaddr + vpages * 4096 > 0x8000000000) return create_app_result::app_corrupt; load_info info = { @@ -217,47 +209,55 @@ namespace mercury::kernel::application { for (unsigned i = 0; i < load_infos.count; ++i) { const auto &info = load_infos.buffer[i]; for (uint64_t j = 0; j < info.vpages; ++j) { - uint64_t paddr = paging::take_2mib_pram_page(); - out->map_page(info.vaddr + j * 0x200000, paddr, + uint64_t paddr = paging::take_pram_page(); + out->map_page(info.vaddr + j * 4096, paddr, info.writable, info.executable, true); - for (int k = 0; k < 512; ++k) { - uint64_t offset_in_segment = j * 0x200000 + k * 4096; - uint64_t kvaddr = paging::find_unmapped_vram_region(1); - paging::map_kernel_page(paddr + k * 4096, kvaddr, true, false); - storage::fs_result result = storage::fs_result::success; - if (info.fsize > offset_in_segment) { - if (info.fsize >= offset_in_segment + 4096) - result = file.read_file( - info.foffset + offset_in_segment, 4096, (void *)kvaddr); - else { - int to_read = info.fsize - offset_in_segment; - result = file.read_file( - info.foffset + offset_in_segment, to_read, (void *)kvaddr); - uint8_t *blank = (uint8_t *)(kvaddr + to_read); - for (int i = 0; i < 4096 - to_read; ++i) - blank[i] = 0; - } - } + uint64_t kvaddr = paging::find_unmapped_vram_region(1); + paging::map_kernel_page(paddr, kvaddr, true, false); + storage::fs_result result = storage::fs_result::success; + if (info.fsize > j * 4096) { + if (info.fsize >= j * 4096 + 4096) + result = file.read_file( + info.foffset + j * 4096, 4096, (void *)kvaddr); else { - uint8_t *blank = (uint8_t *)kvaddr; - for (int i = 0; i < 4096; ++i) + int to_read = info.fsize - j * 4096; + result = file.read_file( + info.foffset + j * 4096, to_read, (void *)kvaddr); + uint8_t *blank = (uint8_t *)(kvaddr + to_read); + for (int i = 0; i < 4096 - to_read; ++i) blank[i] = 0; } - paging::unmap_kernel_page(kvaddr); - if (result == storage::fs_result::device_error) { - delete out; - return create_app_result::device_error; - } - if (result == storage::fs_result::fs_corrupt) { - delete out; - return create_app_result::fs_corrupt; - } + } + else { + uint8_t *blank = (uint8_t *)kvaddr; + for (int i = 0; i < 4096; ++i) + blank[i] = 0; + } + paging::unmap_kernel_page(kvaddr); + if (result == storage::fs_result::device_error) { + delete out; + return create_app_result::device_error; + } + if (result == storage::fs_result::fs_corrupt) { + delete out; + return create_app_result::fs_corrupt; } } } - out->create_stack(); - out->set_instruction_pointer(entry_point); + for (uint64_t vaddr = 0x1000; vaddr < 0x1ff000; vaddr += 4096) { + uint64_t paddr = paging::take_pram_page(); + uint64_t kvaddr = paging::find_unmapped_vram_region(1); + paging::map_kernel_page(paddr, kvaddr, true, false); + uint8_t *p = (uint8_t *)kvaddr; + for (int i = 0; i < 4096; ++i) + p[i] = 0; + paging::unmap_kernel_page(kvaddr); + out->map_page(vaddr, paddr, true, false, true); + } + + out->saved_regs.rsp = 0x1ff000; + out->saved_regs.rip = entry_point; return create_app_result::success; diff --git a/kernel/entry.cpp b/kernel/entry.cpp index cce8066..8ba585f 100644 --- a/kernel/entry.cpp +++ b/kernel/entry.cpp @@ -1,13 +1,13 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include -using namespace mercury::kernel; +using namespace hilbert::kernel; LIMINE_BASE_REVISION(1) @@ -173,8 +173,8 @@ extern "C" [[noreturn]] void entry() { //set up framebuffer and terminal: //TODO: assumes framebuffer is 32-bpp rgb - framebuffer::init_framebuffer( - fb_vaddr, framebuffer->width, framebuffer->height, framebuffer->pitch); + framebuffer::init_framebuffer(fb_start, fb_vaddr, + framebuffer->width, framebuffer->height, framebuffer->pitch); //switch to kernel p4 diff --git a/kernel/framebuffer.cpp b/kernel/framebuffer.cpp index a115e0b..dbd735f 100644 --- a/kernel/framebuffer.cpp +++ b/kernel/framebuffer.cpp @@ -1,20 +1,60 @@ -#include +#include +#include +#include -namespace mercury::kernel::framebuffer { +namespace hilbert::kernel::framebuffer { - uint32_t *vaddr; + static uint64_t paddr; + static uint32_t *vaddr; int width; int height; - int dword_pitch; + static int dword_pitch; - void init_framebuffer( - uint64_t vaddr, uint64_t width, uint64_t height, uint64_t pitch + void encode_color_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx ) { + rax = (uint64_t)encode_color( + rdi & 0xff, (rdi >> 8) & 0xff, (rdi >> 16) & 0xff); + rdi = 0; + rsi = 0; + rdx = 0; + } + + void get_framebuffer_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx + ) { + + auto *app = application::running_app; + if (app->framebuffer_vaddr == 0) { + uint64_t pages_needed = (dword_pitch * height * 4 - 1) / 4096 + 1; + uint64_t vaddr = app->get_free_vaddr_pages(pages_needed); + for (uint64_t i = 0; i < pages_needed; ++i) + app->map_page(vaddr + i * 4096, paddr + i * 4096, true, false, false); + app->framebuffer_vaddr = vaddr; + } + + rax = app->framebuffer_vaddr; + rdi = (uint64_t)(uint32_t)width | ((uint64_t)(uint32_t)height << 32); + rsi = (uint32_t)dword_pitch; + rdx = 0; + + } + + void init_framebuffer(uint64_t paddr, uint64_t vaddr, + uint64_t width, uint64_t height, uint64_t pitch + ) { + //TODO: assumes 32-bpp rgb + + framebuffer::paddr = paddr; framebuffer::vaddr = (uint32_t *)vaddr; framebuffer::width = width; framebuffer::height = height; dword_pitch = pitch / 4; + + syscall::add_syscall(0, &encode_color_syscall); + syscall::add_syscall(1, &get_framebuffer_syscall); + } color encode_color(uint8_t r, uint8_t g, uint8_t b) { diff --git a/kernel/interrupts.cpp b/kernel/interrupts.cpp index 8ac986d..1a95f22 100644 --- a/kernel/interrupts.cpp +++ b/kernel/interrupts.cpp @@ -1,6 +1,6 @@ -#include +#include -using namespace mercury::kernel; +using namespace hilbert::kernel; struct [[gnu::packed]] exception_info_t { diff --git a/kernel/paging.cpp b/kernel/paging.cpp index 17b61f4..d8869fc 100644 --- a/kernel/paging.cpp +++ b/kernel/paging.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include //see also ../documentation/memory.txt @@ -7,7 +7,7 @@ extern "C" { uint64_t __kernel_p4_paddr; } -namespace mercury::kernel::paging { +namespace hilbert::kernel::paging { static constexpr uint64_t kernel_vram_start = 0xffffffffc0000000; static constexpr uint64_t kernel_vram_end = 0xffffffffffe00000; @@ -38,11 +38,9 @@ namespace mercury::kernel::paging { uint64_t kernel_p4e; - uint64_t encode_pte( - uint64_t addr, bool user, bool write, bool execute, bool ps - ) { + uint64_t encode_pte(uint64_t addr, bool user, bool write, bool execute) { return (addr & 0x0000ffffffffffff) | (execute ? 0 : (1ULL << 63)) - | (ps << 7) | (user << 2) | (write << 1) | 1; + | (user << 2) | (write << 1) | 1; } void init_kernel_page_tables(uint64_t kernel_offset) { @@ -50,15 +48,15 @@ namespace mercury::kernel::paging { for (int i = 0; i < 511; ++i) kernel_p4[i] = 0; kernel_p4e = encode_pte( - (uint64_t)kernel_p3 - kernel_offset, false, true, true, false); + (uint64_t)kernel_p3 - kernel_offset, false, true, true); kernel_p4[511] = kernel_p4e; for (int i = 0; i < 511; ++i) kernel_p3[i] = 0; kernel_p3[511] = encode_pte( - (uint64_t)kernel_p2 - kernel_offset, false, true, true, false); + (uint64_t)kernel_p2 - kernel_offset, false, true, true); for (int i = 0; i < 512; ++i) kernel_p2[i] = encode_pte( - (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true, false); + (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true); for (int i = 0; i < 512 * 512; ++i) kernel_p1s[i] = 0; } @@ -66,7 +64,7 @@ namespace mercury::kernel::paging { void map_kernel_page( uint64_t paddr, uint64_t vaddr, bool write, bool execute) { uint64_t i = (vaddr - kernel_vram_start) / 4096; - kernel_p1s[i] = encode_pte(paddr, false, write, execute, false); + kernel_p1s[i] = encode_pte(paddr, false, write, execute); } void unmap_kernel_page(uint64_t vaddr) { @@ -77,7 +75,7 @@ namespace mercury::kernel::paging { ); } - static uint64_t take_pram_page() { + uint64_t take_pram_page() { for (uint64_t i = 0; i < pram_pages / 64; ++i) if (~pram_usage_bitmap[i] != 0) for (int j = 0; j < 64; ++j) @@ -89,21 +87,6 @@ namespace mercury::kernel::paging { return 0; } - uint64_t take_2mib_pram_page() { - for (uint64_t i = 0; i < pram_pages / 512; ++i) { - for (int j = 0; j < 8; ++j) - if (pram_usage_bitmap[i * 8 + j] != 0) - goto next_i; - for (int j = 0; j < 8; ++j) - pram_usage_bitmap[i * 8 + j] = ~0ULL; - return 0x200000 * i; - next_i: - ; - } - //TODO: handle error - return 0; - } - void map_kernel_stacks() { for (uint64_t vaddr = syscall_stack_bottom; vaddr < syscall_stack_top; vaddr += 4096) diff --git a/kernel/storage.cpp b/kernel/storage.cpp index f500f8e..b6b1a04 100644 --- a/kernel/storage.cpp +++ b/kernel/storage.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace mercury::kernel::storage { +namespace hilbert::kernel::storage { bd_result block_device::load_cache_block(uint64_t i) { diff --git a/kernel/storage/bd/memory.cpp b/kernel/storage/bd/memory.cpp index 2f82099..d6a6719 100644 --- a/kernel/storage/bd/memory.cpp +++ b/kernel/storage/bd/memory.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace mercury::kernel::storage::bd { +namespace hilbert::kernel::storage::bd { memory::memory(void *buffer, uint64_t buffer_len) : buffer((uint8_t *)buffer) diff --git a/kernel/storage/fs/tarfs.cpp b/kernel/storage/fs/tarfs.cpp index 4b752a2..fb1eff8 100644 --- a/kernel/storage/fs/tarfs.cpp +++ b/kernel/storage/fs/tarfs.cpp @@ -1,9 +1,9 @@ -#include +#include //in tarfs_instance, node_id_t and directory_iter_t refer to the number //of bytes into the block device that the info sector is located. -namespace mercury::kernel::storage::fs { +namespace hilbert::kernel::storage::fs { #define BD_TO_FS(expr) \ { \ diff --git a/kernel/syscall.asm b/kernel/syscall.asm index e4e0d77..c293402 100644 --- a/kernel/syscall.asm +++ b/kernel/syscall.asm @@ -4,51 +4,7 @@ global start_user_mode section .text -extern syscall_encode_color - -encode_color_syscall: - call syscall_encode_color - mov edi, eax - xor rax, rax - mov eax, edi - xor rdi, rdi - xor rsi, rsi - xor rdx, rdx - jmp syscall_return - -extern syscall_get_fb_vaddr -extern syscall_get_fb_dims -extern syscall_get_fb_pitch - -get_framebuffer_syscall: - call syscall_get_fb_vaddr - push rax - call syscall_get_fb_dims - push rax - call syscall_get_fb_pitch - xor rsi, rsi - mov esi, eax - pop rdi - pop rax - xor rdx, rdx - jmp syscall_return - -extern syscall_copy_framebuffer - -draw_framebuffer_syscall: - call syscall_copy_framebuffer - xor rax, rax - xor rdi, rdi - xor rsi, rsi - xor rdx, rdx - jmp syscall_return - -bad_syscall: - xor rax, rax - xor rdi, rdi - xor rsi, rsi - xor rdx, rdx - jmp syscall_return +extern do_syscall syscall_entry: mov r11, rsp @@ -56,15 +12,23 @@ syscall_entry: push r11 push rcx - cmp rax, 0 - je encode_color_syscall - cmp rax, 1 - je get_framebuffer_syscall - cmp rax, 2 - je draw_framebuffer_syscall - jmp bad_syscall + push rdx + push rsi + push rdi + push rax + + mov rdi, rsp + lea rsi, [rsp + 8] + lea rdx, [rsp + 16] + lea rcx, [rsp + 24] + + call do_syscall + + pop rax + pop rdi + pop rsi + pop rdx -syscall_return: xor r8, r8 xor r9, r9 xor r10, r10 diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index e91d12d..3aa4105 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1,46 +1,36 @@ -#include -#include -#include +#include +#include +#include +#include -using namespace mercury::kernel; +namespace hilbert::kernel::syscall { -extern "C" uint32_t syscall_encode_color(uint32_t c) { - return (uint32_t)framebuffer::encode_color( - c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff - ); -} + syscall_handler handlers[256]; -extern "C" uint64_t syscall_get_fb_vaddr() { - auto *app = application::running_app; - if (app->framebuffer_vaddr != 0) - return app->framebuffer_vaddr; - uint64_t fb_len = framebuffer::dword_pitch * framebuffer::height * 4; - uint64_t fb_pages = (fb_len - 1) / 0x200000 + 1; - uint64_t vaddr = app->get_free_vaddr_pages(fb_pages); - for (uint64_t i = 0; i < fb_pages; ++i) { - uint64_t paddr = paging::take_2mib_pram_page(); - app->map_page(vaddr + i * 0x200000, paddr, true, false, true); + void init_syscalls() { + for (int i = 0; i < 256; ++i) + handlers[i] = 0; } - app->framebuffer_vaddr = vaddr; - return vaddr; -} -extern "C" uint64_t syscall_get_fb_dims() { - return (uint64_t)(uint32_t)framebuffer::width + - ((uint64_t)(uint32_t)framebuffer::height << 32); -} + void add_syscall(uint64_t rax, syscall_handler handler) { + handlers[rax] = handler; + } -extern "C" uint32_t syscall_get_fb_pitch() { - return (uint32_t)framebuffer::dword_pitch; } -extern "C" void syscall_copy_framebuffer() { - auto *app = application::running_app; - if (app->framebuffer_vaddr != 0) { - const uint32_t *source = (const uint32_t *)app->framebuffer_vaddr; - for (int y = 0; y < framebuffer::height; ++y) - for (int x = 0; x < framebuffer::width; ++x) - framebuffer::vaddr[y * framebuffer::dword_pitch + x] - = source[y * framebuffer::dword_pitch + x]; +using namespace hilbert::kernel::syscall; + +extern "C" void do_syscall( + uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx +) { + + if (rax < 256 && handlers[rax] != 0) + handlers[rax](rax, rdi, rsi, rdx); + else { + rax = 0; + rdi = 0; + rsi = 0; + rdx = 0; } + } diff --git a/kernel/terminal.cpp b/kernel/terminal.cpp index 1074fe7..167e6cf 100644 --- a/kernel/terminal.cpp +++ b/kernel/terminal.cpp @@ -1,7 +1,7 @@ -#include -#include +#include +#include -namespace mercury::kernel::terminal { +namespace hilbert::kernel::terminal { uint8_t *termfont; uint64_t termfont_len; diff --git a/kernel/utility.cpp b/kernel/utility.cpp index 865b817..249fb2c 100644 --- a/kernel/utility.cpp +++ b/kernel/utility.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace mercury::kernel::utility { +namespace hilbert::kernel::utility { void mark_bitmap_region_zero( uint64_t *bitmap, uint64_t start_i, uint64_t end_i) { diff --git a/kernel/vfile.cpp b/kernel/vfile.cpp index 3b9dcb2..74cfbf9 100644 --- a/kernel/vfile.cpp +++ b/kernel/vfile.cpp @@ -1,9 +1,9 @@ -#include +#include //TODO: handle symlink loops nicely in vfile::get_child, // vfile::get_children, and lookup_path. -namespace mercury::kernel::vfile { +namespace hilbert::kernel::vfile { void canon_path::parent() { if (segments.count != 0) diff --git a/limine.cfg b/limine.cfg index 505c8f4..4a411a1 100644 --- a/limine.cfg +++ b/limine.cfg @@ -1,5 +1,5 @@ TIMEOUT=0 -:Mercury +:Hilbert PROTOCOL=limine KERNEL_PATH=boot:///kernel.elf diff --git a/makefile b/makefile index 2d103b3..4c285f0 100644 --- a/makefile +++ b/makefile @@ -18,14 +18,14 @@ clean: dist-clean: rm -rf limine - rm -f include/mercury/kernel/limine.hpp + rm -f include/hilbert/kernel/limine.hpp limine: git clone --depth=1 -b v6.x-branch \ https://github.com/limine-bootloader/limine.git limine cd limine && ./bootstrap && ./configure -q --enable-bios --enable-bios-cd +make -C limine - cp limine/limine.h include/mercury/kernel/limine.hpp + cp limine/limine.h include/hilbert/kernel/limine.hpp obj/kernel/entry.cpp.o: kernel/entry.cpp limine @mkdir -p $(@D) diff --git a/readme.txt b/readme.txt index 7f4a2e2..ed4340e 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -mercury is a 64-bit hobby operating system. to build and test it, you will need +hilbert is a 64-bit hobby operating system. to build and test it, you will need some dependencies. these can be installed on debian with: apt install g++ gcc gdb git make nasm qemu-system-x86 xorriso then, just run "make -jx", replacing x with the number of threads to use while diff --git a/stdlib/syscall.asm b/stdlib/syscall.asm index eba7ec0..922ca1b 100644 --- a/stdlib/syscall.asm +++ b/stdlib/syscall.asm @@ -28,8 +28,3 @@ get_framebuffer: pop rcx mov dword [rcx], esi ret - -draw_framebuffer: - mov rax, 2 - syscall - ret -- cgit v1.2.3