From b1a912a8a6ff472a49b2e0a09cfd433adfc2cb24 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sat, 18 May 2024 21:53:38 -0400 Subject: reorganization, cross compiler --- kernel/allocator.cpp | 160 -------- kernel/application.cpp | 280 ------------- kernel/entry.cpp | 230 ----------- kernel/framebuffer.cpp | 65 --- kernel/include/hilbert/kernel/application.hpp | 193 +++++++-- kernel/include/hilbert/kernel/framebuffer.hpp | 10 +- kernel/include/hilbert/kernel/input.hpp | 2 + kernel/include/hilbert/kernel/panic.hpp | 3 +- kernel/include/hilbert/kernel/terminal.hpp | 32 -- kernel/input.cpp | 13 - kernel/interrupts.asm | 344 ---------------- kernel/interrupts.cpp | 230 ----------- kernel/makefile | 19 + kernel/paging.asm | 16 - kernel/paging.cpp | 145 ------- kernel/panic.cpp | 10 - kernel/source/allocator.cpp | 160 ++++++++ kernel/source/application.asm | 171 ++++++++ kernel/source/application.cpp | 550 ++++++++++++++++++++++++++ kernel/source/entry.cpp | 222 +++++++++++ kernel/source/framebuffer.cpp | 40 ++ kernel/source/input.cpp | 22 ++ kernel/source/interrupts.asm | 340 ++++++++++++++++ kernel/source/interrupts.cpp | 152 +++++++ kernel/source/paging.asm | 16 + kernel/source/paging.cpp | 145 +++++++ kernel/source/panic.cpp | 11 + kernel/source/storage.cpp | 67 ++++ kernel/source/storage/bd/memory.cpp | 21 + kernel/source/storage/fs/tarfs.cpp | 238 +++++++++++ kernel/source/syscall.cpp | 538 +++++++++++++++++++++++++ kernel/source/utility.cpp | 51 +++ kernel/source/vfile.cpp | 206 ++++++++++ kernel/storage.cpp | 67 ---- kernel/storage/bd/memory.cpp | 21 - kernel/storage/fs/tarfs.cpp | 238 ----------- kernel/syscall.asm | 88 ----- kernel/syscall.cpp | 262 ------------ kernel/terminal.cpp | 121 ------ kernel/utility.cpp | 51 --- kernel/vfile.cpp | 206 ---------- 41 files changed, 3141 insertions(+), 2615 deletions(-) delete mode 100644 kernel/allocator.cpp delete mode 100644 kernel/application.cpp delete mode 100644 kernel/entry.cpp delete mode 100644 kernel/framebuffer.cpp delete mode 100644 kernel/include/hilbert/kernel/terminal.hpp delete mode 100644 kernel/input.cpp delete mode 100644 kernel/interrupts.asm delete mode 100644 kernel/interrupts.cpp create mode 100644 kernel/makefile delete mode 100644 kernel/paging.asm delete mode 100644 kernel/paging.cpp delete mode 100644 kernel/panic.cpp create mode 100644 kernel/source/allocator.cpp create mode 100644 kernel/source/application.asm create mode 100644 kernel/source/application.cpp create mode 100644 kernel/source/entry.cpp create mode 100644 kernel/source/framebuffer.cpp create mode 100644 kernel/source/input.cpp create mode 100644 kernel/source/interrupts.asm create mode 100644 kernel/source/interrupts.cpp create mode 100644 kernel/source/paging.asm create mode 100644 kernel/source/paging.cpp create mode 100644 kernel/source/panic.cpp create mode 100644 kernel/source/storage.cpp create mode 100644 kernel/source/storage/bd/memory.cpp create mode 100644 kernel/source/storage/fs/tarfs.cpp create mode 100644 kernel/source/syscall.cpp create mode 100644 kernel/source/utility.cpp create mode 100644 kernel/source/vfile.cpp delete mode 100644 kernel/storage.cpp delete mode 100644 kernel/storage/bd/memory.cpp delete mode 100644 kernel/storage/fs/tarfs.cpp delete mode 100644 kernel/syscall.asm delete mode 100644 kernel/syscall.cpp delete mode 100644 kernel/terminal.cpp delete mode 100644 kernel/utility.cpp delete mode 100644 kernel/vfile.cpp (limited to 'kernel') diff --git a/kernel/allocator.cpp b/kernel/allocator.cpp deleted file mode 100644 index 324f992..0000000 --- a/kernel/allocator.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include - -namespace hilbert::kernel::allocator { - - struct free_entry { - uint64_t start; - uint64_t len;//0 for unused - }; - - struct free_page { - free_page *next; - free_entry entries[255]; - }; - - free_page *first_page; - - static_assert(sizeof(free_page) == 4088); - - free_entry *get_entry(uint64_t start, uint64_t len) { - for (free_page *fp = first_page; fp; fp = fp->next) - for (int i = 0; i < 255; ++i) - if (fp->entries[i].start == start && fp->entries[i].len == len) - return fp->entries + i; - return 0; - } - - void add_entry(uint64_t start, uint64_t len) { - for (free_page *fp = first_page; fp; fp = fp->next) - for (int i = 0; i < 255; ++i) - if (fp->entries[i].len == 0) { - fp->entries[i].start = start; - fp->entries[i].len = len; - return; - } - free_page *new_page = (free_page *)paging::map_new_kernel_pages(1); - new_page->next = first_page; - first_page = new_page; - for (int i = 2; i < 255; ++i) - new_page->entries[i].len = 0; - new_page->entries[0].start = (uint64_t)new_page + 4088; - new_page->entries[0].len = 8; - new_page->entries[1].start = start; - new_page->entries[1].len = len; - } - - //len is power of 2, start is len-aligned - void free_block(uint64_t start, uint64_t len) { - free_entry *buddy = get_entry(start ^ len, len); - if (buddy) { - buddy->start = start & ~len; - buddy->len = len * 2; - } - else - add_entry(start, len); - } - - void free_region(uint64_t start, uint64_t len) { - uint64_t block_size = 1; - while (block_size <= len) { - if (start & block_size) { - free_block(start, block_size); - start += block_size; - len -= block_size; - } - block_size *= 2; - } - while (len) { - block_size /= 2; - if (block_size <= len) { - free_block(start, block_size); - start += block_size; - len -= block_size; - } - } - //testing - if (len != 0) - while (1) - ; - } - - uint64_t take_region(uint64_t len) { - - uint64_t min_size = 1; - while (min_size < len) - min_size *= 2; - - free_entry *entry = 0; - - for (free_page *fp = first_page; fp; fp = fp->next) - for (int i = 0; i < 255; ++i) - if (fp->entries[i].len >= min_size) { - if (fp->entries[i].len == min_size) { - entry = fp->entries + i; - goto loop_done; - } - if (entry == 0 || fp->entries[i].len < entry->len) - entry = fp->entries + i; - } - - loop_done: - if (entry != 0) { - uint64_t start = entry->start; - uint64_t block_len = entry->len; - entry->len = 0; - if (block_len != len) - free_region(start + len, block_len - len); - return start; - } - - uint64_t pages = (len - 1) / 4096 + 1; - uint64_t start = (uint64_t)paging::map_new_kernel_pages(pages); - if (pages * 4096 != len) - free_region(start + len, pages * 4096 - len); - return start; - - } - -} - -using namespace hilbert::kernel::allocator; - -void *_new(size_t len) { - if (len == 0) - return 0; - uint64_t vaddr = take_region(len + sizeof(size_t)); - *(size_t *)vaddr = len; - return (void *)(vaddr + sizeof(size_t)); -} - -void _delete(void *ptr) { - if ((uint64_t)ptr == 0) - return; - uint64_t vaddr = (uint64_t)ptr - sizeof(size_t); - free_region(vaddr, *(size_t *)vaddr + sizeof(size_t)); -} - -void *operator new(size_t len) { - return _new(len); -} - -void operator delete(void *ptr, size_t) { - return _delete(ptr); -} - -void operator delete(void *ptr) { - return _delete(ptr); -} - -void *operator new[](size_t len) { - return _new(len); -} - -void operator delete[](void *ptr, size_t) { - return _delete(ptr); -} - -void operator delete[](void *ptr) { - return _delete(ptr); -} 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 -#include - -//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_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/entry.cpp b/kernel/entry.cpp deleted file mode 100644 index cc74e69..0000000 --- a/kernel/entry.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../limine/limine.h" - -using namespace hilbert::kernel; - -LIMINE_BASE_REVISION(1) - -static volatile limine_memmap_request memmap_request { - .id = LIMINE_MEMMAP_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile limine_kernel_address_request kernel_address_request { - .id = LIMINE_KERNEL_ADDRESS_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile limine_framebuffer_request framebuffer_request { - .id = LIMINE_FRAMEBUFFER_REQUEST, - .revision = 0, - .response = 0 -}; - -static volatile limine_hhdm_request hhdm_request { - .id = LIMINE_HHDM_REQUEST, - .revision = 0, - .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 -}; - -bool try_map_module_by_cmdline( - const char *cmdline, void *&vaddr_out, uint64_t &len_out -) { - auto response = module_request.response; - 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) - if (!cmdline[j]) { - - //module start is guaranteed to be page-aligned, end is not. - uint64_t start_paddr = - (uint64_t)file->address - hhdm_request.response->offset; - uint64_t end_paddr = - ((start_paddr + file->size - 1) / 4096 + 1) * 4096; - - uint64_t start_vaddr = - paging::find_unmapped_vram_region((end_paddr - start_paddr) / 4096); - for (uint64_t i = 0; i < end_paddr - start_paddr; i += 4096) - paging::map_kernel_page( - start_paddr + i, start_vaddr + i, true, false); - - vaddr_out = (void *)start_vaddr; - len_out = file->size; - - return true; - } - } - return false; -} - -//defined in linker script, page-aligned: -extern uint8_t __kernel_start; -extern uint8_t __kernel_end; -extern uint8_t __kernel_rx_start; -extern uint8_t __kernel_rx_end; -extern uint8_t __kernel_ro_start; -extern uint8_t __kernel_ro_end; -extern uint8_t __kernel_rw_start; -extern uint8_t __kernel_rw_end; - -uint8_t *initfs; -uint64_t initfs_len; - -[[noreturn]] static void with_kernel_p4(); - -extern "C" void load_gdt_and_idt(); - -extern "C" [[noreturn]] void entry() { - - //TODO?: maybe we should check if the limine requests were - // fulfilled and display some error message if not - - //set up the physical memory usage bitmap: - - paging::mark_all_pram_used(); - auto memmap = memmap_request.response; - for (uint64_t i = 0; i < memmap->entry_count; ++i) { - //we don't allocate any physical pages until after we are done using limine - //structures (specifically at the call to paging::map_kernel_stacks), so - //we consider bootloader reclaimable to be free. usable and bootloader - //reclaimable are guaranteed by limine spec to be page-aligned. - auto entry = memmap->entries[i]; - if (entry->type == LIMINE_MEMMAP_USABLE || - entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) - paging::mark_pram_region_free(entry->base, entry->base + entry->length); - } - - //set up page mappings: - - auto kernel_address = kernel_address_request.response; - uint64_t kernel_offset = kernel_address->virtual_base - - kernel_address->physical_base; - - uint64_t hhdm = hhdm_request.response->offset; - - //framebuffer might not be page-aligned - auto framebuffer = framebuffer_request.response->framebuffers[0]; - uint64_t fb_start = ((uint64_t)framebuffer->address / 4096) * 4096 - hhdm; - uint64_t fb_end = (uint64_t)framebuffer->address - + framebuffer->pitch * framebuffer->height - hhdm; - fb_end = ((fb_end - 1) / 4096 + 1) * 4096; - - paging::init_kernel_page_tables(kernel_offset); - - //kernel image rx - for (uint64_t vaddr = (uint64_t)&__kernel_rx_start; - vaddr < (uint64_t)&__kernel_rx_end; vaddr += 4096) - paging::map_kernel_page(vaddr - kernel_offset, vaddr, false, true); - - //kernel image ro - for (uint64_t vaddr = (uint64_t)&__kernel_ro_start; - vaddr < (uint64_t)&__kernel_ro_end; vaddr += 4096) - paging::map_kernel_page(vaddr - kernel_offset, vaddr, false, false); - - //kernel image rw - for (uint64_t vaddr = (uint64_t)&__kernel_rw_start; - vaddr < (uint64_t)&__kernel_rw_end; vaddr += 4096) - paging::map_kernel_page(vaddr - kernel_offset, vaddr, true, false); - - //framebuffer - uint64_t fb_vaddr = - paging::find_unmapped_vram_region((fb_end - fb_start) / 4096); - 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); - - //set up framebuffer and terminal: - //TODO: assumes framebuffer is 32-bpp rgb - - framebuffer::init_framebuffer(fb_start, fb_vaddr, - framebuffer->width, framebuffer->height, framebuffer->pitch); - - //switch to kernel p4 - - paging::map_kernel_stacks(); - load_gdt_and_idt(); - switch_to_kernel_p4(&with_kernel_p4); - -} - -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(); - - auto *initfs_bd = new storage::bd::memory(initfs, initfs_len); - auto *initfs_fs = new storage::fs::tarfs_instance(initfs_bd); - initfs_bd->mounted_as = initfs_fs; - - vfile::vfile initfs_root; - initfs_root.bd = initfs_bd; - initfs_root.dir_entry.type = storage::file_type::directory; - initfs_root.path.absolute = true; - - if (initfs_fs->get_root_node(initfs_root.dir_entry.node) != - storage::fs_result::success) - panic("failed to get root node of initfs."); - - vfile::set_root(initfs_root); - - input::init_input(); - - utility::string init_path_string("/bin/init.elf", 13); - 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); - -} 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 -#include - -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 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 process_a_threads_waiting_to_read; + utility::queue process_b_threads_waiting_to_read; + utility::queue a_to_b; + utility::queue b_to_a; + bool a_closed; + bool b_closed; + }; + + class socket_stream : public stream { + + private: + socket *sock; + bool are_we_b; + + utility::queue &our_threads_waiting_to_read; + utility::queue &their_threads_waiting_to_read; + utility::queue &them_to_us; + utility::queue &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 waiting_to_accept_connection; + utility::queue 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 threads; + utility::vector environment; + utility::id_allocator open_streams; + utility::id_allocator 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 *processes; + extern utility::queue *paused_threads; + extern utility::queue *threads_waiting_for_input; + extern thread *running_thread; + extern utility::list *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 *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 -#include -#include -#include - -namespace hilbert::kernel::terminal { - - extern uint8_t *termfont; - extern uint64_t termfont_len; - - void init_terminal(); - - extern int width; - extern int height; - - extern int cursor_x; - extern int cursor_y; - - extern framebuffer::color bg_color; - extern framebuffer::color fg_color; - - void put_char(char ch); - void put_string(const utility::string &str); - void put_string_sz(const char *str); - - void put_int_decimal(uint64_t n, bool with_commas = true); - - void put_int_hex(uint64_t n, int digits, bool with_dots = true); - -} 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 -#include -#include - -namespace hilbert::kernel::input { - - utility::queue *key_queue; - - void init_input() { - key_queue = new utility::queue(); - } - -} diff --git a/kernel/interrupts.asm b/kernel/interrupts.asm deleted file mode 100644 index c096ddb..0000000 --- a/kernel/interrupts.asm +++ /dev/null @@ -1,344 +0,0 @@ -bits 64 - -global load_gdt_and_idt - -section .rodata - -;0x28 picked to align with limine choice - -;0x18 - tss -;0x28 - kernel code -;0x30 - kernel data -;0x38 - user data -;0x40 - user code - -tss: - times 9 dd 0 - dq 0xffffffffffeff000 - times 15 dd 0 - -gdtr: - dw 0x47 - dq gdt - -idtr: - dw 4095 - dq idt - -section .bss - -idt: - resq 512 - -global exception_info -exception_info: -.rax: - resq 1 -.rbx: - resq 1 -.rcx: - resq 1 -.rdx: - resq 1 -.rdi: - resq 1 -.rsi: - resq 1 -.rbp: - resq 1 -.rsp: - resq 1 -.r8: - resq 1 -.r9: - resq 1 -.r10: - resq 1 -.r11: - resq 1 -.r12: - resq 1 -.r13: - resq 1 -.r14: - resq 1 -.r15: - resq 1 -.cr2: - resq 1 -.cr3: - resq 1 -.rip: - resq 1 -.rflags: - resq 1 -.error: - resq 1 -.has_error: - resb 1 -.exception_number: - resb 1 - -section .rodata - -has_error_code: - db 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0 - -exception_isrs: - dq exception_00, exception_01, exception_02, exception_03 - dq exception_04, exception_05, exception_06, exception_07 - dq exception_08, exception_09, exception_0a, exception_0b - dq exception_0c, exception_0d, exception_0e, exception_0f - -section .text - -extern print_exception - -exception_00: - mov byte [exception_info.exception_number], 0x00 - jmp exception_common -exception_01: - mov byte [exception_info.exception_number], 0x01 - jmp exception_common -exception_02: - mov byte [exception_info.exception_number], 0x02 - jmp exception_common -exception_03: - mov byte [exception_info.exception_number], 0x03 - jmp exception_common -exception_04: - mov byte [exception_info.exception_number], 0x04 - jmp exception_common -exception_05: - mov byte [exception_info.exception_number], 0x05 - jmp exception_common -exception_06: - mov byte [exception_info.exception_number], 0x06 - jmp exception_common -exception_07: - mov byte [exception_info.exception_number], 0x07 - jmp exception_common -exception_08: - mov byte [exception_info.exception_number], 0x08 - jmp exception_common -exception_09: - mov byte [exception_info.exception_number], 0x09 - jmp exception_common -exception_0a: - mov byte [exception_info.exception_number], 0x0a - jmp exception_common -exception_0b: - mov byte [exception_info.exception_number], 0x0b - jmp exception_common -exception_0c: - mov byte [exception_info.exception_number], 0x0c - jmp exception_common -exception_0d: - mov byte [exception_info.exception_number], 0x0d - jmp exception_common -exception_0e: - mov byte [exception_info.exception_number], 0x0e - jmp exception_common -exception_0f: - mov byte [exception_info.exception_number], 0x0f - jmp exception_common - -exception_common: - mov qword [exception_info.rax], rax - - movzx rax, byte [exception_info.exception_number] - mov al, byte [has_error_code + rax] - test al, al - jz .no_error_code - - mov byte [exception_info.has_error], 1 - pop rax - mov qword [exception_info.error], rax - jmp .post_error_code - -.no_error_code: - mov byte [exception_info.has_error], 0 - -.post_error_code: - mov qword [exception_info.rbx], rbx - mov qword [exception_info.rcx], rcx - mov qword [exception_info.rdx], rdx - mov qword [exception_info.rdi], rdi - mov qword [exception_info.rsi], rsi - mov qword [exception_info.rbp], rbp - mov qword [exception_info.r8], r8 - mov qword [exception_info.r9], r9 - mov qword [exception_info.r10], r10 - mov qword [exception_info.r11], r11 - mov qword [exception_info.r12], r12 - mov qword [exception_info.r13], r13 - mov qword [exception_info.r14], r14 - mov qword [exception_info.r15], r15 - - pop rax - mov qword [exception_info.rip], rax - pop rax - pop rax - mov qword [exception_info.rflags], rax - pop rax - mov qword [exception_info.rsp], rax - - mov rax, cr2 - mov qword [exception_info.cr2], rax - mov rax, cr3 - mov qword [exception_info.cr3], rax - - jmp print_exception - -set_isr: -;rdi - index -;sil - 1 if this is a trap, 0 if it is an interrupt -;rdx - 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 - - or sil, 0x8e - mov byte [rdi + 5], sil - mov word [rdi + 2], 0x28 - mov byte [rdi + 4], 1 - - ret - -section .data - -gdt: - dq 0 - dq 0 - dq 0 -.tss: - dq 0x0000e90000000067 - dq 0;tss is 2 qwords wide - dq 0x002f98000000ffff - dq 0x002f92000000ffff - dq 0x002ff2000000ffff - dq 0x002ff8000000ffff - -section .bss - -section .text - -write_keyboard_byte: - in al, 0x64 - test al, 0x02 - jnz write_keyboard_byte - mov al, dil - out 0x60, al - ret - -extern on_keyboard_interrupt - -keyboard_isr: - - push r11 - push r10 - push r9 - push r8 - push rsi - push rdi - push rdx - push rcx - push rax - - in al, 0x60 - mov dil, al - - call on_keyboard_interrupt - - mov al, 0x20 - out 0x20, al - - pop rax - pop rcx - pop rdx - pop rdi - pop rsi - pop r8 - pop r9 - pop r10 - pop r11 - - iretq - -load_gdt_and_idt: - - ;fill exception entries in idt - - mov rcx, 16 - -.loop: - - mov rdi, rcx - dec rdi - mov sil, 1 - mov rdx, qword [exception_isrs + rdi * 8] - call set_isr - - loop .loop - - ;reset pic and map irqs to 0x20 - 0x2f - - mov al, 0x11 - out 0x20, al - mov al, 0x20 - out 0x21, al - mov al, 0x04 - out 0x21, al - mov al, 0x01 - out 0x21, al - mov al, 0xfd ;mask all but irq 1 - out 0x21, al - - mov al, 0x11 - out 0xa0, al - mov al, 0x28 - out 0xa1, al - mov al, 0x02 - out 0xa1, al - mov al, 0x01 - out 0xa1, al - mov al, 0xff ;mask all - out 0xa1, al - - mov rdi, 0x21 - xor sil, sil - mov rdx, keyboard_isr - call set_isr - - ;set keyboard config - - mov al, 0x60 - out 0x64, al - mov dil, 0x01 - call write_keyboard_byte - - ;make tss entry in gdt - - mov rax, tss - - mov word [gdt.tss + 2], ax - shr rax, 16 - mov byte [gdt.tss + 4], al - mov byte [gdt.tss + 7], ah - shr rax, 16 - mov dword [gdt.tss + 8], eax - - ;load gdt, idt, tss - - lgdt [gdtr] - lidt [idtr] - mov ax, 0x18 - ltr ax - - ret diff --git a/kernel/interrupts.cpp b/kernel/interrupts.cpp deleted file mode 100644 index cd57c4f..0000000 --- a/kernel/interrupts.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include - -using namespace hilbert::kernel; - -struct [[gnu::packed]] exception_info_t { - - 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 cr2; - uint64_t cr3; - uint64_t rip; - uint64_t rflags; - - uint64_t error; - uint8_t has_error;//0 or 1 - uint8_t exception_number; - -}; - -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); - } - - 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); - - while (1) - asm ("hlt"); - -} - -static uint32_t current_flags = 0; - -#define SETBIT(field, bit, cond) \ - field = (cond) ? (field | (bit)) : (field & ~(bit)); - -static void got_key(uint32_t key) { - - input::key_queue->insert(current_flags | key); - - if (key == (input::BREAK | 0x77)) - current_flags ^= input::NUM_LOCK; - - else if (key == (input::BREAK | 0x58)) - current_flags ^= input::CAPS_LOCK; - - else if ((key & 0xff) == 0xa7) - SETBIT(current_flags, input::RIGHT_WIN, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x9f) - SETBIT(current_flags, input::LEFT_WIN, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x91) - SETBIT(current_flags, input::RIGHT_ALT, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x11) - SETBIT(current_flags, input::LEFT_ALT, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x94) - SETBIT(current_flags, input::RIGHT_CTRL, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x14) - SETBIT(current_flags, input::LEFT_CTRL, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x59) - SETBIT(current_flags, input::RIGHT_SHIFT, !(key & input::BREAK)) - - else if ((key & 0xff) == 0x12) - SETBIT(current_flags, input::LEFT_SHIFT, !(key & input::BREAK)) - -} - -static uint8_t key_so_far[8]; -uint8_t key_so_far_len = 0; - -extern "C" void on_keyboard_interrupt(uint8_t byte) { - - key_so_far[key_so_far_len++] = byte; - - if (key_so_far_len == 1) { - if (byte != 0xe0 && byte != 0xe1 && byte != 0xf0) { - got_key(byte); - key_so_far_len = 0; - } - } - - else if (key_so_far_len == 2) { - if (key_so_far[0] == 0xe0 && byte != 0xf0 && byte != 0x12) { - got_key(byte | 0x80); - key_so_far_len = 0; - } - else if (key_so_far[0] == 0xf0) { - got_key(input::BREAK | byte); - key_so_far_len = 0; - } - } - - else if (key_so_far_len == 3) { - if (key_so_far[0] == 0xe0 && key_so_far[1] == 0xf0 && byte != 0x7c) { - got_key(input::BREAK | byte | 0x80); - key_so_far_len = 0; - } - } - - else if (key_so_far_len == 4) { - if (key_so_far[0] == 0xe0 && key_so_far[1] == 0x12 && - key_so_far[2] == 0xe0 && byte == 0x7c) { - got_key(0xe0); - key_so_far_len = 0; - } - } - - else if (key_so_far_len == 6) { - if (key_so_far[0] == 0xe0 && key_so_far[1] == 0xf0 && - key_so_far[2] == 0x7c && key_so_far[3] == 0xe0 && - key_so_far[4] == 0xf0 && byte == 0x12) { - got_key(input::BREAK | 0xe0); - key_so_far_len = 0; - } - } - - else if (key_so_far_len == 8) { - if (key_so_far[0] == 0xe1 && key_so_far[1] == 0x14 && - key_so_far[2] == 0x77 && key_so_far[3] == 0xe1 && - key_so_far[2] == 0xf0 && key_so_far[3] == 0x14 && - key_so_far[4] == 0xf0 && byte == 0x77) { - got_key(0xe1); - got_key(input::BREAK | 0xe1); - } - key_so_far_len = 0; - } - -} 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/paging.asm b/kernel/paging.asm deleted file mode 100644 index f1047a9..0000000 --- a/kernel/paging.asm +++ /dev/null @@ -1,16 +0,0 @@ -bits 64 - -;see also ../documentation/memory.txt - -global switch_to_kernel_p4 - -;from paging.cpp: -extern __kernel_p4_paddr - -section .text - -switch_to_kernel_p4: - mov rax, qword [__kernel_p4_paddr] - mov cr3, rax - mov rsp, 0xfffffffffffff000 - jmp rdi diff --git a/kernel/paging.cpp b/kernel/paging.cpp deleted file mode 100644 index d8869fc..0000000 --- a/kernel/paging.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include - -//see also ../documentation/memory.txt - -extern "C" { - uint64_t __kernel_p4_paddr; -} - -namespace hilbert::kernel::paging { - - static constexpr uint64_t kernel_vram_start = 0xffffffffc0000000; - static constexpr uint64_t kernel_vram_end = 0xffffffffffe00000; - static constexpr uint64_t kernel_vram_pages = - (kernel_vram_end - kernel_vram_start) / 4096; - static constexpr uint64_t syscall_stack_bottom = 0xfffffffffff01000; - static constexpr uint64_t syscall_stack_top = 0xfffffffffffff000; - static constexpr uint64_t interrupt_stack_bottom = 0xffffffffffe01000; - static constexpr uint64_t interrupt_stack_top = 0xffffffffffeff000; - - static constexpr uint64_t pram_pages = 1 << 23; - static uint64_t pram_usage_bitmap[pram_pages / 64]; - - void mark_all_pram_used() { - utility::mark_bitmap_region_one(pram_usage_bitmap, 0, pram_pages); - } - - void mark_pram_region_free(uint64_t start_addr, uint64_t end_addr) { - utility::mark_bitmap_region_zero( - pram_usage_bitmap, start_addr / 4096, - utility::min(end_addr / 4096, pram_pages)); - } - - [[gnu::aligned(4096)]] uint64_t kernel_p4[512]; - [[gnu::aligned(4096)]] uint64_t kernel_p3[512]; - [[gnu::aligned(4096)]] uint64_t kernel_p2[512]; - [[gnu::aligned(4096)]] uint64_t kernel_p1s[512 * 512]; - - uint64_t kernel_p4e; - - uint64_t encode_pte(uint64_t addr, bool user, bool write, bool execute) { - return (addr & 0x0000ffffffffffff) | (execute ? 0 : (1ULL << 63)) - | (user << 2) | (write << 1) | 1; - } - - void init_kernel_page_tables(uint64_t kernel_offset) { - __kernel_p4_paddr = (uint64_t)kernel_p4 - kernel_offset; - for (int i = 0; i < 511; ++i) - kernel_p4[i] = 0; - kernel_p4e = encode_pte( - (uint64_t)kernel_p3 - kernel_offset, false, true, true); - kernel_p4[511] = kernel_p4e; - for (int i = 0; i < 511; ++i) - kernel_p3[i] = 0; - kernel_p3[511] = encode_pte( - (uint64_t)kernel_p2 - kernel_offset, false, true, true); - for (int i = 0; i < 512; ++i) - kernel_p2[i] = encode_pte( - (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true); - for (int i = 0; i < 512 * 512; ++i) - kernel_p1s[i] = 0; - } - - void map_kernel_page( - uint64_t paddr, uint64_t vaddr, bool write, bool execute) { - uint64_t i = (vaddr - kernel_vram_start) / 4096; - kernel_p1s[i] = encode_pte(paddr, false, write, execute); - } - - void unmap_kernel_page(uint64_t vaddr) { - uint64_t i = (vaddr - kernel_vram_start) / 4096; - kernel_p1s[i] = 0; - asm volatile ( - "mov %%cr3, %%rax\nmov %%rax, %%cr3" ::: "%rax" - ); - } - - uint64_t take_pram_page() { - for (uint64_t i = 0; i < pram_pages / 64; ++i) - if (~pram_usage_bitmap[i] != 0) - for (int j = 0; j < 64; ++j) - if (~pram_usage_bitmap[i] & (1ULL << j)) { - pram_usage_bitmap[i] |= (1ULL << j); - return 4096 * (i * 64 + j); - } - //TODO: handle error - return 0; - } - - void map_kernel_stacks() { - for (uint64_t vaddr = syscall_stack_bottom; - vaddr < syscall_stack_top; vaddr += 4096) - map_kernel_page(take_pram_page(), vaddr, true, false); - for (uint64_t vaddr = interrupt_stack_bottom; - vaddr < interrupt_stack_top; vaddr += 4096) - map_kernel_page(take_pram_page(), vaddr, true, false); - } - - uint64_t find_unmapped_vram_region(uint64_t page_count) { - uint64_t start = 0; - uint64_t len = 0; - for (uint64_t i = 0; i < kernel_vram_pages; ++i) - if (kernel_p1s[i] == 0) { - ++len; - if (len == page_count) - return start * 4096 + kernel_vram_start; - } - else { - start = i + 1; - len = 0; - } - //TODO: handle error - return 0; - } - - void *map_new_kernel_pages(uint64_t count) { - uint64_t vaddr = find_unmapped_vram_region(count); - for (uint64_t i = 0; i < count; ++i) - map_kernel_page(take_pram_page(), vaddr + i * 4096, true, false); - return (void *)vaddr; - } - - void map_new_kernel_page(uint64_t &vaddr_out, uint64_t &paddr_out) { - vaddr_out = find_unmapped_vram_region(1); - paddr_out = take_pram_page(); - map_kernel_page(paddr_out, vaddr_out, true, false); - } - - uint64_t get_used_vram_page_count() { - uint64_t count = 0; - for (uint64_t i = 0; i < kernel_vram_pages; ++i) - if (kernel_p1s[i] != 0) - ++count; - return count; - } - - uint64_t get_free_pram_page_count() { - uint64_t used_count = 0; - for (uint64_t i = 0; i < pram_pages / 64; ++i) - for (uint64_t j = 0; j < 64; ++j) - used_count += (pram_usage_bitmap[i] >> j) & 1; - return pram_pages - used_count; - } - -} 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 -#include - -namespace hilbert::kernel { - [[noreturn]] void panic(const char *string_sz) { - terminal::put_string_sz(string_sz); - while (1) - asm ("hlt"); - } -} diff --git a/kernel/source/allocator.cpp b/kernel/source/allocator.cpp new file mode 100644 index 0000000..324f992 --- /dev/null +++ b/kernel/source/allocator.cpp @@ -0,0 +1,160 @@ +#include +#include + +namespace hilbert::kernel::allocator { + + struct free_entry { + uint64_t start; + uint64_t len;//0 for unused + }; + + struct free_page { + free_page *next; + free_entry entries[255]; + }; + + free_page *first_page; + + static_assert(sizeof(free_page) == 4088); + + free_entry *get_entry(uint64_t start, uint64_t len) { + for (free_page *fp = first_page; fp; fp = fp->next) + for (int i = 0; i < 255; ++i) + if (fp->entries[i].start == start && fp->entries[i].len == len) + return fp->entries + i; + return 0; + } + + void add_entry(uint64_t start, uint64_t len) { + for (free_page *fp = first_page; fp; fp = fp->next) + for (int i = 0; i < 255; ++i) + if (fp->entries[i].len == 0) { + fp->entries[i].start = start; + fp->entries[i].len = len; + return; + } + free_page *new_page = (free_page *)paging::map_new_kernel_pages(1); + new_page->next = first_page; + first_page = new_page; + for (int i = 2; i < 255; ++i) + new_page->entries[i].len = 0; + new_page->entries[0].start = (uint64_t)new_page + 4088; + new_page->entries[0].len = 8; + new_page->entries[1].start = start; + new_page->entries[1].len = len; + } + + //len is power of 2, start is len-aligned + void free_block(uint64_t start, uint64_t len) { + free_entry *buddy = get_entry(start ^ len, len); + if (buddy) { + buddy->start = start & ~len; + buddy->len = len * 2; + } + else + add_entry(start, len); + } + + void free_region(uint64_t start, uint64_t len) { + uint64_t block_size = 1; + while (block_size <= len) { + if (start & block_size) { + free_block(start, block_size); + start += block_size; + len -= block_size; + } + block_size *= 2; + } + while (len) { + block_size /= 2; + if (block_size <= len) { + free_block(start, block_size); + start += block_size; + len -= block_size; + } + } + //testing + if (len != 0) + while (1) + ; + } + + uint64_t take_region(uint64_t len) { + + uint64_t min_size = 1; + while (min_size < len) + min_size *= 2; + + free_entry *entry = 0; + + for (free_page *fp = first_page; fp; fp = fp->next) + for (int i = 0; i < 255; ++i) + if (fp->entries[i].len >= min_size) { + if (fp->entries[i].len == min_size) { + entry = fp->entries + i; + goto loop_done; + } + if (entry == 0 || fp->entries[i].len < entry->len) + entry = fp->entries + i; + } + + loop_done: + if (entry != 0) { + uint64_t start = entry->start; + uint64_t block_len = entry->len; + entry->len = 0; + if (block_len != len) + free_region(start + len, block_len - len); + return start; + } + + uint64_t pages = (len - 1) / 4096 + 1; + uint64_t start = (uint64_t)paging::map_new_kernel_pages(pages); + if (pages * 4096 != len) + free_region(start + len, pages * 4096 - len); + return start; + + } + +} + +using namespace hilbert::kernel::allocator; + +void *_new(size_t len) { + if (len == 0) + return 0; + uint64_t vaddr = take_region(len + sizeof(size_t)); + *(size_t *)vaddr = len; + return (void *)(vaddr + sizeof(size_t)); +} + +void _delete(void *ptr) { + if ((uint64_t)ptr == 0) + return; + uint64_t vaddr = (uint64_t)ptr - sizeof(size_t); + free_region(vaddr, *(size_t *)vaddr + sizeof(size_t)); +} + +void *operator new(size_t len) { + return _new(len); +} + +void operator delete(void *ptr, size_t) { + return _delete(ptr); +} + +void operator delete(void *ptr) { + return _delete(ptr); +} + +void *operator new[](size_t len) { + return _new(len); +} + +void operator delete[](void *ptr, size_t) { + return _delete(ptr); +} + +void operator delete[](void *ptr) { + return _delete(ptr); +} 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 +#include +#include + +//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 *processes; + utility::queue *paused_threads; + utility::queue *threads_waiting_for_input; + thread *running_thread; + utility::list *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_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(); + paused_threads = new utility::queue(); + threads_waiting_for_input = new utility::queue(); + all_socket_listeners = new utility::list(); + 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/source/entry.cpp b/kernel/source/entry.cpp new file mode 100644 index 0000000..820b107 --- /dev/null +++ b/kernel/source/entry.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace hilbert::kernel; + +LIMINE_BASE_REVISION(1) + +static volatile limine_memmap_request memmap_request { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_kernel_address_request kernel_address_request { + .id = LIMINE_KERNEL_ADDRESS_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_framebuffer_request framebuffer_request { + .id = LIMINE_FRAMEBUFFER_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_hhdm_request hhdm_request { + .id = LIMINE_HHDM_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_module_request module_request = { + .id = LIMINE_MODULE_REQUEST, + .revision = 2, + .response = 0, + .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) + if (!cmdline[j]) { + + //module start is guaranteed to be page-aligned, end is not. + uint64_t start_paddr = + (uint64_t)file->address - hhdm_request.response->offset; + uint64_t end_paddr = + ((start_paddr + file->size - 1) / 4096 + 1) * 4096; + + uint64_t start_vaddr = + paging::find_unmapped_vram_region((end_paddr - start_paddr) / 4096); + for (uint64_t i = 0; i < end_paddr - start_paddr; i += 4096) + paging::map_kernel_page( + start_paddr + i, start_vaddr + i, true, false); + + vaddr_out = (void *)start_vaddr; + len_out = file->size; + + return true; + } + } + return false; +} + +//defined in linker script, page-aligned: +extern uint8_t __kernel_start; +extern uint8_t __kernel_end; +extern uint8_t __kernel_rx_start; +extern uint8_t __kernel_rx_end; +extern uint8_t __kernel_ro_start; +extern uint8_t __kernel_ro_end; +extern uint8_t __kernel_rw_start; +extern uint8_t __kernel_rw_end; + +uint8_t *initfs; +uint64_t initfs_len; + +[[noreturn]] static void with_kernel_p4(); + +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 + // fulfilled and display some error message if not + + //set up the physical memory usage bitmap: + + paging::mark_all_pram_used(); + auto memmap = memmap_request.response; + for (uint64_t i = 0; i < memmap->entry_count; ++i) { + //we don't allocate any physical pages until after we are done using limine + //structures (specifically at the call to paging::map_kernel_stacks), so + //we consider bootloader reclaimable to be free. usable and bootloader + //reclaimable are guaranteed by limine spec to be page-aligned. + auto entry = memmap->entries[i]; + if (entry->type == LIMINE_MEMMAP_USABLE || + entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) + paging::mark_pram_region_free(entry->base, entry->base + entry->length); + } + + //set up page mappings: + + auto kernel_address = kernel_address_request.response; + uint64_t kernel_offset = kernel_address->virtual_base + - kernel_address->physical_base; + + uint64_t hhdm = hhdm_request.response->offset; + + //framebuffer might not be page-aligned + auto framebuffer = framebuffer_request.response->framebuffers[0]; + uint64_t fb_start = ((uint64_t)framebuffer->address / 4096) * 4096 - hhdm; + uint64_t fb_end = (uint64_t)framebuffer->address + + framebuffer->pitch * framebuffer->height - hhdm; + fb_end = ((fb_end - 1) / 4096 + 1) * 4096; + + paging::init_kernel_page_tables(kernel_offset); + + //kernel image rx + for (uint64_t vaddr = (uint64_t)&__kernel_rx_start; + vaddr < (uint64_t)&__kernel_rx_end; vaddr += 4096) + paging::map_kernel_page(vaddr - kernel_offset, vaddr, false, true); + + //kernel image ro + for (uint64_t vaddr = (uint64_t)&__kernel_ro_start; + vaddr < (uint64_t)&__kernel_ro_end; vaddr += 4096) + paging::map_kernel_page(vaddr - kernel_offset, vaddr, false, false); + + //kernel image rw + for (uint64_t vaddr = (uint64_t)&__kernel_rw_start; + vaddr < (uint64_t)&__kernel_rw_end; vaddr += 4096) + paging::map_kernel_page(vaddr - kernel_offset, vaddr, true, false); + + //framebuffer + uint64_t fb_vaddr = + paging::find_unmapped_vram_region((fb_end - fb_start) / 4096); + for (uint64_t i = 0; i < fb_end - fb_start; i += 4096) + paging::map_kernel_page(fb_start + i, fb_vaddr + i, true, false); + + have_initfs = + try_map_module_by_cmdline("initfs", (void *&)initfs, initfs_len); + + //set up framebuffer and terminal: + //TODO: assumes framebuffer is 32-bpp rgb + + framebuffer::init_framebuffer(fb_start, fb_vaddr, + framebuffer->width, framebuffer->height, framebuffer->pitch); + + //switch to kernel p4 + + paging::map_kernel_stacks(); + load_gdt_and_idt(); + switch_to_kernel_p4(&with_kernel_p4); + +} + +[[noreturn]] static void with_kernel_p4() { + + 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); + initfs_bd->mounted_as = initfs_fs; + + vfile::vfile initfs_root; + initfs_root.bd = initfs_bd; + initfs_root.dir_entry.type = storage::file_type::directory; + initfs_root.path.absolute = true; + + if (initfs_fs->get_root_node(initfs_root.dir_entry.node) != + storage::fs_result::success) + panic(0x48a6ed); + + vfile::set_root(initfs_root); + + 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(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 +#include + +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 +#include +#include +#include + +namespace hilbert::kernel::input { + + utility::queue *key_queue; + + void init_input() { + key_queue = new utility::queue(); + } + + 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/source/interrupts.asm b/kernel/source/interrupts.asm new file mode 100644 index 0000000..babc020 --- /dev/null +++ b/kernel/source/interrupts.asm @@ -0,0 +1,340 @@ +bits 64 + +global load_gdt_and_idt + +section .rodata + +;0x28 picked to align with limine choice + +;0x18 - tss +;0x28 - kernel code +;0x30 - kernel data +;0x38 - user data +;0x40 - user code + +tss: + times 9 dd 0 + dq 0xffffffffffeff000 + times 15 dd 0 + +gdtr: + dw 0x47 + dq gdt + +idtr: + dw 4095 + dq idt + +section .bss + +idt: + resq 512 + +global exception_info +exception_info: +.rax: + resq 1 +.rbx: + resq 1 +.rcx: + resq 1 +.rdx: + resq 1 +.rdi: + resq 1 +.rsi: + resq 1 +.rbp: + resq 1 +.rsp: + resq 1 +.r8: + resq 1 +.r9: + resq 1 +.r10: + resq 1 +.r11: + resq 1 +.r12: + resq 1 +.r13: + resq 1 +.r14: + resq 1 +.r15: + resq 1 +.cr2: + resq 1 +.cr3: + resq 1 +.rip: + resq 1 +.rflags: + resq 1 +.error: + resq 1 +.has_error: + resb 1 +.exception_number: + resb 1 + +section .rodata + +has_error_code: + db 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0 + +exception_isrs: + dq exception_00, exception_01, exception_02, exception_03 + dq exception_04, exception_05, exception_06, exception_07 + dq exception_08, exception_09, exception_0a, exception_0b + dq exception_0c, exception_0d, exception_0e, exception_0f + +section .text + +extern print_exception + +exception_00: + mov byte [exception_info.exception_number], 0x00 + jmp exception_common +exception_01: + mov byte [exception_info.exception_number], 0x01 + jmp exception_common +exception_02: + mov byte [exception_info.exception_number], 0x02 + jmp exception_common +exception_03: + mov byte [exception_info.exception_number], 0x03 + jmp exception_common +exception_04: + mov byte [exception_info.exception_number], 0x04 + jmp exception_common +exception_05: + mov byte [exception_info.exception_number], 0x05 + jmp exception_common +exception_06: + mov byte [exception_info.exception_number], 0x06 + jmp exception_common +exception_07: + mov byte [exception_info.exception_number], 0x07 + jmp exception_common +exception_08: + mov byte [exception_info.exception_number], 0x08 + jmp exception_common +exception_09: + mov byte [exception_info.exception_number], 0x09 + jmp exception_common +exception_0a: + mov byte [exception_info.exception_number], 0x0a + jmp exception_common +exception_0b: + mov byte [exception_info.exception_number], 0x0b + jmp exception_common +exception_0c: + mov byte [exception_info.exception_number], 0x0c + jmp exception_common +exception_0d: + mov byte [exception_info.exception_number], 0x0d + jmp exception_common +exception_0e: + mov byte [exception_info.exception_number], 0x0e + jmp exception_common +exception_0f: + mov byte [exception_info.exception_number], 0x0f + jmp exception_common + +exception_common: + mov qword [exception_info.rax], rax + + movzx rax, byte [exception_info.exception_number] + mov al, byte [has_error_code + rax] + test al, al + jz .no_error_code + + mov byte [exception_info.has_error], 1 + pop rax + mov qword [exception_info.error], rax + jmp .post_error_code + +.no_error_code: + mov byte [exception_info.has_error], 0 + +.post_error_code: + mov qword [exception_info.rbx], rbx + mov qword [exception_info.rcx], rcx + mov qword [exception_info.rdx], rdx + mov qword [exception_info.rdi], rdi + mov qword [exception_info.rsi], rsi + mov qword [exception_info.rbp], rbp + mov qword [exception_info.r8], r8 + mov qword [exception_info.r9], r9 + mov qword [exception_info.r10], r10 + mov qword [exception_info.r11], r11 + mov qword [exception_info.r12], r12 + mov qword [exception_info.r13], r13 + mov qword [exception_info.r14], r14 + mov qword [exception_info.r15], r15 + + pop rax + mov qword [exception_info.rip], rax + pop rax + pop rax + mov qword [exception_info.rflags], rax + pop rax + mov qword [exception_info.rsp], rax + + mov rax, cr2 + mov qword [exception_info.cr2], rax + mov rax, cr3 + mov qword [exception_info.cr3], rax + + jmp print_exception + +set_isr: +;rdi - index +;rsi - isr pointer + + shl rdi, 4 + add rdi, idt + + mov word [rdi], si + shr rsi, 16 + mov word [rdi + 6], si + shr rsi, 16 + mov dword [rdi + 8], esi + + mov byte [rdi + 5], 0x8e + mov word [rdi + 2], 0x28 + mov byte [rdi + 4], 1 + + ret + +section .data + +gdt: + dq 0 + dq 0 + dq 0 +.tss: + dq 0x0000e90000000067 + dq 0;tss is 2 qwords wide + dq 0x002f98000000ffff + dq 0x002f92000000ffff + dq 0x002ff2000000ffff + dq 0x002ff8000000ffff + +section .bss + +section .text + +write_keyboard_byte: + in al, 0x64 + test al, 0x02 + jnz write_keyboard_byte + mov al, dil + out 0x60, al + ret + +extern on_keyboard_interrupt + +keyboard_isr: + + push r11 + push r10 + push r9 + push r8 + push rsi + push rdi + push rdx + push rcx + push rax + + in al, 0x60 + mov dil, al + + call on_keyboard_interrupt + + mov al, 0x20 + out 0x20, al + + pop rax + pop rcx + pop rdx + pop rdi + pop rsi + pop r8 + pop r9 + pop r10 + pop r11 + + iretq + +load_gdt_and_idt: + + ;fill exception entries in idt + + mov rcx, 16 + +.loop: + + mov rdi, rcx + dec rdi + mov rsi, qword [exception_isrs + rdi * 8] + call set_isr + + loop .loop + + ;reset pic and map irqs to 0x20 - 0x2f + + mov al, 0x11 + out 0x20, al + mov al, 0x20 + out 0x21, al + mov al, 0x04 + out 0x21, al + mov al, 0x01 + out 0x21, al + mov al, 0xfd ;mask all but irq 1 + out 0x21, al + + mov al, 0x11 + out 0xa0, al + mov al, 0x28 + out 0xa1, al + mov al, 0x02 + out 0xa1, al + mov al, 0x01 + out 0xa1, al + mov al, 0xff ;mask all + out 0xa1, al + + mov rdi, 0x21 + mov rsi, keyboard_isr + call set_isr + + ;set keyboard config + + mov al, 0x60 + out 0x64, al + mov dil, 0x01 + call write_keyboard_byte + + ;make tss entry in gdt + + mov rax, tss + + mov word [gdt.tss + 2], ax + shr rax, 16 + mov byte [gdt.tss + 4], al + mov byte [gdt.tss + 7], ah + shr rax, 16 + mov dword [gdt.tss + 8], eax + + ;load gdt, idt, tss + + lgdt [gdtr] + lidt [idtr] + mov ax, 0x18 + ltr ax + + ret diff --git a/kernel/source/interrupts.cpp b/kernel/source/interrupts.cpp new file mode 100644 index 0000000..6e22121 --- /dev/null +++ b/kernel/source/interrupts.cpp @@ -0,0 +1,152 @@ +#include +#include + +using namespace hilbert::kernel; + +struct [[gnu::packed]] exception_info_t { + + 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 cr2; + uint64_t cr3; + uint64_t rip; + uint64_t rflags; + + uint64_t error; + uint8_t has_error;//0 or 1 + uint8_t exception_number; + +}; + +extern exception_info_t exception_info; + +extern "C" [[noreturn]] void print_exception() { + + //so exception_info's type is known by gdb + exception_info_t the_exception_info = exception_info; + (void)the_exception_info; + + //TODO: log exception, and recover if possible. + + panic(0xba40bb); + +} + +static uint32_t current_flags = 0; + +#define SETBIT(field, bit, cond) \ + field = (cond) ? (field | (bit)) : (field & ~(bit)); + +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; + + else if (key == (input::BREAK | 0x58)) + current_flags ^= input::CAPS_LOCK; + + else if ((key & 0xff) == 0xa7) + SETBIT(current_flags, input::RIGHT_WIN, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x9f) + SETBIT(current_flags, input::LEFT_WIN, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x91) + SETBIT(current_flags, input::RIGHT_ALT, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x11) + SETBIT(current_flags, input::LEFT_ALT, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x94) + SETBIT(current_flags, input::RIGHT_CTRL, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x14) + SETBIT(current_flags, input::LEFT_CTRL, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x59) + SETBIT(current_flags, input::RIGHT_SHIFT, !(key & input::BREAK)) + + else if ((key & 0xff) == 0x12) + SETBIT(current_flags, input::LEFT_SHIFT, !(key & input::BREAK)) + +} + +static uint8_t key_so_far[8]; +uint8_t key_so_far_len = 0; + +extern "C" void on_keyboard_interrupt(uint8_t byte) { + + key_so_far[key_so_far_len++] = byte; + + if (key_so_far_len == 1) { + if (byte != 0xe0 && byte != 0xe1 && byte != 0xf0) { + got_key(byte); + key_so_far_len = 0; + } + } + + else if (key_so_far_len == 2) { + if (key_so_far[0] == 0xe0 && byte != 0xf0 && byte != 0x12) { + got_key(byte | 0x80); + key_so_far_len = 0; + } + else if (key_so_far[0] == 0xf0) { + got_key(input::BREAK | byte); + key_so_far_len = 0; + } + } + + else if (key_so_far_len == 3) { + if (key_so_far[0] == 0xe0 && key_so_far[1] == 0xf0 && byte != 0x7c) { + got_key(input::BREAK | byte | 0x80); + key_so_far_len = 0; + } + } + + else if (key_so_far_len == 4) { + if (key_so_far[0] == 0xe0 && key_so_far[1] == 0x12 && + key_so_far[2] == 0xe0 && byte == 0x7c) { + got_key(0xe0); + key_so_far_len = 0; + } + } + + else if (key_so_far_len == 6) { + if (key_so_far[0] == 0xe0 && key_so_far[1] == 0xf0 && + key_so_far[2] == 0x7c && key_so_far[3] == 0xe0 && + key_so_far[4] == 0xf0 && byte == 0x12) { + got_key(input::BREAK | 0xe0); + key_so_far_len = 0; + } + } + + else if (key_so_far_len == 8) { + if (key_so_far[0] == 0xe1 && key_so_far[1] == 0x14 && + key_so_far[2] == 0x77 && key_so_far[3] == 0xe1 && + key_so_far[2] == 0xf0 && key_so_far[3] == 0x14 && + key_so_far[4] == 0xf0 && byte == 0x77) { + got_key(0xe1); + got_key(input::BREAK | 0xe1); + } + key_so_far_len = 0; + } + +} diff --git a/kernel/source/paging.asm b/kernel/source/paging.asm new file mode 100644 index 0000000..f1047a9 --- /dev/null +++ b/kernel/source/paging.asm @@ -0,0 +1,16 @@ +bits 64 + +;see also ../documentation/memory.txt + +global switch_to_kernel_p4 + +;from paging.cpp: +extern __kernel_p4_paddr + +section .text + +switch_to_kernel_p4: + mov rax, qword [__kernel_p4_paddr] + mov cr3, rax + mov rsp, 0xfffffffffffff000 + jmp rdi diff --git a/kernel/source/paging.cpp b/kernel/source/paging.cpp new file mode 100644 index 0000000..d8869fc --- /dev/null +++ b/kernel/source/paging.cpp @@ -0,0 +1,145 @@ +#include +#include + +//see also ../documentation/memory.txt + +extern "C" { + uint64_t __kernel_p4_paddr; +} + +namespace hilbert::kernel::paging { + + static constexpr uint64_t kernel_vram_start = 0xffffffffc0000000; + static constexpr uint64_t kernel_vram_end = 0xffffffffffe00000; + static constexpr uint64_t kernel_vram_pages = + (kernel_vram_end - kernel_vram_start) / 4096; + static constexpr uint64_t syscall_stack_bottom = 0xfffffffffff01000; + static constexpr uint64_t syscall_stack_top = 0xfffffffffffff000; + static constexpr uint64_t interrupt_stack_bottom = 0xffffffffffe01000; + static constexpr uint64_t interrupt_stack_top = 0xffffffffffeff000; + + static constexpr uint64_t pram_pages = 1 << 23; + static uint64_t pram_usage_bitmap[pram_pages / 64]; + + void mark_all_pram_used() { + utility::mark_bitmap_region_one(pram_usage_bitmap, 0, pram_pages); + } + + void mark_pram_region_free(uint64_t start_addr, uint64_t end_addr) { + utility::mark_bitmap_region_zero( + pram_usage_bitmap, start_addr / 4096, + utility::min(end_addr / 4096, pram_pages)); + } + + [[gnu::aligned(4096)]] uint64_t kernel_p4[512]; + [[gnu::aligned(4096)]] uint64_t kernel_p3[512]; + [[gnu::aligned(4096)]] uint64_t kernel_p2[512]; + [[gnu::aligned(4096)]] uint64_t kernel_p1s[512 * 512]; + + uint64_t kernel_p4e; + + uint64_t encode_pte(uint64_t addr, bool user, bool write, bool execute) { + return (addr & 0x0000ffffffffffff) | (execute ? 0 : (1ULL << 63)) + | (user << 2) | (write << 1) | 1; + } + + void init_kernel_page_tables(uint64_t kernel_offset) { + __kernel_p4_paddr = (uint64_t)kernel_p4 - kernel_offset; + for (int i = 0; i < 511; ++i) + kernel_p4[i] = 0; + kernel_p4e = encode_pte( + (uint64_t)kernel_p3 - kernel_offset, false, true, true); + kernel_p4[511] = kernel_p4e; + for (int i = 0; i < 511; ++i) + kernel_p3[i] = 0; + kernel_p3[511] = encode_pte( + (uint64_t)kernel_p2 - kernel_offset, false, true, true); + for (int i = 0; i < 512; ++i) + kernel_p2[i] = encode_pte( + (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true); + for (int i = 0; i < 512 * 512; ++i) + kernel_p1s[i] = 0; + } + + void map_kernel_page( + uint64_t paddr, uint64_t vaddr, bool write, bool execute) { + uint64_t i = (vaddr - kernel_vram_start) / 4096; + kernel_p1s[i] = encode_pte(paddr, false, write, execute); + } + + void unmap_kernel_page(uint64_t vaddr) { + uint64_t i = (vaddr - kernel_vram_start) / 4096; + kernel_p1s[i] = 0; + asm volatile ( + "mov %%cr3, %%rax\nmov %%rax, %%cr3" ::: "%rax" + ); + } + + uint64_t take_pram_page() { + for (uint64_t i = 0; i < pram_pages / 64; ++i) + if (~pram_usage_bitmap[i] != 0) + for (int j = 0; j < 64; ++j) + if (~pram_usage_bitmap[i] & (1ULL << j)) { + pram_usage_bitmap[i] |= (1ULL << j); + return 4096 * (i * 64 + j); + } + //TODO: handle error + return 0; + } + + void map_kernel_stacks() { + for (uint64_t vaddr = syscall_stack_bottom; + vaddr < syscall_stack_top; vaddr += 4096) + map_kernel_page(take_pram_page(), vaddr, true, false); + for (uint64_t vaddr = interrupt_stack_bottom; + vaddr < interrupt_stack_top; vaddr += 4096) + map_kernel_page(take_pram_page(), vaddr, true, false); + } + + uint64_t find_unmapped_vram_region(uint64_t page_count) { + uint64_t start = 0; + uint64_t len = 0; + for (uint64_t i = 0; i < kernel_vram_pages; ++i) + if (kernel_p1s[i] == 0) { + ++len; + if (len == page_count) + return start * 4096 + kernel_vram_start; + } + else { + start = i + 1; + len = 0; + } + //TODO: handle error + return 0; + } + + void *map_new_kernel_pages(uint64_t count) { + uint64_t vaddr = find_unmapped_vram_region(count); + for (uint64_t i = 0; i < count; ++i) + map_kernel_page(take_pram_page(), vaddr + i * 4096, true, false); + return (void *)vaddr; + } + + void map_new_kernel_page(uint64_t &vaddr_out, uint64_t &paddr_out) { + vaddr_out = find_unmapped_vram_region(1); + paddr_out = take_pram_page(); + map_kernel_page(paddr_out, vaddr_out, true, false); + } + + uint64_t get_used_vram_page_count() { + uint64_t count = 0; + for (uint64_t i = 0; i < kernel_vram_pages; ++i) + if (kernel_p1s[i] != 0) + ++count; + return count; + } + + uint64_t get_free_pram_page_count() { + uint64_t used_count = 0; + for (uint64_t i = 0; i < pram_pages / 64; ++i) + for (uint64_t j = 0; j < 64; ++j) + used_count += (pram_usage_bitmap[i] >> j) & 1; + return pram_pages - used_count; + } + +} 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 +#include + +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/source/storage.cpp b/kernel/source/storage.cpp new file mode 100644 index 0000000..b6b1a04 --- /dev/null +++ b/kernel/source/storage.cpp @@ -0,0 +1,67 @@ +#include + +namespace hilbert::kernel::storage { + + bd_result block_device::load_cache_block(uint64_t i) { + + if (block_cache_i == i) + return bd_result::success; + + bd_result result = read_blocks_no_cache(i, 1, block_cache); + + if (result != bd_result::success) { + block_cache_i = block_count; + return result; + } + + block_cache_i = i; + return bd_result::success; + + } + + bd_result block_device::read_bytes( + uint64_t start, uint64_t count, void *into + ) { + + if (start + count > block_size * block_count) + return bd_result::out_of_bounds; + + uint8_t *into_u8 = (uint8_t *)into; + + if (start % block_size != 0) { + uint64_t prefix_len = block_size - start % block_size; + bd_result result = load_cache_block(start / block_size); + if (result != bd_result::success) + return result; + for (uint64_t i = 0; i < prefix_len; ++i) + into_u8[i] = block_cache[start % block_size + i]; + into_u8 += prefix_len; + start += prefix_len; + count -= prefix_len; + } + + uint64_t postfix_start = ((start + count) / block_size) * block_size; + + if (postfix_start != start) { + bd_result result = read_blocks_no_cache( + start / block_size, (postfix_start - start) / block_size, into_u8); + if (result != bd_result::success) + return result; + count -= postfix_start - start; + into_u8 += postfix_start - start; + start = postfix_start; + } + + if (count != 0) { + bd_result result = load_cache_block(start / block_size); + if (result != bd_result::success) + return result; + for (uint64_t i = 0; i < count; ++i) + into_u8[i] = block_cache[i]; + } + + return bd_result::success; + + } + +} diff --git a/kernel/source/storage/bd/memory.cpp b/kernel/source/storage/bd/memory.cpp new file mode 100644 index 0000000..d6a6719 --- /dev/null +++ b/kernel/source/storage/bd/memory.cpp @@ -0,0 +1,21 @@ +#include + +namespace hilbert::kernel::storage::bd { + + memory::memory(void *buffer, uint64_t buffer_len) + : buffer((uint8_t *)buffer) + { + block_size = 1; + block_count = buffer_len; + //block cache will never be used, since the block size is 1. + } + + bd_result memory::read_blocks_no_cache( + uint64_t start, uint64_t count, void *into + ) { + for (uint64_t i = 0; i < count; ++i) + ((uint8_t *)into)[i] = buffer[start + i]; + return bd_result::success; + } + +} diff --git a/kernel/source/storage/fs/tarfs.cpp b/kernel/source/storage/fs/tarfs.cpp new file mode 100644 index 0000000..5986f62 --- /dev/null +++ b/kernel/source/storage/fs/tarfs.cpp @@ -0,0 +1,238 @@ +#include + +//in tarfs_instance, node_id_t and directory_iter_t refer to the number +//of bytes into the block device that the info sector is located. + +namespace hilbert::kernel::storage::fs { + + #define BD_TO_FS(expr) \ + { \ + bd_result _result = expr; \ + if (_result == bd_result::out_of_bounds) \ + return fs_result::fs_corrupt; \ + if (_result == bd_result::device_error) \ + return fs_result::device_error; \ + } + + #define FS_TO_FS(expr) \ + { \ + fs_result _result = expr; \ + if (_result != fs_result::success) \ + return _result; \ + } + + tarfs_instance::tarfs_instance(block_device *bd) : bd(bd) {} + + fs_result tarfs_instance::next_node(node_id_t node, node_id_t &out) { + + uint64_t bytes; + FS_TO_FS(read_num(node + 124, 12, bytes)) + out = node + ((bytes - 1) / 512 + 2) * 512; + + uint8_t sector[512]; + BD_TO_FS(bd->read_bytes(node, 512, sector)) + for (unsigned i = 0; i < 512; ++i) + if (sector[i] != 0) + return fs_result::success; + + return fs_result::does_not_exist; + + } + + fs_result tarfs_instance::read_full_name( + node_id_t node, utility::string &out + ) { + + out.count = 0; + out.verify_buffer_len(155); + BD_TO_FS(bd->read_bytes(node + 345, 155, out.buffer)) + + while (out.count < 155 && out.buffer[out.count] != '\0') + ++out.count; + + unsigned new_max = out.count + 100; + out.verify_buffer_len(new_max); + BD_TO_FS(bd->read_bytes(node, 100, out.buffer + out.count)) + + while (out.count < 255 && out.buffer[out.count] != '\0') + ++out.count; + + return fs_result::success; + + } + + //len <= 12. + fs_result tarfs_instance::read_num( + uint64_t offset, unsigned len, uint64_t &out + ) { + + char buf[12]; + BD_TO_FS(bd->read_bytes(offset, len, buf)) + + out = 0; + for (unsigned i = 0; i < len && buf[i] != '\0'; ++i) { + if (buf[i] < '0' || buf[i] > '7') + return fs_result::fs_corrupt; + out = out * 8 + buf[i] - '0'; + } + + return fs_result::success; + + } + + fs_result tarfs_instance::first_child_starting_at( + node_id_t parent, node_id_t start, node_id_t &out + ) { + + utility::string parent_full_name; + FS_TO_FS(read_full_name(parent, parent_full_name)) + + utility::string child_full_name; + out = start; + + while (true) { + + FS_TO_FS(read_full_name(out, child_full_name)) + + if (child_full_name.count > parent_full_name.count && + child_full_name.starts_with(parent_full_name) + ) { + if (child_full_name.buffer[child_full_name.count - 1] == '/') + --child_full_name.count; + for (unsigned i = parent_full_name.count; + i < child_full_name.count; ++i) + if (child_full_name.buffer[i] == '/') + goto next; + return fs_result::success; + } + + next: + FS_TO_FS(next_node(out, out)) + + } + + } + + fs_result tarfs_instance::get_dir_entry(node_id_t node, dir_entry &entry) { + + utility::string full_name; + read_full_name(node, full_name); + + if (full_name.count == 2) + entry.name.count = 0; + + else { + + if (full_name.buffer[full_name.count - 1] == '/') + --full_name.count; + + unsigned last_slash = + utility::find_last(full_name.buffer, full_name.count, '/'); + entry.name.count = full_name.count - last_slash - 1; + entry.name.verify_buffer_len(entry.name.count); + + for (unsigned i = 0; i < entry.name.count; ++i) + entry.name.buffer[i] = full_name.buffer[last_slash + 1 + i]; + + } + + entry.node = node; + + char ch; + BD_TO_FS(bd->read_bytes(node + 156, 1, &ch)); + switch (ch) { + case '0': + entry.type = file_type::regular_file; + break; + case '2': + entry.type = file_type::symlink; + break; + case '5': + entry.type = file_type::directory; + break; + default: + return fs_result::fs_corrupt; + } + + if (entry.type == file_type::regular_file) { + uint64_t length; + FS_TO_FS(read_num(node + 124, 12, length)) + entry.length = length; + } + + else if (entry.type == file_type::symlink) { + utility::string target; + target.verify_buffer_len(100); + BD_TO_FS(bd->read_bytes(node + 157, 100, target.buffer)) + while (target.count < 100 && target.buffer[target.count] != '\0') + ++target.count; + entry.target = utility::move(target); + } + + return fs_result::success; + + } + + fs_result tarfs_instance::get_root_node(node_id_t &out) { + + utility::string full_name; + node_id_t on = 0; + + while (true) { + + FS_TO_FS(read_full_name(on, full_name)) + if (full_name.count == 2) { + out = on; + return fs_result::success; + } + fs_result result = next_node(on, on); + if (result == fs_result::does_not_exist) + return fs_result::fs_corrupt; + FS_TO_FS(result) + + } + + } + + fs_result tarfs_instance::get_first_child( + node_id_t node, dir_entry &out, directory_iter_t &iter_out + ) { + + node_id_t child; + FS_TO_FS(first_child_starting_at(node, 0, child)) + + dir_entry entry; + FS_TO_FS(get_dir_entry(child, entry)) + out = utility::move(entry); + iter_out = (directory_iter_t)child; + return fs_result::success; + + } + + fs_result tarfs_instance::get_next_child( + node_id_t node, dir_entry &out, directory_iter_t &iter + ) { + + node_id_t start; + FS_TO_FS(next_node((node_id_t)iter, start)) + + node_id_t child; + FS_TO_FS(first_child_starting_at(node, start, child)) + + dir_entry entry; + FS_TO_FS(get_dir_entry(child, entry)) + out = utility::move(entry); + iter = (directory_iter_t)child; + return fs_result::success; + + } + + fs_result tarfs_instance::read_bytes_from_file( + node_id_t node, uint64_t start, uint64_t count, void *into + ) { + BD_TO_FS(bd->read_bytes(node + 512 + start, count, into)) + return fs_result::success; + } + + +} 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 +#include +#include +#include +#include +#include + +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/source/utility.cpp b/kernel/source/utility.cpp new file mode 100644 index 0000000..12e88fd --- /dev/null +++ b/kernel/source/utility.cpp @@ -0,0 +1,51 @@ +#include + +void *operator new(size_t, void *ptr) { + return ptr; +} + +void operator delete(void *, void *) {} + +namespace hilbert::kernel::utility { + + void mark_bitmap_region_zero( + uint64_t *bitmap, uint64_t start_i, uint64_t end_i) { + + if (start_i % 64 != 0) { + uint64_t keep = (1 << (start_i % 64)) - 1; + bitmap[start_i / 64] &= keep; + start_i = (start_i / 64 + 1) * 64; + } + + if (end_i % 64 != 0) { + uint64_t replace = (1 << (end_i % 64)) - 1; + bitmap[end_i / 64] &= ~replace; + end_i = (end_i / 64) * 64; + } + + for (uint64_t i = start_i / 64; i < end_i / 64; ++i) + bitmap[i] = 0; + + } + + void mark_bitmap_region_one( + uint64_t *bitmap, uint64_t start_i, uint64_t end_i) { + + if (start_i % 64 != 0) { + uint64_t keep = (1 << (start_i % 64)) - 1; + bitmap[start_i / 64] |= ~keep; + start_i = (start_i / 64 + 1) * 64; + } + + if (end_i % 64 != 0) { + uint64_t replace = (1 << (end_i % 64)) - 1; + bitmap[end_i / 64] |= replace; + end_i = (end_i / 64) * 64; + } + + for (uint64_t i = start_i / 64; i < end_i / 64; ++i) + bitmap[i] = 0xffffffffffffffff; + + } + +} diff --git a/kernel/source/vfile.cpp b/kernel/source/vfile.cpp new file mode 100644 index 0000000..89c95e6 --- /dev/null +++ b/kernel/source/vfile.cpp @@ -0,0 +1,206 @@ +#include + +//TODO: handle symlink loops nicely in vfile::get_child, +// vfile::get_children, and lookup_path. + +namespace hilbert::kernel::vfile { + + void canon_path::parent() { + if (segments.count != 0) + --segments.count; + else if (!absolute) + ++parent_count; + } + + void canon_path::rel(const canon_path &r) { + if (r.absolute) { + segments.count = 0; + absolute = true; + parent_count = 0; + } + for (unsigned i = 0; i < r.parent_count; ++i) + parent(); + for (unsigned i = 0; i < r.segments.count; ++i) + segments.add_end(r.segments.buffer[i]); + } + + void canonize_path(const utility::string &name, canon_path &out) { + + out.absolute = false; + out.parent_count = 0; + out.segments.count = 0; + + const char *str = name.buffer; + unsigned len = name.count; + + if (len == 0) + return; + + if (len == 1 && str[0] == '/') { + out.absolute = true; + return; + } + + if (str[0] == '/') { + out.absolute = true; + ++str; + --len; + } + + while (len != 0) { + + unsigned segment_len = utility::find(str, len, '/'); + unsigned to_skip = segment_len == len ? segment_len : segment_len + 1; + + if (segment_len == 0) + ; + + else if (segment_len == 1 && str[0] == '.') + ; + + else if (segment_len == 2 && str[0] == '.' && str[1] == '.') + out.parent(); + + else { + utility::string segment(str, segment_len); + out.segments.add_end(utility::move(segment)); + } + + str += to_skip; + len -= to_skip; + + } + + } + +#define RET_NOT_SUC(expr) \ + { \ + storage::fs_result _result = expr; \ + if (_result != storage::fs_result::success) \ + return _result; \ + } + + storage::fs_result vfile::follow_symlinks(vfile &out) const { + + if (dir_entry.type != storage::file_type::symlink) { + out = *this; + return storage::fs_result::success; + } + + canon_path target_path; + canonize_path(dir_entry.target, target_path); + canon_path full_path = path; + full_path.parent(); + full_path.rel(target_path); + + vfile next; + RET_NOT_SUC(lookup_path(full_path, next, false)) + + next.path = path; + return next.follow_symlinks(out); + + } + + storage::fs_result vfile::get_child( + vfile &out, const utility::string &name + ) const { + + storage::dir_entry entry; + storage::directory_iter_t iter; + + RET_NOT_SUC(bd->mounted_as->get_first_child(dir_entry.node, entry, iter)) + + while (true) { + + if (entry.name == name) { + + vfile vf; + vf.bd = bd; + vf.dir_entry = utility::move(entry); + vf.path = path; + vf.path.segments.add_end(name); + out = utility::move(vf); + return storage::fs_result::success; + + } + + RET_NOT_SUC(bd->mounted_as->get_next_child(dir_entry.node, entry, iter)) + + } + + } + + storage::fs_result vfile::get_children(utility::vector &out) const { + + storage::dir_entry entry; + storage::directory_iter_t iter; + + storage::fs_result result = + bd->mounted_as->get_first_child(dir_entry.node, entry, iter); + if (result == storage::fs_result::does_not_exist) + return storage::fs_result::success; + else if (result != storage::fs_result::success) + return result; + + while (true) { + + vfile vf; + vf.bd = bd; + vf.path = path; + vf.path.segments.add_end(entry.name); + vf.dir_entry = utility::move(entry); + out.add_end(utility::move(vf)); + + result = bd->mounted_as->get_next_child(dir_entry.node, entry, iter); + if (result == storage::fs_result::does_not_exist) + return storage::fs_result::success; + else if (result != storage::fs_result::success) + return result; + + } + + } + + storage::fs_result vfile::read_file( + uint64_t start, uint64_t length, void *into + ) const { + return bd->mounted_as->read_bytes_from_file( + dir_entry.node, start, length, into); + } + + //TODO: see comment at top of vfile.hpp. + static const vfile *root; + + void set_root(const vfile &root) { + kernel::vfile::root = new vfile(root); + } + + storage::fs_result lookup_path( + const canon_path &path, vfile &out, bool follow_final_symlink + ) { + + //assume path is absolute. + + out = *root; + for (unsigned i = 0; i < path.segments.count; ++i) { + + vfile result; + RET_NOT_SUC(out.follow_symlinks(result)) + out = utility::move(result); + + RET_NOT_SUC(out.get_child(result, path.segments.buffer[i])) + out = utility::move(result); + + } + + if (follow_final_symlink) { + vfile result; + RET_NOT_SUC(out.follow_symlinks(result)) + out = utility::move(result); + } + + return storage::fs_result::success; + + } + +} diff --git a/kernel/storage.cpp b/kernel/storage.cpp deleted file mode 100644 index b6b1a04..0000000 --- a/kernel/storage.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include - -namespace hilbert::kernel::storage { - - bd_result block_device::load_cache_block(uint64_t i) { - - if (block_cache_i == i) - return bd_result::success; - - bd_result result = read_blocks_no_cache(i, 1, block_cache); - - if (result != bd_result::success) { - block_cache_i = block_count; - return result; - } - - block_cache_i = i; - return bd_result::success; - - } - - bd_result block_device::read_bytes( - uint64_t start, uint64_t count, void *into - ) { - - if (start + count > block_size * block_count) - return bd_result::out_of_bounds; - - uint8_t *into_u8 = (uint8_t *)into; - - if (start % block_size != 0) { - uint64_t prefix_len = block_size - start % block_size; - bd_result result = load_cache_block(start / block_size); - if (result != bd_result::success) - return result; - for (uint64_t i = 0; i < prefix_len; ++i) - into_u8[i] = block_cache[start % block_size + i]; - into_u8 += prefix_len; - start += prefix_len; - count -= prefix_len; - } - - uint64_t postfix_start = ((start + count) / block_size) * block_size; - - if (postfix_start != start) { - bd_result result = read_blocks_no_cache( - start / block_size, (postfix_start - start) / block_size, into_u8); - if (result != bd_result::success) - return result; - count -= postfix_start - start; - into_u8 += postfix_start - start; - start = postfix_start; - } - - if (count != 0) { - bd_result result = load_cache_block(start / block_size); - if (result != bd_result::success) - return result; - for (uint64_t i = 0; i < count; ++i) - into_u8[i] = block_cache[i]; - } - - return bd_result::success; - - } - -} diff --git a/kernel/storage/bd/memory.cpp b/kernel/storage/bd/memory.cpp deleted file mode 100644 index d6a6719..0000000 --- a/kernel/storage/bd/memory.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -namespace hilbert::kernel::storage::bd { - - memory::memory(void *buffer, uint64_t buffer_len) - : buffer((uint8_t *)buffer) - { - block_size = 1; - block_count = buffer_len; - //block cache will never be used, since the block size is 1. - } - - bd_result memory::read_blocks_no_cache( - uint64_t start, uint64_t count, void *into - ) { - for (uint64_t i = 0; i < count; ++i) - ((uint8_t *)into)[i] = buffer[start + i]; - return bd_result::success; - } - -} diff --git a/kernel/storage/fs/tarfs.cpp b/kernel/storage/fs/tarfs.cpp deleted file mode 100644 index 5986f62..0000000 --- a/kernel/storage/fs/tarfs.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include - -//in tarfs_instance, node_id_t and directory_iter_t refer to the number -//of bytes into the block device that the info sector is located. - -namespace hilbert::kernel::storage::fs { - - #define BD_TO_FS(expr) \ - { \ - bd_result _result = expr; \ - if (_result == bd_result::out_of_bounds) \ - return fs_result::fs_corrupt; \ - if (_result == bd_result::device_error) \ - return fs_result::device_error; \ - } - - #define FS_TO_FS(expr) \ - { \ - fs_result _result = expr; \ - if (_result != fs_result::success) \ - return _result; \ - } - - tarfs_instance::tarfs_instance(block_device *bd) : bd(bd) {} - - fs_result tarfs_instance::next_node(node_id_t node, node_id_t &out) { - - uint64_t bytes; - FS_TO_FS(read_num(node + 124, 12, bytes)) - out = node + ((bytes - 1) / 512 + 2) * 512; - - uint8_t sector[512]; - BD_TO_FS(bd->read_bytes(node, 512, sector)) - for (unsigned i = 0; i < 512; ++i) - if (sector[i] != 0) - return fs_result::success; - - return fs_result::does_not_exist; - - } - - fs_result tarfs_instance::read_full_name( - node_id_t node, utility::string &out - ) { - - out.count = 0; - out.verify_buffer_len(155); - BD_TO_FS(bd->read_bytes(node + 345, 155, out.buffer)) - - while (out.count < 155 && out.buffer[out.count] != '\0') - ++out.count; - - unsigned new_max = out.count + 100; - out.verify_buffer_len(new_max); - BD_TO_FS(bd->read_bytes(node, 100, out.buffer + out.count)) - - while (out.count < 255 && out.buffer[out.count] != '\0') - ++out.count; - - return fs_result::success; - - } - - //len <= 12. - fs_result tarfs_instance::read_num( - uint64_t offset, unsigned len, uint64_t &out - ) { - - char buf[12]; - BD_TO_FS(bd->read_bytes(offset, len, buf)) - - out = 0; - for (unsigned i = 0; i < len && buf[i] != '\0'; ++i) { - if (buf[i] < '0' || buf[i] > '7') - return fs_result::fs_corrupt; - out = out * 8 + buf[i] - '0'; - } - - return fs_result::success; - - } - - fs_result tarfs_instance::first_child_starting_at( - node_id_t parent, node_id_t start, node_id_t &out - ) { - - utility::string parent_full_name; - FS_TO_FS(read_full_name(parent, parent_full_name)) - - utility::string child_full_name; - out = start; - - while (true) { - - FS_TO_FS(read_full_name(out, child_full_name)) - - if (child_full_name.count > parent_full_name.count && - child_full_name.starts_with(parent_full_name) - ) { - if (child_full_name.buffer[child_full_name.count - 1] == '/') - --child_full_name.count; - for (unsigned i = parent_full_name.count; - i < child_full_name.count; ++i) - if (child_full_name.buffer[i] == '/') - goto next; - return fs_result::success; - } - - next: - FS_TO_FS(next_node(out, out)) - - } - - } - - fs_result tarfs_instance::get_dir_entry(node_id_t node, dir_entry &entry) { - - utility::string full_name; - read_full_name(node, full_name); - - if (full_name.count == 2) - entry.name.count = 0; - - else { - - if (full_name.buffer[full_name.count - 1] == '/') - --full_name.count; - - unsigned last_slash = - utility::find_last(full_name.buffer, full_name.count, '/'); - entry.name.count = full_name.count - last_slash - 1; - entry.name.verify_buffer_len(entry.name.count); - - for (unsigned i = 0; i < entry.name.count; ++i) - entry.name.buffer[i] = full_name.buffer[last_slash + 1 + i]; - - } - - entry.node = node; - - char ch; - BD_TO_FS(bd->read_bytes(node + 156, 1, &ch)); - switch (ch) { - case '0': - entry.type = file_type::regular_file; - break; - case '2': - entry.type = file_type::symlink; - break; - case '5': - entry.type = file_type::directory; - break; - default: - return fs_result::fs_corrupt; - } - - if (entry.type == file_type::regular_file) { - uint64_t length; - FS_TO_FS(read_num(node + 124, 12, length)) - entry.length = length; - } - - else if (entry.type == file_type::symlink) { - utility::string target; - target.verify_buffer_len(100); - BD_TO_FS(bd->read_bytes(node + 157, 100, target.buffer)) - while (target.count < 100 && target.buffer[target.count] != '\0') - ++target.count; - entry.target = utility::move(target); - } - - return fs_result::success; - - } - - fs_result tarfs_instance::get_root_node(node_id_t &out) { - - utility::string full_name; - node_id_t on = 0; - - while (true) { - - FS_TO_FS(read_full_name(on, full_name)) - if (full_name.count == 2) { - out = on; - return fs_result::success; - } - fs_result result = next_node(on, on); - if (result == fs_result::does_not_exist) - return fs_result::fs_corrupt; - FS_TO_FS(result) - - } - - } - - fs_result tarfs_instance::get_first_child( - node_id_t node, dir_entry &out, directory_iter_t &iter_out - ) { - - node_id_t child; - FS_TO_FS(first_child_starting_at(node, 0, child)) - - dir_entry entry; - FS_TO_FS(get_dir_entry(child, entry)) - out = utility::move(entry); - iter_out = (directory_iter_t)child; - return fs_result::success; - - } - - fs_result tarfs_instance::get_next_child( - node_id_t node, dir_entry &out, directory_iter_t &iter - ) { - - node_id_t start; - FS_TO_FS(next_node((node_id_t)iter, start)) - - node_id_t child; - FS_TO_FS(first_child_starting_at(node, start, child)) - - dir_entry entry; - FS_TO_FS(get_dir_entry(child, entry)) - out = utility::move(entry); - iter = (directory_iter_t)child; - return fs_result::success; - - } - - fs_result tarfs_instance::read_bytes_from_file( - node_id_t node, uint64_t start, uint64_t count, void *into - ) { - BD_TO_FS(bd->read_bytes(node + 512 + start, count, into)) - return fs_result::success; - } - - -} 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 -#include -#include -#include -#include - -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 -#include - -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('.'); - } - } - -} diff --git a/kernel/utility.cpp b/kernel/utility.cpp deleted file mode 100644 index 12e88fd..0000000 --- a/kernel/utility.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include - -void *operator new(size_t, void *ptr) { - return ptr; -} - -void operator delete(void *, void *) {} - -namespace hilbert::kernel::utility { - - void mark_bitmap_region_zero( - uint64_t *bitmap, uint64_t start_i, uint64_t end_i) { - - if (start_i % 64 != 0) { - uint64_t keep = (1 << (start_i % 64)) - 1; - bitmap[start_i / 64] &= keep; - start_i = (start_i / 64 + 1) * 64; - } - - if (end_i % 64 != 0) { - uint64_t replace = (1 << (end_i % 64)) - 1; - bitmap[end_i / 64] &= ~replace; - end_i = (end_i / 64) * 64; - } - - for (uint64_t i = start_i / 64; i < end_i / 64; ++i) - bitmap[i] = 0; - - } - - void mark_bitmap_region_one( - uint64_t *bitmap, uint64_t start_i, uint64_t end_i) { - - if (start_i % 64 != 0) { - uint64_t keep = (1 << (start_i % 64)) - 1; - bitmap[start_i / 64] |= ~keep; - start_i = (start_i / 64 + 1) * 64; - } - - if (end_i % 64 != 0) { - uint64_t replace = (1 << (end_i % 64)) - 1; - bitmap[end_i / 64] |= replace; - end_i = (end_i / 64) * 64; - } - - for (uint64_t i = start_i / 64; i < end_i / 64; ++i) - bitmap[i] = 0xffffffffffffffff; - - } - -} diff --git a/kernel/vfile.cpp b/kernel/vfile.cpp deleted file mode 100644 index 89c95e6..0000000 --- a/kernel/vfile.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include - -//TODO: handle symlink loops nicely in vfile::get_child, -// vfile::get_children, and lookup_path. - -namespace hilbert::kernel::vfile { - - void canon_path::parent() { - if (segments.count != 0) - --segments.count; - else if (!absolute) - ++parent_count; - } - - void canon_path::rel(const canon_path &r) { - if (r.absolute) { - segments.count = 0; - absolute = true; - parent_count = 0; - } - for (unsigned i = 0; i < r.parent_count; ++i) - parent(); - for (unsigned i = 0; i < r.segments.count; ++i) - segments.add_end(r.segments.buffer[i]); - } - - void canonize_path(const utility::string &name, canon_path &out) { - - out.absolute = false; - out.parent_count = 0; - out.segments.count = 0; - - const char *str = name.buffer; - unsigned len = name.count; - - if (len == 0) - return; - - if (len == 1 && str[0] == '/') { - out.absolute = true; - return; - } - - if (str[0] == '/') { - out.absolute = true; - ++str; - --len; - } - - while (len != 0) { - - unsigned segment_len = utility::find(str, len, '/'); - unsigned to_skip = segment_len == len ? segment_len : segment_len + 1; - - if (segment_len == 0) - ; - - else if (segment_len == 1 && str[0] == '.') - ; - - else if (segment_len == 2 && str[0] == '.' && str[1] == '.') - out.parent(); - - else { - utility::string segment(str, segment_len); - out.segments.add_end(utility::move(segment)); - } - - str += to_skip; - len -= to_skip; - - } - - } - -#define RET_NOT_SUC(expr) \ - { \ - storage::fs_result _result = expr; \ - if (_result != storage::fs_result::success) \ - return _result; \ - } - - storage::fs_result vfile::follow_symlinks(vfile &out) const { - - if (dir_entry.type != storage::file_type::symlink) { - out = *this; - return storage::fs_result::success; - } - - canon_path target_path; - canonize_path(dir_entry.target, target_path); - canon_path full_path = path; - full_path.parent(); - full_path.rel(target_path); - - vfile next; - RET_NOT_SUC(lookup_path(full_path, next, false)) - - next.path = path; - return next.follow_symlinks(out); - - } - - storage::fs_result vfile::get_child( - vfile &out, const utility::string &name - ) const { - - storage::dir_entry entry; - storage::directory_iter_t iter; - - RET_NOT_SUC(bd->mounted_as->get_first_child(dir_entry.node, entry, iter)) - - while (true) { - - if (entry.name == name) { - - vfile vf; - vf.bd = bd; - vf.dir_entry = utility::move(entry); - vf.path = path; - vf.path.segments.add_end(name); - out = utility::move(vf); - return storage::fs_result::success; - - } - - RET_NOT_SUC(bd->mounted_as->get_next_child(dir_entry.node, entry, iter)) - - } - - } - - storage::fs_result vfile::get_children(utility::vector &out) const { - - storage::dir_entry entry; - storage::directory_iter_t iter; - - storage::fs_result result = - bd->mounted_as->get_first_child(dir_entry.node, entry, iter); - if (result == storage::fs_result::does_not_exist) - return storage::fs_result::success; - else if (result != storage::fs_result::success) - return result; - - while (true) { - - vfile vf; - vf.bd = bd; - vf.path = path; - vf.path.segments.add_end(entry.name); - vf.dir_entry = utility::move(entry); - out.add_end(utility::move(vf)); - - result = bd->mounted_as->get_next_child(dir_entry.node, entry, iter); - if (result == storage::fs_result::does_not_exist) - return storage::fs_result::success; - else if (result != storage::fs_result::success) - return result; - - } - - } - - storage::fs_result vfile::read_file( - uint64_t start, uint64_t length, void *into - ) const { - return bd->mounted_as->read_bytes_from_file( - dir_entry.node, start, length, into); - } - - //TODO: see comment at top of vfile.hpp. - static const vfile *root; - - void set_root(const vfile &root) { - kernel::vfile::root = new vfile(root); - } - - storage::fs_result lookup_path( - const canon_path &path, vfile &out, bool follow_final_symlink - ) { - - //assume path is absolute. - - out = *root; - for (unsigned i = 0; i < path.segments.count; ++i) { - - vfile result; - RET_NOT_SUC(out.follow_symlinks(result)) - out = utility::move(result); - - RET_NOT_SUC(out.get_child(result, path.segments.buffer[i])) - out = utility::move(result); - - } - - if (follow_final_symlink) { - vfile result; - RET_NOT_SUC(out.follow_symlinks(result)) - out = utility::move(result); - } - - return storage::fs_result::success; - - } - -} -- cgit v1.2.3