summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/allocator.cpp2
-rw-r--r--kernel/application.cpp16
-rw-r--r--kernel/entry.cpp29
-rw-r--r--kernel/framebuffer.cpp38
-rw-r--r--kernel/include/hilbert/kernel/application.hpp77
-rw-r--r--kernel/include/hilbert/kernel/framebuffer.hpp31
-rw-r--r--kernel/include/hilbert/kernel/paging.hpp42
-rw-r--r--kernel/include/hilbert/kernel/storage.hpp106
-rw-r--r--kernel/include/hilbert/kernel/storage/bd/memory.hpp20
-rw-r--r--kernel/include/hilbert/kernel/storage/fs/tarfs.hpp33
-rw-r--r--kernel/include/hilbert/kernel/terminal.hpp32
-rw-r--r--kernel/include/hilbert/kernel/utility.hpp297
-rw-r--r--kernel/include/hilbert/kernel/vfile.hpp63
-rw-r--r--kernel/storage/fs/tarfs.cpp102
-rw-r--r--kernel/syscall.cpp250
-rw-r--r--kernel/utility.cpp6
-rw-r--r--kernel/vfile.cpp85
17 files changed, 1060 insertions, 169 deletions
diff --git a/kernel/allocator.cpp b/kernel/allocator.cpp
index 807bc94..324f992 100644
--- a/kernel/allocator.cpp
+++ b/kernel/allocator.cpp
@@ -1,5 +1,5 @@
#include <hilbert/kernel/paging.hpp>
-#include <cstddef>
+#include <stddef.h>
namespace hilbert::kernel::allocator {
diff --git a/kernel/application.cpp b/kernel/application.cpp
index ed8795b..af31a09 100644
--- a/kernel/application.cpp
+++ b/kernel/application.cpp
@@ -72,6 +72,15 @@ namespace hilbert::kernel::application {
}
+ bool app_instance::is_page_owned(uint64_t vaddr) {
+ uint64_t i = ((vaddr / 4096) / 512) / 512;
+ uint64_t j = ((vaddr / 4096) / 512) % 512;
+ uint64_t k = (vaddr / 4096) % 512;
+ return
+ i < 512 && p1s[i] != 0 && p1s[i][j] != 0 &&
+ p1s[i][j][k] != 0 && p1es_to_free_on_exit[i][j][k];
+ }
+
uint64_t app_instance::get_free_vaddr_pages(uint64_t count) {
uint64_t start = 0x200000 / 4096;
uint64_t length = 0;
@@ -129,7 +138,10 @@ namespace hilbert::kernel::application {
bool executable;
};
- create_app_result create_app(const vfile::vfile &file, app_instance *&out) {
+ create_app_result create_app(
+ const vfile::vfile &file, app_instance *&out,
+ const vfile::vfile &working_dir
+ ) {
uint8_t magic[16];
if (file.dir_entry.length < 64)
@@ -259,6 +271,8 @@ namespace hilbert::kernel::application {
out->saved_regs.rsp = 0x1ff000;
out->saved_regs.rip = entry_point;
+ out->working_dir = working_dir;
+
return create_app_result::success;
}
diff --git a/kernel/entry.cpp b/kernel/entry.cpp
index 8ba585f..3a42df7 100644
--- a/kernel/entry.cpp
+++ b/kernel/entry.cpp
@@ -3,9 +3,9 @@
#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/framebuffer.hpp>
#include <hilbert/kernel/terminal.hpp>
-#include <hilbert/kernel/limine.hpp>
#include <hilbert/kernel/paging.hpp>
#include <hilbert/kernel/vfile.hpp>
+#include "../limine/limine.h"
using namespace hilbert::kernel;
@@ -197,32 +197,31 @@ extern "C" [[noreturn]] void start_user_mode(
terminal::init_terminal();
- storage::bd::memory initfs_bd(initfs, initfs_len);
- storage::fs::tarfs_instance initfs_fs(&initfs_bd);
- initfs_bd.mounted_as = &initfs_fs;
+ auto *initfs_bd = new storage::bd::memory(initfs, initfs_len);
+ auto *initfs_fs = new storage::fs::tarfs_instance(initfs_bd);
+ initfs_bd->mounted_as = initfs_fs;
- vfile::vfile vfs_root;
- vfs_root.bd = &initfs_bd;
- vfs_root.dir_entry.type = storage::file_type::directory;
- vfs_root.path.absolute = true;
+ vfile::vfile initfs_root;
+ initfs_root.bd = initfs_bd;
+ initfs_root.dir_entry.type = storage::file_type::directory;
+ initfs_root.path.absolute = true;
- if (initfs_fs.get_root_node(vfs_root.dir_entry.node) !=
+ if (initfs_fs->get_root_node(initfs_root.dir_entry.node) !=
storage::fs_result::success)
print_and_halt("failed to get root node of initfs.");
+ vfile::set_root(initfs_root);
+
utility::string init_path_string("/bin/init.elf", 13);
vfile::canon_path init_path;
vfile::canonize_path(init_path_string, init_path);
- std::optional<vfile::vfile> init_file;
- if (vfile::lookup_path(vfs_root, init_path, init_file) !=
- storage::fs_result::success)
+ vfile::vfile init_file;
+ if (vfile::lookup_path(init_path, init_file) != storage::fs_result::success)
print_and_halt("failed to look up /bin/init.elf.");
- if (!init_file)
- print_and_halt("/bin/init.elf does not exist.");
application::app_instance *init;
- if (application::create_app(*init_file, init) !=
+ if (application::create_app(init_file, init, initfs_root) !=
application::create_app_result::success)
print_and_halt("failed to parse /bin/init.elf.");
diff --git a/kernel/framebuffer.cpp b/kernel/framebuffer.cpp
index dbd735f..08d0e16 100644
--- a/kernel/framebuffer.cpp
+++ b/kernel/framebuffer.cpp
@@ -1,44 +1,13 @@
#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/syscall.hpp>
namespace hilbert::kernel::framebuffer {
- static uint64_t paddr;
+ uint64_t paddr;
static uint32_t *vaddr;
int width;
int height;
- static int dword_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;
-
- }
+ int dword_pitch;
void init_framebuffer(uint64_t paddr, uint64_t vaddr,
uint64_t width, uint64_t height, uint64_t pitch
@@ -52,9 +21,6 @@ namespace hilbert::kernel::framebuffer {
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/include/hilbert/kernel/application.hpp b/kernel/include/hilbert/kernel/application.hpp
new file mode 100644
index 0000000..51f304d
--- /dev/null
+++ b/kernel/include/hilbert/kernel/application.hpp
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <hilbert/kernel/vfile.hpp>
+#include <stdint.h>
+
+//TODO: end application, threading.
+
+namespace hilbert::kernel::application {
+
+ void init_syscalls();
+
+ enum class app_state {
+ running,
+ paused,
+ zombie
+ };
+
+ struct app_instance {
+
+ utility::id_allocator<vfile::vfile> open_files;
+
+ vfile::vfile working_dir;
+
+ 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
+ int32_t 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);
+
+ //where "owned" means in lower half and marked free on exit
+ bool is_page_owned(uint64_t vaddr);
+
+ //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, const vfile::vfile &working_dir);
+
+}
diff --git a/kernel/include/hilbert/kernel/framebuffer.hpp b/kernel/include/hilbert/kernel/framebuffer.hpp
new file mode 100644
index 0000000..fb28462
--- /dev/null
+++ b/kernel/include/hilbert/kernel/framebuffer.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <stdint.h>
+
+namespace hilbert::kernel::framebuffer {
+
+ extern uint64_t paddr;
+ extern int width;
+ extern int height;
+ extern int dword_pitch;
+
+ 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);
+
+}
diff --git a/kernel/include/hilbert/kernel/paging.hpp b/kernel/include/hilbert/kernel/paging.hpp
new file mode 100644
index 0000000..91ab5f7
--- /dev/null
+++ b/kernel/include/hilbert/kernel/paging.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <stdint.h>
+
+//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;
+
+}
diff --git a/kernel/include/hilbert/kernel/storage.hpp b/kernel/include/hilbert/kernel/storage.hpp
new file mode 100644
index 0000000..2e2169e
--- /dev/null
+++ b/kernel/include/hilbert/kernel/storage.hpp
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <hilbert/kernel/utility.hpp>
+#include <stdint.h>
+
+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,
+ does_not_exist
+ };
+
+ 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, dir_entry &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, dir_entry &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);
+
+ };
+
+}
diff --git a/kernel/include/hilbert/kernel/storage/bd/memory.hpp b/kernel/include/hilbert/kernel/storage/bd/memory.hpp
new file mode 100644
index 0000000..e057241
--- /dev/null
+++ b/kernel/include/hilbert/kernel/storage/bd/memory.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <hilbert/kernel/storage.hpp>
+
+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;
+
+ };
+
+}
diff --git a/kernel/include/hilbert/kernel/storage/fs/tarfs.hpp b/kernel/include/hilbert/kernel/storage/fs/tarfs.hpp
new file mode 100644
index 0000000..cef35f2
--- /dev/null
+++ b/kernel/include/hilbert/kernel/storage/fs/tarfs.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <hilbert/kernel/storage.hpp>
+
+namespace hilbert::kernel::storage::fs {
+
+ class tarfs_instance : public file_system_instance {
+
+ private:
+ block_device *bd;
+
+ fs_result next_node(node_id_t node, node_id_t &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, node_id_t &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,
+ dir_entry &out, directory_iter_t &iter_out);
+ fs_result get_next_child(
+ node_id_t node, dir_entry &out, directory_iter_t &iter);
+ fs_result read_bytes_from_file(
+ node_id_t node, uint64_t start, uint64_t count, void *into);
+
+ };
+
+}
diff --git a/kernel/include/hilbert/kernel/terminal.hpp b/kernel/include/hilbert/kernel/terminal.hpp
new file mode 100644
index 0000000..350d79b
--- /dev/null
+++ b/kernel/include/hilbert/kernel/terminal.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <hilbert/kernel/framebuffer.hpp>
+#include <hilbert/kernel/utility.hpp>
+#include <stddef.h>
+#include <stdint.h>
+
+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);
+
+}
diff --git a/kernel/include/hilbert/kernel/utility.hpp b/kernel/include/hilbert/kernel/utility.hpp
new file mode 100644
index 0000000..2df1d65
--- /dev/null
+++ b/kernel/include/hilbert/kernel/utility.hpp
@@ -0,0 +1,297 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+void *operator new(size_t, void *ptr);
+void operator delete(void *, void *);
+
+namespace hilbert::kernel::utility {
+
+ template <class t>
+ struct no_ref;
+ template <class t>
+ struct no_ref<t &&> {
+ typedef t _t;
+ };
+ template <class t>
+ struct no_ref<t &> {
+ typedef t _t;
+ };
+ template <class t>
+ struct no_ref {
+ typedef t _t;
+ };
+
+ template <class t>
+ constexpr typename no_ref<t>::_t &&move(t &&v) {
+ return static_cast<typename no_ref<t>::_t &&>(v);
+ }
+
+ template <class t>
+ 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 <class value_t>
+ struct list {
+
+ struct node {
+ value_t value;
+ node *next;
+ node *prev;
+ };
+
+ node *first;
+ node *last;
+
+ list() : first(0), last(0) {}
+
+ list(const list &other) = delete;
+ list(list &&other) = delete;
+
+ ~list() {
+ if (first) {
+ for (node *n = first->next; n; n = n->next)
+ delete n->prev;
+ delete last;
+ }
+ }
+
+ list &operator =(const list &other) = delete;
+ list &operator =(list &&other) = delete;
+
+ 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 <class value_t>
+ 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(vector &&other) = delete;
+
+ ~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] = 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] = 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<char> string;
+
+ template <class value_t>
+ struct id_allocator {
+
+ vector<value_t *> the_vector;
+
+ public:
+ id_allocator() : the_vector() {}
+ id_allocator(const id_allocator &other) = delete;
+ id_allocator(id_allocator &&other) = delete;
+ id_allocator &operator =(const id_allocator &other) = delete;
+ id_allocator &operator =(id_allocator &&other) = delete;
+
+ //returns id; pointer becomes owned by id_allocator
+ unsigned add(value_t *v) {
+ for (unsigned i = 0; i < the_vector.count; ++i)
+ if (the_vector.buffer[i] == 0) {
+ the_vector.buffer[i] = v;
+ return i;
+ }
+ the_vector.add_end(v);
+ return the_vector.count - 1;
+ }
+
+ //returns id
+ unsigned add_new(value_t &&v) {
+ return add(new value_t(move(v)));
+ }
+
+ bool has_id(unsigned i) {
+ return i < the_vector.count && the_vector.buffer[i] != 0;
+ }
+
+ value_t &get(unsigned i) {
+ return *the_vector.buffer[i];
+ }
+
+ void remove_id(unsigned i) {
+ delete the_vector.buffer[i];
+ the_vector.buffer[i] = 0;
+ }
+
+ };
+
+}
diff --git a/kernel/include/hilbert/kernel/vfile.hpp b/kernel/include/hilbert/kernel/vfile.hpp
new file mode 100644
index 0000000..f8a387d
--- /dev/null
+++ b/kernel/include/hilbert/kernel/vfile.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <hilbert/kernel/storage.hpp>
+#include <hilbert/kernel/utility.hpp>
+
+//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<utility::string> 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;
+
+ storage::fs_result follow_symlinks(vfile &out) const;
+
+ //dir_entry.type is assumed to be directory.
+ storage::fs_result get_child(
+ vfile &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<vfile> &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;
+
+ };
+
+ //TODO: see comment at top of file.
+ void set_root(const vfile &root);
+
+ //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.
+ storage::fs_result lookup_path(const canon_path &path, vfile &out);
+
+}
diff --git a/kernel/storage/fs/tarfs.cpp b/kernel/storage/fs/tarfs.cpp
index fb1eff8..5986f62 100644
--- a/kernel/storage/fs/tarfs.cpp
+++ b/kernel/storage/fs/tarfs.cpp
@@ -5,27 +5,25 @@
namespace hilbert::kernel::storage::fs {
-#define BD_TO_FS(expr) \
- { \
- bd_result _result = expr; \
- if (_result == bd_result::out_of_bounds) \
- return fs_result::fs_corrupt; \
- if (_result == bd_result::device_error) \
- return fs_result::device_error; \
- }
+ #define BD_TO_FS(expr) \
+ { \
+ bd_result _result = expr; \
+ if (_result == bd_result::out_of_bounds) \
+ return fs_result::fs_corrupt; \
+ if (_result == bd_result::device_error) \
+ return fs_result::device_error; \
+ }
-#define FS_TO_FS(expr) \
- { \
- fs_result _result = expr; \
- if (_result != fs_result::success) \
- return _result; \
- }
+ #define FS_TO_FS(expr) \
+ { \
+ fs_result _result = expr; \
+ if (_result != fs_result::success) \
+ return _result; \
+ }
tarfs_instance::tarfs_instance(block_device *bd) : bd(bd) {}
- fs_result tarfs_instance::next_node(
- node_id_t node, std::optional<node_id_t> &out
- ) {
+ fs_result tarfs_instance::next_node(node_id_t node, node_id_t &out) {
uint64_t bytes;
FS_TO_FS(read_num(node + 124, 12, bytes))
@@ -37,8 +35,7 @@ namespace hilbert::kernel::storage::fs {
if (sector[i] != 0)
return fs_result::success;
- out = {};
- return fs_result::success;
+ return fs_result::does_not_exist;
}
@@ -84,7 +81,7 @@ namespace hilbert::kernel::storage::fs {
}
fs_result tarfs_instance::first_child_starting_at(
- node_id_t parent, node_id_t start, std::optional<node_id_t> &out
+ node_id_t parent, node_id_t start, node_id_t &out
) {
utility::string parent_full_name;
@@ -93,9 +90,9 @@ namespace hilbert::kernel::storage::fs {
utility::string child_full_name;
out = start;
- do {
+ while (true) {
- FS_TO_FS(read_full_name(*out, child_full_name))
+ FS_TO_FS(read_full_name(out, child_full_name))
if (child_full_name.count > parent_full_name.count &&
child_full_name.starts_with(parent_full_name)
@@ -110,11 +107,9 @@ namespace hilbert::kernel::storage::fs {
}
next:
- next_node(*out, out);
+ FS_TO_FS(next_node(out, out))
- } while (out);
-
- return fs_result::success;
+ }
}
@@ -171,7 +166,7 @@ namespace hilbert::kernel::storage::fs {
BD_TO_FS(bd->read_bytes(node + 157, 100, target.buffer))
while (target.count < 100 && target.buffer[target.count] != '\0')
++target.count;
- entry.target = std::move(target);
+ entry.target = utility::move(target);
}
return fs_result::success;
@@ -181,64 +176,53 @@ namespace hilbert::kernel::storage::fs {
fs_result tarfs_instance::get_root_node(node_id_t &out) {
utility::string full_name;
- std::optional<node_id_t> on = 0;
+ node_id_t on = 0;
- do {
+ while (true) {
- FS_TO_FS(read_full_name(*on, full_name))
+ FS_TO_FS(read_full_name(on, full_name))
if (full_name.count == 2) {
- out = *on;
+ out = on;
return fs_result::success;
}
- next_node(*on, on);
-
- } while (on);
+ fs_result result = next_node(on, on);
+ if (result == fs_result::does_not_exist)
+ return fs_result::fs_corrupt;
+ FS_TO_FS(result)
- return fs_result::fs_corrupt;
+ }
}
fs_result tarfs_instance::get_first_child(
- node_id_t node, std::optional<dir_entry> &out, directory_iter_t &iter_out
+ node_id_t node, dir_entry &out, directory_iter_t &iter_out
) {
- std::optional<node_id_t> child;
+ node_id_t child;
FS_TO_FS(first_child_starting_at(node, 0, child))
- if (!child) {
- out = {};
- return fs_result::success;
- }
dir_entry entry;
- FS_TO_FS(get_dir_entry(*child, entry))
- out = std::move(entry);
- iter_out = (directory_iter_t)*child;
+ FS_TO_FS(get_dir_entry(child, entry))
+ out = utility::move(entry);
+ iter_out = (directory_iter_t)child;
return fs_result::success;
}
fs_result tarfs_instance::get_next_child(
- node_id_t node, std::optional<dir_entry> &out, directory_iter_t &iter
+ node_id_t node, dir_entry &out, directory_iter_t &iter
) {
- std::optional<node_id_t> start;
+ node_id_t start;
FS_TO_FS(next_node((node_id_t)iter, start))
- if (!start) {
- out = {};
- return fs_result::success;
- }
- std::optional<node_id_t> child;
- FS_TO_FS(first_child_starting_at(node, *start, child))
- if (!child) {
- out = {};
- return fs_result::success;
- }
+ node_id_t child;
+ FS_TO_FS(first_child_starting_at(node, start, child))
dir_entry entry;
- FS_TO_FS(get_dir_entry(*child, entry))
- out = std::move(entry);
- iter = (directory_iter_t)*child;
+ FS_TO_FS(get_dir_entry(child, entry))
+ out = utility::move(entry);
+ iter = (directory_iter_t)child;
return fs_result::success;
}
diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp
index 3aa4105..3c72d23 100644
--- a/kernel/syscall.cpp
+++ b/kernel/syscall.cpp
@@ -1,21 +1,247 @@
#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/syscall.hpp>
#include <hilbert/kernel/paging.hpp>
+#include <hilbert/kernel/vfile.hpp>
namespace hilbert::kernel::syscall {
- syscall_handler handlers[256];
+ enum file_result : uint64_t {
+ file_result_success,
+ file_result_bad_file_handle,
+ file_result_device_error,
+ file_result_file_system_corrupt,
+ file_result_out_of_bounds,
+ file_result_does_not_exist,
+ file_result_directory
+ };
- void init_syscalls() {
- for (int i = 0; i < 256; ++i)
- handlers[i] = 0;
+ bool is_range_owned_by_application(uint64_t start, uint64_t end) {
+ auto *app = application::running_app;
+ uint64_t pstart = (start / 4096) * 4096;
+ uint64_t pend = ((end - 1) / 4096 + 1) * 4096;
+ for (uint64_t p = pstart; p < pend; p += 4096)
+ if (!app->is_page_owned(p))
+ return false;
+ return true;
}
- void add_syscall(uint64_t rax, syscall_handler handler) {
- handlers[rax] = handler;
+ void set_zero(uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
+ rax = 0;
+ rdi = 0;
+ rsi = 0;
+ rdx = 0;
+ }
+
+ void encode_color_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+ rax = (uint64_t)framebuffer::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 =
+ (framebuffer::dword_pitch * framebuffer::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, framebuffer::paddr + i * 4096, true, false, false);
+ app->framebuffer_vaddr = vaddr;
+ }
+
+ rax = app->framebuffer_vaddr;
+ rdi =
+ (uint64_t)(uint32_t)framebuffer::width |
+ ((uint64_t)(uint32_t)framebuffer::height << 32);
+ rsi = (uint32_t)framebuffer::dword_pitch;
+ rdx = 0;
+
+ }
+
+ void open_file_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ if (!is_range_owned_by_application(rdi, rdi + rsi)) {
+ set_zero(rax, rdi, rsi, rdx);
+ return;
+ }
+
+ utility::string path((const char *)rdi, rsi);
+ vfile::canon_path cp;
+ vfile::canonize_path(path, cp);
+
+ set_zero(rax, rdi, rsi, rdx);
+
+ vfile::vfile file;
+ switch (vfile::lookup_path(cp, file)) {
+ case storage::fs_result::success:
+ break;
+ case storage::fs_result::device_error:
+ rax = file_result_device_error;
+ return;
+ case storage::fs_result::fs_corrupt:
+ rax = file_result_file_system_corrupt;
+ return;
+ case storage::fs_result::does_not_exist:
+ rax = file_result_does_not_exist;
+ return;
+ }
+
+ vfile::vfile real_file;
+ switch (file.follow_symlinks(real_file)) {
+ case storage::fs_result::success:
+ break;
+ case storage::fs_result::device_error:
+ rax = file_result_device_error;
+ return;
+ case storage::fs_result::fs_corrupt:
+ rax = file_result_file_system_corrupt;
+ return;
+ case storage::fs_result::does_not_exist:
+ rax = file_result_does_not_exist;
+ return;
+ }
+
+ if (real_file.dir_entry.type != storage::file_type::regular_file) {
+ rax = file_result_directory;
+ return;
+ }
+
+ unsigned handler =
+ application::running_app->open_files.add_new(utility::move(real_file));
+ rax = file_result_success;
+ rdi = (uint64_t)handler;
+
}
+ void get_file_length_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ auto &open_files = application::running_app->open_files;
+ unsigned handle = (unsigned)rdi;
+
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (!open_files.has_id(handle)) {
+ rax = file_result_bad_file_handle;
+ return;
+ }
+
+ rax = file_result_success;
+ rdi = open_files.get(handle).dir_entry.length;
+
+ }
+
+ void read_from_file_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ if (!is_range_owned_by_application(rdi, rdi + 32)) {
+ set_zero(rax, rdi, rsi, rdx);
+ return;
+ }
+
+ const uint64_t *request = (const uint64_t *)rdi;
+ unsigned handle = (unsigned)request[0];
+ uint64_t start = request[1];
+ uint64_t length = request[2];
+ uint64_t buffer_vaddr = request[3];
+
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (!is_range_owned_by_application(buffer_vaddr, buffer_vaddr + length))
+ return;
+
+ auto &open_files = application::running_app->open_files;
+
+ if (!open_files.has_id(handle))
+ rax = file_result_bad_file_handle;
+
+ vfile::vfile &file = open_files.get(handle);
+
+ if (start + length > file.dir_entry.length)
+ rax = file_result_out_of_bounds;
+
+ switch (file.read_file(start, length, (void *)buffer_vaddr)) {
+ case storage::fs_result::success:
+ rax = file_result_success;
+ return;
+ case storage::fs_result::device_error:
+ rax = file_result_device_error;
+ return;
+ case storage::fs_result::fs_corrupt:
+ case storage::fs_result::does_not_exist:
+ rax = file_result_file_system_corrupt;
+ return;
+ }
+
+ }
+
+ [[noreturn]] void end_this_process_syscall(
+ uint64_t &, uint64_t &, uint64_t &, uint64_t &
+ ) {
+
+ //TODO
+ while (1)
+ ;
+
+ }
+
+ void get_new_pages_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ uint64_t count = rdi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *app = application::running_app;
+ uint64_t vaddr = app->get_free_vaddr_pages(count);
+
+ for (uint64_t i = 0; i < count; ++i) {
+ uint64_t paddr = paging::take_pram_page();
+ app->map_page(vaddr + i * 4096, paddr, true, false, true);
+ }
+
+ rax = vaddr;
+
+ }
+
+ void close_file_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ application::running_app->open_files.remove_id(handle);
+
+ }
+
+ typedef void (*syscall_handler)(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
+
+ syscall_handler handlers[] = {
+ &encode_color_syscall,
+ &get_framebuffer_syscall,
+ &open_file_syscall,
+ &get_file_length_syscall,
+ &read_from_file_syscall,
+ &end_this_process_syscall,
+ &get_new_pages_syscall,
+ &close_file_syscall
+ };
+
+ static constexpr int max_syscall_number = 7;
+
}
using namespace hilbert::kernel::syscall;
@@ -24,13 +250,9 @@ extern "C" void do_syscall(
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
) {
- if (rax < 256 && handlers[rax] != 0)
+ if (rax <= max_syscall_number && handlers[rax] != 0)
handlers[rax](rax, rdi, rsi, rdx);
- else {
- rax = 0;
- rdi = 0;
- rsi = 0;
- rdx = 0;
- }
+ else
+ set_zero(rax, rdi, rsi, rdx);
}
diff --git a/kernel/utility.cpp b/kernel/utility.cpp
index 249fb2c..12e88fd 100644
--- a/kernel/utility.cpp
+++ b/kernel/utility.cpp
@@ -1,5 +1,11 @@
#include <hilbert/kernel/utility.hpp>
+void *operator new(size_t, void *ptr) {
+ return ptr;
+}
+
+void operator delete(void *, void *) {}
+
namespace hilbert::kernel::utility {
void mark_bitmap_region_zero(
diff --git a/kernel/vfile.cpp b/kernel/vfile.cpp
index 74cfbf9..028db6d 100644
--- a/kernel/vfile.cpp
+++ b/kernel/vfile.cpp
@@ -63,7 +63,7 @@ namespace hilbert::kernel::vfile {
else {
utility::string segment(str, segment_len);
- out.segments.add_end(std::move(segment));
+ out.segments.add_end(utility::move(segment));
}
str += to_skip;
@@ -80,9 +80,7 @@ namespace hilbert::kernel::vfile {
return _result; \
}
- storage::fs_result vfile::follow_symlinks(
- const vfile &root, std::optional<vfile> &out
- ) const {
+ storage::fs_result vfile::follow_symlinks(vfile &out) const {
if (dir_entry.type != storage::file_type::symlink) {
out = *this;
@@ -95,37 +93,33 @@ namespace hilbert::kernel::vfile {
full_path.parent();
full_path.rel(target_path);
- std::optional<vfile> next;
- RET_NOT_SUC(lookup_path(root, full_path, next))
- if (!next) {
- out = {};
- return storage::fs_result::success;
- }
+ vfile next;
+ RET_NOT_SUC(lookup_path(full_path, next))
- next->path = path;
- return next->follow_symlinks(root, out);
+ next.path = path;
+ return next.follow_symlinks(out);
}
storage::fs_result vfile::get_child(
- std::optional<vfile> &out, const utility::string &name
+ vfile &out, const utility::string &name
) const {
- std::optional<storage::dir_entry> entry;
+ storage::dir_entry entry;
storage::directory_iter_t iter;
RET_NOT_SUC(bd->mounted_as->get_first_child(dir_entry.node, entry, iter))
- while (entry) {
+ while (true) {
- if (entry->name == name) {
+ if (entry.name == name) {
vfile vf;
vf.bd = bd;
- vf.dir_entry = std::move(*entry);
+ vf.dir_entry = utility::move(entry);
vf.path = path;
vf.path.segments.add_end(name);
- out = std::move(vf);
+ out = utility::move(vf);
return storage::fs_result::success;
}
@@ -134,33 +128,37 @@ namespace hilbert::kernel::vfile {
}
- out = {};
- return storage::fs_result::success;
-
}
storage::fs_result vfile::get_children(utility::vector<vfile> &out) const {
- std::optional<storage::dir_entry> entry;
+ storage::dir_entry entry;
storage::directory_iter_t iter;
- RET_NOT_SUC(bd->mounted_as->get_first_child(dir_entry.node, entry, iter))
+ storage::fs_result result =
+ bd->mounted_as->get_first_child(dir_entry.node, entry, iter);
+ if (result == storage::fs_result::does_not_exist)
+ return storage::fs_result::success;
+ else if (result != storage::fs_result::success)
+ return result;
- while (entry) {
+ while (true) {
vfile vf;
vf.bd = bd;
vf.path = path;
- vf.path.segments.add_end(entry->name);
- vf.dir_entry = std::move(*entry);
- out.add_end(std::move(vf));
+ vf.path.segments.add_end(entry.name);
+ vf.dir_entry = utility::move(entry);
+ out.add_end(utility::move(vf));
- RET_NOT_SUC(bd->mounted_as->get_next_child(dir_entry.node, entry, iter))
+ result = bd->mounted_as->get_next_child(dir_entry.node, entry, iter);
+ if (result == storage::fs_result::does_not_exist)
+ return storage::fs_result::success;
+ else if (result != storage::fs_result::success)
+ return result;
}
- return storage::fs_result::success;
-
}
storage::fs_result vfile::read_file(
@@ -170,25 +168,26 @@ namespace hilbert::kernel::vfile {
dir_entry.node, start, length, into);
}
- storage::fs_result lookup_path(
- const vfile &root, const canon_path &path, std::optional<vfile> &out
- ) {
+ //TODO: see comment at top of vfile.hpp.
+ static const vfile *root;
+
+ void set_root(const vfile &root) {
+ kernel::vfile::root = new vfile(root);
+ }
+
+ storage::fs_result lookup_path(const canon_path &path, vfile &out) {
//assume path is absolute.
- out = root;
+ out = *root;
for (unsigned i = 0; i < path.segments.count; ++i) {
- std::optional<vfile> result;
- RET_NOT_SUC(out->follow_symlinks(root, result))
- out = std::move(result);
- if (!out)
- return storage::fs_result::success;
+ vfile result;
+ RET_NOT_SUC(out.follow_symlinks(result))
+ out = utility::move(result);
- RET_NOT_SUC(out->get_child(result, path.segments.buffer[i]))
- out = std::move(result);
- if (!out)
- return storage::fs_result::success;
+ RET_NOT_SUC(out.get_child(result, path.segments.buffer[i]))
+ out = utility::move(result);
}