summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorBenji Dial <benji@benjidial.net>2024-05-18 21:53:38 -0400
committerBenji Dial <benji@benjidial.net>2024-05-18 21:53:38 -0400
commitb1a912a8a6ff472a49b2e0a09cfd433adfc2cb24 (patch)
tree5009d4415ba13e4baa37f3d0271852528130fd3b /kernel
parenta8a80d326de9550b2a25b1255a2093ab43219ede (diff)
downloadhilbert-os-b1a912a8a6ff472a49b2e0a09cfd433adfc2cb24.tar.gz
reorganization, cross compiler
Diffstat (limited to 'kernel')
-rw-r--r--kernel/application.cpp280
-rw-r--r--kernel/framebuffer.cpp65
-rw-r--r--kernel/include/hilbert/kernel/application.hpp193
-rw-r--r--kernel/include/hilbert/kernel/framebuffer.hpp10
-rw-r--r--kernel/include/hilbert/kernel/input.hpp2
-rw-r--r--kernel/include/hilbert/kernel/panic.hpp3
-rw-r--r--kernel/include/hilbert/kernel/terminal.hpp32
-rw-r--r--kernel/input.cpp13
-rw-r--r--kernel/makefile19
-rw-r--r--kernel/panic.cpp10
-rw-r--r--kernel/source/allocator.cpp (renamed from kernel/allocator.cpp)0
-rw-r--r--kernel/source/application.asm171
-rw-r--r--kernel/source/application.cpp550
-rw-r--r--kernel/source/entry.cpp (renamed from kernel/entry.cpp)76
-rw-r--r--kernel/source/framebuffer.cpp40
-rw-r--r--kernel/source/input.cpp22
-rw-r--r--kernel/source/interrupts.asm (renamed from kernel/interrupts.asm)22
-rw-r--r--kernel/source/interrupts.cpp (renamed from kernel/interrupts.cpp)90
-rw-r--r--kernel/source/paging.asm (renamed from kernel/paging.asm)0
-rw-r--r--kernel/source/paging.cpp (renamed from kernel/paging.cpp)0
-rw-r--r--kernel/source/panic.cpp11
-rw-r--r--kernel/source/storage.cpp (renamed from kernel/storage.cpp)0
-rw-r--r--kernel/source/storage/bd/memory.cpp (renamed from kernel/storage/bd/memory.cpp)0
-rw-r--r--kernel/source/storage/fs/tarfs.cpp (renamed from kernel/storage/fs/tarfs.cpp)0
-rw-r--r--kernel/source/syscall.cpp538
-rw-r--r--kernel/source/utility.cpp (renamed from kernel/utility.cpp)0
-rw-r--r--kernel/source/vfile.cpp (renamed from kernel/vfile.cpp)0
-rw-r--r--kernel/syscall.asm88
-rw-r--r--kernel/syscall.cpp262
-rw-r--r--kernel/terminal.cpp121
30 files changed, 1572 insertions, 1046 deletions
diff --git a/kernel/application.cpp b/kernel/application.cpp
deleted file mode 100644
index af31a09..0000000
--- a/kernel/application.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-#include <hilbert/kernel/application.hpp>
-#include <hilbert/kernel/paging.hpp>
-
-//TODO - scheduling.
-
-namespace hilbert::kernel::application {
-
- app_instance::app_instance()
- : state(app_state::paused), 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 p3_vaddr;
- paging::map_new_kernel_page(p3_vaddr, p3_paddr);
- p3 = (uint64_t *)p3_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;
-
- for (int i = 0; i < 512; ++i) {
- p3[i] = 0;
- p2s[i] = 0;
- p1s[i] = 0;
- p1es_to_free_on_exit[i] = 0;
- }
-
- }
-
- void app_instance::map_page(uint64_t vaddr, uint64_t paddr,
- bool write, bool execute, bool free_pram_on_exit
- ) {
-
- 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;
- }
- }
-
- 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;
-
- }
-
- 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;
- while (start + length <= 0x8000000000 / 4096) {
- if (length == count)
- 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;
- length = 0;
- }
- }
- //TODO: handle out of memory
- return 0;
- }
-
- uint64_t app_instance::count_mapped_vram_pages() {
- uint64_t count = 0;
- 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;
- }
-
- app_instance *running_app;
-
- static uint8_t correct_magic[16] = {
- 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
- 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00
- };
-
-#define READ(a, b, c) \
- { \
- storage::fs_result _result = file.read_file(a, b, c); \
- if (_result == storage::fs_result::device_error) \
- return create_app_result::device_error; \
- if (_result == storage::fs_result::fs_corrupt) \
- return create_app_result::fs_corrupt; \
- }
-
- struct load_info {
- uint64_t foffset;
- uint64_t fsize;
- uint64_t vaddr;
- uint64_t vpages;
- bool writable;
- bool executable;
- };
-
- 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)
- return create_app_result::app_corrupt;
- READ(0, 8, magic)
- READ(16, 8, magic + 8)
- for (int i = 0; i < 16; ++i)
- if (magic[i] != correct_magic[i])
- return create_app_result::app_corrupt;
-
- uint64_t entry_point;
- uint64_t phead_start;
- uint16_t phead_entry_size;
- uint16_t phead_entry_count;
-
- READ(24, 8, &entry_point)
- READ(32, 8, &phead_start)
- READ(54, 2, &phead_entry_size)
- READ(56, 2, &phead_entry_count)
-
- if (file.dir_entry.length <
- phead_start + phead_entry_size * phead_entry_count)
- return create_app_result::app_corrupt;
-
- utility::vector<load_info> load_infos;
-
- for (uint16_t i = 0; i < phead_entry_count; ++i) {
-
- uint64_t entry_start = phead_start + phead_entry_size * i;
-
- uint32_t seg_type;
- READ(entry_start, 4, &seg_type)
- if (seg_type != 1)
- continue;
-
- uint64_t foffset;
- uint64_t vaddr;
- uint64_t fsize;
- uint64_t vsize;
- uint32_t flags;
-
- READ(entry_start + 8, 8, &foffset)
- READ(entry_start + 16, 8, &vaddr)
- READ(entry_start + 32, 8, &fsize)
- READ(entry_start + 40, 8, &vsize)
- READ(entry_start + 4, 4, &flags)
-
- 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 < 0x200000)
- return create_app_result::app_corrupt;
-
- uint64_t vpages = (vsize - 1) / 4096 + 1;
-
- if (vaddr + vpages * 4096 > 0x8000000000)
- return create_app_result::app_corrupt;
-
- load_info info = {
- .foffset = foffset,
- .fsize = fsize,
- .vaddr = vaddr,
- .vpages = vpages,
- .writable = (flags & 2) == 2,
- .executable = (flags & 1) == 1
- };
- load_infos.add_end(info);
-
- }
-
- out = new app_instance();
-
- 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_pram_page();
- out->map_page(info.vaddr + j * 4096, paddr,
- info.writable, info.executable, true);
- 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 {
- 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;
- }
- }
- 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;
- }
- }
- }
-
- 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;
-
- out->working_dir = working_dir;
-
- return create_app_result::success;
-
- }
-
-}
diff --git a/kernel/framebuffer.cpp b/kernel/framebuffer.cpp
deleted file mode 100644
index 08d0e16..0000000
--- a/kernel/framebuffer.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include <hilbert/kernel/application.hpp>
-#include <hilbert/kernel/framebuffer.hpp>
-
-namespace hilbert::kernel::framebuffer {
-
- uint64_t paddr;
- static uint32_t *vaddr;
- int width;
- int height;
- int dword_pitch;
-
- 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;
-
- }
-
- color encode_color(uint8_t r, uint8_t g, uint8_t b) {
- return ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
- }
-
- void set_pixel(int x, int y, color c) {
- vaddr[y * dword_pitch + x] = c;
- }
-
- 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
- ) {
-
- int region_width = from_end_x - from_start_x;
- int region_height = from_end_y - from_start_y;
-
- int from_start_offset = from_start_y * dword_pitch + from_start_x;
- int to_start_offset = to_start_y * dword_pitch + to_start_x;
-
- if (from_start_offset > to_start_offset)
- for (int y = 0; y < region_height; ++y)
- for (int x = 0; x < region_width; ++x)
- vaddr[to_start_offset + y * dword_pitch + x] =
- vaddr[from_start_offset + y * dword_pitch + x];
-
- else if (from_start_offset < to_start_offset)
- for (int y = region_height - 1; y >= 0; --y)
- for (int x = region_width - 1; x >= 0; --x)
- vaddr[to_start_offset + y * dword_pitch + x] =
- vaddr[from_start_offset + y * dword_pitch + x];
-
- }
-
- void fill_region(int start_x, int start_y, int end_x, int end_y, color c) {
- for (int y = start_y; y < end_y; ++y)
- for (int x = start_x; x < end_x; ++x)
- vaddr[y * dword_pitch + x] = c;
- }
-
-}
diff --git a/kernel/include/hilbert/kernel/application.hpp b/kernel/include/hilbert/kernel/application.hpp
index 51f304d..7d48d8d 100644
--- a/kernel/include/hilbert/kernel/application.hpp
+++ b/kernel/include/hilbert/kernel/application.hpp
@@ -7,21 +7,165 @@
namespace hilbert::kernel::application {
- void init_syscalls();
+ class process;
+ class thread;
- enum class app_state {
+ enum class thread_state {
running,
paused,
- zombie
+ waiting
};
- struct app_instance {
+ enum class stream_result {
+ success,
+ bad_handle,
+ io_error,
+ out_of_bounds,
+ does_not_exist,
+ not_a_regular_file,
+ not_an_executable,
+ not_writable,
+ not_seekable,
+ socket_id_already_used,
+ socket_id_not_in_use,
+ socket_listener_closed,
+ other_end_closed,
+ already_exists,
+ not_sized
+ };
+
+ enum class seek_origin {
+ beginning,
+ end,
+ current_position
+ };
+
+ class stream {
+ public:
+ virtual ~stream() {}
+ virtual stream_result seek(seek_origin origin, int64_t offset) = 0;
+ virtual stream_result read(uint64_t count, void *into) = 0;
+ virtual stream_result write(uint64_t count, const void *from) = 0;
+ virtual stream_result get_length(uint64_t &out) = 0;
+ virtual stream_result set_length(uint64_t to) = 0;
+ };
+
+ class vfile_stream : public stream {
- utility::id_allocator<vfile::vfile> open_files;
+ private:
+ vfile::vfile file;
+ uint64_t offset;
- vfile::vfile working_dir;
+ public:
+ vfile_stream(vfile::vfile &&file);
+ virtual stream_result seek(seek_origin origin, int64_t offset) override;
+ virtual stream_result read(uint64_t count, void *into) override;
+ virtual stream_result write(uint64_t count, const void *from) override;
+ virtual stream_result get_length(uint64_t &out) override;
+ virtual stream_result set_length(uint64_t to) override;
- app_state state;
+ };
+
+ struct socket {
+ utility::queue<thread *> process_a_threads_waiting_to_read;
+ utility::queue<thread *> process_b_threads_waiting_to_read;
+ utility::queue<uint8_t> a_to_b;
+ utility::queue<uint8_t> b_to_a;
+ bool a_closed;
+ bool b_closed;
+ };
+
+ class socket_stream : public stream {
+
+ private:
+ socket *sock;
+ bool are_we_b;
+
+ utility::queue<thread *> &our_threads_waiting_to_read;
+ utility::queue<thread *> &their_threads_waiting_to_read;
+ utility::queue<uint8_t> &them_to_us;
+ utility::queue<uint8_t> &us_to_them;
+ bool &them_closed;
+ bool &us_closed;
+
+ public:
+ socket_stream(socket *sock, bool are_we_b);
+ ~socket_stream();
+ virtual stream_result seek(seek_origin origin, int64_t offset) override;
+ virtual stream_result read(uint64_t count, void *into) override;
+ virtual stream_result write(uint64_t count, const void *from) override;
+ virtual stream_result get_length(uint64_t &out) override;
+ virtual stream_result set_length(uint64_t to) override;
+
+ };
+
+ struct string_pair {
+ utility::string a;
+ utility::string b;
+ };
+
+ struct socket_listener {
+ utility::string id;
+ utility::queue<thread *> waiting_to_accept_connection;
+ utility::queue<thread *> waiting_to_connect;
+ bool is_listening;
+ };
+
+ struct [[gnu::packed]] cpu_state {
+
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+
+ uint64_t rflags;
+ uint64_t rip;
+ uint64_t cr3;
+
+ //only used if in_syscall is true. starts at rsp. no red zone
+ //needs to be saved since save_thread_state doesn't use it.
+ void *kernel_stack_copy;
+ bool in_syscall;
+
+ };
+
+ struct thread {
+
+ //propogated to process on destruction if this is the last thread.
+ int exit_code;
+ ~thread();
+
+ process *the_process;
+ thread_state state;
+ //only valid if paused or waiting
+ cpu_state cpu;
+
+ stream *just_connected_to;
+ stream *just_accepted;
+
+ };
+
+ struct process {
+
+ void end_process(unsigned exit_code);
+ void cleanup();
+
+ utility::list<thread *> threads;
+ utility::vector<string_pair> environment;
+ utility::id_allocator<stream *> open_streams;
+ utility::id_allocator<socket_listener *> socket_listeners;
uint64_t *p4;
uint64_t *p3;
@@ -35,17 +179,10 @@ namespace hilbert::kernel::application {
//set to 0 if none
uint64_t framebuffer_vaddr;
- //only valid if state is zombie
+ //only valid if there are no threads
int32_t exit_code;
- //only valid if state is paused
- struct {
- uint64_t rip;
- uint64_t rsp;
- //TODO: etc.
- } saved_regs;
-
- app_instance();
+ process();
//vaddr and paddr must be aligned, and vaddr must be < 0x0080.0000.0000
void map_page(uint64_t vaddr, uint64_t paddr,
@@ -62,16 +199,22 @@ namespace hilbert::kernel::application {
};
- extern app_instance *running_app;
+ extern utility::id_allocator<process *> *processes;
+ extern utility::queue<thread *> *paused_threads;
+ extern utility::queue<thread *> *threads_waiting_for_input;
+ extern thread *running_thread;
+ extern utility::list<socket_listener *> *all_socket_listeners;
- enum class create_app_result {
- success,
- device_error,
- app_corrupt,
- fs_corrupt
- };
+ stream_result create_application(
+ const vfile::vfile &file, process *&process_out, thread *&thread_out);
+
+ void init_applications();
+
+ //returns true when resumed, false right now.
+ //must be called from non-interruptable syscall context.
+ extern "C" bool save_thread_state(cpu_state &into);
- create_app_result create_app(const vfile::vfile &file,
- app_instance *&out, const vfile::vfile &working_dir);
+ //must be called from non-interruptable context
+ [[noreturn]] void resume_next();
}
diff --git a/kernel/include/hilbert/kernel/framebuffer.hpp b/kernel/include/hilbert/kernel/framebuffer.hpp
index fb28462..d4d6b1c 100644
--- a/kernel/include/hilbert/kernel/framebuffer.hpp
+++ b/kernel/include/hilbert/kernel/framebuffer.hpp
@@ -18,14 +18,6 @@ namespace hilbert::kernel::framebuffer {
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);
+ void fill_color(color c);
}
diff --git a/kernel/include/hilbert/kernel/input.hpp b/kernel/include/hilbert/kernel/input.hpp
index cccb71f..2209ddc 100644
--- a/kernel/include/hilbert/kernel/input.hpp
+++ b/kernel/include/hilbert/kernel/input.hpp
@@ -19,6 +19,8 @@ namespace hilbert::kernel::input {
};
extern utility::queue<uint32_t> *key_queue;
+ //notify a process waiting for input
+ void got_input();
//must be post switch to kernel page tables and mounting of file systems
void init_input();
diff --git a/kernel/include/hilbert/kernel/panic.hpp b/kernel/include/hilbert/kernel/panic.hpp
index 545d703..0478142 100644
--- a/kernel/include/hilbert/kernel/panic.hpp
+++ b/kernel/include/hilbert/kernel/panic.hpp
@@ -1,6 +1,5 @@
#pragma once
namespace hilbert::kernel {
- //prints to terminal and then halts.
- [[noreturn]] void panic(const char *string_sz);
+ [[noreturn]] void panic(uint32_t code);
}
diff --git a/kernel/include/hilbert/kernel/terminal.hpp b/kernel/include/hilbert/kernel/terminal.hpp
deleted file mode 100644
index 350d79b..0000000
--- a/kernel/include/hilbert/kernel/terminal.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#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/input.cpp b/kernel/input.cpp
deleted file mode 100644
index 6bed7f5..0000000
--- a/kernel/input.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <hilbert/kernel/input.hpp>
-#include <hilbert/kernel/panic.hpp>
-#include <hilbert/kernel/vfile.hpp>
-
-namespace hilbert::kernel::input {
-
- utility::queue<uint32_t> *key_queue;
-
- void init_input() {
- key_queue = new utility::queue<uint32_t>();
- }
-
-}
diff --git a/kernel/makefile b/kernel/makefile
new file mode 100644
index 0000000..1cb2d52
--- /dev/null
+++ b/kernel/makefile
@@ -0,0 +1,19 @@
+SOURCES = \
+ storage/bd/memory.cpp storage/fs/tarfs.cpp application.asm application.cpp \
+ framebuffer.cpp interrupts.asm interrupts.cpp allocator.cpp storage.cpp \
+ syscall.cpp utility.cpp paging.asm paging.cpp entry.cpp input.cpp panic.cpp \
+ vfile.cpp
+
+build/%.asm.o: source/%.asm
+ @mkdir -p $(@D)
+ $(HILBERT_NASM) $^ -o $@
+
+build/%.cpp.o: source/%.cpp
+ @mkdir -p $(@D)
+ $(HILBERT_CC) -c -ffreestanding -mcmodel=kernel -I ${LIMINE_DIR} $^ -o $@
+
+build/kernel.elf: $(SOURCES:%=build/%.o)
+ $(HILBERT_LD) -T link.ld $^ -o $@
+
+clean:
+ rm -rf build
diff --git a/kernel/panic.cpp b/kernel/panic.cpp
deleted file mode 100644
index 233fcf4..0000000
--- a/kernel/panic.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <hilbert/kernel/terminal.hpp>
-#include <hilbert/kernel/panic.hpp>
-
-namespace hilbert::kernel {
- [[noreturn]] void panic(const char *string_sz) {
- terminal::put_string_sz(string_sz);
- while (1)
- asm ("hlt");
- }
-}
diff --git a/kernel/allocator.cpp b/kernel/source/allocator.cpp
index 324f992..324f992 100644
--- a/kernel/allocator.cpp
+++ b/kernel/source/allocator.cpp
diff --git a/kernel/source/application.asm b/kernel/source/application.asm
new file mode 100644
index 0000000..ed8b190
--- /dev/null
+++ b/kernel/source/application.asm
@@ -0,0 +1,171 @@
+bits 64
+
+extern do_syscall
+
+section .text
+
+syscall_entry:
+ mov r11, rsp
+ mov rsp, 0xfffffffffffff000
+ push r11
+ push rcx
+
+ 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
+
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ or r11, 0x200
+ pop rcx
+ pop rsp
+
+ o64 sysret
+
+global init_applications_asm
+init_applications_asm:
+
+ ;efer <- efer | 0x1
+ mov rcx, 0xc0000080
+ rdmsr
+ or al, 1
+ wrmsr
+
+ ;lstar <- syscall_entry
+ mov rdx, syscall_entry
+ mov eax, edx
+ shr rdx, 32
+ mov ecx, 0xc0000082
+ wrmsr
+
+ ;star <- 0x0030.0028.0000.0000
+ mov edx, 0x00300028
+ xor eax, eax
+ mov ecx, 0xc0000081
+ wrmsr
+
+ ;sfmask <- 0x0000.0000.0000.0200 (if)
+ xor edx, edx
+ mov eax, 0x200
+ mov ecx, 0xc0000084
+ wrmsr
+
+ ret
+
+section .bss
+
+resume_stack:
+ resb 4096
+
+section .text
+
+extern restore_syscall_stack
+;rdi = pointer to copy
+;rsi = intended rsp
+
+global resume_thread
+resume_thread:
+;rdi = ptr to cpu_state
+;rdi is not inside stack
+;interrupts are disabled
+
+ mov al, byte [rdi + 160] ;in_syscall
+ test al, al
+ jnz .in_syscall
+
+ mov rax, 0x3b
+ mov rbx, 0x43
+
+.common:
+ push rax
+ mov rax, qword [rdi + 56] ;rsp
+ push rax
+ mov rax, qword [rdi + 128] ;rflags
+ push rax
+ push rbx
+ mov rax, qword [rdi + 136] ;rip
+ push rax
+
+ mov rax, qword [rdi + 144] ;cr3
+ mov cr3, rax
+
+ mov rax, qword [rdi]
+ mov rbx, qword [rdi + 8]
+ mov rcx, qword [rdi + 16]
+ mov rdx, qword [rdi + 24]
+ mov rsi, qword [rdi + 40]
+ mov rbp, qword [rdi + 48]
+ mov r8, qword [rdi + 64]
+ mov r9, qword [rdi + 72]
+ mov r10, qword [rdi + 80]
+ mov r11, qword [rdi + 88]
+ mov r12, qword [rdi + 96]
+ mov r13, qword [rdi + 104]
+ mov r14, qword [rdi + 112]
+ mov r15, qword [rdi + 120]
+ mov rdi, qword [rdi + 32]
+
+ iretq
+
+.in_syscall:
+ mov rsp, resume_stack + 4096
+
+ push rdi
+ mov rsi, qword [rdi + 56] ;rsp
+ mov rdi, qword [rdi + 152] ;kernel_stack_copy
+ call restore_syscall_stack
+ pop rdi
+
+ mov rax, 0x30
+ mov rbx, 0x28
+ jmp .common
+
+extern copy_syscall_stack
+;rdi = bottom
+
+global save_thread_state
+save_thread_state:
+;rdi = pointer to cpu state structure
+
+ ;only saving registers that need to be preserved by this function
+ mov qword [rdi + 8], rbx
+ mov qword [rdi + 48], rbp
+ mov qword [rdi + 56], rsp
+ mov qword [rdi + 96], r12
+ mov qword [rdi + 104], r13
+ mov qword [rdi + 112], r14
+ mov qword [rdi + 120], r15
+
+ mov qword [rdi + 136], .resume_to ;rip
+ mov rax, cr3
+ mov qword [rdi + 144], rax ;cr3
+
+ push rdi
+ lea rdi, [rsp + 8]
+ call copy_syscall_stack
+ pop rdi
+
+ mov qword [rdi + 152], rax ;kernel_stack_copy
+ mov byte [rdi + 160], 0x01 ;in_syscall
+
+ xor al, al
+ ret
+
+.resume_to:
+ mov al, 0x01
+ ret
diff --git a/kernel/source/application.cpp b/kernel/source/application.cpp
new file mode 100644
index 0000000..c3ce2f1
--- /dev/null
+++ b/kernel/source/application.cpp
@@ -0,0 +1,550 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/paging.hpp>
+#include <hilbert/kernel/panic.hpp>
+
+//TODO - scheduling.
+
+namespace hilbert::kernel::application {
+
+ process::process() : 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 p3_vaddr;
+ paging::map_new_kernel_page(p3_vaddr, p3_paddr);
+ p3 = (uint64_t *)p3_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;
+
+ for (int i = 0; i < 512; ++i) {
+ p3[i] = 0;
+ p2s[i] = 0;
+ p1s[i] = 0;
+ p1es_to_free_on_exit[i] = 0;
+ }
+
+ }
+
+ void process::map_page(uint64_t vaddr, uint64_t paddr,
+ bool write, bool execute, bool free_pram_on_exit
+ ) {
+
+ 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;
+ }
+ }
+
+ 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;
+
+ }
+
+ bool process::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 process::get_free_vaddr_pages(uint64_t count) {
+ uint64_t start = 0x200000 / 4096;
+ uint64_t length = 0;
+ while (start + length <= 0x8000000000 / 4096) {
+ if (length == count)
+ 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;
+ length = 0;
+ }
+ }
+ //TODO: handle out of memory
+ return 0;
+ }
+
+ uint64_t process::count_mapped_vram_pages() {
+ uint64_t count = 0;
+ 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;
+ }
+
+ utility::id_allocator<process *> *processes;
+ utility::queue<thread *> *paused_threads;
+ utility::queue<thread *> *threads_waiting_for_input;
+ thread *running_thread;
+ utility::list<socket_listener *> *all_socket_listeners;
+
+ static uint8_t correct_magic[16] = {
+ 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
+ 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00
+ };
+
+#define READ(a, b, c) \
+ { \
+ storage::fs_result _result = file.read_file(a, b, c); \
+ if (_result != storage::fs_result::success) \
+ return stream_result::io_error; \
+ }
+
+#define TRY_MAR(expr) \
+ { \
+ storage::fs_result _result = expr; \
+ if (_result != storage::fs_result::success) { \
+ delete process_out; \
+ return stream_result::io_error; \
+ } \
+ }
+
+ struct load_info {
+ uint64_t foffset;
+ uint64_t fsize;
+ uint64_t vaddr;
+ uint64_t voffset;
+ uint64_t vpages;
+ bool writable;
+ bool executable;
+ };
+
+ storage::fs_result map_and_read(
+ const vfile::vfile &file, process *process, uint64_t vaddr, uint64_t faddr,
+ uint64_t len, bool writable, bool executable
+ ) {
+
+ uint64_t page_vaddr = vaddr & ~4095;
+ int at_start = vaddr & 4095;
+ int at_end = 4096 - len - at_start;
+
+ uint64_t page_paddr = paging::take_pram_page();
+ process->map_page(page_vaddr, page_paddr, writable, executable, true);
+ uint64_t page_kvaddr = paging::find_unmapped_vram_region(1);
+ paging::map_kernel_page(page_paddr, page_kvaddr, true, false);
+
+ storage::fs_result result = storage::fs_result::success;
+
+ if (at_start) {
+ uint8_t *blank = (uint8_t *)page_kvaddr;
+ for (int i = 0; i < at_start; ++i)
+ blank[i] = 0;
+ }
+
+ if (len != 0)
+ result = file.read_file(faddr, len, (void *)(page_kvaddr + at_start));
+
+ if (at_end) {
+ uint8_t *blank = (uint8_t *)(page_kvaddr + at_start + len);
+ for (int i = 0; i < at_end; ++i)
+ blank[i] = 0;
+ }
+
+ paging::unmap_kernel_page(page_kvaddr);
+ return result;
+
+ }
+
+ stream_result create_application(
+ const vfile::vfile &file, process *&process_out, thread *&thread_out
+ ) {
+
+ uint8_t magic[16];
+ if (file.dir_entry.type != storage::file_type::regular_file)
+ return stream_result::not_a_regular_file;
+ if (file.dir_entry.length < 64)
+ return stream_result::not_an_executable;
+ READ(0, 8, magic)
+ READ(16, 8, magic + 8)
+ for (int i = 0; i < 16; ++i)
+ if (magic[i] != correct_magic[i])
+ return stream_result::not_an_executable;
+
+ uint64_t entry_point;
+ uint64_t phead_start;
+ uint16_t phead_entry_size;
+ uint16_t phead_entry_count;
+
+ READ(24, 8, &entry_point)
+ READ(32, 8, &phead_start)
+ READ(54, 2, &phead_entry_size)
+ READ(56, 2, &phead_entry_count)
+
+ if (file.dir_entry.length <
+ phead_start + phead_entry_size * phead_entry_count)
+ return stream_result::not_an_executable;
+
+ utility::vector<load_info> load_infos;
+
+ for (uint16_t i = 0; i < phead_entry_count; ++i) {
+
+ uint64_t entry_start = phead_start + phead_entry_size * i;
+
+ uint32_t seg_type;
+ READ(entry_start, 4, &seg_type)
+ if (seg_type != 1)
+ continue;
+
+ uint64_t foffset;
+ uint64_t vaddr;
+ uint64_t voffset;
+ uint64_t fsize;
+ uint64_t vsize;
+ uint32_t flags;
+
+ READ(entry_start + 8, 8, &foffset)
+ READ(entry_start + 16, 8, &vaddr)
+ READ(entry_start + 32, 8, &fsize)
+ READ(entry_start + 40, 8, &vsize)
+ READ(entry_start + 4, 4, &flags)
+
+ voffset = vaddr % 4096;
+ vaddr -= voffset;
+
+ if (vsize == 0)
+ continue;
+
+ if (file.dir_entry.length < foffset + fsize)
+ return stream_result::not_an_executable;
+ if (fsize > vsize)
+ return stream_result::not_an_executable;
+
+ if (vaddr < 0x200000)
+ return stream_result::not_an_executable;
+
+ uint64_t vpages = (voffset + vsize - 1) / 4096 + 1;
+
+ if (vaddr + vpages * 4096 > 0x8000000000)
+ return stream_result::not_an_executable;
+
+ load_info info = {
+ .foffset = foffset,
+ .fsize = fsize,
+ .vaddr = vaddr,
+ .voffset = voffset,
+ .vpages = vpages,
+ .writable = (flags & 2) == 2,
+ .executable = (flags & 1) == 1
+ };
+ load_infos.add_end(info);
+
+ }
+
+ process_out = new process();
+
+ for (unsigned i = 0; i < load_infos.count; ++i) {
+ const auto &info = load_infos.buffer[i];
+
+ uint64_t vaddr = info.vaddr + info.voffset;
+ uint64_t faddr = info.foffset;
+ uint64_t v_remaining = info.vpages * 4096 - info.voffset;
+ uint64_t f_remaining = info.fsize;
+
+ if (info.voffset != 0) {
+ int to_read = info.fsize < 4096 - info.voffset
+ ? info.fsize : 4096 - info.voffset;
+ if (to_read > 0) {
+ TRY_MAR(map_and_read(file, process_out, vaddr, faddr, to_read,
+ info.writable, info.executable))
+ vaddr += to_read;
+ faddr += to_read;
+ v_remaining -= to_read;
+ f_remaining -= to_read;
+ }
+ }
+
+ while (f_remaining > 0) {
+ int to_read = f_remaining < 4096 ? f_remaining : 4096;
+ TRY_MAR(map_and_read(file, process_out, vaddr, faddr, to_read,
+ info.writable, info.executable))
+ vaddr += to_read;
+ faddr += to_read;
+ v_remaining -= to_read;
+ f_remaining -= to_read;
+ }
+
+ if (vaddr & 4095) {
+ v_remaining -= 4096 - (vaddr & 4095);
+ vaddr += 4096 - (vaddr & 4095);
+ }
+
+ while (v_remaining > 0) {
+ map_and_read(
+ file, process_out, vaddr, 0, 0, info.writable, info.executable);
+ vaddr += 4096;
+ v_remaining -= 4096;
+ }
+
+ }
+
+ 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);
+ process_out->map_page(vaddr, paddr, true, false, true);
+ }
+
+ thread_out = new thread();
+ process_out->threads.insert_end(thread_out);
+ thread_out->the_process = process_out;
+
+ thread_out->state = thread_state::paused;
+
+ thread_out->cpu.rax = 0;
+ thread_out->cpu.rbx = 0;
+ thread_out->cpu.rcx = 0;
+ thread_out->cpu.rdx = 0;
+ thread_out->cpu.rdi = 0;
+ thread_out->cpu.rsi = 0;
+ thread_out->cpu.rbp = 0;
+ thread_out->cpu.rsp = 0x1ff000;
+ thread_out->cpu.r8 = 0;
+ thread_out->cpu.r9 = 0;
+ thread_out->cpu.r10 = 0;
+ thread_out->cpu.r11 = 0;
+ thread_out->cpu.r12 = 0;
+ thread_out->cpu.r13 = 0;
+ thread_out->cpu.r14 = 0;
+ thread_out->cpu.r15 = 0;
+
+ thread_out->cpu.rflags = 0x200;
+ thread_out->cpu.rip = entry_point;
+ thread_out->cpu.cr3 = process_out->p4_paddr;
+ thread_out->cpu.in_syscall = false;
+
+ return stream_result::success;
+
+ }
+
+ extern "C" void init_applications_asm();
+
+ void init_applications() {
+ processes = new utility::id_allocator<process *>();
+ paused_threads = new utility::queue<thread *>();
+ threads_waiting_for_input = new utility::queue<thread *>();
+ all_socket_listeners = new utility::list<socket_listener *>();
+ init_applications_asm();
+ }
+
+ //only called from non-interruptable contexts.
+ //cpu argument not on stack.
+ extern "C" [[noreturn]] void resume_thread(const cpu_state &cpu);
+
+ extern "C" void *copy_syscall_stack(uint8_t *rsp) {
+ uint64_t size = 0xfffffffffffff000 - (uint64_t)rsp;
+ uint8_t *buffer = new uint8_t[size];
+ for (uint64_t i = 0; i < size; ++i)
+ buffer[i] = rsp[i];
+ return buffer;
+ }
+
+ extern "C" void restore_syscall_stack(const uint8_t *from, uint8_t *rsp) {
+ uint64_t size = 0xfffffffffffff000 - (uint64_t)rsp;
+ for (uint64_t i = 0; i < size; ++i)
+ rsp[i] = from[i];
+ delete[] from;
+ }
+
+ thread::~thread() {
+ for (auto *p = the_process->threads.first; p; p = p->next)
+ if (p->value == this) {
+ the_process->threads.remove(p);
+ break;
+ }
+ if (the_process->threads.first == 0) {
+ the_process->exit_code = exit_code;
+ the_process->cleanup();
+ }
+ if (state != thread_state::running)
+ panic(0x9af5e6);
+ }
+
+ [[noreturn]] void resume_next() {
+ while (paused_threads->count == 0)
+ asm volatile ("sti\nhlt\ncli");
+ auto *t = paused_threads->take();
+ running_thread = t;
+ t->state = thread_state::running;
+ resume_thread(t->cpu);
+ }
+
+ void process::end_process(unsigned exit_code) {
+ while (threads.first != 0)
+ delete threads.first->value;
+ this->exit_code = exit_code;
+ cleanup();
+ }
+
+ void process::cleanup() {
+ //TODO
+ panic(0x9af5e6);
+ }
+
+ socket_stream::socket_stream(socket *sock, bool are_we_b)
+ : sock(sock), are_we_b(are_we_b),
+ our_threads_waiting_to_read(are_we_b
+ ? sock->process_b_threads_waiting_to_read
+ : sock->process_a_threads_waiting_to_read),
+ their_threads_waiting_to_read(are_we_b
+ ? sock->process_a_threads_waiting_to_read
+ : sock->process_b_threads_waiting_to_read),
+ them_to_us(are_we_b ? sock->a_to_b : sock->b_to_a),
+ us_to_them(are_we_b ? sock->b_to_a : sock->a_to_b),
+ them_closed(are_we_b ? sock->a_closed : sock->b_closed),
+ us_closed(are_we_b ? sock->b_closed : sock->a_closed) {}
+
+ stream_result socket_stream::seek(seek_origin, int64_t) {
+ return stream_result::not_seekable;
+ }
+
+ stream_result socket_stream::read(uint64_t count, void *into) {
+ uint8_t *buffer = (uint8_t *)into;
+ for (uint64_t i = 0; i < count; ++i) {
+ while (them_to_us.count == 0) {
+ if (them_closed)
+ return stream_result::other_end_closed;
+ if (!save_thread_state(running_thread->cpu)) {
+ running_thread->state = thread_state::waiting;
+ our_threads_waiting_to_read.insert(running_thread);
+ resume_next();
+ }
+ }
+ buffer[i] = them_to_us.take();
+ }
+ return stream_result::success;
+ }
+
+ stream_result socket_stream::write(uint64_t count, const void *from) {
+ if (them_closed)
+ return stream_result::other_end_closed;
+ const uint8_t *buffer = (const uint8_t *)from;
+ for (uint64_t i = 0; i < count; ++i) {
+ if (their_threads_waiting_to_read.count > 0) {
+ auto *ot = their_threads_waiting_to_read.take();
+ ot->state = thread_state::paused;
+ paused_threads->insert(ot);
+ }
+ us_to_them.insert(buffer[i]);
+ }
+ return stream_result::success;
+ }
+
+ stream_result socket_stream::get_length(uint64_t &) {
+ return stream_result::not_sized;
+ }
+
+ stream_result socket_stream::set_length(uint64_t) {
+ return stream_result::not_sized;
+ }
+
+ socket_stream::~socket_stream() {
+ if (our_threads_waiting_to_read.count > 0)
+ panic(0x9af5e6);
+ if (them_closed)
+ delete sock;
+ else {
+ us_closed = true;
+ while (their_threads_waiting_to_read.count > 0) {
+ auto *t = their_threads_waiting_to_read.take();
+ t->state = thread_state::paused;
+ paused_threads->insert(t);
+ }
+ }
+ }
+
+ vfile_stream::vfile_stream(vfile::vfile &&file)
+ : file(utility::move(file)), offset(0) {}
+
+ stream_result vfile_stream::seek(seek_origin origin, int64_t offset) {
+ uint64_t start_at = {};
+ switch (origin) {
+ case seek_origin::beginning:
+ start_at = 0;
+ break;
+ case seek_origin::end:
+ start_at = file.dir_entry.length;
+ break;
+ case seek_origin::current_position:
+ start_at = this->offset;
+ break;
+ }
+ if (offset < 0 && (uint64_t)-offset > start_at)
+ return stream_result::out_of_bounds;
+ if (offset + start_at > file.dir_entry.length)
+ return stream_result::out_of_bounds;
+ this->offset = start_at + offset;
+ return stream_result::success;
+ }
+
+ stream_result vfile_stream::read(uint64_t count, void *into) {
+ if (offset + count > file.dir_entry.length)
+ return stream_result::out_of_bounds;
+ if (file.read_file(offset, count, into) != storage::fs_result::success)
+ return stream_result::io_error;
+ offset += count;
+ return stream_result::success;
+ }
+
+ stream_result vfile_stream::write(uint64_t count, const void *from) {
+ if (offset + count > file.dir_entry.length)
+ return stream_result::out_of_bounds;
+ (void)from;
+ panic(0x9af5e6);
+ }
+
+ stream_result vfile_stream::get_length(uint64_t &out) {
+ out = file.dir_entry.length;
+ return stream_result::success;
+ }
+
+ stream_result vfile_stream::set_length(uint64_t to) {
+ (void)to;
+ panic(0x9af5e6);
+ }
+
+}
diff --git a/kernel/entry.cpp b/kernel/source/entry.cpp
index cc74e69..820b107 100644
--- a/kernel/entry.cpp
+++ b/kernel/source/entry.cpp
@@ -2,12 +2,11 @@
#include <hilbert/kernel/storage/fs/tarfs.hpp>
#include <hilbert/kernel/application.hpp>
#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/paging.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
#include <hilbert/kernel/vfile.hpp>
-#include "../limine/limine.h"
+#include <limine.h>
using namespace hilbert::kernel;
@@ -37,34 +36,20 @@ static volatile limine_hhdm_request hhdm_request {
.response = 0
};
-static limine_internal_module initfs_module = {
- .path = "initfs.tgz",
- .cmdline = "initfs",
- .flags = LIMINE_INTERNAL_MODULE_REQUIRED | LIMINE_INTERNAL_MODULE_COMPRESSED
-};
-
-static limine_internal_module termfont_module = {
- .path = "termfont.psf",
- .cmdline = "termfont",
- .flags = LIMINE_INTERNAL_MODULE_REQUIRED
-};
-
-static limine_internal_module *internal_modules[] = {
- &initfs_module, &termfont_module
-};
-
static volatile limine_module_request module_request = {
.id = LIMINE_MODULE_REQUEST,
.revision = 2,
.response = 0,
- .internal_module_count = 2,
- .internal_modules = internal_modules
+ .internal_module_count = 0,
+ .internal_modules = 0
};
bool try_map_module_by_cmdline(
const char *cmdline, void *&vaddr_out, uint64_t &len_out
) {
auto response = module_request.response;
+ if (!response)
+ return false;
for (uint64_t i = 0; i < response->module_count; ++i) {
limine_file *file = response->modules[i];
for (uint64_t j = 0; cmdline[j] == file->cmdline[j]; ++j)
@@ -108,6 +93,8 @@ uint64_t initfs_len;
extern "C" void load_gdt_and_idt();
+static bool have_initfs;
+
extern "C" [[noreturn]] void entry() {
//TODO?: maybe we should check if the limine requests were
@@ -166,11 +153,8 @@ extern "C" [[noreturn]] void entry() {
for (uint64_t i = 0; i < fb_end - fb_start; i += 4096)
paging::map_kernel_page(fb_start + i, fb_vaddr + i, true, false);
- //initfs and termfont - these are required modules
- //so there is no worry about them not being present.
- try_map_module_by_cmdline("initfs", (void *&)initfs, initfs_len);
- try_map_module_by_cmdline(
- "termfont", (void *&)terminal::termfont, terminal::termfont_len);
+ have_initfs =
+ try_map_module_by_cmdline("initfs", (void *&)initfs, initfs_len);
//set up framebuffer and terminal:
//TODO: assumes framebuffer is 32-bpp rgb
@@ -186,12 +170,13 @@ extern "C" [[noreturn]] void entry() {
}
-extern "C" [[noreturn]] void start_user_mode(
- uint64_t rip, uint64_t rsp, uint64_t p4_paddr);
-
[[noreturn]] static void with_kernel_p4() {
- terminal::init_terminal();
+ if (!have_initfs)
+ panic(0x5f8860);
+
+ input::init_input();
+ application::init_applications();
auto *initfs_bd = new storage::bd::memory(initfs, initfs_len);
auto *initfs_fs = new storage::fs::tarfs_instance(initfs_bd);
@@ -204,27 +189,34 @@ extern "C" [[noreturn]] void start_user_mode(
if (initfs_fs->get_root_node(initfs_root.dir_entry.node) !=
storage::fs_result::success)
- panic("failed to get root node of initfs.");
+ panic(0x48a6ed);
vfile::set_root(initfs_root);
- input::init_input();
-
- utility::string init_path_string("/bin/init.elf", 13);
+ utility::string init_path_string("/bin/init", 9);
vfile::canon_path init_path;
vfile::canonize_path(init_path_string, init_path);
vfile::vfile init_file;
if (vfile::lookup_path(init_path, init_file, true) !=
storage::fs_result::success)
- panic("failed to look up /bin/init.elf.");
-
- application::app_instance *init;
- if (application::create_app(init_file, init, initfs_root) !=
- application::create_app_result::success)
- panic("failed to parse /bin/init.elf.");
-
- application::running_app = init;
- start_user_mode(init->saved_regs.rip, init->saved_regs.rsp, init->p4_paddr);
+ panic(0x7e874d);
+
+ application::process *init_process;
+ application::thread *init_thread;
+ if (application::create_application(init_file, init_process, init_thread) !=
+ application::stream_result::success)
+ panic(0xc39db3);
+
+ init_process->environment.add_end({
+ .a = utility::string("ARGC", 4),
+ .b = utility::string("1", 1)});
+ init_process->environment.add_end({
+ .a = utility::string("ARGV0", 5),
+ .b = utility::string("/bin/init", 9)});
+
+ init_thread->state = application::thread_state::paused;
+ application::paused_threads->insert(init_thread);
+ application::resume_next();
}
diff --git a/kernel/source/framebuffer.cpp b/kernel/source/framebuffer.cpp
new file mode 100644
index 0000000..ab1b3d7
--- /dev/null
+++ b/kernel/source/framebuffer.cpp
@@ -0,0 +1,40 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/framebuffer.hpp>
+
+namespace hilbert::kernel::framebuffer {
+
+ uint64_t paddr;
+ static uint32_t *vaddr;
+ int width;
+ int height;
+ int dword_pitch;
+
+ 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;
+
+ }
+
+ color encode_color(uint8_t r, uint8_t g, uint8_t b) {
+ return ((uint32_t)r << 16) | ((uint32_t)g << 8) | (uint32_t)b;
+ }
+
+ void set_pixel(int x, int y, color c) {
+ vaddr[y * dword_pitch + x] = c;
+ }
+
+ void fill_color(color c) {
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ vaddr[y * dword_pitch + x] = c;
+ }
+
+}
diff --git a/kernel/source/input.cpp b/kernel/source/input.cpp
new file mode 100644
index 0000000..696cb13
--- /dev/null
+++ b/kernel/source/input.cpp
@@ -0,0 +1,22 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/input.hpp>
+#include <hilbert/kernel/panic.hpp>
+#include <hilbert/kernel/vfile.hpp>
+
+namespace hilbert::kernel::input {
+
+ utility::queue<uint32_t> *key_queue;
+
+ void init_input() {
+ key_queue = new utility::queue<uint32_t>();
+ }
+
+ void got_input() {
+ if (application::threads_waiting_for_input->count > 0) {
+ auto *t = application::threads_waiting_for_input->take();
+ t->state = application::thread_state::paused;
+ application::paused_threads->insert(t);
+ }
+ }
+
+}
diff --git a/kernel/interrupts.asm b/kernel/source/interrupts.asm
index c096ddb..babc020 100644
--- a/kernel/interrupts.asm
+++ b/kernel/source/interrupts.asm
@@ -192,20 +192,18 @@ exception_common:
set_isr:
;rdi - index
-;sil - 1 if this is a trap, 0 if it is an interrupt
-;rdx - isr pointer
+;rsi - isr pointer
shl rdi, 4
add rdi, idt
- mov word [rdi], dx
- shr rdx, 16
- mov word [rdi + 6], dx
- shr rdx, 16
- mov dword [rdi + 8], edx
+ mov word [rdi], si
+ shr rsi, 16
+ mov word [rdi + 6], si
+ shr rsi, 16
+ mov dword [rdi + 8], esi
- or sil, 0x8e
- mov byte [rdi + 5], sil
+ mov byte [rdi + 5], 0x8e
mov word [rdi + 2], 0x28
mov byte [rdi + 4], 1
@@ -281,8 +279,7 @@ load_gdt_and_idt:
mov rdi, rcx
dec rdi
- mov sil, 1
- mov rdx, qword [exception_isrs + rdi * 8]
+ mov rsi, qword [exception_isrs + rdi * 8]
call set_isr
loop .loop
@@ -312,8 +309,7 @@ load_gdt_and_idt:
out 0xa1, al
mov rdi, 0x21
- xor sil, sil
- mov rdx, keyboard_isr
+ mov rsi, keyboard_isr
call set_isr
;set keyboard config
diff --git a/kernel/interrupts.cpp b/kernel/source/interrupts.cpp
index cd57c4f..6e22121 100644
--- a/kernel/interrupts.cpp
+++ b/kernel/source/interrupts.cpp
@@ -1,4 +1,3 @@
-#include <hilbert/kernel/terminal.hpp>
#include <hilbert/kernel/input.hpp>
#include <hilbert/kernel/panic.hpp>
@@ -36,93 +35,15 @@ struct [[gnu::packed]] exception_info_t {
extern exception_info_t exception_info;
-static const char *exception_types[] = {
- "division error",
- "",
- "non-maskable interrupt",
- "",
- "",
- "",
- "invalid opcode",
- "",
- "double fault (uh oh)",
- "",
- "",
- "",
- "stack fault",
- "general protection fault",
- "page fault",
- ""
-};
-
-static const char *flag_names[] = {
- " cf",
- "",
- " pf",
- "",
- " af",
- "",
- " zf",
- " sf",
- " tf",
- " if",
- " df",
- " of",
- "",
- "",
- " nt",
- " md"
-};
-
-static void print_line(const char *r1, const char *r2, uint64_t r1v, uint64_t r2v) {
- terminal::put_string_sz("\n ");
- terminal::put_string_sz(r1);
- terminal::put_string_sz(": 0x");
- terminal::put_int_hex(r1v, 16);
- terminal::put_string_sz(" ");
- terminal::put_string_sz(r2);
- terminal::put_string_sz(": 0x");
- terminal::put_int_hex(r2v, 16);
-}
-
extern "C" [[noreturn]] void print_exception() {
- terminal::put_string_sz("exception handler:\n type: ");
- terminal::put_string_sz(exception_types[exception_info.exception_number]);
- terminal::put_string_sz(" (0x");
- terminal::put_int_hex(exception_info.exception_number, 2);
- terminal::put_char(')');
-
- if (exception_info.has_error == 1) {
- terminal::put_string_sz("\n error code: 0x");
- terminal::put_int_hex(exception_info.error, 16);
- }
-
- terminal::put_string_sz("\n flags:");
- if (exception_info.rflags == 0)
- terminal::put_string_sz(" [none]");
- else
- for (int i = 0; i < 16; ++i)
- if (((exception_info.rflags >> i) & 1) == 1)
- terminal::put_string_sz(flag_names[i]);
-
- if (exception_info.exception_number == 0x0e) {
- terminal::put_string_sz("\n cr2: 0x");
- terminal::put_int_hex(exception_info.cr2, 16);
- }
+ //so exception_info's type is known by gdb
+ exception_info_t the_exception_info = exception_info;
+ (void)the_exception_info;
- print_line("cr3", "rip", exception_info.cr3, exception_info.rip);
- print_line("rax", "rbx", exception_info.rax, exception_info.rbx);
- print_line("rcx", "rdx", exception_info.rcx, exception_info.rdx);
- print_line("rdi", "rsi", exception_info.rdi, exception_info.rsi);
- print_line("rbp", "rsp", exception_info.rbp, exception_info.rsp);
- print_line("r8 ", "r9 ", exception_info.r8 , exception_info.r9 );
- print_line("r10", "r11", exception_info.r10, exception_info.r11);
- print_line("r12", "r13", exception_info.r12, exception_info.r13);
- print_line("r14", "r15", exception_info.r14, exception_info.r15);
+ //TODO: log exception, and recover if possible.
- while (1)
- asm ("hlt");
+ panic(0xba40bb);
}
@@ -134,6 +55,7 @@ static uint32_t current_flags = 0;
static void got_key(uint32_t key) {
input::key_queue->insert(current_flags | key);
+ input::got_input();
if (key == (input::BREAK | 0x77))
current_flags ^= input::NUM_LOCK;
diff --git a/kernel/paging.asm b/kernel/source/paging.asm
index f1047a9..f1047a9 100644
--- a/kernel/paging.asm
+++ b/kernel/source/paging.asm
diff --git a/kernel/paging.cpp b/kernel/source/paging.cpp
index d8869fc..d8869fc 100644
--- a/kernel/paging.cpp
+++ b/kernel/source/paging.cpp
diff --git a/kernel/source/panic.cpp b/kernel/source/panic.cpp
new file mode 100644
index 0000000..d99be91
--- /dev/null
+++ b/kernel/source/panic.cpp
@@ -0,0 +1,11 @@
+#include <hilbert/kernel/framebuffer.hpp>
+#include <hilbert/kernel/panic.hpp>
+
+namespace hilbert::kernel {
+ [[noreturn]] void panic(uint32_t code) {
+ framebuffer::fill_color(framebuffer::encode_color(
+ code >> 16, (code >> 8) & 0xff, code & 0xff));
+ while (1)
+ asm ("hlt");
+ }
+}
diff --git a/kernel/storage.cpp b/kernel/source/storage.cpp
index b6b1a04..b6b1a04 100644
--- a/kernel/storage.cpp
+++ b/kernel/source/storage.cpp
diff --git a/kernel/storage/bd/memory.cpp b/kernel/source/storage/bd/memory.cpp
index d6a6719..d6a6719 100644
--- a/kernel/storage/bd/memory.cpp
+++ b/kernel/source/storage/bd/memory.cpp
diff --git a/kernel/storage/fs/tarfs.cpp b/kernel/source/storage/fs/tarfs.cpp
index 5986f62..5986f62 100644
--- a/kernel/storage/fs/tarfs.cpp
+++ b/kernel/source/storage/fs/tarfs.cpp
diff --git a/kernel/source/syscall.cpp b/kernel/source/syscall.cpp
new file mode 100644
index 0000000..768ff0d
--- /dev/null
+++ b/kernel/source/syscall.cpp
@@ -0,0 +1,538 @@
+#include <hilbert/kernel/application.hpp>
+#include <hilbert/kernel/framebuffer.hpp>
+#include <hilbert/kernel/paging.hpp>
+#include <hilbert/kernel/input.hpp>
+#include <hilbert/kernel/panic.hpp>
+#include <hilbert/kernel/vfile.hpp>
+
+namespace hilbert::kernel::syscall {
+
+ 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
+ };
+
+ bool is_range_owned_by_application(uint64_t start, uint64_t end) {
+ auto *process = application::running_thread->the_process;
+ uint64_t pstart = (start / 4096) * 4096;
+ uint64_t pend = ((end - 1) / 4096 + 1) * 4096;
+ for (uint64_t p = pstart; p < pend; p += 4096)
+ if (!process->is_page_owned(p))
+ return false;
+ return true;
+ }
+
+ 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 *process = application::running_thread->the_process;
+ if (process->framebuffer_vaddr == 0) {
+ uint64_t pages_needed =
+ (framebuffer::dword_pitch * framebuffer::height * 4 - 1) / 4096 + 1;
+ uint64_t vaddr = process->get_free_vaddr_pages(pages_needed);
+ for (uint64_t i = 0; i < pages_needed; ++i)
+ process->map_page(
+ vaddr + i * 4096, framebuffer::paddr + i * 4096, true, false, false);
+ process->framebuffer_vaddr = vaddr;
+ }
+
+ rax = process->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_string((const char *)rdi, rsi);
+
+ set_zero(rax, rdi, rsi, rdx);
+
+ vfile::canon_path cp;
+ vfile::vfile file;
+ vfile::canonize_path(path_string, cp);
+
+ switch (vfile::lookup_path(cp, file, true)) {
+
+ case storage::fs_result::device_error:
+ case storage::fs_result::fs_corrupt:
+
+ rax = (uint64_t)application::stream_result::io_error;
+ return;
+
+ case storage::fs_result::does_not_exist:
+
+ if (!(rdx & 1)) {
+ rax = (uint64_t)application::stream_result::does_not_exist;
+ return;
+ }
+
+ //TODO: create the file
+ panic(0x9af5e6);
+
+ case storage::fs_result::success:
+
+ if (rdx & 2) {
+ rax = (uint64_t)application::stream_result::already_exists;
+ return;
+ }
+
+ if (file.dir_entry.type != storage::file_type::regular_file) {
+ rax = (uint64_t)application::stream_result::not_a_regular_file;
+ return;
+ }
+
+ rax = (uint64_t)application::stream_result::success;
+ rdi = application::running_thread->the_process->open_streams.add_new(
+ new application::vfile_stream(utility::move(file)));
+
+ return;
+
+ }
+
+ }
+
+ void end_this_thread_syscall(
+ uint64_t &, uint64_t &rdi, uint64_t &, uint64_t &
+ ) {
+ application::running_thread->exit_code = (int)(uint32_t)rdi;
+ delete application::running_thread;
+ application::resume_next();
+ }
+
+ 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 *p = application::running_thread->the_process;
+ uint64_t vaddr = p->get_free_vaddr_pages(count);
+
+ for (uint64_t i = 0; i < count; ++i) {
+ uint64_t kvaddr;
+ uint64_t paddr;
+ paging::map_new_kernel_page(kvaddr, paddr);
+ for (int i = 0; i < 4096; ++i)
+ ((uint8_t *)kvaddr)[i] = 0;
+ paging::unmap_kernel_page((uint64_t)kvaddr);
+ p->map_page(vaddr + i * 4096, paddr, true, false, true);
+ }
+
+ rax = vaddr;
+
+ }
+
+ void read_key_packet_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ set_zero(rax, rdi, rsi, rdx);
+ auto *t = application::running_thread;
+
+ do
+ if (input::key_queue->count > 0) {
+ rax = (uint64_t)input::key_queue->take();
+ return;
+ }
+ while (application::save_thread_state(t->cpu));
+
+ t->state = application::thread_state::waiting;
+ application::threads_waiting_for_input->insert(t);
+ application::resume_next();
+
+ }
+
+ void create_private_socket_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+ auto *s = new application::socket;
+ auto *ss1 = new application::socket_stream(s, false);
+ auto *ss2 = new application::socket_stream(s, true);
+ set_zero(rax, rdi, rsi, rdx);
+ auto *p = application::running_thread->the_process;
+ rax = (uint64_t)p->open_streams.add_new(ss1);
+ rdi = (uint64_t)p->open_streams.add_new(ss2);
+ }
+
+ void create_socket_listener_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 id_string((const char *)rdi, rsi);
+ set_zero(rax, rdi, rsi, rdx);
+
+ for (auto *p = application::all_socket_listeners->first; p; p = p->next)
+ if (p->value->id == id_string) {
+ rax = (uint64_t)application::stream_result::socket_id_already_used;
+ return;
+ }
+
+ auto *sl = new application::socket_listener();
+ sl->id = utility::move(id_string);
+ sl->is_listening = true;
+ rax = (uint64_t)application::stream_result::success;
+ rdi = (uint64_t)application::running_thread->the_process
+ ->socket_listeners.add_new(utility::move(sl));
+
+ }
+
+ void stop_socket_listener_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ auto *p = application::running_thread->the_process;
+
+ if (p->socket_listeners.has_id(handle)) {
+ auto *sl = p->socket_listeners.get(handle);
+ p->socket_listeners.remove_id(handle);
+ if (sl->waiting_to_accept_connection.count > 0 ||
+ sl->waiting_to_connect.count > 0) {
+ sl->is_listening = false;
+ while (sl->waiting_to_accept_connection.count > 0) {
+ auto *t = sl->waiting_to_accept_connection.take();
+ t->state = application::thread_state::paused;
+ application::paused_threads->insert(t);
+ }
+ while (sl->waiting_to_connect.count > 0) {
+ auto *t = sl->waiting_to_connect.take();
+ t->state = application::thread_state::paused;
+ application::paused_threads->insert(t);
+ }
+ }
+ else
+ delete sl;
+ }
+
+ }
+
+ void accept_socket_connection_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ auto *t = application::running_thread;
+ auto *p = t->the_process;
+
+ if (!p->socket_listeners.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::socket_id_not_in_use;
+ return;
+ }
+
+ auto *sl = p->socket_listeners.get(handle);
+
+ if (sl->waiting_to_connect.count > 0) {
+ auto *ot = sl->waiting_to_connect.take();
+ auto *sock = new application::socket();
+ application::stream *s1 = new application::socket_stream(sock, false);
+ application::stream *s2 = new application::socket_stream(sock, true);
+ unsigned handle = p->open_streams.add_new(utility::move(s1));
+ ot->just_connected_to = s2;
+ ot->state = application::thread_state::paused;
+ application::paused_threads->insert(ot);
+ rax = (uint64_t)application::stream_result::success;
+ rdi = handle;
+ return;
+ }
+
+ if (application::save_thread_state(t->cpu)) {
+ if (sl->is_listening) {
+ rax = (uint64_t)application::stream_result::success;
+ rdi = p->open_streams.add_new(utility::move(t->just_accepted));
+ }
+ else {
+ if (sl->waiting_to_accept_connection.count == 0 &&
+ sl->waiting_to_connect.count == 0)
+ delete sl;
+ rax = (uint64_t)application::stream_result::socket_listener_closed;
+ }
+ return;
+ }
+
+ t->state = application::thread_state::waiting;
+ sl->waiting_to_accept_connection.insert(t);
+ application::resume_next();
+
+ }
+
+ void connect_to_socket_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 id_string((const char *)rdi, rsi);
+ set_zero(rax, rdi, rsi, rdx);
+
+ for (auto *i = application::all_socket_listeners->first; i; i = i->next)
+ if (i->value->id == id_string) {
+ auto *sl = i->value;
+ auto *t = application::running_thread;
+ auto *p = t->the_process;
+
+ if (sl->waiting_to_accept_connection.count > 0) {
+ auto *ot = sl->waiting_to_accept_connection.take();
+ auto *sock = new application::socket();
+ auto *s1 = new application::socket_stream(sock, false);
+ auto *s2 = new application::socket_stream(sock, true);
+ unsigned handle = p->open_streams.add_new(utility::move(s1));
+ ot->just_accepted = s2;
+ ot->state = application::thread_state::paused;
+ application::paused_threads->insert(ot);
+ rax = (uint64_t)application::stream_result::success;
+ rdi = handle;
+ return;
+ }
+
+ if (application::save_thread_state(t->cpu)) {
+ if (sl->is_listening) {
+ rax = (uint64_t)application::stream_result::success;
+ rdi = p->open_streams.add_new(utility::move(t->just_connected_to));
+ }
+ else {
+ if (sl->waiting_to_accept_connection.count == 0 &&
+ sl->waiting_to_connect.count == 0)
+ delete sl;
+ rax = (uint64_t)application::stream_result::socket_id_not_in_use;
+ }
+ return;
+ }
+
+ t->state = application::thread_state::waiting;
+ sl->waiting_to_connect.insert(t);
+ application::resume_next();
+
+ }
+
+ rax = (uint64_t)application::stream_result::socket_id_not_in_use;
+
+ }
+
+ void close_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+ auto *p = application::running_thread->the_process;
+
+ if (p->open_streams.has_id(handle)) {
+ application::stream *s = p->open_streams.get(handle);
+ p->open_streams.remove_id(handle);
+ delete s;
+ }
+
+ }
+
+ void seek_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint8_t origin = (uint8_t)rsi;
+ int64_t offset = (int64_t)rdx;
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (origin >= 3)
+ return;
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)
+ ->seek((application::seek_origin)origin, offset);
+
+ }
+
+ void read_from_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint64_t count = (uint64_t)rsi;
+ uint64_t buffer = (uint64_t)rdx;
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (!is_range_owned_by_application(buffer, buffer + count))
+ return;
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)->read(count, (void *)buffer);
+
+ }
+
+ void write_to_stream_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint64_t count = (uint64_t)rsi;
+ uint64_t buffer = (uint64_t)rdx;
+ set_zero(rax, rdi, rsi, rdx);
+
+ if (!is_range_owned_by_application(buffer, buffer + count))
+ return;
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)
+ ->write(count, (const void *)buffer);
+
+ }
+
+ void get_stream_length_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)->get_length(rdi);
+
+ }
+
+ void start_process_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+ //TODO
+ (void)rax;
+ (void)rdi;
+ (void)rsi;
+ (void)rdx;
+ panic(0x9af5e6);
+ }
+
+ void end_this_process_syscall(
+ uint64_t &, uint64_t &rdi, uint64_t &, uint64_t &
+ ) {
+ application::running_thread->the_process->end_process((unsigned)rdi);
+ application::resume_next();
+ }
+
+ void set_stream_length_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+ ) {
+
+ unsigned handle = (unsigned)rdi;
+ uint64_t new_length = rsi;
+ set_zero(rax, rdi, rsi, rdx);
+
+ auto *p = application::running_thread->the_process;
+
+ if (!p->open_streams.has_id(handle)) {
+ rax = (uint64_t)application::stream_result::bad_handle;
+ return;
+ }
+
+ rax = (uint64_t)p->open_streams.get(handle)->set_length(new_length);
+
+ }
+
+ 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,
+ &end_this_thread_syscall,
+ &get_new_pages_syscall,
+ &read_key_packet_syscall,
+ &create_private_socket_syscall,
+ &create_socket_listener_syscall,
+ &stop_socket_listener_syscall,
+ &accept_socket_connection_syscall,
+ &connect_to_socket_syscall,
+ &close_stream_syscall,
+ &seek_stream_syscall,
+ &read_from_stream_syscall,
+ &write_to_stream_syscall,
+ &get_stream_length_syscall,
+ &start_process_syscall,
+ &end_this_process_syscall,
+ &set_stream_length_syscall
+ };
+
+ static constexpr int max_syscall_number = 18;
+
+}
+
+using namespace hilbert::kernel::syscall;
+
+extern "C" void do_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
+) {
+
+ if (rax <= max_syscall_number && handlers[rax] != 0)
+ handlers[rax](rax, rdi, rsi, rdx);
+ else
+ set_zero(rax, rdi, rsi, rdx);
+
+}
diff --git a/kernel/utility.cpp b/kernel/source/utility.cpp
index 12e88fd..12e88fd 100644
--- a/kernel/utility.cpp
+++ b/kernel/source/utility.cpp
diff --git a/kernel/vfile.cpp b/kernel/source/vfile.cpp
index 89c95e6..89c95e6 100644
--- a/kernel/vfile.cpp
+++ b/kernel/source/vfile.cpp
diff --git a/kernel/syscall.asm b/kernel/syscall.asm
deleted file mode 100644
index c293402..0000000
--- a/kernel/syscall.asm
+++ /dev/null
@@ -1,88 +0,0 @@
-bits 64
-
-global start_user_mode
-
-section .text
-
-extern do_syscall
-
-syscall_entry:
- mov r11, rsp
- mov rsp, 0xfffffffffffff000
- push r11
- push rcx
-
- 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
-
- xor r8, r8
- xor r9, r9
- xor r10, r10
- xor r11, r11
- or r11, 0x200
- pop rcx
- pop rsp
-
- o64 sysret
-
-start_user_mode:
-;intended rip in rdi
-;intended rsp in rsi
-;intended p4_paddr in rdx
-
- mov rax, rdx
- mov cr3, rax
-
- ;efer <- efer | 0x1
- mov rcx, 0xc0000080
- rdmsr
- or al, 1
- wrmsr
-
- ;lstar <- syscall_entry
- mov rdx, syscall_entry
- mov eax, edx
- shr rdx, 32
- mov ecx, 0xc0000082
- wrmsr
-
- ;star <- 0x0030.0028.0000.0000
- mov edx, 0x00300028
- xor eax, eax
- mov ecx, 0xc0000081
- wrmsr
-
- mov rcx, rdi
- mov rsp, rsi
- xor r11, r11
- or r11, 0x200
-
- xor rax, rax
- xor rbx, rbx
- xor rdx, rdx
- xor rdi, rdi
- xor rsi, rsi
- xor rbp, rbp
- xor r8, r8
- xor r9, r9
- xor r10, r10
- xor r12, r12
- xor r13, r13
- xor r14, r14
- xor r15, r15
-
- o64 sysret
diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp
deleted file mode 100644
index e194eb1..0000000
--- a/kernel/syscall.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-#include <hilbert/kernel/application.hpp>
-#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/paging.hpp>
-#include <hilbert/kernel/input.hpp>
-#include <hilbert/kernel/vfile.hpp>
-
-namespace hilbert::kernel::syscall {
-
- 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
- };
-
- 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 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, true)) {
- 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 (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(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);
-
- }
-
- void read_key_packet_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
- ) {
-
- set_zero(rax, rdi, rsi, rdx);
-
- asm ("cli");
-
- while (input::key_queue->count == 0)
- asm ("sti\nhlt\ncli");
-
- rax = (uint64_t)input::key_queue->take();
-
- asm ("sti");
-
- }
-
- 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,
- &read_key_packet_syscall
- };
-
- static constexpr int max_syscall_number = 8;
-
-}
-
-using namespace hilbert::kernel::syscall;
-
-extern "C" void do_syscall(
- uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx
-) {
-
- if (rax <= max_syscall_number && handlers[rax] != 0)
- handlers[rax](rax, rdi, rsi, rdx);
- else
- set_zero(rax, rdi, rsi, rdx);
-
-}
diff --git a/kernel/terminal.cpp b/kernel/terminal.cpp
deleted file mode 100644
index 167e6cf..0000000
--- a/kernel/terminal.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-#include <hilbert/kernel/framebuffer.hpp>
-#include <hilbert/kernel/terminal.hpp>
-
-namespace hilbert::kernel::terminal {
-
- uint8_t *termfont;
- uint64_t termfont_len;
-
- int width;
- int height;
-
- int cursor_x;
- int cursor_y;
-
- framebuffer::color bg_color;
- framebuffer::color fg_color;
-
- static uint8_t glyph_height;
-
- void init_terminal() {
- //TODO - verify that termfont fits inside termfont_len (i.e. that no other
- // functions in this file will try to access memory outside termfont)
- //TODO - check magic header to verify that this is actually a font and to
- // see whether this is a psf1 font or a psf2 font.
- //TODO - support psf2 fonts. currently psf1 is assumed.
- //TODO - read unicode table if there is one. currently it is assumed that
- // all 256 codepoints have glyphs, and that they appear in order.
-
- glyph_height = termfont[3];
- width = framebuffer::width / 8;
- height = framebuffer::height / glyph_height;
- cursor_x = 0;
- cursor_y = 0;
- bg_color = framebuffer::encode_color(0, 0, 0);
- fg_color = framebuffer::encode_color(255, 255, 255);
-
- }
-
- static void cursor_down() {
- if (++cursor_y == height) {
- --cursor_y;
- framebuffer::move_region(
- 0, glyph_height, width * 8, height * glyph_height, 0, 0);
- framebuffer::fill_region(0, (height - 1) * glyph_height,
- width * 8, height * glyph_height, bg_color);
- }
- }
-
- static void cursor_right() {
- if (++cursor_x == width) {
- cursor_x = 0;
- cursor_down();
- }
- }
-
- void draw_char(char ch, int x, int y) {
- const uint8_t *glyph = termfont + 4 + glyph_height * (unsigned)ch;
- for (int i = 0; i < glyph_height; ++i)
- for (int j = 0; j < 8; ++j)
- framebuffer::set_pixel(x * 8 + j, y * glyph_height + i,
- ((glyph[i] << j) & 0x80) ? fg_color : bg_color);
- }
-
- void put_char(char ch) {
- switch (ch) {
- case '\n':
- cursor_x = 0;
- cursor_down();
- break;
- default:
- draw_char(ch, cursor_x, cursor_y);
- cursor_right();
- break;
- }
- }
-
- void put_string(const utility::string &str) {
- for (size_t i = 0; i < str.count; ++i)
- put_char(str.buffer[i]);
- }
-
- void put_string_sz(const char *str) {
- for (size_t i = 0; str[i]; ++i)
- put_char(str[i]);
- }
-
- void put_int_decimal(uint64_t n, bool with_commas) {
-
- if (n == 0) {
- put_char('0');
- return;
- }
-
- uint64_t d = 1;
- int i = 0;
- while (d <= n / 10) {
- d *= 10;
- ++i;
- }
-
- while (d) {
- put_char('0' + ((n / d) % 10));
- d /= 10;
- if (with_commas && (i % 3 == 0) && (i != 0))
- put_char(',');
- --i;
- }
-
- }
-
- static char hex_digits[] = "0123456789abcdef";
-
- void put_int_hex(uint64_t n, int digits, bool with_dots) {
- for (int digit = digits - 1; digit >= 0; --digit) {
- put_char(hex_digits[(n >> (digit * 4)) & 0xf]);
- if (with_dots && digit % 4 == 0 && digit != 0)
- put_char('.');
- }
- }
-
-}