diff options
Diffstat (limited to 'kernel')
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('.'); - } - } - -} |