From ace65b453151845bc361f21f3e5b651c35f9f126 Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Wed, 22 May 2024 13:00:41 -0400 Subject: massive refactor for mp and organization --- Makefile | 19 +-- arch/arch.h | 8 - arch/x86_64/cpu.c | 35 ++++ arch/x86_64/cpu.h | 13 -- arch/x86_64/elf.c | 55 ------ arch/x86_64/elf.h | 78 --------- arch/x86_64/elf_load.c | 58 +++++++ arch/x86_64/gdt.c | 83 ++++----- arch/x86_64/idt.c | 68 ++------ arch/x86_64/int_handler.c | 52 ++++++ arch/x86_64/interrupt.h | 11 -- arch/x86_64/kexec.c | 50 ++++++ arch/x86_64/msr.c | 67 ++++++++ arch/x86_64/page.c | 173 +++++++++++++++++++ arch/x86_64/page.h | 28 ++++ arch/x86_64/pagedirectory.c | 138 +++++++++++++++ arch/x86_64/pagefault.c | 39 +++++ arch/x86_64/paging.c | 257 ---------------------------- arch/x86_64/paging.h | 28 ---- arch/x86_64/processor.c | 40 +++++ arch/x86_64/restore.S | 20 +++ arch/x86_64/savestate.S | 39 ----- arch/x86_64/serial.c | 62 ------- arch/x86_64/serial.h | 27 --- arch/x86_64/syscall.c | 1 - arch/x86_64/syscall_entry.c | 25 +++ arch/x86_64/syscall_setup.S | 41 ----- arch/x86_64/tables.c | 8 - arch/x86_64/tables.h | 60 ------- arch/x86_64/tasking.c | 86 ---------- arch/x86_64/tcb_prepare.c | 9 + arch/x86_64/tcb_switch.c | 18 ++ arch/x86_64/tss.h | 20 --- arch/x86_64/uart.h | 19 --- arch/x86_64/umode_enter.S | 8 - arch/x86_64/umode_enter.c | 17 ++ arch/x86_64/vm_tophys.c | 23 +++ boot/boot.h | 40 ----- boot/cmdline.c | 27 +-- boot/cmdline.h | 10 -- boot/limine/limine.c | 2 +- compile_flags.txt | 4 - config.mk | 5 +- device/processor.c | 4 + device/serial.c | 77 +++++++++ include/api/errno.h | 9 + include/api/syscall.h | 39 +++++ include/arch/cpu.h | 14 ++ include/arch/elf.h | 12 ++ include/arch/page.h | 34 ++++ include/arch/processor.h | 39 +++++ include/arch/x86_64/cpu.h | 6 + include/arch/x86_64/elf.h | 93 +++++++++++ include/arch/x86_64/gdt.h | 23 +++ include/arch/x86_64/idt.h | 25 +++ include/arch/x86_64/msr.h | 56 +++++++ include/arch/x86_64/page.h | 40 +++++ include/arch/x86_64/processor.h | 17 ++ include/arch/x86_64/tables.h | 57 +++++++ include/arch/x86_64/tss.h | 20 +++ include/assert.h | 10 ++ include/boot.h | 38 +++++ include/commandline.h | 8 + include/device/serial.h | 48 ++++++ include/device/uart.h | 19 +++ include/initrd.h | 17 ++ include/jove.h | 13 ++ include/memory.h | 49 ++++++ include/print.h | 25 +++ include/slab.h | 44 +++++ include/string.h | 18 ++ include/tasking.h | 44 +++++ include/umode_vma.h | 10 ++ include/zone.h | 38 +++++ initrd/initrd.c | 84 ++++++++++ initrd/tar.h | 18 ++ io/interrupt.h | 6 - io/log.c | 68 -------- io/log.h | 22 --- ird/initrd.c | 88 ---------- ird/initrd.h | 21 --- ird/tar.h | 18 -- klib/buddymap.c | 170 +++++++++++++++++++ klib/buddymap.h | 35 ++++ klib/format.h | 13 ++ klib/hash.h | 18 ++ klib/kpanic.c | 16 ++ klib/linkedlist.c | 34 ++++ klib/linkedlist.h | 26 +++ klib/ltostr.c | 26 +++ klib/mem.c | 52 ++++++ klib/rbtree.c | 361 ++++++++++++++++++++++++++++++++++++++++ klib/rbtree.h | 48 ++++++ klib/sfmt.c | 115 +++++++++++++ klib/spinlock.h | 27 +++ klib/string.c | 16 ++ klib/toupper.c | 26 +++ lib/buddymap.c | 168 ------------------- lib/buddymap.h | 35 ---- lib/format.h | 13 -- lib/hashtable.c | 109 ------------ lib/hashtable.h | 34 ---- lib/jove.h | 15 -- lib/kpanic.c | 15 -- lib/linkedlist.c | 34 ---- lib/linkedlist.h | 26 --- lib/ltostr.c | 26 --- lib/mem.c | 52 ------ lib/sfmt.c | 112 ------------- lib/spinlock.h | 27 --- lib/string.c | 16 -- lib/string.h | 18 -- lib/toupper.c | 26 --- main.c | 41 +++-- mem/memory.c | 10 -- mem/memory.h | 94 ----------- mem/phys.c | 39 ----- mem/slab.c | 209 ----------------------- mem/slab.h | 33 ---- mem/zone.c | 146 ---------------- mem/zone.h | 71 -------- memory/alloc/calloc.c | 21 +++ memory/alloc/free.c | 80 +++++++++ memory/alloc/malloc.c | 206 +++++++++++++++++++++++ memory/alloc/malloc.h | 183 ++++++++++++++++++++ memory/alloc/realloc.c | 73 ++++++++ memory/alloc/reallocarray.c | 37 ++++ memory/bump.c | 33 ++++ memory/bump.h | 10 ++ memory/memory.c | 39 +++++ memory/phys.c | 39 +++++ memory/slab.c | 148 ++++++++++++++++ memory/zone.c | 145 ++++++++++++++++ print.c | 40 +++++ sys/errno.h | 10 -- sys/permission.h | 11 -- sys/syscall.h | 69 -------- sys/types.h | 32 ---- syscall/dbg_log.c | 19 +++ syscall/exit.c | 17 ++ syscall/handler.c | 23 +++ syscall/handler.h | 19 +++ task/exrtab.c | 19 +++ task/init.c | 22 +++ task/stack.c | 14 ++ task/tasking.c | 45 +++++ task/umode_vma.c | 37 ++++ usr/elf.h | 12 -- usr/syscall.c | 104 ------------ usr/syscall.h | 11 -- usr/tasking.c | 7 - usr/tasking.h | 28 ---- usr/umode.c | 39 ----- usr/umode.h | 8 - 154 files changed, 4195 insertions(+), 2899 deletions(-) delete mode 100644 arch/arch.h create mode 100644 arch/x86_64/cpu.c delete mode 100644 arch/x86_64/cpu.h delete mode 100644 arch/x86_64/elf.c delete mode 100644 arch/x86_64/elf.h create mode 100644 arch/x86_64/elf_load.c create mode 100644 arch/x86_64/int_handler.c delete mode 100644 arch/x86_64/interrupt.h create mode 100644 arch/x86_64/kexec.c create mode 100644 arch/x86_64/msr.c create mode 100644 arch/x86_64/page.c create mode 100644 arch/x86_64/page.h create mode 100644 arch/x86_64/pagedirectory.c create mode 100644 arch/x86_64/pagefault.c delete mode 100644 arch/x86_64/paging.c delete mode 100644 arch/x86_64/paging.h create mode 100644 arch/x86_64/processor.c create mode 100644 arch/x86_64/restore.S delete mode 100644 arch/x86_64/savestate.S delete mode 100644 arch/x86_64/serial.c delete mode 100644 arch/x86_64/serial.h delete mode 100644 arch/x86_64/syscall.c create mode 100644 arch/x86_64/syscall_entry.c delete mode 100644 arch/x86_64/syscall_setup.S delete mode 100644 arch/x86_64/tables.c delete mode 100644 arch/x86_64/tables.h delete mode 100644 arch/x86_64/tasking.c create mode 100644 arch/x86_64/tcb_prepare.c create mode 100644 arch/x86_64/tcb_switch.c delete mode 100644 arch/x86_64/tss.h delete mode 100644 arch/x86_64/uart.h delete mode 100644 arch/x86_64/umode_enter.S create mode 100644 arch/x86_64/umode_enter.c create mode 100644 arch/x86_64/vm_tophys.c delete mode 100644 boot/boot.h delete mode 100644 boot/cmdline.h delete mode 100644 compile_flags.txt create mode 100644 device/processor.c create mode 100644 device/serial.c create mode 100644 include/api/errno.h create mode 100644 include/api/syscall.h create mode 100644 include/arch/cpu.h create mode 100644 include/arch/elf.h create mode 100644 include/arch/page.h create mode 100644 include/arch/processor.h create mode 100644 include/arch/x86_64/cpu.h create mode 100644 include/arch/x86_64/elf.h create mode 100644 include/arch/x86_64/gdt.h create mode 100644 include/arch/x86_64/idt.h create mode 100644 include/arch/x86_64/msr.h create mode 100644 include/arch/x86_64/page.h create mode 100644 include/arch/x86_64/processor.h create mode 100644 include/arch/x86_64/tables.h create mode 100644 include/arch/x86_64/tss.h create mode 100644 include/assert.h create mode 100644 include/boot.h create mode 100644 include/commandline.h create mode 100644 include/device/serial.h create mode 100644 include/device/uart.h create mode 100644 include/initrd.h create mode 100644 include/jove.h create mode 100644 include/memory.h create mode 100644 include/print.h create mode 100644 include/slab.h create mode 100644 include/string.h create mode 100644 include/tasking.h create mode 100644 include/umode_vma.h create mode 100644 include/zone.h create mode 100644 initrd/initrd.c create mode 100644 initrd/tar.h delete mode 100644 io/interrupt.h delete mode 100644 io/log.c delete mode 100644 io/log.h delete mode 100644 ird/initrd.c delete mode 100644 ird/initrd.h delete mode 100644 ird/tar.h create mode 100644 klib/buddymap.c create mode 100644 klib/buddymap.h create mode 100644 klib/format.h create mode 100644 klib/hash.h create mode 100644 klib/kpanic.c create mode 100644 klib/linkedlist.c create mode 100644 klib/linkedlist.h create mode 100644 klib/ltostr.c create mode 100644 klib/mem.c create mode 100644 klib/rbtree.c create mode 100644 klib/rbtree.h create mode 100644 klib/sfmt.c create mode 100644 klib/spinlock.h create mode 100644 klib/string.c create mode 100644 klib/toupper.c delete mode 100644 lib/buddymap.c delete mode 100644 lib/buddymap.h delete mode 100644 lib/format.h delete mode 100644 lib/hashtable.c delete mode 100644 lib/hashtable.h delete mode 100644 lib/jove.h delete mode 100644 lib/kpanic.c delete mode 100644 lib/linkedlist.c delete mode 100644 lib/linkedlist.h delete mode 100644 lib/ltostr.c delete mode 100644 lib/mem.c delete mode 100644 lib/sfmt.c delete mode 100644 lib/spinlock.h delete mode 100644 lib/string.c delete mode 100644 lib/string.h delete mode 100644 lib/toupper.c delete mode 100644 mem/memory.c delete mode 100644 mem/memory.h delete mode 100644 mem/phys.c delete mode 100644 mem/slab.c delete mode 100644 mem/slab.h delete mode 100644 mem/zone.c delete mode 100644 mem/zone.h create mode 100644 memory/alloc/calloc.c create mode 100644 memory/alloc/free.c create mode 100644 memory/alloc/malloc.c create mode 100644 memory/alloc/malloc.h create mode 100644 memory/alloc/realloc.c create mode 100644 memory/alloc/reallocarray.c create mode 100644 memory/bump.c create mode 100644 memory/bump.h create mode 100644 memory/memory.c create mode 100644 memory/phys.c create mode 100644 memory/slab.c create mode 100644 memory/zone.c create mode 100644 print.c delete mode 100644 sys/errno.h delete mode 100644 sys/permission.h delete mode 100644 sys/syscall.h delete mode 100644 sys/types.h create mode 100644 syscall/dbg_log.c create mode 100644 syscall/exit.c create mode 100644 syscall/handler.c create mode 100644 syscall/handler.h create mode 100644 task/exrtab.c create mode 100644 task/init.c create mode 100644 task/stack.c create mode 100644 task/tasking.c create mode 100644 task/umode_vma.c delete mode 100644 usr/elf.h delete mode 100644 usr/syscall.c delete mode 100644 usr/syscall.h delete mode 100644 usr/tasking.c delete mode 100644 usr/tasking.h delete mode 100644 usr/umode.c delete mode 100644 usr/umode.h diff --git a/Makefile b/Makefile index 6697fc6..84244de 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,19 @@ include config.mk +CDIRS := boot device initrd klib memory task syscall +CDIRS += memory/alloc +CDIRS += boot/$(TARGET_BOOTLOADER) +CDIRS += arch/$(TARGET_MACHINE) + CFILES := $(wildcard *.c) -CFILES += $(wildcard */*.c) -CFILES += $(wildcard boot/$(TARGET_BOOTLOADER)/*.c) -CFILES += $(wildcard arch/$(TARGET_MACHINE)/*.c) -CFILES += $(wildcard arch/$(TARGET_MACHINE)/*/*.c) +CFILES += $(foreach dir, $(CDIRS), $(wildcard $(dir)/*.c)) SFILES := $(wildcard *.S) -SFILES += $(wildcard */*.S) -SFILES += $(wildcard arch/$(TARGET_MACHINE)/*.S) -SFILES += $(wildcard arch/$(TARGET_MACHINE)/*/*.S) +SFILES += $(foreach dir, $(CDIRS), $(wildcard $(dir)/*.S)) OBJFILES := $(patsubst %.c,%.o,$(CFILES)) OBJFILES += $(patsubst %.S,%.o,$(SFILES)) -DFILES := $(wildcard *.d) -DFILES += $(wildcard */*.d) -DFILES += $(wildcard arch/$(TARGET_MACHINE)/*.d) -DFILES += $(wildcard arch/$(TARGET_MACHINE)/*/*.d) - BIN := jove.elf all: $(BIN) diff --git a/arch/arch.h b/arch/arch.h deleted file mode 100644 index 6e569fd..0000000 --- a/arch/arch.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JOVE_ARCH_H -#define JOVE_ARCH_H 1 - -extern void serial_setup(void); - -extern void arch_tables_setup(void); - -#endif diff --git a/arch/x86_64/cpu.c b/arch/x86_64/cpu.c new file mode 100644 index 0000000..d088fcd --- /dev/null +++ b/arch/x86_64/cpu.c @@ -0,0 +1,35 @@ +#include "arch/cpu.h" +#include "arch/x86_64/msr.h" + +extern void _syscall_entry(void); + +extern void idt_init(); + +void +cpu_setup(void) +{ + idt_init(); + + cpu_arch_enable_sce(); + cpu_set_syscall_entry((void*)_syscall_entry); +} + +void cpu_arch_enable_sce(void) +{ + msr_efer_t feat = msr_efer_read(); + feat.sce = 1; + msr_efer_write(feat); + + msr_star_t star = msr_star_read(); + star.kcs = 0x08; + star.ucs = 0x18; + msr_star_write(star); +} + +void +cpu_set_syscall_entry(void *ptr) +{ + msr_lstar_t lstar = (msr_lstar_t)ptr; + msr_lstar_write(lstar); +} + diff --git a/arch/x86_64/cpu.h b/arch/x86_64/cpu.h deleted file mode 100644 index 942c8d9..0000000 --- a/arch/x86_64/cpu.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef ARCH_x86_64_CPU_H -#define ARCH_x86_64_CPU_H 1 - -#include - -struct Registers -{ - uint64_t r15, r14, r13, r12, r11, r10, r9, r8; - uint64_t bp, di, si, dx, cx, bx, ax; - uint64_t ip, cs, flags, sp, ss; -}; - -#endif diff --git a/arch/x86_64/elf.c b/arch/x86_64/elf.c deleted file mode 100644 index 969cbf0..0000000 --- a/arch/x86_64/elf.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "elf.h" -#include "lib/string.h" -#include "usr/elf.h" -#include "io/log.h" -#include "mem/memory.h" - -void* -elf_load(const void *data, size_t len) -{ - if(data == NULL) return NULL; - if(len < 4) return NULL; - - struct ELF_header *ehdr = (struct ELF_header*)data; - if(ehdr->e_ident[EI_MAG0] != E_IDENT_MAG0 && - ehdr->e_ident[EI_MAG1] != E_IDENT_MAG1 && - ehdr->e_ident[EI_MAG2] != E_IDENT_MAG2 && - ehdr->e_ident[EI_MAG3] != E_IDENT_MAG3) - return NULL; - - if(ehdr->e_ident[EI_CLASS] != E_IDENT_CLASS64) { - klogf("Jove does not support ELF files of class CLASS32\n"); - return NULL; - } - - if(ehdr->e_type != ET_EXEC) { - klogf("Jove does not support ELF files other than ET_EXEC\n"); - return NULL; - } - - uint64_t entry = ehdr->e_entry; - - size_t phdrc = ehdr->e_phnum; - struct ELF_phdr *phdrs = (struct ELF_phdr*)((uintptr_t)data + ehdr->e_phoff); - - for(size_t phdri = 0; phdri < phdrc; phdri++) - { - struct ELF_phdr *phdr = &phdrs[phdri]; - void *pdata = (void*)phdr->p_vaddr; - - mem_ensure_range( - phdr->p_vaddr, - phdr->p_vaddr + phdr->p_memsz, - (page_flags_t) { - .present = true, - .writeable = true, - .useraccess = true, - .executable = true - }); - if(phdr->p_type == PT_LOAD) - { - memcpy(pdata, (void*)((uintptr_t)data + phdr->p_offset), phdr->p_filesz); - } - } - return (void*)entry; -} diff --git a/arch/x86_64/elf.h b/arch/x86_64/elf.h deleted file mode 100644 index ebcd228..0000000 --- a/arch/x86_64/elf.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef JOVE_ARCH_x86_64_ELF_H -#define JOVE_ARCH_x86_64_ELF_H 1 - -#include - -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 -#define EI_ABIVERSION 8 -#define EI_PAD 9 - -#define E_IDENT_MAG0 0x7F -#define E_IDENT_MAG1 'E' -#define E_IDENT_MAG2 'L' -#define E_IDENT_MAG3 'F' - -#define E_IDENT_CLASS32 1 -#define E_IDENT_CLASS64 2 - -#define ET_EXEC 0x02 - -struct ELF_header -{ - uint8_t e_ident[15]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - uint64_t e_entry; - uint64_t e_phoff; - uint64_t e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; -}; - -#define PT_NULL 0 -#define PT_LOAD 1 - -#define PF_X 1 -#define PF_W 2 -#define PF_R 4 - -struct ELF_phdr -{ - uint32_t p_type; - uint32_t p_flags; - uint64_t p_offset; - uint64_t p_vaddr; - uint64_t p_paddr; - uint64_t p_filesz; - uint64_t p_memsz; - uint64_t p_align; -}; - -struct ELF_shdr -{ - uint32_t sh_name; - uint32_t sh_type; - uint64_t sh_flags; - uint64_t sh_addr; - uint64_t sh_offset; - uint64_t sh_size; - uint32_t sh_link; - uint32_t sh_info; - uint64_t sh_addralign; - uint64_t sh_entsize; -}; - -#endif diff --git a/arch/x86_64/elf_load.c b/arch/x86_64/elf_load.c new file mode 100644 index 0000000..d7d1b29 --- /dev/null +++ b/arch/x86_64/elf_load.c @@ -0,0 +1,58 @@ +#include "arch/elf.h" +#include "string.h" +#include "memory.h" +#include "print.h" + +uintptr_t +elf_load(const void *data, size_t len) +{ + if(data == NULL) return 0; + if(len < 4) return 0; + + elf_header_t *ehdr = (elf_header_t*)data; + if(ehdr->ei_mag[0] != EI_MAG0 || + ehdr->ei_mag[1] != EI_MAG1 || + ehdr->ei_mag[2] != EI_MAG2 || + ehdr->ei_mag[3] != EI_MAG3) return 0; + + if(ehdr->ei_class != EI_CLASS_64) { + kerrf("Jove does not support ELF files of class CLASS32\n"); + return 0; + } + + if(ehdr->e_type != ET_EXEC) { + kerrf("Jove does not support ELF files other than ET_EXEC\n"); + return 0; + } + + uint64_t entry = ehdr->e_entry; + + size_t phdrc = ehdr->e_phnum; + elf_phdr_t *phdrs = (elf_phdr_t*)((uintptr_t)data + ehdr->e_phoff); + + for(size_t phdri = 0; phdri < phdrc; phdri++) + { + elf_phdr_t *phdr = &phdrs[phdri]; + void *pdata = (void*)phdr->p_vaddr; + + vm_ensure( + phdr->p_vaddr, + phdr->p_vaddr + phdr->p_memsz, + (page_flags_t) { + .present = true, + .writeable = true, + .useraccess = true, + .executable = true + }); + + if(phdr->p_type == PT_LOAD) + { + kdbgf("PT_LOAD %#016X [%#016X] -> %#016X\n", + (uintptr_t)data + phdr->p_offset, + phdr->p_filesz, + pdata); + memcpy(pdata, (void*)((uintptr_t)data + phdr->p_offset), phdr->p_filesz); + } + } + return entry; +} diff --git a/arch/x86_64/gdt.c b/arch/x86_64/gdt.c index 07a8097..614ec30 100644 --- a/arch/x86_64/gdt.c +++ b/arch/x86_64/gdt.c @@ -1,24 +1,10 @@ -#include "tables.h" -#include "tss.h" +#include "arch/x86_64/gdt.h" +#include "arch/x86_64/tss.h" +#include "arch/processor.h" +#include "string.h" +#include "print.h" -enum -{ - GDT_SEGMENT_KERNEL_NULL = 0, - GDT_SEGMENT_KERNEL_CODE, - GDT_SEGMENT_KERNEL_DATA, - - GDT_SEGMENT_USER_NULL, - GDT_SEGMENT_USER_DATA, - GDT_SEGMENT_USER_CODE, - - GDT_SEGMENT_TSS_LOW, - GDT_SEGMENT_TSS_HIGH, - - GDT_SEGMENT_COUNT -}; - -__attribute__((aligned(0x1000))) -static struct SegmentDescriptor s_gdtd[GDT_SEGMENT_COUNT] = +static gdt_t s_baseline_gdt = { { 0 }, /* Kernel NULL */ { /* Kernel Code (64-bit RO EX DPL0) */ @@ -99,43 +85,40 @@ static struct SegmentDescriptor s_gdtd[GDT_SEGMENT_COUNT] = }, { 0 } }; -static struct XDTR s_gdtr = { - .length = sizeof(s_gdtd) - 1, - .address = (uintptr_t)&s_gdtd -}; -static struct TSS s_tss = { - -}; - -extern void x86_64_lgdt(struct XDTR *gdtr); -extern void x86_64_flush_tss(void); void -x86_64_load_gdt(void) +gdt_setup(processor_t *proc) { - { - struct SegmentDescriptor *tss_lo = &s_gdtd[GDT_SEGMENT_TSS_LOW]; - struct SegmentDescriptor *tss_hi = &s_gdtd[GDT_SEGMENT_TSS_HIGH]; - uintptr_t tssb = (uintptr_t)&s_tss; - tss_lo->base_0_15 = tssb & 0xFFFF; - tss_lo->base_16_23 = (tssb >> 16) & 0xFF; - tss_lo->base_24_31 = (tssb >> 24) & 0xFF; - tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF; - tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF; + memcpy(proc->_gdt, s_baseline_gdt, sizeof(gdt_t)); + proc->_gdtr = (struct XDTR) { + .length = sizeof(gdt_t) - 1, + .address = (uintptr_t)&proc->_gdt + }; + klogf("Processor %i GDT %#016X L%i\n", proc->id, proc->_gdt, proc->_gdtr.length); +} - size_t tssl = sizeof(struct TSS) - 1; - tss_lo->limit_0_15 = tssl & 0xFFFF; - tss_lo->limit_16_19 = (tssl >> 16) & 0xF; +void +tss_setup(processor_t *proc) +{ + segment_descriptor_t *tss_lo = &proc->_gdt[GDT_SEGMENT_TSS_LOW]; + segment_descriptor_t *tss_hi = &proc->_gdt[GDT_SEGMENT_TSS_HIGH]; + uintptr_t tssb = (uintptr_t)&(proc->_tss); + tss_lo->base_0_15 = tssb & 0xFFFF; + tss_lo->base_16_23 = (tssb >> 16) & 0xFF; + tss_lo->base_24_31 = (tssb >> 24) & 0xFF; + tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF; + tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF; - s_tss.iobp = sizeof(struct TSS); - } + size_t tssl = sizeof(struct TSS) - 1; + tss_lo->limit_0_15 = tssl & 0xFFFF; + tss_lo->limit_16_19 = (tssl >> 16) & 0xF; - x86_64_lgdt(&s_gdtr); - x86_64_flush_tss(); + proc->_tss.iobp = sizeof(struct TSS); } -void tss_set_rsp(uint8_t dpl, uintptr_t rsp) +void +tss_set_rsp(struct TSS *tss, uint8_t dpl, uintptr_t rsp) { - s_tss.rsp[dpl][0] = rsp & 0xFFFFFFFF; - s_tss.rsp[dpl][1] = (rsp >> 32) & 0xFFFFFFFF; + tss->rsp[dpl][0] = rsp & 0xFFFFFFFF; + tss->rsp[dpl][1] = (rsp >> 32) & 0xFFFFFFFF; } diff --git a/arch/x86_64/idt.c b/arch/x86_64/idt.c index 05dcf43..5ddda50 100644 --- a/arch/x86_64/idt.c +++ b/arch/x86_64/idt.c @@ -1,64 +1,25 @@ -#include "tables.h" -#include "cpu.h" -#include "lib/jove.h" -#include "io/log.h" +#include +#include "arch/x86_64/tables.h" +#include "arch/x86_64/idt.h" +#include "arch/processor.h" +#include "print.h" +#include "jove.h" PAGEALIGN -static struct InterruptTrapGate s_idtd[48]; -static struct Registers *(*s_int_handlers[48])(struct Registers*); -static struct XDTR s_idtr = { - .length = sizeof(s_idtd) - 1, - .address = (uintptr_t)&s_idtd -}; +static interrupt_gate_t s_idtd[48]; uint64_t __isr_err; uint64_t __isr_num; -void -int_set_handler(uint8_t code, struct Registers *(*handler)(struct Registers*)) -{ - if(code >= 48) return; - s_int_handlers[code] = handler; -} - -struct Registers* -irq_handle(struct Registers *state) -{ - if(__isr_num < 48) { - if(s_int_handlers[__isr_num] != NULL) { - return s_int_handlers[__isr_num](state); - } - } - klogf("Interrupt %i\nerror code %#016X\n", __isr_num, __isr_err); - klogf("IP: %#016X\n", state->ip); - klogf("AX: %#016X\n", state->ax); - klogf("BX: %#016X\n", state->bx); - klogf("CX: %#016X\n", state->cx); - klogf("DX: %#016X\n", state->dx); - klogf("SI: %#016X\n", state->si); - klogf("DI: %#016X\n", state->di); - klogf("BP: %#016X\n", state->bp); - klogf("R8: %#016X\n", state->r8); - klogf("R9: %#016X\n", state->r9); - klogf("R10: %#016X\n", state->r10); - klogf("R11: %#016X\n", state->r11); - klogf("R12: %#016X\n", state->r12); - klogf("R13: %#016X\n", state->r13); - klogf("R14: %#016X\n", state->r14); - klogf("R15: %#016X\n", state->r15); - kpanic("Unhandled exception\n"); - return state; -} - extern void x86_64_lidt(struct XDTR *idtr); void -x86_64_load_idt(void) +idt_init(void) { extern uintptr_t __isr_stubs[22]; for(int i = 0; i < 22; i++) { uintptr_t base = __isr_stubs[i]; - s_idtd[i] = (struct InterruptTrapGate){ + s_idtd[i] = (interrupt_gate_t){ .base_0_15 = (base & 0xFFFF), .segment_selector = 0x8, .ist = 0, @@ -71,7 +32,14 @@ x86_64_load_idt(void) .base_32_63 = (base >> 32) & 0xFFFFFFFF, .resv = 0 }; - klogf("INT %2i : %#016X (%016X)\n", i, base, s_idtd[i]); } - x86_64_lidt(&s_idtr); +} + +void +idt_setup(processor_t *proc) +{ + proc->_idtr = (struct XDTR){ + .length = sizeof(s_idtd) - 1, + .address = (uintptr_t)s_idtd + }; } diff --git a/arch/x86_64/int_handler.c b/arch/x86_64/int_handler.c new file mode 100644 index 0000000..3674d1c --- /dev/null +++ b/arch/x86_64/int_handler.c @@ -0,0 +1,52 @@ +#include "arch/x86_64/idt.h" +#include "arch/processor.h" +#include "print.h" +#include "jove.h" +#include "assert.h" +#include + +static int_handler_t s_handlers[48]; + +int_state_t* +irq_handle(int_state_t *state) +{ + if(__isr_num < 48) { + if(s_handlers[__isr_num] != NULL) { + return s_handlers[__isr_num](state); + } + } + + klogf("Interrupt %i\nerror code %#016X\n", __isr_num, __isr_err); + int_state_print(state); + kpanic("Unhandled exception\n"); + return state; +} + +void +int_handler_set(uint8_t i, int_handler_t handler) +{ + assert(i < 48); + s_handlers[i] = handler; +} + +int_handler_t +int_handler_get(uint8_t i) +{ + assert(i < 48); + return s_handlers[i]; +} + +void +int_state_print(int_state_t *state) +{ + if(!state) return; + klogf("IP: %016p\n", state->ip); + klogf("AX: %016p BX: %016p\n", state->ax, state->bx); + klogf("CX: %016p DX: %016p\n", state->cx, state->dx); + klogf("SI: %016p DI: %016p\n", state->si, state->di); + klogf("SP: %016p BP: %016p\n", state->sp, state->bp); + klogf("R8: %016p R9: %016p\n", state->r8, state->r9); + klogf("R10: %016p R11: %016p\n", state->r10, state->r11); + klogf("R12: %016p R13: %016p\n", state->r12, state->r13); + klogf("R14: %016p R15: %016p\n", state->r14, state->r15); +} diff --git a/arch/x86_64/interrupt.h b/arch/x86_64/interrupt.h deleted file mode 100644 index 9ae63f9..0000000 --- a/arch/x86_64/interrupt.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef JOVE_ARCH_INTERRUPT_H -#define JOVE_ARCH_INTERRUPT_H 1 - -#include "cpu.h" - -/**Register a handler for a specified interrupt code. - * @param code interrupt to handle. - * @param handler to call.*/ -void int_set_handler(unsigned char code, struct Registers *(*handler)(struct Registers*)); - -#endif diff --git a/arch/x86_64/kexec.c b/arch/x86_64/kexec.c new file mode 100644 index 0000000..406e8e7 --- /dev/null +++ b/arch/x86_64/kexec.c @@ -0,0 +1,50 @@ +#include "tasking.h" +#include "memory.h" +#include "string.h" +#include "arch/cpu.h" + +#define UMODE_STACK_TOP (USERLAND_MEMORY_LIMIT) +#define UMODE_STACKW PAGE_SIZE + +static void* +s_umode_stack(void) +{ + uintptr_t top = UMODE_STACK_TOP; + uintptr_t bottom = top - (UMODE_STACKW - 1); + + vm_ensure(bottom, top, (page_flags_t) { + .present = true, + .writeable = true, + .useraccess = true, + .executable = false + }); + return (void*)top; +} + +static inline void* +s_stack_push(void *sp, void *data, size_t len) +{ + sp = (void*)((uintptr_t)sp - len); + memcpy(sp, data, len); + return sp; +} + +void +kexec(void *ip, int kargc, char **kargv, int kenvc, char **kenvp) +{ + /* Allocate a page for the user stack. */ + void *sp = s_umode_stack(); + + intmax_t argc = kargc; + sp = s_stack_push(sp, &argc, sizeof(intmax_t)); + + /* TODO: Proper argv, envp*/ + sp = s_stack_push(sp, &kargv, sizeof(char**)); + + intmax_t envc = kenvc; + sp = s_stack_push(sp, &envc, sizeof(intmax_t)); + + sp = s_stack_push(sp, &kenvp, sizeof(char**)); + + umode_enter(ip, sp); +} diff --git a/arch/x86_64/msr.c b/arch/x86_64/msr.c new file mode 100644 index 0000000..1891126 --- /dev/null +++ b/arch/x86_64/msr.c @@ -0,0 +1,67 @@ +#include "arch/x86_64/msr.h" + +void +msr_write(uint32_t msr, uint64_t v) +{ + __asm__ volatile("wrmsr":: "a"(v), "d"(v >> 32), "c"(msr)); +} + +uint64_t +msr_read(uint32_t msr) +{ + uint32_t lo, hi; + __asm__ volatile("rdmsr": "=a"(lo), "=d"(hi): "c"(msr)); + uint64_t v = hi; + v = (v << 32) | lo; + return v; +} + +void +msr_efer_write(msr_efer_t v) +{ + msr_write(MSR_EFER, *((uintptr_t*)&v)); +} + +msr_efer_t +msr_efer_read(void) +{ + uint64_t rawv = msr_read(MSR_EFER); + return *((msr_efer_t*)&rawv); +} + +void +msr_star_write(msr_star_t v) +{ + msr_write(MSR_STAR, *((uintptr_t*)&v)); +} + +msr_star_t +msr_star_read(void) +{ + uint64_t rawv = msr_read(MSR_STAR); + return *((msr_star_t*)&rawv); +} + +void +msr_lstar_write(msr_lstar_t v) +{ + msr_write(MSR_LSTAR, v); +} + +msr_lstar_t +msr_lstar_read(void) +{ + return msr_read(MSR_LSTAR); +} + +void +msr_gsbase_write(uintptr_t gsbase) +{ + msr_write(MSR_GSBASE, gsbase); +} + +uintptr_t +msr_gsbase_read(void) +{ + return msr_read(MSR_GSBASE); +} diff --git a/arch/x86_64/page.c b/arch/x86_64/page.c new file mode 100644 index 0000000..d816f66 --- /dev/null +++ b/arch/x86_64/page.c @@ -0,0 +1,173 @@ +#include "arch/x86_64/page.h" +#include "klib/rbtree.h" +#include "arch/processor.h" +#include "string.h" +#include "jove.h" +#include "memory.h" +#include "print.h" + +extern void *_kernel_end; + +struct PageDirectoryListEntry { + struct PageDirectoryListEntry *next; + page_directory_t pd; +}; + +struct PageStateCache { + page_directory_t *pd; + size_t pmli[4]; + pmle_t *pml[4]; +} s_state_cache; + +const uintptr_t USERLAND_MEMORY_BASE = KiB; +const uintptr_t USERLAND_MEMORY_LIMIT = 0x00007FFFFFFFFFFFULL; + +const uintptr_t PHYSMAP_MEMORY_BASE = 0xFFFF800000000000ULL; +const uintptr_t PHYSMAP_MEMORY_LIMIT = PHYSMAP_MEMORY_BASE + (1 * GiB); + +const uintptr_t KERNEL_MEMORY_BASE = 0xFFFF800000000000ULL; +const uintptr_t KERNEL_MEMORY_LIMIT = 0xFFFFFFFFFFFFFFFFULL; + +static size_t +s_paging_pmli(size_t l, uintptr_t addr) +{ + size_t shift = (PAGE_SHIFT + (9 * l)); + return (addr & (0x1FFULL << shift)) >> shift; +} + +static pmle_t* +s_paging_fetch_table(pmle_t *pml, size_t l, uintptr_t virt) +{ + size_t pmli = s_paging_pmli(l, virt); + if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL) + return s_state_cache.pml[l]; + + pmle_t entry = pml[pmli]; + bool entry_new = false; + if(!entry.p) { + entry_new = true; + entry.value = pm_alloc(1); + entry.p = 1; + entry.rw = 1; + entry.us = 1; + pml[pmli] = entry; + } + pmle_t *table = (pmle_t*)(pm_tovirt(entry.paddr << PAGE_SHIFT)); + if(entry_new) memset(table, 0, PAGE_SIZE); + + s_state_cache.pmli[l] = pmli; + s_state_cache.pml[l] = table; + return table; +} + +static void +s_paging_cache_tables(page_directory_t *pd, uintptr_t virt) +{ + pmle_t *pml4 = pd->pml; + if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache)); + + pmle_t *pml3 = s_paging_fetch_table(pml4, 3, virt); + pmle_t *pml2 = s_paging_fetch_table(pml3, 2, virt); + pmle_t *pml1 = s_paging_fetch_table(pml2, 1, virt); +} + +static pmle_t* +s_paging_get_table(pmle_t *pt, size_t l, uintptr_t virt) +{ + if(pt == NULL) return NULL; + size_t pmli = s_paging_pmli(l, virt); + if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL) + return s_state_cache.pml[l]; + + pmle_t entry = pt[pmli]; + if(!entry.p) return NULL; + return (pmle_t*)(pm_tovirt(entry.paddr << PAGE_SHIFT)); +} + +page_mapping_t +vm_pd_mapping_get(page_directory_t *pd, uintptr_t addr) +{ + spinlock_acquire(pd->lock); + page_mapping_t mapping = { 0 }; + + pmle_t *pml4 = pd->pml; + if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache)); + + pmle_t *pml3 = s_paging_get_table(pml4, 3, addr); + pmle_t *pml2 = s_paging_get_table(pml3, 2, addr); + pmle_t *pml1 = s_paging_get_table(pml2, 1, addr); + if(pml1 == NULL) goto release_return; + + size_t pml1i = s_paging_pmli(0, addr); + pmle_t pml1e = pml1[pml1i]; + + mapping = (page_mapping_t) { + .phys = (pml1e.paddr << PAGE_SHIFT) & ~PAGE_MASK, + .pf = { + .present = pml1e.p, + .writeable = pml1e.rw, + .useraccess = pml1e.us, + .executable = !pml1e.xd + } + }; +release_return: + spinlock_release(pd->lock); + return mapping; +} + +page_mapping_t vm_mapping_get(uintptr_t addr) +{ return vm_pd_mapping_get(pd_current(), addr); } + +void +mem_set_mapping_as(page_directory_t *pd, page_mapping_t mapping, uintptr_t virt) +{ + spinlock_acquire(pd->lock); + s_paging_cache_tables(pd, virt); + pmle_t *pml1 = s_state_cache.pml[0]; + size_t pml1i = s_paging_pmli(0, virt); + + pml1[pml1i] = (pmle_t) { + .p = mapping.pf.present, + .rw = mapping.pf.writeable, + .us = mapping.pf.useraccess, + .xd = !mapping.pf.executable, + .paddr = mapping.phys >> PAGE_SHIFT + }; + spinlock_release(pd->lock); +} + +void mem_set_mapping(page_mapping_t mapping, uintptr_t virt) +{ mem_set_mapping_as(pd_current(), mapping, virt); } + +void +vm_pd_ensure(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg) +{ + spinlock_acquire(pd->lock); + from &= ~(PAGE_SIZE - 1); + to += (to % PAGE_SIZE > 0 ? (PAGE_SIZE - (to % PAGE_SIZE)) : 0); + + if(to < from) to = from; + size_t pages = (to - from) >> PAGE_SHIFT; + if(pages == 0) pages = 1; + for(size_t i = 0; i < pages; i++) { + uintptr_t waddr = from + (i << PAGE_SHIFT); + s_paging_cache_tables(pd, waddr); + pmle_t *pml1 = s_state_cache.pml[1]; + size_t pml1i = s_paging_pmli(0, waddr); + + if(!pml1[pml1i].p) { + physptr_t phys = pm_alloc(1); + pml1[pml1i] = (pmle_t) { + .p = flg.present, + .rw = flg.writeable, + .us = flg.useraccess, + .xd = !flg.executable, + .paddr = phys >> PAGE_SHIFT + }; + } + } + spinlock_release(pd->lock); +} + +void vm_ensure(uintptr_t from, uintptr_t to, page_flags_t flg) +{ vm_pd_ensure(pd_current(), from, to, flg); } diff --git a/arch/x86_64/page.h b/arch/x86_64/page.h new file mode 100644 index 0000000..28dfad2 --- /dev/null +++ b/arch/x86_64/page.h @@ -0,0 +1,28 @@ +#ifndef JOVE_ARCH_x86_64_PAGING_H +#define JOVE_ARCH_x86_64_PAGING_H 1 + +#include + +typedef union PageMappingLevelEntry +{ + struct { + uint8_t p : 1; /* Present */ + uint8_t rw : 1; /* Read/write. 0 for RO.*/ + uint8_t us : 1; /* User/supervisor. 0 for DPL3 forbid */ + uint8_t pwt : 1; + uint8_t pcd : 1; + uint8_t a : 1; /* Accessed */ + uint8_t d : 1; /* Dirty */ + uint8_t ps_pat : 1; + uint8_t g : 1; /* Global */ + uint8_t _r0 : 2; + uint8_t r : 1; + uint64_t paddr : 35; + uint8_t _r1; + uint8_t pk : 4; + uint8_t xd : 1; + }__attribute__((packed)); + uint64_t value; +} __attribute__((packed)) pmle_t; + +#endif diff --git a/arch/x86_64/pagedirectory.c b/arch/x86_64/pagedirectory.c new file mode 100644 index 0000000..cdfffeb --- /dev/null +++ b/arch/x86_64/pagedirectory.c @@ -0,0 +1,138 @@ +#include "arch/page.h" +#include "arch/processor.h" +#include "klib/rbtree.h" +#include "boot.h" +#include "memory.h" +#include "string.h" +#include "print.h" + +PAGEALIGN static uint64_t s_kernel_initial_pml4[512]; +PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512]; +PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512]; +PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512]; +static page_directory_t s_kernel_initial_pd; + +static rbtree_t s_page_directories; +static intmax_t s_next_pdid = 0; + +page_directory_t* +pd_new() +{ + page_directory_t newpd = { + .id = s_next_pdid++, + .phys = pm_alloc(1), + }; + newpd.pml = (void*)pm_tovirt(newpd.phys); + for(size_t i = 256; i < 512; i++) { + pmle_t *kpe = &(s_kernel_initial_pd.pml)[i]; + pmle_t *ppe = &(newpd.pml)[i]; + *ppe = *kpe; + } + + return rbtree_insert(&s_page_directories, newpd.id, &newpd); +} + +static void +s_pd_dup_pml(pmle_t *src, pmle_t *dest, size_t l, size_t i) +{ + pmle_t srce = src[i]; + if(!srce.p) return; + + dest[i] = srce; + dest[i].paddr = pm_alloc(1); + pmle_t dste = dest[i]; + + pmle_t *srct = (pmle_t*)pm_tovirt(srce.paddr << PAGE_SHIFT); + pmle_t *dstt = (pmle_t*)pm_tovirt(dste.paddr << PAGE_SHIFT); + + if(l == 0) { + memcpy(dstt, srct, PAGE_SIZE); + return; + } + + for(i = 0; i < 512; i++) { + dstt[i] = srct[i]; + if(!srct[i].p) continue; + s_pd_dup_pml(srct, dstt, l - 1, i); + } +} + +page_directory_t* +pd_dup(page_directory_t *pd) +{ + page_directory_t *newpd = pd_new(); + for(size_t i = 0; i < 256; i++) { + s_pd_dup_pml(pd->pml, newpd->pml, 3, i); + } + return newpd; +} + +page_directory_t* +pd_get(pdid_t pdid) +{ + return rbtree_find(&s_page_directories, pdid); +} + +void +pd_switch(page_directory_t *pd) +{ + processor_t *pc = processor_current(); + if(pc->pd == pd) return; + pc->pd = pd; + __asm__ volatile("movq %0, %%cr3":: "r"(pd->phys)); +} + +void +vm_setup_early(void) +{ + memset(s_kernel_initial_pml4, 0, PAGE_SIZE); + memset(s_kernel_initial_pml3, 0, 2 * PAGE_SIZE); + memset(s_kernel_initial_pml2, 0, 2 * PAGE_SIZE); + memset(s_kernel_initial_pml1, 0, PAGE_SIZE); + s_kernel_initial_pd = (page_directory_t){ + .phys = vm_tophys_koff((uintptr_t)&s_kernel_initial_pml4), + .pml = (pmle_t*)&s_kernel_initial_pml4, + .id = s_next_pdid++ + }; + processor_current()->pd = &s_kernel_initial_pd; + + /* Map first few GiBs */ + s_kernel_initial_pml4[256] = + vm_tophys_koff((uintptr_t)&s_kernel_initial_pml3[0]) + | 3; + s_kernel_initial_pml3[0][0] = + vm_tophys_koff((uintptr_t)&s_kernel_initial_pml2[0]) + | 3; + for(int i = 0; i < 512; i++) { + s_kernel_initial_pml2[0][i] = (i * (PAGE_SIZE * 512)) | 0x80 | 3; + } + + size_t kernel_pml3e = (_kernel_virtual_base >> (30)) % 512; + size_t kernel_pml2e = (_kernel_virtual_base >> (21)) % 512; + size_t kernel_npages = ((((uintptr_t)&_kernel_end) - _kernel_virtual_base) >> 12) + 1; + klogf("Kernel has %i pages\n", kernel_npages); + + /* Map kernel pages */ + s_kernel_initial_pml4[511] = + vm_tophys_koff((uintptr_t)&s_kernel_initial_pml3[1]) | 3; + s_kernel_initial_pml3[1][kernel_pml3e] = + vm_tophys_koff((uintptr_t)&s_kernel_initial_pml2[1]) | 3; + s_kernel_initial_pml2[1][kernel_pml2e] = + vm_tophys_koff((uintptr_t)&s_kernel_initial_pml1[0]) | 3; + for(size_t i = 0; i < kernel_npages; i++) { + s_kernel_initial_pml1[0][i] = (i * PAGE_SIZE) + boot_kernel_physical_address | 3; + } + + extern int_state_t *_pagefault_handler(int_state_t*); + int_handler_set(14, _pagefault_handler); + __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.phys)); +} + +void +vm_setup(void) +{ + rbtree_new(&s_page_directories, page_directory_t); + + processor_t *proc = processor_current(); + pd_switch(pd_new()); +} diff --git a/arch/x86_64/pagefault.c b/arch/x86_64/pagefault.c new file mode 100644 index 0000000..5bba20b --- /dev/null +++ b/arch/x86_64/pagefault.c @@ -0,0 +1,39 @@ +#include "arch/x86_64/idt.h" +#include "arch/processor.h" +#include "memory.h" +#include "print.h" +#include "jove.h" + +#include + +int_state_t* +_pagefault_handler(int_state_t *state) +{ + extern uint64_t __isr_err; + + uintptr_t fault_addr = 0; + __asm__ volatile("movq %%cr2, %0": "=r"(fault_addr)); + + if(fault_addr < USERLAND_MEMORY_LIMIT) { + // Check if there is an entry in the exception return table. + processor_t *proc = processor_current(); + if(proc->ert_i > 0) { + state->ip = (uintptr_t)_exrtab_pop(); + return state; + } + } + + bool present = __isr_err & 1; + bool write = __isr_err & 2; + bool user = __isr_err & 4; + + klogf("Page fault at %016X\n", fault_addr); + klogf("%s %s from a %s address\n", + user ? "user" : "kernel", + write ? "wrote" : "read", + present ? "present" : "non-present"); + + int_state_print(state); + kpanic("Unhandled page fault\n"); + return state; +} diff --git a/arch/x86_64/paging.c b/arch/x86_64/paging.c deleted file mode 100644 index dc27ca2..0000000 --- a/arch/x86_64/paging.c +++ /dev/null @@ -1,257 +0,0 @@ -#include "paging.h" -#include "interrupt.h" -#include "io/log.h" -#include "lib/jove.h" -#include "lib/string.h" -#include "lib/hashtable.h" -#include "mem/memory.h" -#include "boot/boot.h" - -extern void *_kernel_end; - -PAGEALIGN static uint64_t s_kernel_initial_pml4[512]; -PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512]; -PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512]; -PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512]; -static intmax_t s_next_pdid = 0; -static page_directory_t s_kernel_initial_pd; - -page_directory_t *current_page_directory; - -struct PageStateCache { - page_directory_t *pd; - size_t pmli[4]; - pmle_t *pml[4]; -} s_state_cache; - -physptr_t -mem_linear_tophys_koffset(uintptr_t virt) -{ - return (virt - boot_kernel_virtual_base) + boot_kernel_physical_address; -} - -uintptr_t -mem_phys_tolinear(physptr_t phys) -{ - return (uintptr_t)(phys + 0xFFFF800000000000ULL); -} - -static size_t -s_paging_pmli(size_t l, uintptr_t addr) -{ - size_t shift = (12 + (9 * l)); - return (addr & (0x1FFULL << shift)) >> shift; -} - -static pmle_t* -s_paging_fetch_table(pmle_t *pml, size_t l, uintptr_t virt) -{ - size_t pmli = s_paging_pmli(l, virt); - if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL) - return s_state_cache.pml[l]; - - pmle_t entry = pml[pmli]; - bool entry_new = false; - if(!entry.p) { - entry_new = true; - entry.value = mem_phys_alloc(1); - entry.p = 1; - entry.rw = 1; - entry.us = 1; - pml[pmli] = entry; - } - pmle_t *table = (pmle_t*)(mem_phys_tolinear(entry.paddr << 12)); - if(entry_new) memset(table, 0, PAGE_SIZE); - - s_state_cache.pmli[l] = pmli; - s_state_cache.pml[l] = table; - return table; -} - -static void -s_paging_cache_tables(page_directory_t *pd, uintptr_t virt) -{ - pmle_t *pml4 = (pmle_t*)pd->virt; - if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache)); - - pmle_t *pml3 = s_paging_fetch_table(pml4, 3, virt); - pmle_t *pml2 = s_paging_fetch_table(pml3, 2, virt); - pmle_t *pml1 = s_paging_fetch_table(pml2, 1, virt); -} - -static pmle_t* -s_paging_get_table(pmle_t *pt, size_t l, uintptr_t virt) -{ - if(pt == NULL) return NULL; - size_t pmli = s_paging_pmli(l, virt); - if(s_state_cache.pmli[l] == pmli && s_state_cache.pml[l] != NULL) - return s_state_cache.pml[l]; - - pmle_t entry = pt[pmli]; - if(!entry.p) return NULL; - return (pmle_t*)(mem_phys_tolinear(entry.paddr << 12)); -} - -page_mapping_t -mem_get_mapping_as(page_directory_t *pd, uintptr_t addr) -{ - spinlock_acquire(pd->lock); - page_mapping_t mapping = { 0 }; - - pmle_t *pml4 = (pmle_t*)pd->virt; - if(s_state_cache.pd != pd) memset(&s_state_cache, 0, sizeof(s_state_cache)); - - pmle_t *pml3 = s_paging_get_table(pml4, 3, addr); - pmle_t *pml2 = s_paging_get_table(pml3, 2, addr); - pmle_t *pml1 = s_paging_get_table(pml2, 1, addr); - if(pml1 == NULL) goto release_return; - - size_t pml1i = s_paging_pmli(0, addr); - pmle_t pml1e = pml1[pml1i]; - - mapping = (page_mapping_t) { - .phys = (pml1e.paddr << 12) & ~PAGE_MASK, - .pf = { - .present = pml1e.p, - .writeable = pml1e.rw, - .useraccess = pml1e.us, - .executable = !pml1e.xd - } - }; -release_return: - spinlock_release(pd->lock); - return mapping; -} - -page_mapping_t mem_get_mapping(uintptr_t addr) -{ return mem_get_mapping_as(current_page_directory, addr); } - - -bool -mem_check_ptr(const void *ptr) -{ - return mem_get_mapping((uintptr_t)ptr).pf.present != 0; -} - -void -mem_set_mapping_as(page_directory_t *pd, page_mapping_t mapping, uintptr_t virt) -{ - spinlock_acquire(pd->lock); - s_paging_cache_tables(pd, virt); - pmle_t *pml1 = s_state_cache.pml[0]; - size_t pml1i = s_paging_pmli(0, virt); - - pml1[pml1i] = (pmle_t) { - .p = mapping.pf.present, - .rw = mapping.pf.writeable, - .us = mapping.pf.useraccess, - .xd = !mapping.pf.executable, - .paddr = mapping.phys >> 12 - }; - spinlock_release(pd->lock); -} - -void mem_set_mapping(page_mapping_t mapping, uintptr_t virt) -{ mem_set_mapping_as(current_page_directory, mapping, virt); } - -void -mem_ensure_range_as(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg) -{ - spinlock_acquire(pd->lock); - from &= ~(PAGE_SIZE - 1); - - if(to < from) to = from; - size_t pages = (to - from) >> 12; - if(pages == 0) pages = 1; - for(size_t i = 0; i < pages; i++) { - uintptr_t waddr = from + (i << 12); - s_paging_cache_tables(pd, waddr); - pmle_t *pml1 = s_state_cache.pml[1]; - size_t pml1i = s_paging_pmli(0, waddr); - - if(!pml1[pml1i].p) { - physptr_t phys = mem_phys_alloc(1); - pml1[pml1i] = (pmle_t) { - .p = flg.present, - .rw = flg.writeable, - .us = flg.useraccess, - .xd = !flg.executable, - .paddr = phys >> 12 - }; - } - } - spinlock_release(pd->lock); -} - -void mem_ensure_range(uintptr_t from, uintptr_t to, page_flags_t flg) -{ mem_ensure_range_as(current_page_directory, from, to, flg); } - -struct Registers* -s_pagefault_handler(struct Registers *state) -{ - extern uint64_t __isr_err; - - uintptr_t fault_addr = 0; - __asm__ volatile("movq %%cr2, %0": "=r"(fault_addr)); - - bool present = __isr_err & 1; - bool write = __isr_err & 2; - bool user = __isr_err & 4; - bool fetch = __isr_err & 16; - - klogf("Page fault at %016X\n", fault_addr); - klogf("%s %s from a %s address\n", - user ? "user" : "kernel", - write ? "wrote" : "read", - present ? "present" : "non-present"); - - kpanic("Unhandled page fault at %016X\n", state->ip); - return state; -} - -void -mem_paging_setup(void) -{ - memset(s_kernel_initial_pml4, 0, PAGE_SIZE); - memset(s_kernel_initial_pml3, 0, 2 * PAGE_SIZE); - memset(s_kernel_initial_pml2, 0, 2 * PAGE_SIZE); - memset(s_kernel_initial_pml1, 0, PAGE_SIZE); - s_kernel_initial_pd = (page_directory_t){ - .phys = mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml4), - .virt = (union PageEntry*)&s_kernel_initial_pml4, - .ref = 1, - .id = s_next_pdid++ - }; - current_page_directory = &s_kernel_initial_pd; - - /* Map first few GiBs */ - s_kernel_initial_pml4[256] = - mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[0]) - | 3; - s_kernel_initial_pml3[0][0] = - mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[0]) - | 3; - for(int i = 0; i < 512; i++) { - s_kernel_initial_pml2[0][i] = (i * (PAGE_SIZE * 512)) | 0x80 | 3; - } - - size_t kernel_pml4e = (boot_kernel_virtual_base >> (39)); - size_t kernel_pml3e = (boot_kernel_virtual_base >> (30)) % 512; - size_t kernel_pml2e = (boot_kernel_virtual_base >> (21)) % 512; - size_t kernel_npages = ((((uintptr_t)&_kernel_end) - boot_kernel_virtual_base) >> 12) + 1; - klogf("Kernel has %i pages\n", kernel_npages); - - /* Map kernel pages */ - s_kernel_initial_pml4[511] = - mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[1]) | 3; - s_kernel_initial_pml3[1][kernel_pml3e] = - mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[1]) | 3; - s_kernel_initial_pml2[1][kernel_pml2e] = - mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml1[0]) | 3; - for(int i = 0; i < kernel_npages; i++) { - s_kernel_initial_pml1[0][i] = (i * PAGE_SIZE) + boot_kernel_physical_address | 3; - } - - int_set_handler(14, s_pagefault_handler); - __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.phys)); -} diff --git a/arch/x86_64/paging.h b/arch/x86_64/paging.h deleted file mode 100644 index 28dfad2..0000000 --- a/arch/x86_64/paging.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef JOVE_ARCH_x86_64_PAGING_H -#define JOVE_ARCH_x86_64_PAGING_H 1 - -#include - -typedef union PageMappingLevelEntry -{ - struct { - uint8_t p : 1; /* Present */ - uint8_t rw : 1; /* Read/write. 0 for RO.*/ - uint8_t us : 1; /* User/supervisor. 0 for DPL3 forbid */ - uint8_t pwt : 1; - uint8_t pcd : 1; - uint8_t a : 1; /* Accessed */ - uint8_t d : 1; /* Dirty */ - uint8_t ps_pat : 1; - uint8_t g : 1; /* Global */ - uint8_t _r0 : 2; - uint8_t r : 1; - uint64_t paddr : 35; - uint8_t _r1; - uint8_t pk : 4; - uint8_t xd : 1; - }__attribute__((packed)); - uint64_t value; -} __attribute__((packed)) pmle_t; - -#endif diff --git a/arch/x86_64/processor.c b/arch/x86_64/processor.c new file mode 100644 index 0000000..44d437a --- /dev/null +++ b/arch/x86_64/processor.c @@ -0,0 +1,40 @@ +#include "arch/processor.h" +#include "arch/cpu.h" +#include "arch/x86_64/msr.h" + +processor_t s_processors[PROCESSOR_MAX]; +processor_t *proc_bsp = &s_processors[0]; + +extern void x86_64_lgdt(struct XDTR *gdtr); +extern void x86_64_flush_tss(void); +extern void x86_64_lidt(struct XDTR *idtr); + +extern void gdt_setup(processor_t*); +extern void tss_setup(processor_t*); +extern void idt_setup(processor_t*); + +void +processor_setup(processor_t *proc) +{ + gdt_setup(proc); + tss_setup(proc); + idt_setup(proc); + + x86_64_lgdt(&proc->_gdtr); + x86_64_lidt(&proc->_idtr); + x86_64_flush_tss(); + + msr_gsbase_write((uintptr_t)proc); +} + +processor_t* +processor_list(void) +{ + return s_processors; +} + +processor_t* +processor_current(void) +{ + return (processor_t*)msr_gsbase_read(); +} diff --git a/arch/x86_64/restore.S b/arch/x86_64/restore.S new file mode 100644 index 0000000..f4aa939 --- /dev/null +++ b/arch/x86_64/restore.S @@ -0,0 +1,20 @@ +.global _arch_context_restore +.type _arch_context_restore @function +_arch_context_restore: + movq %rdi, %rsp + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rbp + popq %rdi + popq %rsi + popq %rdx + popq %rcx + popq %rbx + popq %rax + retq diff --git a/arch/x86_64/savestate.S b/arch/x86_64/savestate.S deleted file mode 100644 index c89933b..0000000 --- a/arch/x86_64/savestate.S +++ /dev/null @@ -1,39 +0,0 @@ -.global saveregs -.type saveregs @function -saveregs: - pushq %rax - pushq %rbx - pushq %rcx - pushq %rdx - pushq %rsi - pushq %rdi - pushq %rbp - pushq %r8 - pushq %r9 - pushq %r10 - pushq %r11 - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - retq - -.global loadregs -.type loadregs @function -loadregs: - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %r11 - popq %r10 - popq %r9 - popq %r8 - popq %rbp - popq %rdi - popq %rsi - popq %rdx - popq %rcx - popq %rbx - popq %rax - diff --git a/arch/x86_64/serial.c b/arch/x86_64/serial.c deleted file mode 100644 index 1b49e3f..0000000 --- a/arch/x86_64/serial.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "serial.h" -#include "uart.h" -#include "io/log.h" - -static struct LogDevice s_serial_logdev = - { .out = serial_out, .chain = NULL }; - -bool serial_supported = true; - -void -serial_setup(void) -{ - /* Disable interrupts. */ - poutb(SERIAL_UART_COM_IER(SERIAL_UART_COM1), 0x0); - /* Enable DLAB. */ - poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 0x80); - /* Set divisor to 3 (38400 baud)*/ - poutb(SERIAL_UART_COM_DLAB_DLL(SERIAL_UART_COM1), 3); - poutb(SERIAL_UART_COM_DLAB_DLH(SERIAL_UART_COM1), 0); - /* Set flags for LCR (8 bits, no parity, one stop)*/ - poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 1 | 2); - /* Enable & clear FIFO, 14-byte threshold */ - poutb(SERIAL_UART_COM_FCR(SERIAL_UART_COM1), 1 | 2 | 4 | 0xC0); - /* Enable interrupts, set RTS/DSR. */ - poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 8); - /* Set loopback mode for testing. */ - poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 2 | 4 | 8 | 0x10); - /* Test serial output. */ - poutb(SERIAL_UART_COM1, 0xAE); - if(pinb(SERIAL_UART_COM1) != 0xAE) { - serial_supported = false; - return; - } - - /* Serial is not faulty. - * No loopback, enable output 1 & 2.*/ - poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 4 | 8); - - klog_newdev(&s_serial_logdev); -} - -static ALWAYS_INLINE bool -serial_transmit_empty(uint16_t com) -{ - return pinb(SERIAL_UART_COM_LSR(com) & 0x20); -} - -static inline void -serial_outb(uint16_t com, uint8_t b) -{ - if(b == '\n') serial_outb(com, '\r'); - while(!serial_transmit_empty(SERIAL_UART_COM1)); - poutb(com, b); -} - -void -serial_out(const char *s, size_t len) -{ - if(!serial_supported) return; - for(; len > 0; len--) - serial_outb(SERIAL_UART_COM1, *(s++)); -} diff --git a/arch/x86_64/serial.h b/arch/x86_64/serial.h deleted file mode 100644 index ecb896d..0000000 --- a/arch/x86_64/serial.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef JOVE_KERNEL_ARCH_x86_64_SERIAL_H -#define JOVE_KERNEL_ARCH_x86_64_SERIAL_H 1 - -#include -#include - -#define SERIAL_UART_COM1 0x3F8 -#define SERIAL_UART_COM2 0x2F8 - -#define SERIAL_UART_COM_THR(COM) COM -#define SERIAL_UART_COM_RBR(COM) COM -#define SERIAL_UART_COM_DLAB_DLL(COM) COM -#define SERIAL_UART_COM_IER(COM) (COM + 1) -#define SERIAL_UART_COM_DLAB_DLH(COM) (COM + 1) -#define SERIAL_UART_COM_IIR(COM) (COM + 2) -#define SERIAL_UART_COM_FCR(COM) (COM + 2) -#define SERIAL_UART_COM_LCR(COM) (COM + 3) -#define SERIAL_UART_COM_MCR(COM) (COM + 4) -#define SERIAL_UART_COM_LSR(COM) (COM + 5) -#define SERIAL_UART_COM_MSR(COM) (COM + 6) -#define SERIAL_UART_COM_SR(COM) (COM + 7) - -extern bool serial_supported; - -void serial_out(const char *s, size_t len); - -#endif diff --git a/arch/x86_64/syscall.c b/arch/x86_64/syscall.c deleted file mode 100644 index 0398f11..0000000 --- a/arch/x86_64/syscall.c +++ /dev/null @@ -1 +0,0 @@ -#include "usr/umode.h" diff --git a/arch/x86_64/syscall_entry.c b/arch/x86_64/syscall_entry.c new file mode 100644 index 0000000..56dedce --- /dev/null +++ b/arch/x86_64/syscall_entry.c @@ -0,0 +1,25 @@ +#include "arch/processor.h" +#include "syscall/handler.h" + +__attribute__((naked)) +void _syscall_entry() +{ + __asm__ volatile(" \ + pushq %%r11; \ + pushq %%rcx; \ + swapgs; \ + movq %%gs:%c[tcb], %%rax; \ + movq %%rsp, %c[sp](%%rax); \ + movq %c[ksp](%%rax), %%rsp; \ + pushq %c[sp](%%rax); \ + callq _syscall_handler; \ + swapgs; \ + popq %%rsp; \ + popq %%rcx; \ + popq %%r11; \ + sysretq; \ + " + :: [tcb] "i"(offsetof(processor_t, tcb)), + [sp] "i"(offsetof(tcb_t, sp)), + [ksp] "i"(offsetof(tcb_t, ksp))); +} diff --git a/arch/x86_64/syscall_setup.S b/arch/x86_64/syscall_setup.S deleted file mode 100644 index 4f5c6f0..0000000 --- a/arch/x86_64/syscall_setup.S +++ /dev/null @@ -1,41 +0,0 @@ -.extern _kernel_task_sp -.extern syscall_handler - -.global syscall_entry -.type syscall_entry @function -syscall_entry: - swapgs - movq %rsp, %rax - movq _kernel_task_bp, %rsp - pushq %rax - pushq %rbp - pushq %rcx - pushq %r11 - call syscall_handler - popq %r11 - popq %rcx - popq %rbp - popq %rsp - swapgs - sysretq - -.global syscall_setup_syscall -.type syscall_setup_syscall @function -syscall_setup_syscall: - movq $0xc0000080, %rcx - rdmsr - or $1, %eax - wrmsr - - movq $0xc0000081, %rcx - rdmsr - mov $0x001b0008, %edx - wrmsr - - movq $0xc0000082, %rcx - leaq syscall_entry, %rdx - mov %edx, %eax - shr $32, %rdx - wrmsr - - retq diff --git a/arch/x86_64/tables.c b/arch/x86_64/tables.c deleted file mode 100644 index f530089..0000000 --- a/arch/x86_64/tables.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "tables.h" - -void -arch_tables_setup(void) -{ - x86_64_load_gdt(); - x86_64_load_idt(); -} diff --git a/arch/x86_64/tables.h b/arch/x86_64/tables.h deleted file mode 100644 index e160c66..0000000 --- a/arch/x86_64/tables.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef JOVE_ARCH_X86_64_TABLES_H -#define JOVE_ARCH_X86_64_TABLES_H 1 - -#include - -#define CD_SEGMENT_TYPE_ACCESSED 1 -#define CD_SEGMENT_TYPE_WRITEABLE 2 -#define CD_SEGMENT_TYPE_DATA_EXPAND_DOWN 4 -#define CD_SEGMENT_TYPE_CODE_CONFORMING 4 -#define CD_SEGMENT_TYPE_CODE 8 - -#define S_SEGMENT_TYPE_LDT 2 -#define S_SEGMENT_TYPE_TSS_AVAIL 9 -#define S_SEGMENT_TYPE_TSS_BUSY 11 -#define S_SEGMENT_TYPE_CALLGATE 12 -#define S_SEGMENT_TYPE_INT_GATE 14 -#define S_SEGMENT_TYPE_TRAP_GATE 15 - -struct SegmentDescriptor -{ - uint16_t limit_0_15; /* Segment limit. */ - uint16_t base_0_15; /* Segment base. */ - uint8_t base_16_23; - uint8_t type : 4; /* Segment type. */ - uint8_t s : 1; /* Descriptor type (0 = system, 1 = code/data)*/ - uint8_t dpl : 2; /* Descriptor privilege level. */ - uint8_t p : 1; ; /* Present. */ - uint8_t limit_16_19 : 4; - uint8_t avl : 1; /* Available for use by system software. */ - uint8_t l : 1; /* 64-bit segment (Ext). */ - uint8_t d_b : 1; /* Default operation size (0 = 16-bit, 1 = 32-bit)*/ - uint8_t g : 1; /* Granularity. */ - uint8_t base_24_31; -}__attribute__((packed)); - -struct InterruptTrapGate -{ - uint16_t base_0_15; - uint16_t segment_selector; - uint8_t ist : 3; - uint8_t zero_0 : 5; - uint8_t type : 4; - uint8_t zero_1 : 1; - uint8_t dpl : 2; - uint8_t p : 1; - uint16_t base_16_31; - uint32_t base_32_63; - uint32_t resv; -}__attribute__((packed)); - -struct XDTR /* Generic table descriptor struct */ -{ - uint16_t length; - uint64_t address; -}__attribute__((packed)); - -void x86_64_load_gdt(void); -void x86_64_load_idt(void); - -#endif diff --git a/arch/x86_64/tasking.c b/arch/x86_64/tasking.c deleted file mode 100644 index 9b29330..0000000 --- a/arch/x86_64/tasking.c +++ /dev/null @@ -1,86 +0,0 @@ -#include "usr/tasking.h" -#include "mem/memory.h" -#include "io/log.h" -#include "lib/hashtable.h" -#include "lib/string.h" -#include "paging.h" -#include "cpu.h" -#include "tss.h" - -struct TaskBody { - struct Task base; - struct Registers state; -}; - -struct Task *task_current; -uintptr_t _kernel_task_bp = 0; - -//static struct SLinkedList s_tasks; -static struct HashTable s_tasks; - -static struct SlabCache s_task_cache; -static struct SlabCache s_kbp_cache; - -static tid_t s_task_id_next = 1; - -static size_t -s_task_hash_func(const void* tid, size_t _) -{ - return (tid_t)tid; -} - -void -tasking_setup(void) -{ - hashtable_new(&s_tasks, struct TaskBody*, tid_t); - s_tasks.hash_function = s_task_hash_func; - - mem_slabcache_new(&s_task_cache, "tasks", sizeof(struct TaskBody)); - mem_slabcache_new(&s_kbp_cache, "kernel stacks", 4096); - - struct TaskBody *ktask = mem_slab_alloc(&s_task_cache); - *ktask = (struct TaskBody){ - .base.id = s_task_id_next++, - .base.kbp = ((uintptr_t)mem_slab_alloc(&s_kbp_cache)) + 0xFF0, - .base.perm = (size_t)-1, - .base.pd = current_page_directory - }; - hashtable_insert(&s_tasks, 0, ktask); - - task_current = (struct Task*)ktask; - tss_set_rsp(0, task_current->kbp); - _kernel_task_bp = task_current->kbp; -} - -struct Task* -task_new(struct Task *parent) -{ - struct TaskBody *new = mem_slab_alloc(&s_task_cache); - memcpy(new, parent, sizeof(struct TaskBody)); - new->base.id = s_task_id_next++; - - uintptr_t ksp_base = (uintptr_t)mem_slab_alloc(&s_kbp_cache); - new->base.kbp = ksp_base + 0xFFF; - new->base.perm = parent->perm; - - hashtable_insert(&s_tasks, (void*)new->base.id, new); - return (struct Task*)new; -} - -struct Task* -task_get(tid_t id) -{ - struct Task **task = hashtable_get(&s_tasks, (void*)id, struct Task*); - if(task == NULL) return NULL; - return *task; -} - -void -task_free(struct Task *task) -{ - struct TaskBody *body = (struct TaskBody*)task; - task->pd->ref--; - task->kbp -= 0xFFF; - mem_slab_free(&s_kbp_cache, (void*)(task->kbp)); - klogf("Need impl for task_free\n"); -} diff --git a/arch/x86_64/tcb_prepare.c b/arch/x86_64/tcb_prepare.c new file mode 100644 index 0000000..238d70d --- /dev/null +++ b/arch/x86_64/tcb_prepare.c @@ -0,0 +1,9 @@ +#include "tasking.h" + +void +tcb_prepare(tcb_t *tcb, void *ip) +{ + uintptr_t state[15] = { 0 }; + tcb_stack_push(tcb, &ip, sizeof(void*)); + tcb_stack_push(tcb, state, sizeof(state)); +} diff --git a/arch/x86_64/tcb_switch.c b/arch/x86_64/tcb_switch.c new file mode 100644 index 0000000..bc8808d --- /dev/null +++ b/arch/x86_64/tcb_switch.c @@ -0,0 +1,18 @@ +#include "tasking.h" +#include "arch/processor.h" + +extern void _arch_context_restore(uintptr_t rsp); + +void +tcb_switch(tcb_t *to) +{ + processor_t *proc = processor_current(); + tcb_t *from = proc->tcb; + + proc->tcb = to; + if(from != to) { + pd_switch(to->pd); + } + tss_set_rsp(&proc->_tss, 0, to->ksp); + _arch_context_restore(to->ksp); +} diff --git a/arch/x86_64/tss.h b/arch/x86_64/tss.h deleted file mode 100644 index dcdd01c..0000000 --- a/arch/x86_64/tss.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef JOVE_ARCH_x86_64_TSS_H -#define JOVE_ARCH_x86_64_TSS_H 1 - -#include -#include - -struct TSS -{ - uint32_t resv0; - uint32_t rsp[3][2]; - uint64_t resv1; - uint32_t ist[8][2]; - uint64_t resv2; - uint16_t resv3; - uint16_t iobp; -}; - -void tss_set_rsp(uint8_t dpl, uintptr_t rsp); - -#endif diff --git a/arch/x86_64/uart.h b/arch/x86_64/uart.h deleted file mode 100644 index 8386eb7..0000000 --- a/arch/x86_64/uart.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef JOVE_KERNEL_ARCH_x86_64_UART_H -#define JOVE_KERNEL_ARCH_x86_64_UART_H 1 - -#include "lib/jove.h" -#include - -ALWAYS_INLINE uint8_t pinb(uint16_t port) -{ - uint8_t v; - __asm__ volatile("inb %1, %0": "=a"(v): "Nd"(port)); - return v; -} - -ALWAYS_INLINE void poutb(uint16_t port, uint8_t b) -{ - __asm__ volatile("outb %0, %1":: "a"(b), "Nd"(port)); -} - -#endif diff --git a/arch/x86_64/umode_enter.S b/arch/x86_64/umode_enter.S deleted file mode 100644 index 29aa4e3..0000000 --- a/arch/x86_64/umode_enter.S +++ /dev/null @@ -1,8 +0,0 @@ -.global umode_enter -.type umode_enter @function -umode_enter: - movq %rdi, %rcx - movq %rsi, %rsp - movq $0x0202, %r11 - cli - sysretq diff --git a/arch/x86_64/umode_enter.c b/arch/x86_64/umode_enter.c new file mode 100644 index 0000000..3c7fa18 --- /dev/null +++ b/arch/x86_64/umode_enter.c @@ -0,0 +1,17 @@ +#include "tasking.h" + +__attribute__((noreturn)) +void +umode_enter(void *ip, void *sp) +{ + __asm__ volatile("mov %0, %%rsp; \ + push %%rcx; \ + mov %1, %%rcx; \ + mov $0x202, %%r11; \ + cli; \ + swapgs; \ + sysretq":: + "r"(sp), "r"(ip): + "memory"); + for(;;); +} diff --git a/arch/x86_64/vm_tophys.c b/arch/x86_64/vm_tophys.c new file mode 100644 index 0000000..2b16880 --- /dev/null +++ b/arch/x86_64/vm_tophys.c @@ -0,0 +1,23 @@ +#include "memory.h" +#include "boot.h" + +uintptr_t +pm_tovirt(physptr_t phys) +{ + if(phys < (1 * GiB)) + return (uintptr_t)(phys + PHYSMAP_MEMORY_BASE); + kpanic("Missing impl for physical addresses > 1GiB (%#016X)\n", + phys); +} + +physptr_t +vm_tophys(uintptr_t virt) +{ + return vm_mapping_get(virt).phys; +} + +physptr_t +vm_tophys_koff(uintptr_t virt) +{ + return (virt - _kernel_virtual_base) + boot_kernel_physical_address; +} diff --git a/boot/boot.h b/boot/boot.h deleted file mode 100644 index cfdfa68..0000000 --- a/boot/boot.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef JOVE_BOOT_H -#define JOVE_BOOT_H 1 - -#include -#include -#include - -struct MemoryMapEntry { - uintptr_t base; - size_t length; - bool usable; -}; - -#define MEMORY_MAP_MAX_ENTRIES 128 -struct MemoryMap { - size_t count; - struct MemoryMapEntry entries[MEMORY_MAP_MAX_ENTRIES]; -}; - -#define BOOT_MODULE_MAX_ENTRIES 4 -struct BootModule { - char *path; - char *cmdline; - size_t size; - uintptr_t addr; -}; - -#define KERNEL_INITIAL_STACK_WIDTH (0x1000 * 4) -extern void *boot_kernel_initial_stack_base; -extern uintptr_t boot_kernel_physical_address; -extern const char *boot_kernel_cmdline; - -extern struct MemoryMap boot_memorymap; - -extern struct BootModule boot_modules[BOOT_MODULE_MAX_ENTRIES]; -extern size_t boot_module_count; - -#define boot_kernel_virtual_base 0xFFFFFFFF80000000ULL - -#endif diff --git a/boot/cmdline.c b/boot/cmdline.c index aa6aa05..5a68466 100644 --- a/boot/cmdline.c +++ b/boot/cmdline.c @@ -1,15 +1,18 @@ -#include "cmdline.h" +#include "commandline.h" +#include "klib/hash.h" +#include "klib/rbtree.h" +#include "string.h" #include "boot.h" -#include "mem/memory.h" -#include "lib/string.h" -#include "io/log.h" +#include "memory.h" +#include "print.h" -static struct HashTable s_cmdline_kernel; +static rbtree_t s_cmdline_kernel; const char* cmdline_get(const char *key) { - const char** value = hashtable_get(&s_cmdline_kernel, key, const char*); + intmax_t hash = string_hash(key); + char** value = rbtree_find(&s_cmdline_kernel, hash); if(value == NULL) return NULL; return *value; } @@ -17,7 +20,7 @@ cmdline_get(const char *key) void cmdline_kernel_setup(void) { - hashtable_news(&s_cmdline_kernel, const char*); + rbtree_new(&s_cmdline_kernel, char*); size_t cmdi = 0; const char *cmdline = boot_kernel_cmdline; @@ -28,23 +31,23 @@ cmdline_kernel_setup(void) size_t keyi = cmdi; while(cmdline[keyi] != '=' && cmdline[keyi] != 0) keyi++; if(cmdline[keyi] == 0 || keyi == 0) { - klogf("kernel cmdline is empty or malformed; skipping.\n"); + kwarnf("kernel cmdline is empty or malformed; skipping.\n"); break; } size_t keylen = keyi - cmdi; - char *key = mem_alloc(keylen); + char *key = kmalloc(keylen); memcpy(key, &cmdline[cmdi], keylen); size_t valuei = keyi + 1; while(cmdline[valuei] != ' ' && cmdline[valuei] != 0) valuei++; size_t valuelen = (valuei - keyi) - 1; - char *value = mem_alloc(valuelen); + char *value = kmalloc(valuelen); if(valuelen != 0) memcpy(value, &cmdline[keyi + 1], valuelen); - klogf("%s = %s\n", key, value); - hashtable_insert(&s_cmdline_kernel, key, &value); + kdbgf("%s = %s\n", key, value); + rbtree_insert(&s_cmdline_kernel, string_hash(key), &value); cmdi = valuei + 1; } } diff --git a/boot/cmdline.h b/boot/cmdline.h deleted file mode 100644 index b1162b7..0000000 --- a/boot/cmdline.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef JOVE_BOOT_CMDLINE_H -#define JOVE_BOOT_CMDLINE_H 1 - -#include "lib/hashtable.h" - -const char *cmdline_get(const char *key); - -void cmdline_kernel_setup(void); - -#endif diff --git a/boot/limine/limine.c b/boot/limine/limine.c index 7cc50d0..14f85f5 100644 --- a/boot/limine/limine.c +++ b/boot/limine/limine.c @@ -1,5 +1,5 @@ #include "limine.h" -#include "boot/boot.h" +#include "boot.h" static char s_kernel_stack[KERNEL_INITIAL_STACK_WIDTH]; diff --git a/compile_flags.txt b/compile_flags.txt deleted file mode 100644 index 8a9f09e..0000000 --- a/compile_flags.txt +++ /dev/null @@ -1,4 +0,0 @@ --I. --ffreestanding --nostdlib --lgcc diff --git a/config.mk b/config.mk index 11ce9f4..e2a9836 100644 --- a/config.mk +++ b/config.mk @@ -10,7 +10,8 @@ CFLAGS = \ -fno-pie \ -fno-pic \ -g \ - -D$(TARGET_MACHINE) \ + -D__$(TARGET_MACHINE)__ \ + -Iinclude \ -I. LDFLAGS = -nostdlib \ @@ -20,5 +21,5 @@ LDFLAGS = -nostdlib \ ifeq "$(TARGET_MACHINE)" "x86_64" CFLAGS += -mno-red-zone \ -mcmodel=kernel \ - -MMD + -mfsgsbase endif diff --git a/device/processor.c b/device/processor.c new file mode 100644 index 0000000..5c4b500 --- /dev/null +++ b/device/processor.c @@ -0,0 +1,4 @@ +#include "arch/processor.h" + +page_directory_t *pd_current(void) { return processor_current()->pd; } +tcb_t *tcb_current(void) { return processor_current()->tcb; } diff --git a/device/serial.c b/device/serial.c new file mode 100644 index 0000000..5000e0e --- /dev/null +++ b/device/serial.c @@ -0,0 +1,77 @@ +#include "device/serial.h" +#include "device/uart.h" +#include "jove.h" + +serial_dev_t COM1; + +serial_dev_t +serial_new(uint16_t com) +{ + serial_dev_t dev = { .com = com }; + serial_set_int(&dev, false); + serial_set_baud(&dev, 3); + serial_set_lcr(&dev, 1 | 2); + serial_set_fcr(&dev, 1 | 2 | 4 | 0xC0); + serial_set_fcr(&dev, 1 | 2 | 8); + serial_set_mcr(&dev, 1 | 2 | 4 | 8); + return dev; +} + +void +serial_set_int(serial_dev_t *dev, bool enable) +{ + poutb(SERIAL_UART_COM_IER(dev->com), enable); +} + +void +serial_set_baud(serial_dev_t *dev, uint16_t baud) +{ + /* Enable DLAB. */ + poutb(SERIAL_UART_COM_LCR(dev->com), SERIAL_UART_COM_LCR(dev->com) | 0x80); + /* Write low & high bits. */ + poutb(SERIAL_UART_COM_DLAB_DLL(dev->com), baud & 0xFF); + poutb(SERIAL_UART_COM_DLAB_DLH(dev->com), (baud >> 8) & 0xFF); + /* Disable DLAB. */ + poutb(SERIAL_UART_COM_LCR(dev->com), SERIAL_UART_COM_LCR(dev->com) & 0x7F); +} + +void +serial_set_fcr(serial_dev_t *dev, uint16_t flg) +{ + poutb(SERIAL_UART_COM_FCR(dev->com), flg); +} + +void +serial_set_lcr(serial_dev_t *dev, uint16_t flg) +{ + poutb(SERIAL_UART_COM_LCR(dev->com), flg); +} + +void +serial_set_mcr(serial_dev_t *dev, uint16_t flg) +{ + poutb(SERIAL_UART_COM_MCR(dev->com), flg); +} + +uint8_t +serial_line_status(serial_dev_t *dev) +{ + return pinb(SERIAL_UART_COM_LSR(dev->com)); +} + +void +serial_write(serial_dev_t *dev, const char *s, size_t len) +{ + for(; len > 0; len--) { + char c = *(s++); + while((serial_line_status(dev) & 0x20) == 0) {} + if(c == '\n') poutb(dev->com, '\r'); + poutb(dev->com, c); + } +} + +void +serial_setup(void) +{ + COM1 = serial_new(SERIAL_UART_COM1); +} diff --git a/include/api/errno.h b/include/api/errno.h new file mode 100644 index 0000000..51921d2 --- /dev/null +++ b/include/api/errno.h @@ -0,0 +1,9 @@ +#ifndef _JOVE_ERRNO_H +#define _JOVE_ERRNO_H 1 + +enum { + EFAIL = 1, + EACCESS +}; + +#endif diff --git a/include/api/syscall.h b/include/api/syscall.h new file mode 100644 index 0000000..eb4235d --- /dev/null +++ b/include/api/syscall.h @@ -0,0 +1,39 @@ +#ifndef _JOVE_API_SYSCALL_H +#define _JOVE_API_SYSCALL_H 1 + +#include +#include + +typedef intmax_t syscall_id_t; + +static int __syscall(void *data) +{ + intmax_t r; + __asm__ volatile(" \ + movq %1, %%rdi; \ + syscall; \ + movq %%rax, %0" + : "=r"(r) + : "r"(data)); + return r; +} + +enum { + SC_DBG_LOGF = 0, + SC_EXIT +}; + +struct sc_dbg_log +{ + syscall_id_t id; + size_t w; + const char *s; +}; + +struct sc_exit +{ + syscall_id_t id; + int exit_code; +}; + +#endif diff --git a/include/arch/cpu.h b/include/arch/cpu.h new file mode 100644 index 0000000..fe89dc0 --- /dev/null +++ b/include/arch/cpu.h @@ -0,0 +1,14 @@ +#ifndef _JOVE_ARCH_CPU_H +#define _JOVE_ARCH_CPU_H 1 + +#ifdef __x86_64__ +#include "x86_64/cpu.h" +#endif + +void cpu_setup(void); + +void cpu_set_syscall_entry(void *entry); + +void umode_enter(void *ip, void *sp); + +#endif diff --git a/include/arch/elf.h b/include/arch/elf.h new file mode 100644 index 0000000..1b8c3dc --- /dev/null +++ b/include/arch/elf.h @@ -0,0 +1,12 @@ +#ifndef _JOVE_ARCH_ELF_H +#define _JOVE_ARCH_ELF_H 1 + +#ifdef __x86_64__ +#include "x86_64/elf.h" +#endif + +#include + +uintptr_t elf_load(const void *data, size_t len); + +#endif diff --git a/include/arch/page.h b/include/arch/page.h new file mode 100644 index 0000000..25c5294 --- /dev/null +++ b/include/arch/page.h @@ -0,0 +1,34 @@ +#ifndef _JOVE_ARCH_PAGE_H +#define _JOVE_ARCH_PAGE_H 1 + +#define PAGE_SHIFT (12) +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (PAGE_SIZE - 1) + +#ifdef __x86_64__ +#include "x86_64/page.h" +#endif + +typedef struct page_mapping_flags +{ + char present : 1; + char writeable : 1; + char useraccess : 1; + char executable : 1; +} page_flags_t; + +typedef struct page_mapping +{ + uintptr_t phys; + page_flags_t pf; +} page_mapping_t; + +typedef intmax_t pdid_t; + +page_directory_t *pd_new(void); +page_directory_t *pd_dup(page_directory_t *pd); +page_directory_t *pd_get(pdid_t id); + +void pd_switch(page_directory_t *pd); + +#endif diff --git a/include/arch/processor.h b/include/arch/processor.h new file mode 100644 index 0000000..871e5c7 --- /dev/null +++ b/include/arch/processor.h @@ -0,0 +1,39 @@ +#ifndef _JOVE_ARCH_PROCESSOR_H +#define _JOVE_ARCH_PROCESSOR_H 1 + +#ifdef __x86_64__ +#include "x86_64/processor.h" +#endif + +#include "memory.h" +#include "tasking.h" +#include "klib/spinlock.h" + +#define _EXRTAB_C (PAGE_SIZE / sizeof(uintptr_t)) + +typedef struct processor +{ + ARCH_SPECIFIC_PROCESSOR_MEMBERS; + unsigned int id; + unsigned int isr_depth; + page_directory_t *pd; + tcb_t *tcb; + + uintptr_t exrtab[_EXRTAB_C]; + size_t ert_i; +} processor_t; + +extern processor_t *proc_bsp; + +void processor_setup(processor_t *proc); + +processor_t *processor_list(void); + +processor_t *processor_current(void); +page_directory_t *pd_current(void); +tcb_t *tcb_current(void); + +void _exrtab_push(void *v); +void *_exrtab_pop(void); + +#endif diff --git a/include/arch/x86_64/cpu.h b/include/arch/x86_64/cpu.h new file mode 100644 index 0000000..6e467c1 --- /dev/null +++ b/include/arch/x86_64/cpu.h @@ -0,0 +1,6 @@ +#ifndef _JOVE_x86_64_CPU_H +#define _JOVE_x86_64_CPU_H 1 + +void cpu_arch_enable_sce(void); + +#endif diff --git a/include/arch/x86_64/elf.h b/include/arch/x86_64/elf.h new file mode 100644 index 0000000..1aaf116 --- /dev/null +++ b/include/arch/x86_64/elf.h @@ -0,0 +1,93 @@ +#ifndef _JOVE_x86_64_ELF_H +#define _JOVE_x86_64_ELF_H 1 + +#include + +#define EI_MAG0 0x7F +#define EI_MAG1 'E' +#define EI_MAG2 'L' +#define EI_MAG3 'F' + +#define EI_CLASS_32 1 +#define EI_CLASS_64 2 + +#define EI_DATA_LE 1 +#define EI_DATA_BE 2 + +#define EI_VERSION_CURRENT 1 + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 + +typedef struct elf64_file_header +{ + union { + struct { + uint8_t ei_mag[4]; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_osabi; + uint8_t ei_abiver; + uint8_t ei_pad[7]; + }; + uint8_t e_ident[16]; + }; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} elf_header_t; + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 + +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 + +typedef struct elf64_program_header +{ + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} elf_phdr_t; + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 + +typedef struct elf64_section_header +{ + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint64_t sh_addralign; + uint64_t sh_entsize; +} elf_shdr_t; + +#endif diff --git a/include/arch/x86_64/gdt.h b/include/arch/x86_64/gdt.h new file mode 100644 index 0000000..c17c9eb --- /dev/null +++ b/include/arch/x86_64/gdt.h @@ -0,0 +1,23 @@ +#ifndef _JOVE_x86_64_GDT_H +#define _JOVE_x86_64_GDT_H 1 + +#include "tables.h" + +enum +{ + GDT_SEGMENT_KERNEL_NULL = 0, + GDT_SEGMENT_KERNEL_CODE, + GDT_SEGMENT_KERNEL_DATA, + + GDT_SEGMENT_USER_NULL, + GDT_SEGMENT_USER_DATA, + GDT_SEGMENT_USER_CODE, + + GDT_SEGMENT_TSS_LOW, + GDT_SEGMENT_TSS_HIGH, + + GDT_SEGMENT_COUNT +}; +typedef segment_descriptor_t gdt_t[GDT_SEGMENT_COUNT]; + +#endif diff --git a/include/arch/x86_64/idt.h b/include/arch/x86_64/idt.h new file mode 100644 index 0000000..7a5c468 --- /dev/null +++ b/include/arch/x86_64/idt.h @@ -0,0 +1,25 @@ +#ifndef _JOVE_x86_64_IDT_H +#define _JOVE_x86_64_IDT_H 1 + +#include "tables.h" + +typedef struct interrupt_state +{ + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t bp, di, si, dx, cx, bx, ax; + uint64_t ip, cs, flags, sp, ss; +} int_state_t; + +typedef interrupt_gate_t idt_t[48]; + +typedef int_state_t *(*int_handler_t)(int_state_t *); + +void int_handler_set(uint8_t i, int_handler_t handler); +int_handler_t int_handler_get(uint8_t i); + +void int_state_print(int_state_t *state); + +extern uint64_t __isr_err; +extern uint64_t __isr_num; + +#endif diff --git a/include/arch/x86_64/msr.h b/include/arch/x86_64/msr.h new file mode 100644 index 0000000..c20f8fc --- /dev/null +++ b/include/arch/x86_64/msr.h @@ -0,0 +1,56 @@ +#ifndef _JOVE_x86_64_MSR_H +#define _JOVE_x86_64_MSR_H 1 + +#include +#include + +#define MSR_EFER 0xC0000080 +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_SFMASK 0xC0000084 + +#define MSR_FSBASE 0xC0000100 +#define MSR_GSBASE 0xC0000101 +#define MSR_KERNELGSBASE 0xC0000102 + +typedef union msr_efer +{ + struct { + uint8_t sce : 1; + uint8_t resv : 7; + uint8_t lme : 1; + uint8_t unk0 : 1; + uint8_t lma : 1; + uint8_t nxe : 1; + uint8_t svme : 1; + uint8_t lmsle : 1; + uint8_t ffxsr : 1; + uint8_t tce : 1; + }; + uint32_t v[2]; +} msr_efer_t; + +typedef union msr_star +{ + struct { + uint32_t eip; + uint16_t kcs; + uint16_t ucs; + }; + uint32_t v[2]; +} msr_star_t; +typedef uintptr_t msr_lstar_t; + +void msr_efer_write(msr_efer_t v); +msr_efer_t msr_efer_read(void); + +void msr_star_write(msr_star_t v); +msr_star_t msr_star_read(void); + +void msr_lstar_write(msr_lstar_t v); +msr_lstar_t msr_lstar_read(void); + +void msr_gsbase_write(uintptr_t gsbase); +uintptr_t msr_gsbase_read(void); + +#endif diff --git a/include/arch/x86_64/page.h b/include/arch/x86_64/page.h new file mode 100644 index 0000000..cbbf642 --- /dev/null +++ b/include/arch/x86_64/page.h @@ -0,0 +1,40 @@ +#ifndef _JOVE_x86_64_PAGE_H +#define _JOVE_x86_64_PAGE_H 1 + +#include +#include "klib/spinlock.h" +#include "assert.h" + +typedef union page_mapping_level_entry +{ + struct { + uint8_t p : 1; /* Present */ + uint8_t rw : 1; /* Read/write. 0 for RO.*/ + uint8_t us : 1; /* User/supervisor. 0 for DPL3 forbid */ + uint8_t pwt : 1; + uint8_t pcd : 1; + uint8_t a : 1; /* Accessed */ + uint8_t d : 1; /* Dirty */ + uint8_t ps_pat : 1; + uint8_t g : 1; /* Global */ + uint8_t _r0 : 2; + uint8_t r : 1; + uint64_t paddr : 35; + uint8_t _r1; + uint8_t pk : 4; + uint8_t xd : 1; + }__attribute__((packed)); + uint64_t value; +} __attribute__((packed)) pmle_t; + +typedef struct page_directory +{ + spinlock_t lock; + intmax_t id; + uintptr_t phys; + pmle_t *pml; +} page_directory_t; + +#define _kernel_virtual_base 0xFFFFFFFF80000000ULL + +#endif diff --git a/include/arch/x86_64/processor.h b/include/arch/x86_64/processor.h new file mode 100644 index 0000000..c208eb1 --- /dev/null +++ b/include/arch/x86_64/processor.h @@ -0,0 +1,17 @@ +#ifndef _JOVE_x86_64_PROCESSOR_H +#define _JOVE_x86_64_PROCESSOR_H 1 + +#include "tables.h" +#include "gdt.h" +#include "idt.h" +#include "tss.h" + +#define PROCESSOR_MAX 8 + +#define ARCH_SPECIFIC_PROCESSOR_MEMBERS \ + __attribute__((aligned(0x1000))) gdt_t _gdt; \ + struct TSS _tss; \ + struct XDTR _gdtr; \ + struct XDTR _idtr + +#endif diff --git a/include/arch/x86_64/tables.h b/include/arch/x86_64/tables.h new file mode 100644 index 0000000..e311192 --- /dev/null +++ b/include/arch/x86_64/tables.h @@ -0,0 +1,57 @@ +#ifndef _JOVE_X86_64_TABLES_H +#define _JOVE_X86_64_TABLES_H 1 + +#include + +#define CD_SEGMENT_TYPE_ACCESSED 1 +#define CD_SEGMENT_TYPE_WRITEABLE 2 +#define CD_SEGMENT_TYPE_DATA_EXPAND_DOWN 4 +#define CD_SEGMENT_TYPE_CODE_CONFORMING 4 +#define CD_SEGMENT_TYPE_CODE 8 + +#define S_SEGMENT_TYPE_LDT 2 +#define S_SEGMENT_TYPE_TSS_AVAIL 9 +#define S_SEGMENT_TYPE_TSS_BUSY 11 +#define S_SEGMENT_TYPE_CALLGATE 12 +#define S_SEGMENT_TYPE_INT_GATE 14 +#define S_SEGMENT_TYPE_TRAP_GATE 15 + +typedef struct segment_descriptor +{ + uint16_t limit_0_15; /* Segment limit. */ + uint16_t base_0_15; /* Segment base. */ + uint8_t base_16_23; + uint8_t type : 4; /* Segment type. */ + uint8_t s : 1; /* Descriptor type (0 = system, 1 = code/data)*/ + uint8_t dpl : 2; /* Descriptor privilege level. */ + uint8_t p : 1; /* Present. */ + uint8_t limit_16_19 : 4; + uint8_t avl : 1; /* Available for use by system software. */ + uint8_t l : 1; /* 64-bit segment (Ext). */ + uint8_t d_b : 1; /* Default operation size (0 = 16-bit, 1 = 32-bit)*/ + uint8_t g : 1; /* Granularity. */ + uint8_t base_24_31; +}__attribute__((packed)) segment_descriptor_t; + +typedef struct interrupt_gate +{ + uint16_t base_0_15; + uint16_t segment_selector; + uint8_t ist : 3; + uint8_t zero_0 : 5; + uint8_t type : 4; + uint8_t zero_1 : 1; + uint8_t dpl : 2; + uint8_t p : 1; + uint16_t base_16_31; + uint32_t base_32_63; + uint32_t resv; +}__attribute__((packed)) interrupt_gate_t; + +struct XDTR /* Generic table descriptor struct */ +{ + uint16_t length; + uint64_t address; +}__attribute__((packed)); + +#endif diff --git a/include/arch/x86_64/tss.h b/include/arch/x86_64/tss.h new file mode 100644 index 0000000..3184df5 --- /dev/null +++ b/include/arch/x86_64/tss.h @@ -0,0 +1,20 @@ +#ifndef JOVE_ARCH_x86_64_TSS_H +#define JOVE_ARCH_x86_64_TSS_H 1 + +#include +#include + +struct TSS +{ + uint32_t resv0; + uint32_t rsp[3][2]; + uint64_t resv1; + uint32_t ist[8][2]; + uint64_t resv2; + uint16_t resv3; + uint16_t iobp; +}; + +void tss_set_rsp(struct TSS *tss, uint8_t dpl, uintptr_t rsp); + +#endif diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 0000000..f208235 --- /dev/null +++ b/include/assert.h @@ -0,0 +1,10 @@ +#ifndef JOVE_LIB_ASSERT_H +#define JOVE_LIB_ASSERT_H 1 + +#include "jove.h" + +#define assert(cond) \ + if(!(cond)) \ + kpanic("Assert failure : %s\n", #cond) + +#endif diff --git a/include/boot.h b/include/boot.h new file mode 100644 index 0000000..c4aa541 --- /dev/null +++ b/include/boot.h @@ -0,0 +1,38 @@ +#ifndef JOVE_BOOT_H +#define JOVE_BOOT_H 1 + +#include +#include +#include + +struct MemoryMapEntry { + uintptr_t base; + size_t length; + bool usable; +}; + +#define MEMORY_MAP_MAX_ENTRIES 128 +struct MemoryMap { + size_t count; + struct MemoryMapEntry entries[MEMORY_MAP_MAX_ENTRIES]; +}; + +#define BOOT_MODULE_MAX_ENTRIES 4 +struct BootModule { + char *path; + char *cmdline; + size_t size; + uintptr_t addr; +}; + +#define KERNEL_INITIAL_STACK_WIDTH (0x1000 * 4) +extern void *boot_kernel_initial_stack_base; +extern uintptr_t boot_kernel_physical_address; +extern const char *boot_kernel_cmdline; + +extern struct MemoryMap boot_memorymap; + +extern struct BootModule boot_modules[BOOT_MODULE_MAX_ENTRIES]; +extern size_t boot_module_count; + +#endif diff --git a/include/commandline.h b/include/commandline.h new file mode 100644 index 0000000..5c66cd3 --- /dev/null +++ b/include/commandline.h @@ -0,0 +1,8 @@ +#ifndef _JOVE_COMMANDLINE_H +#define _JOVE_COMMANDLINE_H 1 + +const char *cmdline_get(const char *key); + +void cmdline_kernel_setup(void); + +#endif diff --git a/include/device/serial.h b/include/device/serial.h new file mode 100644 index 0000000..d59b00f --- /dev/null +++ b/include/device/serial.h @@ -0,0 +1,48 @@ +#ifndef _JOVE_DEVICE_SERIAL_H +#define _JOVE_DEVICE_SERIAL_H 1 + +#include +#include +#include +#include "klib/spinlock.h" + +#define SERIAL_UART_COM1 0x3F8 +#define SERIAL_UART_COM2 0x2F8 + +#define SERIAL_UART_COM_THR(COM) COM +#define SERIAL_UART_COM_RBR(COM) COM +#define SERIAL_UART_COM_DLAB_DLL(COM) COM +#define SERIAL_UART_COM_IER(COM) (COM + 1) +#define SERIAL_UART_COM_DLAB_DLH(COM) (COM + 1) +#define SERIAL_UART_COM_IIR(COM) (COM + 2) +#define SERIAL_UART_COM_FCR(COM) (COM + 2) +#define SERIAL_UART_COM_LCR(COM) (COM + 3) +#define SERIAL_UART_COM_MCR(COM) (COM + 4) +#define SERIAL_UART_COM_LSR(COM) (COM + 5) +#define SERIAL_UART_COM_MSR(COM) (COM + 6) +#define SERIAL_UART_COM_SR(COM) (COM + 7) + +typedef struct serial_device +{ + uint16_t com; + spinlock_t lock; +} serial_dev_t; + +extern serial_dev_t COM1; + +void serial_setup(void); +serial_dev_t serial_new(uint16_t com); + +void serial_set_int(serial_dev_t *dev, bool enable); +void serial_set_baud(serial_dev_t *dev, uint16_t baud); + +void serial_set_fcr(serial_dev_t *dev, uint16_t flg); +void serial_set_lcr(serial_dev_t *dev, uint16_t flg); +void serial_set_mcr(serial_dev_t *dev, uint16_t flg); +void serial_set_lsr(serial_dev_t *dev, uint16_t flg); +void serial_set_msr(serial_dev_t *dev, uint16_t flg); + +uint8_t serial_line_status(serial_dev_t *dev); +void serial_write(serial_dev_t *dev, const char *s, size_t len); + +#endif diff --git a/include/device/uart.h b/include/device/uart.h new file mode 100644 index 0000000..1724eb5 --- /dev/null +++ b/include/device/uart.h @@ -0,0 +1,19 @@ +#ifndef JOVE_KERNEL_ARCH_x86_64_UART_H +#define JOVE_KERNEL_ARCH_x86_64_UART_H 1 + +#include "jove.h" +#include + +ALWAYS_INLINE uint8_t pinb(uint16_t port) +{ + uint8_t v; + __asm__ volatile("inb %1, %0": "=a"(v): "Nd"(port)); + return v; +} + +ALWAYS_INLINE void poutb(uint16_t port, uint8_t b) +{ + __asm__ volatile("outb %0, %1":: "a"(b), "Nd"(port)); +} + +#endif diff --git a/include/initrd.h b/include/initrd.h new file mode 100644 index 0000000..7e7fe1e --- /dev/null +++ b/include/initrd.h @@ -0,0 +1,17 @@ +#ifndef _JOVE_INITRD_H +#define _JOVE_INITRD_H 1 + +#include + +typedef struct initrd_file { + void *header; + const char *name; + const void *data; + size_t size; +} initrd_file_t; + +void initrd_setup(void); + +initrd_file_t *ird_getfile(const char *path); + +#endif diff --git a/include/jove.h b/include/jove.h new file mode 100644 index 0000000..2330492 --- /dev/null +++ b/include/jove.h @@ -0,0 +1,13 @@ +#ifndef JOVE_LIB_JOVE_H +#define JOVE_LIB_JOVE_H 1 + +#define ALWAYS_INLINE inline __attribute__((always_inline)) +#define PAGEALIGN __attribute__((aligned(0x1000))) + +extern void *_kernel_start; +extern void *_kernel_end; + +__attribute__((noreturn)) void _kpanic(const char *file, int line, const char *fmt, ...); +#define kpanic(...) _kpanic(__FILE__, __LINE__, __VA_ARGS__) + +#endif diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 0000000..35198e6 --- /dev/null +++ b/include/memory.h @@ -0,0 +1,49 @@ +#ifndef _JOVE_MEMORY_H +#define _JOVE_MEMORY_H 1 + +#define KiB 1024ULL +#define MiB (KiB * KiB) +#define GiB (MiB * KiB) +#define TiB (GiB * KiB) + +#include +#include +#include "arch/page.h" + +typedef uintptr_t physptr_t; + +extern const uintptr_t USERLAND_MEMORY_BASE; +extern const uintptr_t USERLAND_MEMORY_LIMIT; +extern const uintptr_t PHYSMAP_MEMORY_BASE; +extern const uintptr_t PHYSMAP_MEMORY_LIMIT; +extern const uintptr_t KERNEL_MEMORY_BASE; +extern const uintptr_t KERNEL_MEMORY_LIMIT; + +page_mapping_t vm_pd_mapping_get(page_directory_t *pd, uintptr_t addr); +void vm_pd_mapping_set(page_directory_t *pd, page_mapping_t mapping, uintptr_t addr); +void vm_pd_ensure(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg); + +page_mapping_t vm_mapping_get(uintptr_t addr); +void vm_mapping_set(page_mapping_t mapping, uintptr_t virt); +void vm_ensure(uintptr_t from, uintptr_t to, page_flags_t flg); + +physptr_t vm_tophys(uintptr_t virt); +physptr_t vm_tophys_koff(uintptr_t virt); + +uintptr_t pm_tovirt(physptr_t phys); + +physptr_t pm_alloc(size_t pages); +void pm_reserve(physptr_t start, physptr_t end); +void pm_release(physptr_t start, physptr_t end); + +void mm_setup_early(void); +void vm_setup_early(void); + +void mm_setup(void); +void vm_setup(void); + +void* kmalloc(size_t width); +void *krealloc(void *ptr, size_t width); +void kfree(void *ptr); + +#endif diff --git a/include/print.h b/include/print.h new file mode 100644 index 0000000..38a1dbc --- /dev/null +++ b/include/print.h @@ -0,0 +1,25 @@ +#ifndef _JOVE_PRINT_H +#define _JOVE_PRINT_H 1 + +#include + +enum { + PRINT_DEBUG = 0, + PRINT_LOG, + PRINT_WARN, + PRINT_ERROR +}; + +#define PRINT_BUFFERW 512 + +void prawf(const char *fmt, ...); + +void _plogvf(const char *file, const char *func, int line, int lvl, const char *fmt, va_list ap); +void _plogf(const char *file, const char *func, int line, int lvl, const char *fmt, ...); + +#define kdbgf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_DEBUG, __VA_ARGS__) +#define klogf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_LOG , __VA_ARGS__) +#define kwarnf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_WARN, __VA_ARGS__) +#define kerrf(...) _plogf(__FILE__, __FUNCTION__, __LINE__, PRINT_ERROR, __VA_ARGS__) + +#endif diff --git a/include/slab.h b/include/slab.h new file mode 100644 index 0000000..04d42e4 --- /dev/null +++ b/include/slab.h @@ -0,0 +1,44 @@ +#ifndef JOVE_MEMORY_SLAB_H +#define JOVE_MEMORY_SLAB_H 1 + +#include +#include +#include + +#define SLABCACHE_NAME_LIMIT 32 +typedef struct slab_cache +{ + char name[SLABCACHE_NAME_LIMIT]; + + struct slab *list_free; + struct slab *list_partial; + struct slab *list_full; + + size_t obj_count; + size_t obj_size; + size_t obj_capacity; + + size_t slab_pages; +} slab_cache_t; + +typedef struct slab +{ + struct slab *prev; + struct slab *next; + void *slab_base; + void *obj_base; + + size_t free_count; + int free_index; + uintptr_t free[]; +} slab_t; + +void slabcache_new(slab_cache_t *cache, char *name, size_t objsize); + +void* slab_alloc(slab_cache_t *cache); +void slab_free(slab_cache_t *cache, void *ptr); + +void* slab_get(slab_cache_t *cache, size_t index); +void slab_set(slab_cache_t *cache, size_t index, void *data); + +#endif diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..a91ec94 --- /dev/null +++ b/include/string.h @@ -0,0 +1,18 @@ +#ifndef JOVE_LIB_STRING_H +#define JOVE_LIB_STRING_H 1 + +#include + +int toupper(int c); +char *stoupper(char *s); +char *sntoupper(char *s, size_t limit); + +size_t strlen(const char *s); + +void *memset(void *dest, int c, size_t n); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +int memcmp(const void *a, const void *b, size_t n); +int strcmp(const char *a, const char *b); + +#endif diff --git a/include/tasking.h b/include/tasking.h new file mode 100644 index 0000000..04118a9 --- /dev/null +++ b/include/tasking.h @@ -0,0 +1,44 @@ +#ifndef _JOVE_TASKING_H +#define _JOVE_TASKING_H 1 + +#include "arch/page.h" +#include +#include + +#define KERNEL_STACKW 4096 + +typedef intmax_t tcbid_t; + +typedef enum +{ + TCB_RUNNING, + TCB_PAUSED, + TCB_DEAD +} tcb_state_t; + +typedef struct task_control_block +{ + tcbid_t id; + void *stack; + uintptr_t sp, ksp; + page_directory_t *pd; + tcb_state_t state; + + int exit_code; +} tcb_t; + +void tasking_setup(void); + +tcb_t *tcb_new(void *ip, page_directory_t *pd); +void tcb_prepare(tcb_t *tcb, void *ip); +void tcb_kill(tcb_t *tcb, int code); + +void tcb_switch(tcb_t *to); + +void tcb_stack_push(tcb_t *tcb, void *data, size_t len); + +void kexec(void *ip, int kargc, char **kargv, int kenvc, char **kenvp); + +void *umode_stack_new(void); + +#endif diff --git a/include/umode_vma.h b/include/umode_vma.h new file mode 100644 index 0000000..23619be --- /dev/null +++ b/include/umode_vma.h @@ -0,0 +1,10 @@ +#ifndef _JOVE_UMODE_VMA_H +#define _JOVE_UMODE_VMA_H 1 + +#include +#include + +int user_vma_read(void *dest, const void *src, size_t w); +int user_vma_write(void *dest, const void *src, size_t w); + +#endif diff --git a/include/zone.h b/include/zone.h new file mode 100644 index 0000000..002d1fc --- /dev/null +++ b/include/zone.h @@ -0,0 +1,38 @@ +#ifndef JOVE_MEM_ZONE_H +#define JOVE_MEM_ZONE_H 1 + +#include +#include "klib/buddymap.h" + +enum { + MEM_ZONE_STANDARD = 0, /* First GiB of physical memory. */ + MEM_ZONE_HIGHER, + MEM_ZONE_COUNT +}; + +#define MEM_ZONE_STANDARD_BASE 0 +#define MEM_ZONE_STANDARD_LIMIT (1 * GiB) +#define MEM_ZONE_HIGHER_BASE MEM_ZONE_STANDARD_LIMIT + +#define MEM_BUDDY_ORDERS 12 +struct PhysicalMemoryZone +{ + const char *name; + + uintptr_t base; + uintptr_t limit; + + struct BuddyMap freemap; +}; + +int pm_zone_for(uintptr_t addr); +uintptr_t pm_zone_bound_lower(size_t zone); +uintptr_t pm_zone_bound_upper(size_t zone); +size_t pm_zone_pages_free(size_t zone); +int pm_zone_resv(size_t zone, uintptr_t base, uintptr_t limit); +int pm_zone_free(size_t zone, uintptr_t base, uintptr_t limit); +uintptr_t pm_zone_alloc(size_t zone, size_t pages); + +void pm_zone_setup(void); + +#endif diff --git a/initrd/initrd.c b/initrd/initrd.c new file mode 100644 index 0000000..8fe0f01 --- /dev/null +++ b/initrd/initrd.c @@ -0,0 +1,84 @@ +#include "initrd.h" +#include "tar.h" +#include "string.h" +#include "commandline.h" +#include "memory.h" +#include "print.h" +#include "klib/rbtree.h" +#include "klib/hash.h" +#include "boot.h" + +static rbtree_t s_initrd_files; + +static size_t +s_tar_oct_dec(const char *oct) +{ + size_t value = 0; + while(*oct != 0) { + value *= 8; + value += (*oct) - '0'; + oct++; + } + return value; +} + +static void +s_initrd_parse(struct BootModule *module) +{ + struct tar_block *sector = (struct tar_block*)module->addr; + while(true) { + tar_header_t *header = (tar_header_t*)sector; + if(header->name[0] == 0) break; + + initrd_file_t file_tmp; + initrd_file_t *file = rbtree_insert( + &s_initrd_files, + string_hash(header->name), + &file_tmp); + + *file = (initrd_file_t){ + .header = header, + .name = header->name, + .size = s_tar_oct_dec(header->size), + .data = §or[1] + }; + kdbgf("File %s size %i\n", file->name, file->size); + + sector = §or[(file->size / 512) + 1]; + if(file->size % 512 > 0) sector = §or[1]; + } +} + +initrd_file_t * +ird_getfile(const char *path) +{ + initrd_file_t *file = rbtree_find(&s_initrd_files, string_hash(path)); + return file; +} + +void +initrd_setup(void) +{ + const char *initrd_path = cmdline_get("initrd"); + if(initrd_path == 0) { + kerrf("No initrd loaded!\n"); + return; + } + kdbgf("Initrd located in module path %s\n", initrd_path); + struct BootModule *initrd_module = NULL; + for(size_t i = 0; i < boot_module_count; i++) { + struct BootModule *module = &boot_modules[i]; + if(strcmp(module->path, initrd_path) == 0) { + initrd_module = module; + break; + } + } + + if(initrd_module == NULL) { + klogf("Initrd not found in modules!\n"); + return; + } + + rbtree_new(&s_initrd_files, initrd_file_t); + s_initrd_parse(initrd_module); +} diff --git a/initrd/tar.h b/initrd/tar.h new file mode 100644 index 0000000..5325a51 --- /dev/null +++ b/initrd/tar.h @@ -0,0 +1,18 @@ +#ifndef JOVE_INITRD_TAR_H +#define JOVE_INITRD_TAR_H 1 + +struct tar_block { char data[512]; }; + +typedef struct tar_header { + char name[100]; + char mode[8]; + char owner[8]; + char group[8]; + char size[12]; + char modified[12]; + char checksum[8]; + char link; + char linkname[100]; +} tar_header_t; + +#endif diff --git a/io/interrupt.h b/io/interrupt.h deleted file mode 100644 index 444ff01..0000000 --- a/io/interrupt.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef JOVE_IO_INTERRUPT_H -#define JOVE_IO_INTERRUPT_H 1 - - - -#endif diff --git a/io/log.c b/io/log.c deleted file mode 100644 index 14397a7..0000000 --- a/io/log.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "log.h" -#include "lib/jove.h" -#include "lib/string.h" -#include "lib/format.h" - -static struct LogDevice *s_first_logdev = NULL; - -void -klog_newdev(struct LogDevice *dev) -{ - if(s_first_logdev == NULL) { - s_first_logdev = dev; - }else{ - dev->chain = s_first_logdev; - s_first_logdev = dev; - } -} - -static void -s_klogc(struct LogDevice *dev, char c) -{ - dev->out(&c, 1); - if(dev->chain != NULL) - s_klogc(dev->chain, c); -} - -void -klogc(char c) -{ - s_klogc(s_first_logdev, c); -} - -static void -s_klogs(struct LogDevice *dev, const char *s, size_t slen) -{ - dev->out(s, slen); - if(dev->chain != NULL) - s_klogs(dev->chain, s, slen); -} - -void -klogs(const char *s) -{ - size_t slen = strlen(s); - s_klogs(s_first_logdev, s, slen); -} - -void -klogsn(const char *s, size_t len) -{ - s_klogs(s_first_logdev, s, len); -} - -void -kvlogf(const char *fmt, va_list ap) -{ - char buffer[256]; - svfmt(buffer, 256, fmt, ap); - klogs(buffer); -} - -void klogf(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - kvlogf(fmt, ap); - va_end(ap); -} diff --git a/io/log.h b/io/log.h deleted file mode 100644 index ad1526d..0000000 --- a/io/log.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef JOVE_IO_LOG_H -#define JOVE_IO_LOG_H 1 - -#include - -struct LogDevice -{ - void (*out)(const char*, size_t); - struct LogDevice *chain; -}; - -void klog_newdev(struct LogDevice *dev); - -void klogc(char c); -void klogs(const char *s); -void klogsn(const char *s, size_t len); - -#include -void kvlogf(const char *fmt, va_list ap); -void klogf(const char *fmt, ...); - -#endif diff --git a/ird/initrd.c b/ird/initrd.c deleted file mode 100644 index f219243..0000000 --- a/ird/initrd.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "initrd.h" -#include "lib/string.h" -#include "io/log.h" -#include "boot/boot.h" -#include "boot/cmdline.h" -#include "mem/memory.h" - -struct SlabCache s_initrd_cache; -struct SLinkedList s_initrd_files; - -static size_t -s_tar_oct_dec(const char *oct) -{ - size_t value = 0; - while(*oct != 0) { - value *= 8; - value += (*oct) - '0'; - oct++; - } - return value; -} - -static void -s_initrd_parse(struct BootModule *module) -{ - struct TARSector *sector = (struct TARSector*)module->addr; - while(true) { - struct TARHeader *header = (struct TARHeader*)sector; - if(header->name[0] == 0) break; - - struct InitrdFile *file = mem_slab_alloc(&s_initrd_cache); - *file = (struct InitrdFile){ - .header = header, - .name = header->name, - .size = s_tar_oct_dec(header->size), - .data = §or[1] - }; - klogf("File %s size %i\n", file->name, file->size); - sll_push(&s_initrd_files, file); - - sector = §or[(file->size / 512) + 1]; - if(file->size % 512 > 0) sector = §or[1]; - } -} - -struct InitrdFile * -ird_getfile(const char *path) -{ - for(struct SLLNode *node = s_initrd_files.head; node != NULL; node = node->next) { - struct InitrdFile *file = (struct InitrdFile*)node; - if(strcmp(file->name, path) == 0) return file; - } - return NULL; -} - -struct SLinkedList * -ird_getfiles(void) -{ - return &s_initrd_files; -} - -void -initrd_setup(void) -{ - const char *initrd_path = cmdline_get("initrd"); - if(initrd_path == 0) { - klogf("No initrd loaded!\n"); - return; - } - klogf("Initrd located in module path %s\n", initrd_path); - struct BootModule *initrd_module = NULL; - for(size_t i = 0; i < boot_module_count; i++) { - struct BootModule *module = &boot_modules[i]; - if(strcmp(module->path, initrd_path) == 0) { - initrd_module = module; - break; - } - } - - if(initrd_module == NULL) { - klogf("Initrd not found in modules!\n"); - return; - } - - sll_new(&s_initrd_files, sizeof(struct InitrdFile)); - mem_slabcache_new(&s_initrd_cache, "initrd files", sizeof(struct InitrdFile)); - s_initrd_parse(initrd_module); -} diff --git a/ird/initrd.h b/ird/initrd.h deleted file mode 100644 index f236fa1..0000000 --- a/ird/initrd.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef JOVE_INITRD_H -#define JOVE_INITRD_H 1 - -#include -#include "tar.h" -#include "lib/linkedlist.h" - -struct InitrdFile { - struct InitrdFile *next; - struct TARHeader *header; - const char *name; - size_t size; - const void *data; -}; - -void initrd_setup(void); - -struct InitrdFile *ird_getfile(const char *path); -struct SLinkedList *ird_getfiles(void); - -#endif diff --git a/ird/tar.h b/ird/tar.h deleted file mode 100644 index 5c72620..0000000 --- a/ird/tar.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef JOVE_INITRD_TAR_H -#define JOVE_INITRD_TAR_H 1 - -struct TARSector { char data[512]; }; - -struct TARHeader { - char name[100]; - char mode[8]; - char owner[8]; - char group[8]; - char size[12]; - char modified[12]; - char checksum[8]; - char link; - char linkname[100]; -}; - -#endif diff --git a/klib/buddymap.c b/klib/buddymap.c new file mode 100644 index 0000000..62cecf1 --- /dev/null +++ b/klib/buddymap.c @@ -0,0 +1,170 @@ +#include "buddymap.h" +#include "jove.h" +#include "print.h" + +#define BLOCK_AT_LAYER(blocks, l, i) blocks[l][i / BUDDY_BLOCK_BITS] +#define BLOCK_BITMASK(i) (1ULL << (i % BUDDY_BLOCK_BITS)) +#define LOG2(v) (31 - __builtin_clz(v)) + +bool +buddy_bit_test(struct BuddyMap *map, size_t l, size_t i) +{ + return (BLOCK_AT_LAYER(map->blocks, l, i) & BLOCK_BITMASK(i)) > 0; +} + +void +buddy_bit_mark(struct BuddyMap *map, size_t l, size_t i) +{ + size_t wi = i << l; + size_t bits = 1ULL << l; + for(size_t wl = 0; wl < map->orders; wl++) { + if(bits == 0) { + if(buddy_bit_test(map, wl - 1, (wi << 1) + 1)) bits = 1; + } + for(size_t bit = 0; bit < bits; bit++) { + size_t rbit = bit + wi; + if(l == 0 && !buddy_bit_test(map, 0, rbit)) map->free--; + BLOCK_AT_LAYER(map->blocks, wl, rbit) |= BLOCK_BITMASK(rbit); + } + bits >>= 1; + wi >>= 1; + } +} + +void +buddy_bit_free(struct BuddyMap *map, size_t l, size_t i) +{ + size_t wi = i << l; + size_t bits = 1ULL << l; + for(size_t wl = 0; wl < map->orders; wl++) { + if(bits == 0) bits = 1; + for(size_t bit = 0; bit < bits; bit++) { + size_t rbit = bit + wi; + if(l == 0 && buddy_bit_test(map, 0, rbit)) map->free++; + BLOCK_AT_LAYER(map->blocks, wl, rbit) &= ~BLOCK_BITMASK(rbit); + } + bits >>= 1; + wi >>= 1; + } +} + +static void +s_buddy_op_range( + struct BuddyMap *map, + size_t l, + size_t start, + size_t end, + void (*op)(struct BuddyMap*, size_t, size_t)) +{ + size_t layerw = 1ULL << l; + size_t start_off = start % layerw; + size_t end_off = end % layerw; + + size_t start_real = start + (start_off > 0 ? (layerw - start_off) : 0); + size_t end_real = end - end_off; + + if(start_real != start) s_buddy_op_range(map, l - 1, start, start_real, op); + if(end_real != end) s_buddy_op_range(map, l - 1, end_real, end, op); + + size_t start_bit = start_real >> l; + size_t end_bit = end_real >> l; + if(start_bit == end_bit || end_bit < start_bit) return; + for(size_t bit = start_bit; bit < end_bit; bit++) + op(map, l, bit); +} + +static size_t +s_buddy_layer_bestfit(struct BuddyMap *map, size_t length) +{ + if(length == 1) return 0; + size_t length_log2 = LOG2(length); + if(length_log2 > map->orders) length_log2 = map->orders - 1; + return length_log2; +} + +void +buddy_mark_range(struct BuddyMap *map, size_t start, size_t end) +{ + size_t l = s_buddy_layer_bestfit(map, end - start); + s_buddy_op_range(map, l, start, end, buddy_bit_mark); +} +void +buddy_free_range(struct BuddyMap *map, size_t start, size_t end) +{ + size_t l = s_buddy_layer_bestfit(map, end - start); + s_buddy_op_range(map, l, start, end, buddy_bit_free); +} + +static intmax_t +s_buddy_top_firstfree(struct BuddyMap *map) +{ + size_t layer = map->orders - 1; + size_t layer_bits = map->bits >> layer; + size_t layer_blocks = layer_bits / BUDDY_BLOCK_BITS; + for(size_t i = 0; i < layer_blocks; i++) { + if(map->blocks[layer][i] == (uintptr_t)-1) continue; + for(size_t j = 0; j < BUDDY_BLOCK_BITS; j++) { + size_t bit = (i * BUDDY_BLOCK_BITS) + j; + if(buddy_bit_test(map, layer, bit)) continue; + return bit; + } + } + return -1; +} + +static intmax_t +s_buddy_top_alloc_contig(struct BuddyMap *map, size_t length) +{ + size_t layer = map->orders - 1; + size_t layer_bits = map->bits >> layer; + + size_t contig_base = 0; + size_t contig_bits = 0; + for(size_t i = 0; i < layer_bits; i++) { + if(buddy_bit_test(map, layer, i)) { + contig_base = i + 1; + contig_bits = 0; + continue; + } + if(++contig_bits == length) { + return contig_base; + } + } + return -1; +} + +intmax_t +buddy_alloc(struct BuddyMap *map, size_t length) +{ + size_t layer = s_buddy_layer_bestfit(map, length); + size_t layerw = 1ULL << layer; + size_t allocw = length / layerw; + + if(allocw == 0) allocw = 1; + if(allocw > 1) + return s_buddy_top_alloc_contig(map, length); + + intmax_t alloci = s_buddy_top_firstfree(map); + if(alloci < 0) { + klogf("Top layer is full!\n"); + return -1; + } + + for(int wlayer = map->orders - 2; wlayer > layer; wlayer--) { + alloci <<= 1; + if(buddy_bit_test(map, wlayer, alloci)) { + alloci++; + } + } + alloci <<= 1; + if(buddy_bit_test(map, layer, alloci)) alloci++; + + s_buddy_op_range(map, layer, alloci, alloci + length, buddy_bit_mark); + return alloci; +} + +void +buddy_free(struct BuddyMap *map, size_t i, size_t length) +{ + buddy_free_range(map, i, i + length); +} diff --git a/klib/buddymap.h b/klib/buddymap.h new file mode 100644 index 0000000..1af8dfb --- /dev/null +++ b/klib/buddymap.h @@ -0,0 +1,35 @@ +#ifndef JOVE_LIB_BUDDYMAP_H +#define JOVE_LIB_BUDDYMAP_H 1 + +#include +#include +#include + +#define BUDDY_BLOCK_BYTES sizeof(intmax_t) +#define BUDDY_BLOCK_BITS (BUDDY_BLOCK_BYTES * 8) + +#define BUDDY_BITS_FOR(range) (range * 2) +#define BUDDY_BLOCKS_FOR(range) (BUDDY_BITS_FOR(range) / BUDDY_BLOCK_BITS) + +struct BuddyMap +{ + size_t orders; + size_t bits; + size_t free; + uintmax_t **blocks; +}; + +#define BUDDY_BIT_PARTIAL 0 +#define BUDDY_BIT_FULL 1 + +bool buddy_bit_test(struct BuddyMap *map, size_t l, size_t i); +void buddy_bit_mark(struct BuddyMap *map, size_t l, size_t i); +void buddy_bit_free(struct BuddyMap *map, size_t l, size_t i); + +void buddy_mark_range(struct BuddyMap *map, size_t start, size_t end); +void buddy_free_range(struct BuddyMap *map, size_t start, size_t end); + +intmax_t buddy_alloc(struct BuddyMap *map, size_t length); +void buddy_free(struct BuddyMap *map, size_t i, size_t length); + +#endif diff --git a/klib/format.h b/klib/format.h new file mode 100644 index 0000000..5a2b75c --- /dev/null +++ b/klib/format.h @@ -0,0 +1,13 @@ +#ifndef JOVE_LIB_FORMAT_H +#define JOVE_LIB_FORMAT_H 1 + +#include +#include + +size_t ltostr(char *s, size_t limit, unsigned long l, bool sgn, int radix); + +char *sfmt(char *s, size_t limit, const char *fmt, ...); +#include +char *svfmt(char *s, size_t limit, const char *fmt, va_list ap); + +#endif diff --git a/klib/hash.h b/klib/hash.h new file mode 100644 index 0000000..03b0f3a --- /dev/null +++ b/klib/hash.h @@ -0,0 +1,18 @@ +#ifndef JOVE_LIB_HASH_H +#define JOVE_LIB_HASH_H 1 + +#include + +static intmax_t +string_hash(const char *str) +{ + /* Hash function courtesy of the following website: + * http://www.cse.yorku.ca/~oz/hash.html*/ + intmax_t r = 5381; + while (*str) { + r = (r * 33) ^ *(str++); + } + return r; +} + +#endif diff --git a/klib/kpanic.c b/klib/kpanic.c new file mode 100644 index 0000000..2918711 --- /dev/null +++ b/klib/kpanic.c @@ -0,0 +1,16 @@ +#include "jove.h" +#include "print.h" + +#include +#include + +__attribute__((noreturn)) +void _kpanic(const char *file, int line, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + klogf("!!! PANIC !!!\n%s:%i\n", file, line); + _plogvf(NULL, NULL, 0, PRINT_LOG, fmt, ap); + va_end(ap); + for(;;) __asm__ volatile("hlt"); +} diff --git a/klib/linkedlist.c b/klib/linkedlist.c new file mode 100644 index 0000000..6cc6403 --- /dev/null +++ b/klib/linkedlist.c @@ -0,0 +1,34 @@ +#include "linkedlist.h" + +void +sll_new(struct SLinkedList *list, size_t obj_size) +{ + list->obj_size = obj_size; + list->count = 0; + list->head = list->tail = NULL; +}; + +void +sll_push(struct SLinkedList *list, void *data) +{ + struct SLLNode *node = (struct SLLNode*)data; + if(list->tail != NULL) { + list->tail->next = node; + } + if(list->head == NULL) + list->head = node; + list->tail = node; + list->count++; +} + +void* +sll_get(struct SLinkedList *list, size_t index) +{ + struct SLLNode *node = list->head; + if(node == NULL) return NULL; + if(index > list->count) return list->tail; + for(size_t i = 0; i < index; i++) { + node = node->next; + } + return node; +} diff --git a/klib/linkedlist.h b/klib/linkedlist.h new file mode 100644 index 0000000..26c148e --- /dev/null +++ b/klib/linkedlist.h @@ -0,0 +1,26 @@ +#ifndef JOVE_LIB_LINKEDLIST_H +#define JOVE_LIB_LINKEDLIST_H 1 + +#include +#include + +struct SLLNode { + struct SLLNode *next; + char data[]; +}; + +/*Singly Linked List*/ +struct SLinkedList +{ + struct SLLNode *head; + struct SLLNode *tail; + + size_t obj_size; + size_t count; +}; + +void sll_new(struct SLinkedList *list, size_t obj_size); +void sll_push(struct SLinkedList *list, void *node); +void *sll_get(struct SLinkedList *list, size_t index); + +#endif diff --git a/klib/ltostr.c b/klib/ltostr.c new file mode 100644 index 0000000..e28be31 --- /dev/null +++ b/klib/ltostr.c @@ -0,0 +1,26 @@ +#include "format.h" + +size_t +ltostr(char *s, size_t limit, unsigned long l, bool sgn, int radix) +{ + size_t si = 0; + size_t digits = 0; + if((long)l < 0 && sgn) { + l = -((long)l); + s[0] = '-'; + } + for(unsigned long lv = l; lv != 0; lv /= radix) + digits++; + digits = digits > limit ? limit : digits; + + if(digits-- == 0) + s[si++] = '0'; + for(unsigned long lv = l; lv != 0; lv /= radix) + { + if(si >= limit) return si; + int digit = lv % radix; + s[(digits - si)] = (digit >= 10 ? (digit + 'a' - 10) : digit + '0'); + si++; + } + return si; +} diff --git a/klib/mem.c b/klib/mem.c new file mode 100644 index 0000000..cf9e2aa --- /dev/null +++ b/klib/mem.c @@ -0,0 +1,52 @@ +#include "string.h" +#include "memory.h" + +void* +memset(void *dest, int c, size_t n) +{ + char *destc = (char*)dest; + for(size_t i = 0; i < n; i++) + destc[i] = c; + return dest; +} + +void* +memcpy(void *dest, const void *src, size_t n) +{ + char *destc = (char*)dest; + const char *srcc = (const char*)src; + for(size_t i = 0; i < n; i++) + destc[i] = srcc[i]; + return dest; +} + +void* +memmove(void *dest, const void *src, size_t n) +{ + char *destc = (char*)dest; + const char *srcc = (const char*)src; + if(destc + n < srcc) return memcpy(dest, src, n); + char buffer[n]; + memcpy(buffer, src, n); + return memcpy(destc, buffer, n); +} + +int +memcmp(const void *a, const void *b, size_t n) +{ + const char *ac = (const char*)a; + const char *bc = (const char*)b; + for(size_t i = 0; i < n; i++) { + if(ac[i] != bc[i]) return ac[i] - bc[i]; + } + return 0; +} + +char* +strdup(const char *s) +{ + size_t slen = strlen(s); + char *ret = kmalloc(slen); + memcpy(ret, s, slen); + return ret; +} diff --git a/klib/rbtree.c b/klib/rbtree.c new file mode 100644 index 0000000..2920384 --- /dev/null +++ b/klib/rbtree.c @@ -0,0 +1,361 @@ +#include "rbtree.h" +#include "assert.h" +#include "string.h" + +#define BLACK 0 +#define RED 1 + +#define LEFT 0 +#define left children[LEFT] + +#define RIGHT 1 +#define right children[RIGHT] + +#define CHILD_DIR(c) (c->parent->children[LEFT] == c ? LEFT : RIGHT) + +/**Given a root and a direction, rotate the subtree such that the order of the + * elements are unchanged. + * The opposite direction child of the given root is treated as the pivot point + * The dir-most child of the pivot becomes the opposite dir child of the root. + * The pivot becomes the root and vice-versa. + * @param tree to do rotation on. + * @param root of rotation. + * @param dir to rotate by. + * @return new root node.*/ +rbnode_t* +s_node_rotate(rbtree_t *tree, rbnode_t *root, bool dir) +{ + assert(root != NULL); + rbnode_t *gparent = root->parent; + rbnode_t *sibling = root->children[1-dir]; + rbnode_t *child = NULL; + + assert(sibling != NULL); + child = sibling->children[dir]; + + /* Opposite child of root is dir-most child of sibling.*/ + root->children[1-dir] = child; + if(child != NULL) child->parent = root; + + /* Child of sibling is the root.*/ + sibling->children[ dir] = root; + root->parent = sibling; + + /* Parent of sibling is the grandparent. */ + sibling->parent = gparent; + if(gparent != NULL) + gparent->children[CHILD_DIR(root)] = sibling; + else + tree->root = sibling; + + return sibling; +} + +/**Search the rbtree for a node that matches the key. + * If no such node is found, returns NULL. + * @param tree to search through. + * @param key to search for. + * @return found node.*/ +rbnode_t* +s_find(rbtree_t *tree, intmax_t key) +{ + rbnode_t *node = tree->root; + while(node != NULL && node->key != key) { + node = node->children[node->key > key]; + } + return node; +} + +rbnode_t* +s_closest(rbtree_t *tree, intmax_t key) +{ + rbnode_t *node = tree->root; + while(node != NULL && node->key != key) { + rbnode_t *child = node->children[node->key > key]; + if(child == NULL) return node; + node = child; + } + return node; +} + +/**Find the left-most node for this subtree. + * @param node root of the subtree to search through. + * @return left-most node.*/ +rbnode_t* +s_node_min(rbnode_t *node) +{ + while(node->left != NULL) node = node->left; + return node; +} + +/**Find the successor for the specified node. + * The successor is defined as the left-most node of the right sub-tree. + * (the smallest node larger than the root) + * @param node to search for. + * @return the successor.*/ +rbnode_t* +s_node_successor(rbnode_t *node) +{ + if(node->right != NULL) + return s_node_min(node->right); + /* If the node has no left child (meaning that the node is larger than it's + * parents), we cycle up through the RHS of the parent tree (such that each + * parent is smaller than the child) until we reach a point by which the + * child node is smaller than the parent.*/ + rbnode_t *parent = node->parent; + while(parent != NULL && node == parent->right) { + node = parent; + parent = node->parent; + } + return parent; +} + +/**Copy the data from one node onto another, keeping parent and child relations. + * @prarm tree for metadata purposes. + * @param dest destination node. + * @param src source node.*/ +void +s_node_copy_value(rbtree_t *tree, rbnode_t *dest, rbnode_t *src) +{ + dest->key = src->key; + memcpy(dest->data, src->data, tree->objw); +} + +/**Perform tree adjustments after insertion to rebalance the rbtree. + * @param tree to rebalance. + * @param node that was inserted. + * @param parent of the node. + * @param dir that the node was inserted in.*/ +void +s_node_insert_fix( + rbtree_t *tree, + rbnode_t *node, + rbnode_t *parent, + bool dir) +{ + rbnode_t *gparent; + rbnode_t *uncle; + while((parent = node->parent) != NULL) { + if(parent->color == BLACK) return; /* Tree is valid. no fixes needed.*/ + /*Parent is known to be red.*/ + if((gparent = parent->parent) == NULL) { + /*Parent is red and the root. We can just fix it and return.*/ + parent->color = BLACK; + return; + } + /* Parent is red and has a parent. + * We now need to fix the parent.*/ + dir = CHILD_DIR(parent); + uncle = gparent->children[1-dir]; + if(uncle == NULL || uncle->color == BLACK) { + /* Parent is red, but uncle (opposite child of gparent) is black. + * We need to rotate the gparent node such that the parent takes + * its place. However, if the current node is an inner child of + * gparent, we need to rotate N into P.*/ + if(node == parent->children[1-dir]) { + /* Node is an inner child. We need to rotate N and P first.*/ + s_node_rotate(tree, parent, dir); + node = parent; + parent = gparent->children[dir]; + } + /* N is not an inner child, we can rotate the tree properly.*/ + s_node_rotate(tree, gparent, 1-dir); + parent->color = BLACK; + gparent->color = RED; + return; + } + } +} + +/**Insert a node into the rbtree on the parent and direction given. + * @param tree to insert into. + * @param node to insert. + * @param parent node to insert onto. + * @param dir direction to insert node.*/ +void +s_node_insert(rbtree_t *tree, rbnode_t *node, rbnode_t *parent, bool dir) +{ + node->color = RED; + node->left = NULL; + node->right = NULL; + node->parent = parent; + if(parent == NULL) { + tree->root = node; + return; + } + parent->children[dir] = node; + s_node_insert_fix(tree, node, parent, dir); +} + +void +s_node_remove_fixup(rbtree_t *tree, rbnode_t *node) +{ + bool dir; + rbnode_t *parent = node->parent; + rbnode_t *sibling; + rbnode_t *cnephew; + rbnode_t *dnephew; + + dir = CHILD_DIR(node); + parent->children[dir] = NULL; + while((parent = node->parent) != NULL) + { + dir = CHILD_DIR(node); + sibling = parent->children[1-dir]; + cnephew = parent->children[ dir]; + dnephew = parent->children[1-dir]; + if(sibling->color == RED) + goto case3; + if(dnephew != NULL && dnephew->color == RED) + goto case6; + if(cnephew != NULL && cnephew->color == RED) + goto case5; + if(parent->color == RED) + goto case4; + + /* The parent, both nephews, and sibling are black. We need to paint + * the sibling black and move up a level.*/ + sibling->color = RED; + node = parent; + } + return; + +case3: + /* The sibling is red, which means both nephews and the parent are black. + * We rotate the subtree so that the parent moves to become the siblings + * left child. The tree is then repainted.*/ + s_node_rotate(tree, parent, dir); + parent->color = RED; + sibling->color = BLACK; + /* Now we are working on the sibling subtree.*/ + sibling = cnephew; + dnephew = sibling->children[1-dir]; + if(dnephew != NULL && dnephew->color == BLACK) + goto case6; + cnephew = sibling->children[dir]; + if(cnephew != NULL && cnephew->color == RED) + goto case5; + +case4: + sibling->color = RED; + parent->color = BLACK; + return; + +case5: + s_node_rotate(tree, sibling, 1-dir); + sibling->color = RED; + cnephew->color = BLACK; + dnephew = sibling; + sibling = cnephew; + +case6: + s_node_rotate(tree, parent, dir); + sibling->color = parent->color; + parent->color = BLACK; + dnephew->color = BLACK; +} + +void +s_node_remove(rbtree_t *tree, rbnode_t *node) +{ + rbnode_t *parent = node->parent; + if(node->left != NULL && node->right != NULL) { + /* Node is a full tree. We can replace the node with it's successor to + * keep the balance. + * Needs to recurse if the successor has a right-most child, which is + * dealt with in the next case.*/ + rbnode_t *successor = s_node_successor(node); + s_node_copy_value(tree, node, successor); + s_node_remove(tree, successor); + return; + } else if(node->left == NULL && node->right == NULL) { + if(parent == NULL) { + tree->root = NULL; + kfree(node); + return; + } + if(node->color == RED) { + parent->children[CHILD_DIR(node)] = NULL; + kfree(node); + return; + } + s_node_remove_fixup(tree, node); + } else { + /* Node has a single child. Because the child must be red as per spec, + * and this node must be black, we can simply replace the node + * with it's child and color it black.*/ + rbnode_t *child = node->left == NULL ? node->right : node->left; + memcpy(node, child, sizeof(rbnode_t) + tree->objw); + node->parent = parent; + node->color = BLACK; + kfree(child); + return; + } +} + +void +__rbtree_new(rbtree_t *tree, size_t objw) +{ + *tree = (rbtree_t) { + .root = NULL, + .objw = objw, + }; +} + +void* +rbtree_find(rbtree_t *tree, intmax_t key) +{ + rbnode_t *found = s_find(tree, key); + if(found == NULL) return NULL; + return found->data; +} + +rbnode_t* +s_node_new(rbtree_t *tree, intmax_t key, void *data) +{ + rbnode_t *node = kmalloc(sizeof(rbnode_t) + tree->objw); + if(data != NULL) memcpy(node->data, data, tree->objw); + node->key = key; + return node; +} + +void* +rbtree_insert(rbtree_t *tree, intmax_t key, void *data) +{ + assert(tree != NULL); + + rbnode_t *node = s_closest(tree, key); + if(node != NULL && node->key == key) { + memcpy(node->data, data, tree->objw); + } else if(node != NULL) { + rbnode_t *child = s_node_new(tree, key, data); + s_node_insert(tree, child, node, node->key > key); + return child->data; + } else { + node = s_node_new(tree, key, data); + node->parent = NULL; + node->children[0] = node->children[1] = NULL; + node->color = BLACK; + tree->root = node; + } + return node->data; +} + +void *rbtree_reserve(rbtree_t *tree, intmax_t key) +{ + assert(tree != NULL); + + rbnode_t *node = s_closest(tree, key); + if(node != NULL && node->key == key) { + return node->data; + } else if(node != NULL) { + rbnode_t *child = s_node_new(tree, key, NULL); + s_node_insert(tree, child, node, node->key > key); + return child->data; + } else { + node = s_node_new(tree, key, NULL); + tree->root = node; + } + return node->data; +} + diff --git a/klib/rbtree.h b/klib/rbtree.h new file mode 100644 index 0000000..4376713 --- /dev/null +++ b/klib/rbtree.h @@ -0,0 +1,48 @@ +#ifndef JOVE_LIB_RBTREE_H +#define JOVE_LIB_RBTREE_H 1 + +#include +#include +#include +#include "memory.h" + +typedef struct rbnode +{ + struct rbnode *parent; + struct rbnode *children[2]; + intmax_t key; + bool color; + char data[]; +} rbnode_t; + +typedef struct rbtree +{ + rbnode_t *root; + size_t objw; +} rbtree_t; + +/**Instantiate a new tree based on the given type. + * @param tree to instantiate into. + * @param type to instantiate for.*/ +#define rbtree_new(tree, type) __rbtree_new(tree, sizeof(type)) +void __rbtree_new(rbtree_t *tree, size_t objw); + +/**Find the data corresponding to the key in the tree. + * usage: rbtree_find(type)(tree, key); + * @param tree to search through. + * @param key to search for. + * @return */ +void *rbtree_find(rbtree_t *tree, intmax_t key); + +/**Insert a value into the given tree using the given key. + * If the key is already present within the tree, the existing data is + * overwritten. + * @param tree to insert into. + * @param key to insert. + * @param value to insert. + * @return pointer to inserted data. + * */ +void *rbtree_insert(rbtree_t *tree, intmax_t key, void *value); +void *rbtree_reserve(rbtree_t *tree, intmax_t key); + +#endif diff --git a/klib/sfmt.c b/klib/sfmt.c new file mode 100644 index 0000000..519fbf4 --- /dev/null +++ b/klib/sfmt.c @@ -0,0 +1,115 @@ +#include "string.h" +#include "format.h" + +char* +sfmt(char *s, size_t limit, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + s = svfmt(s, limit, fmt, ap); + + va_end(ap); + return s; +} + +char* +svfmt(char *s, size_t limit, const char *fmt, va_list ap) +{ + + size_t fmtlen = strlen(fmt); + size_t si = 0; + for(size_t fmti = 0; fmti < fmtlen; fmti++) + { + if(si >= limit) break; + if(fmt[fmti] != '%') { + s[si++] = fmt[fmti]; + continue; + } + // TODO: Format flags + fmti++; + + bool alt = false; + bool zpad = false; + for(;;fmti++){ + if(fmt[fmti] == '#') { alt = true; continue; } + if(fmt[fmti] == '0') { zpad = true; continue; } + break; + } + int fwidth = 0; + if(fmt[fmti] >= '1' && fmt[fmti] <= '9') + { + for(;fmt[fmti] >= '0' && fmt[fmti] <= '9';fmti++) { + fwidth *= 10; + fwidth += fmt[fmti] - '0'; + } + } + int precision = 0; + if(fmt[fmti] == '.') + { + fmti++; + for(;fmt[fmti] >= '0' && fmt[fmti] <= '9';fmti++) { + precision *= 10; + precision += fmt[fmti] - '0'; + } + } + + bool sgn = true; + bool upper = false; + int radix = 10; + switch(fmt[fmti]) + { + case '%': + s[si++] = '%'; + break; + case 'p': + radix = 16; + alt = true; + case 'b': + if(radix == 10) radix = 2; + case 'X': + upper = true; + case 'x': + if(radix == 10) + radix = 16; + case 'o': + if(radix == 10) + radix = 8; + case 'u': + sgn = false; + case 'i': { + if((radix == 8 || radix == 16) && alt) { + s[si++] = '0'; + if(radix == 16) { + s[si++] = 'x'; + } + if(radix == 2) { + s[si++] = 'b'; + } + } + size_t osi = si; + size_t nlen = ltostr(&s[si], limit - si, va_arg(ap, long), sgn, radix); + if(upper) sntoupper(&s[si], nlen); + si += nlen; + + int lpad = fwidth - (int)nlen; + if(lpad > 0) + { + if(lpad + osi >= limit) lpad = (limit - osi - 1); + memmove(&s[osi + lpad], &s[osi], nlen); + memset(&s[osi], zpad ? '0' : ' ', lpad); + si += lpad; + } + } break; + case 's': { + const char *str = va_arg(ap, char*); + size_t slen = strlen(str); + size_t wlen = slen > limit - si ? limit - si : slen; + for(size_t i = 0; i < wlen; i++) + s[si++] = str[i]; + } break; + } + } + s[si] = 0; + return s; +} diff --git a/klib/spinlock.h b/klib/spinlock.h new file mode 100644 index 0000000..75af28a --- /dev/null +++ b/klib/spinlock.h @@ -0,0 +1,27 @@ +#ifndef JOVE_LIB_SPINLOCK_H +#define JOVE_LIB_SPINLOCK_H 1 + +#include + +typedef struct Spinlock +{ + atomic_flag flg; + + const char *locker_file; + const char *locker_func; + int locker_line; +} spinlock_t; + +#define spinlock_acquire(lock) \ + while(atomic_flag_test_and_set_explicit(&lock.flg, memory_order_acquire)) \ + __builtin_ia32_pause(); \ + lock.locker_file = __FILE__; \ + lock.locker_func = __FUNCTION__; \ + lock.locker_line = __LINE__ + +#define spinlock_release(lock) \ + atomic_flag_clear_explicit(&lock.flg, memory_order_release); \ + lock.locker_file = lock.locker_func = NULL; \ + lock.locker_line = -1 + +#endif diff --git a/klib/string.c b/klib/string.c new file mode 100644 index 0000000..4bb1bad --- /dev/null +++ b/klib/string.c @@ -0,0 +1,16 @@ +#include "string.h" + +size_t strlen(const char *s) { + size_t l = 0; + for(; *s != 0; s++, l++); + return l; +} + +int strcmp(const char *a, const char *b) +{ + size_t i = 0; + for(; a[i] != 0 && b[i] != 0; i++) { + if(a[i] != b[i]) return a[i] - b[i]; + } + return a[i] - b[i]; +} diff --git a/klib/toupper.c b/klib/toupper.c new file mode 100644 index 0000000..807eb38 --- /dev/null +++ b/klib/toupper.c @@ -0,0 +1,26 @@ +#include "string.h" + +int +toupper(int c) +{ + if(c >= 'a' && c <= 'z') + c -= ('a' - 'A'); + return c; +} + +char* +stoupper(char *s) +{ + char *o = s; + for(; *s != 0; s++) + *s = toupper(*s); + return o; +} + +char* +sntoupper(char *s, size_t limit) +{ + for(size_t i = 0; i < limit; i++) + s[i] = toupper(s[i]); + return s; +} diff --git a/lib/buddymap.c b/lib/buddymap.c deleted file mode 100644 index 6a616c9..0000000 --- a/lib/buddymap.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "buddymap.h" -#include "jove.h" - -#define BLOCK_AT_LAYER(blocks, l, i) blocks[l][i / BUDDY_BLOCK_BITS] -#define BLOCK_BITMASK(i) (1ULL << (i % BUDDY_BLOCK_BITS)) - -bool -buddy_bit_test(struct BuddyMap *map, size_t l, size_t i) -{ - return (BLOCK_AT_LAYER(map->blocks, l, i) & BLOCK_BITMASK(i)) > 0; -} - -void -buddy_bit_mark(struct BuddyMap *map, size_t l, size_t i) -{ - size_t wi = i << l; - size_t bits = 1ULL << l; - for(size_t wl = 0; wl < map->orders; wl++) { - if(bits == 0) { - if(buddy_bit_test(map, wl - 1, (wi << 1) + 1)) bits = 1; - } - for(size_t bit = 0; bit < bits; bit++) { - size_t rbit = bit + wi; - if(l == 0 && !buddy_bit_test(map, 0, rbit)) map->free--; - BLOCK_AT_LAYER(map->blocks, wl, rbit) |= BLOCK_BITMASK(rbit); - } - bits >>= 1; - wi >>= 1; - } -} - -void -buddy_bit_free(struct BuddyMap *map, size_t l, size_t i) -{ - size_t wi = i << l; - size_t bits = 1ULL << l; - for(size_t wl = 0; wl < map->orders; wl++) { - if(bits == 0) bits = 1; - for(size_t bit = 0; bit < bits; bit++) { - size_t rbit = bit + wi; - if(l == 0 && buddy_bit_test(map, 0, rbit)) map->free++; - BLOCK_AT_LAYER(map->blocks, wl, rbit) &= ~BLOCK_BITMASK(rbit); - } - bits >>= 1; - wi >>= 1; - } -} - -static void -s_buddy_op_range( - struct BuddyMap *map, - size_t l, - size_t start, - size_t end, - void (*op)(struct BuddyMap*, size_t, size_t)) -{ - size_t layerw = 1ULL << l; - size_t start_off = start % layerw; - size_t end_off = end % layerw; - - size_t start_real = start + (start_off > 0 ? (layerw - start_off) : 0); - size_t end_real = end - end_off; - - if(start_real != start) s_buddy_op_range(map, l - 1, start, start_real, op); - if(end_real != end) s_buddy_op_range(map, l - 1, end_real, end, op); - - size_t start_bit = start_real >> l; - size_t end_bit = end_real >> l; - if(start_bit == end_bit || end_bit < start_bit) return; - for(size_t bit = start_bit; bit < end_bit; bit++) - op(map, l, bit); -} - -static size_t -s_buddy_layer_bestfit(struct BuddyMap *map, size_t length) -{ - if(length == 1) return 0; - size_t length_log2 = LOG2(length); - if(length_log2 > map->orders) length_log2 = map->orders - 1; - return length_log2; -} - -void -buddy_mark_range(struct BuddyMap *map, size_t start, size_t end) -{ - size_t l = s_buddy_layer_bestfit(map, end - start); - s_buddy_op_range(map, l, start, end, buddy_bit_mark); -} -void -buddy_free_range(struct BuddyMap *map, size_t start, size_t end) -{ - size_t l = s_buddy_layer_bestfit(map, end - start); - s_buddy_op_range(map, l, start, end, buddy_bit_free); -} - -static intmax_t -s_buddy_top_firstfree(struct BuddyMap *map) -{ - size_t layer = map->orders - 1; - size_t layer_bits = map->bits >> layer; - size_t layer_blocks = layer_bits / BUDDY_BLOCK_BITS; - for(size_t i = 0; i < layer_blocks; i++) { - if(map->blocks[layer][i] == (uintptr_t)-1) continue; - for(size_t j = 0; j < BUDDY_BLOCK_BITS; j++) { - size_t bit = (i * BUDDY_BLOCK_BITS) + j; - if(buddy_bit_test(map, layer, bit)) continue; - return bit; - } - } - return -1; -} - -static intmax_t -s_buddy_top_alloc_contig(struct BuddyMap *map, size_t length) -{ - size_t layer = map->orders - 1; - size_t layer_bits = map->bits >> layer; - - size_t contig_base = 0; - size_t contig_bits = 0; - for(size_t i = 0; i < layer_bits; i++) { - if(buddy_bit_test(map, layer, i)) { - contig_base = i + 1; - contig_bits = 0; - continue; - } - if(++contig_bits == length) { - return contig_base; - } - } - return -1; -} - -intmax_t -buddy_alloc(struct BuddyMap *map, size_t length) -{ - size_t layer = s_buddy_layer_bestfit(map, length); - size_t layerw = 1ULL << layer; - size_t allocw = length / layerw; - - if(allocw == 0) allocw = 1; - if(allocw > 1) - return s_buddy_top_alloc_contig(map, length); - - intmax_t alloci = s_buddy_top_firstfree(map); - if(alloci < 0) { - klogf("Top layer is full!\n"); - return -1; - } - - for(int wlayer = map->orders - 2; wlayer > layer; wlayer--) { - alloci <<= 1; - if(buddy_bit_test(map, wlayer, alloci)) { - alloci++; - } - } - alloci <<= 1; - if(buddy_bit_test(map, layer, alloci)) alloci++; - - s_buddy_op_range(map, layer, alloci, alloci + length, buddy_bit_mark); - return alloci; -} - -void -buddy_free(struct BuddyMap *map, size_t i, size_t length) -{ - buddy_free_range(map, i, i + length); -} diff --git a/lib/buddymap.h b/lib/buddymap.h deleted file mode 100644 index 1af8dfb..0000000 --- a/lib/buddymap.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef JOVE_LIB_BUDDYMAP_H -#define JOVE_LIB_BUDDYMAP_H 1 - -#include -#include -#include - -#define BUDDY_BLOCK_BYTES sizeof(intmax_t) -#define BUDDY_BLOCK_BITS (BUDDY_BLOCK_BYTES * 8) - -#define BUDDY_BITS_FOR(range) (range * 2) -#define BUDDY_BLOCKS_FOR(range) (BUDDY_BITS_FOR(range) / BUDDY_BLOCK_BITS) - -struct BuddyMap -{ - size_t orders; - size_t bits; - size_t free; - uintmax_t **blocks; -}; - -#define BUDDY_BIT_PARTIAL 0 -#define BUDDY_BIT_FULL 1 - -bool buddy_bit_test(struct BuddyMap *map, size_t l, size_t i); -void buddy_bit_mark(struct BuddyMap *map, size_t l, size_t i); -void buddy_bit_free(struct BuddyMap *map, size_t l, size_t i); - -void buddy_mark_range(struct BuddyMap *map, size_t start, size_t end); -void buddy_free_range(struct BuddyMap *map, size_t start, size_t end); - -intmax_t buddy_alloc(struct BuddyMap *map, size_t length); -void buddy_free(struct BuddyMap *map, size_t i, size_t length); - -#endif diff --git a/lib/format.h b/lib/format.h deleted file mode 100644 index 5a2b75c..0000000 --- a/lib/format.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef JOVE_LIB_FORMAT_H -#define JOVE_LIB_FORMAT_H 1 - -#include -#include - -size_t ltostr(char *s, size_t limit, unsigned long l, bool sgn, int radix); - -char *sfmt(char *s, size_t limit, const char *fmt, ...); -#include -char *svfmt(char *s, size_t limit, const char *fmt, va_list ap); - -#endif diff --git a/lib/hashtable.c b/lib/hashtable.c deleted file mode 100644 index 17f1e74..0000000 --- a/lib/hashtable.c +++ /dev/null @@ -1,109 +0,0 @@ -#include "hashtable.h" -#include "string.h" -#include "mem/memory.h" - -static size_t -s_hash_function_mul(const void *data, size_t len) -{ - size_t hash = 1; - const char *cdata = (const char*)data; - for(size_t i = 0; i < len; i++) { - hash *= ((size_t)cdata[i]) + 1; - } - return hash; -} - -static size_t -s_hash_function_mul_s(const void *data, size_t _) -{ - return s_hash_function_mul(data, strlen(data)); -} - -void -_hashtable_new(struct HashTable *table, size_t obj_size, size_t key_size) -{ - *table = (struct HashTable){ - .buckets = NULL, - .bucket_count = 0, - .bucket_capacity = 2, - .obj_size = obj_size, - .key_size = key_size, - .hash_function = s_hash_function_mul - }; - table->buckets = mem_alloc(sizeof(struct SLinkedList) * 2); -} - -void -_hashtable_news(struct HashTable *table, size_t obj_size) -{ - *table = (struct HashTable){ - .buckets = NULL, - .bucket_count = 0, - .bucket_capacity = 2, - .obj_size = obj_size, - .key_size = -1, - .hash_function = s_hash_function_mul_s - }; - table->buckets = mem_alloc(sizeof(struct SLinkedList) * 2); -} - -void -hashtable_insert(struct HashTable *table, const void *key, void *data) -{ - size_t hash = table->hash_function(key, table->key_size); - if(table->bucket_capacity == table->bucket_count) { - struct SLinkedList *old_buckets = table->buckets; - size_t old_buckets_count = table->bucket_count; - - table->bucket_capacity *= 2; - table->bucket_count = 0; - table->buckets = mem_alloc(sizeof(struct SLinkedList) * table->bucket_capacity); - for(size_t i = 0; i < old_buckets_count; i++) { - for(struct SLLNode *node = old_buckets[i].head; node != NULL; node = node->next) { - struct HashTableValue *value = (struct HashTableValue*)(&node->data); - hashtable_insert(table, value->key, value->value); - mem_free(node); - } - } - } - - size_t index = hash % table->bucket_capacity; - struct SLinkedList *bucket = &table->buckets[index]; - struct SLLNode *node = mem_alloc(sizeof(struct SLLNode) + sizeof(struct HashTableValue) + table->obj_size); - struct HashTableValue *value = (struct HashTableValue*)(node->data); - - value->key = key; - memcpy(value->value, data, table->obj_size); - - table->bucket_count++; - if(bucket->count == 0) { - sll_new(bucket, table->obj_size); - sll_push(bucket, node); - return; - } - for(struct SLLNode *onode = bucket->head; onode != NULL; onode = onode->next) - { - struct HashTableValue *ovalue = (struct HashTableValue*)onode->data; - size_t keylen = table->key_size > 0 ? table->key_size : strlen((const char*)key) + 1; - if(memcmp(ovalue->key, value->key, keylen) == 0) { - memcpy(ovalue->value, value->value, table->obj_size); - return; - } - } - sll_push(bucket, node); -} - -void* -_hashtable_get(struct HashTable *table, const void *key) -{ - size_t hash = table->hash_function(key, table->key_size); - size_t index = hash % table->bucket_capacity; - struct SLinkedList *bucket = &table->buckets[index]; - for(struct SLLNode *node = bucket->head; node != NULL; node = node->next) - { - struct HashTableValue *value = (struct HashTableValue*)node->data; - size_t keylen = table->key_size > 0 ? table->key_size : strlen((const char*)value->key); - if(memcmp(key, value->key, keylen) == 0) return value->value; - } - return NULL; -} diff --git a/lib/hashtable.h b/lib/hashtable.h deleted file mode 100644 index fe6f5c3..0000000 --- a/lib/hashtable.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef JOVE_LIB_HASHTABLE_H -#define JOVE_LIB_HASHTABLE_H 1 - -#include -#include -#include "linkedlist.h" - -struct HashTableValue -{ - const void *key; - char value[]; -}; - -struct HashTable { - struct SLinkedList *buckets; - size_t bucket_count; - size_t bucket_capacity; - - size_t obj_size; - int key_size; - size_t (*hash_function)(const void*, size_t); -}; - -void _hashtable_new(struct HashTable *table, size_t obj_size, size_t key_size); -#define hashtable_new(table, type, keytype) _hashtable_new(table, sizeof(type), sizeof(keytype)) - -void _hashtable_news(struct HashTable *table, size_t obj_size); -#define hashtable_news(table, type) _hashtable_news(table, sizeof(type)) - -void hashtable_insert(struct HashTable *table, const void *key, void *data); -void *_hashtable_get(struct HashTable *table, const void *key); -#define hashtable_get(table, key, type) (type*)_hashtable_get(table, key) - -#endif diff --git a/lib/jove.h b/lib/jove.h deleted file mode 100644 index 6015112..0000000 --- a/lib/jove.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef JOVE_LIB_JOVE_H -#define JOVE_LIB_JOVE_H 1 - -#define ALWAYS_INLINE inline __attribute__((always_inline)) -#define PAGEALIGN __attribute__((aligned(0x1000))) - -#define LOG2(n) (31 - __builtin_clz(n)) - -extern void *_kernel_start; -extern void *_kernel_end; - -__attribute__((noreturn)) void _kpanic(const char *file, int line, const char *fmt, ...); -#define kpanic(...) _kpanic(__FILE__, __LINE__, __VA_ARGS__) - -#endif diff --git a/lib/kpanic.c b/lib/kpanic.c deleted file mode 100644 index 97e42eb..0000000 --- a/lib/kpanic.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "jove.h" -#include "io/log.h" - -#include - -__attribute__((noreturn)) -void _kpanic(const char *file, int line, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - klogf("!!! PANIC !!!\n%s:%i\n", file, line); - kvlogf(fmt, ap); - va_end(ap); - for(;;) __asm__ volatile("hlt"); -} diff --git a/lib/linkedlist.c b/lib/linkedlist.c deleted file mode 100644 index 6cc6403..0000000 --- a/lib/linkedlist.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "linkedlist.h" - -void -sll_new(struct SLinkedList *list, size_t obj_size) -{ - list->obj_size = obj_size; - list->count = 0; - list->head = list->tail = NULL; -}; - -void -sll_push(struct SLinkedList *list, void *data) -{ - struct SLLNode *node = (struct SLLNode*)data; - if(list->tail != NULL) { - list->tail->next = node; - } - if(list->head == NULL) - list->head = node; - list->tail = node; - list->count++; -} - -void* -sll_get(struct SLinkedList *list, size_t index) -{ - struct SLLNode *node = list->head; - if(node == NULL) return NULL; - if(index > list->count) return list->tail; - for(size_t i = 0; i < index; i++) { - node = node->next; - } - return node; -} diff --git a/lib/linkedlist.h b/lib/linkedlist.h deleted file mode 100644 index 26c148e..0000000 --- a/lib/linkedlist.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef JOVE_LIB_LINKEDLIST_H -#define JOVE_LIB_LINKEDLIST_H 1 - -#include -#include - -struct SLLNode { - struct SLLNode *next; - char data[]; -}; - -/*Singly Linked List*/ -struct SLinkedList -{ - struct SLLNode *head; - struct SLLNode *tail; - - size_t obj_size; - size_t count; -}; - -void sll_new(struct SLinkedList *list, size_t obj_size); -void sll_push(struct SLinkedList *list, void *node); -void *sll_get(struct SLinkedList *list, size_t index); - -#endif diff --git a/lib/ltostr.c b/lib/ltostr.c deleted file mode 100644 index e28be31..0000000 --- a/lib/ltostr.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "format.h" - -size_t -ltostr(char *s, size_t limit, unsigned long l, bool sgn, int radix) -{ - size_t si = 0; - size_t digits = 0; - if((long)l < 0 && sgn) { - l = -((long)l); - s[0] = '-'; - } - for(unsigned long lv = l; lv != 0; lv /= radix) - digits++; - digits = digits > limit ? limit : digits; - - if(digits-- == 0) - s[si++] = '0'; - for(unsigned long lv = l; lv != 0; lv /= radix) - { - if(si >= limit) return si; - int digit = lv % radix; - s[(digits - si)] = (digit >= 10 ? (digit + 'a' - 10) : digit + '0'); - si++; - } - return si; -} diff --git a/lib/mem.c b/lib/mem.c deleted file mode 100644 index b60fbbd..0000000 --- a/lib/mem.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "string.h" -#include "mem/memory.h" - -void* -memset(void *dest, int c, size_t n) -{ - char *destc = (char*)dest; - for(size_t i = 0; i < n; i++) - destc[i] = c; - return dest; -} - -void* -memcpy(void *dest, const void *src, size_t n) -{ - char *destc = (char*)dest; - const char *srcc = (const char*)src; - for(size_t i = 0; i < n; i++) - destc[i] = srcc[i]; - return dest; -} - -void* -memmove(void *dest, const void *src, size_t n) -{ - char *destc = (char*)dest; - const char *srcc = (const char*)src; - if(destc + n < srcc) return memcpy(dest, src, n); - char buffer[n]; - memcpy(buffer, src, n); - return memcpy(destc, buffer, n); -} - -int -memcmp(const void *a, const void *b, size_t n) -{ - const char *ac = (const char*)a; - const char *bc = (const char*)b; - for(size_t i = 0; i < n; i++) { - if(ac[i] != bc[i]) return ac[i] - bc[i]; - } - return 0; -} - -char* -strdup(const char *s) -{ - size_t slen = strlen(s); - char *ret = mem_alloc(slen); - memcpy(ret, s, slen); - return ret; -} diff --git a/lib/sfmt.c b/lib/sfmt.c deleted file mode 100644 index f903cbf..0000000 --- a/lib/sfmt.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "string.h" -#include "format.h" - -char* -sfmt(char *s, size_t limit, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - s = svfmt(s, limit, fmt, ap); - - va_end(ap); - return s; -} - -char* -svfmt(char *s, size_t limit, const char *fmt, va_list ap) -{ - - size_t fmtlen = strlen(fmt); - size_t si = 0; - for(size_t fmti = 0; fmti < fmtlen; fmti++) - { - if(si >= limit) break; - if(fmt[fmti] != '%') { - s[si++] = fmt[fmti]; - continue; - } - // TODO: Format flags - fmti++; - - bool alt = false; - bool zpad = false; - for(;;fmti++){ - if(fmt[fmti] == '#') { alt = true; continue; } - if(fmt[fmti] == '0') { zpad = true; continue; } - break; - } - int fwidth = 0; - if(fmt[fmti] >= '1' && fmt[fmti] <= '9') - { - for(;fmt[fmti] >= '0' && fmt[fmti] <= '9';fmti++) { - fwidth *= 10; - fwidth += fmt[fmti] - '0'; - } - } - int precision = 0; - if(fmt[fmti] == '.') - { - fmti++; - for(;fmt[fmti] >= '0' && fmt[fmti] <= '9';fmti++) { - precision *= 10; - precision += fmt[fmti] - '0'; - } - } - - bool sgn = true; - bool upper = false; - int radix = 10; - switch(fmt[fmti]) - { - case '%': - s[si++] = '%'; - break; - case 'b': - radix = 2; - case 'X': - upper = true; - case 'x': - if(radix == 10) - radix = 16; - case 'o': - if(radix == 10) - radix = 8; - case 'u': - sgn = false; - case 'i': { - if((radix == 8 || radix == 16) && alt) { - s[si++] = '0'; - if(radix == 16) { - s[si++] = 'x'; - } - if(radix == 2) { - s[si++] = 'b'; - } - } - size_t osi = si; - size_t nlen = ltostr(&s[si], limit - si, va_arg(ap, long), sgn, radix); - if(upper) sntoupper(&s[si], nlen); - si += nlen; - - int lpad = fwidth - (int)nlen; - if(lpad > 0) - { - if(lpad + osi >= limit) lpad = (limit - osi - 1); - memmove(&s[osi + lpad], &s[osi], nlen); - memset(&s[osi], zpad ? '0' : ' ', lpad); - si += lpad; - } - } break; - case 's': { - const char *str = va_arg(ap, char*); - size_t slen = strlen(str); - size_t wlen = slen > limit - si ? limit - si : slen; - for(size_t i = 0; i < wlen; i++) - s[si++] = str[i]; - } break; - } - } - s[si] = 0; - return s; -} diff --git a/lib/spinlock.h b/lib/spinlock.h deleted file mode 100644 index 75af28a..0000000 --- a/lib/spinlock.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef JOVE_LIB_SPINLOCK_H -#define JOVE_LIB_SPINLOCK_H 1 - -#include - -typedef struct Spinlock -{ - atomic_flag flg; - - const char *locker_file; - const char *locker_func; - int locker_line; -} spinlock_t; - -#define spinlock_acquire(lock) \ - while(atomic_flag_test_and_set_explicit(&lock.flg, memory_order_acquire)) \ - __builtin_ia32_pause(); \ - lock.locker_file = __FILE__; \ - lock.locker_func = __FUNCTION__; \ - lock.locker_line = __LINE__ - -#define spinlock_release(lock) \ - atomic_flag_clear_explicit(&lock.flg, memory_order_release); \ - lock.locker_file = lock.locker_func = NULL; \ - lock.locker_line = -1 - -#endif diff --git a/lib/string.c b/lib/string.c deleted file mode 100644 index 4bb1bad..0000000 --- a/lib/string.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "string.h" - -size_t strlen(const char *s) { - size_t l = 0; - for(; *s != 0; s++, l++); - return l; -} - -int strcmp(const char *a, const char *b) -{ - size_t i = 0; - for(; a[i] != 0 && b[i] != 0; i++) { - if(a[i] != b[i]) return a[i] - b[i]; - } - return a[i] - b[i]; -} diff --git a/lib/string.h b/lib/string.h deleted file mode 100644 index a91ec94..0000000 --- a/lib/string.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef JOVE_LIB_STRING_H -#define JOVE_LIB_STRING_H 1 - -#include - -int toupper(int c); -char *stoupper(char *s); -char *sntoupper(char *s, size_t limit); - -size_t strlen(const char *s); - -void *memset(void *dest, int c, size_t n); -void *memcpy(void *dest, const void *src, size_t n); -void *memmove(void *dest, const void *src, size_t n); -int memcmp(const void *a, const void *b, size_t n); -int strcmp(const char *a, const char *b); - -#endif diff --git a/lib/toupper.c b/lib/toupper.c deleted file mode 100644 index 807eb38..0000000 --- a/lib/toupper.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "string.h" - -int -toupper(int c) -{ - if(c >= 'a' && c <= 'z') - c -= ('a' - 'A'); - return c; -} - -char* -stoupper(char *s) -{ - char *o = s; - for(; *s != 0; s++) - *s = toupper(*s); - return o; -} - -char* -sntoupper(char *s, size_t limit) -{ - for(size_t i = 0; i < limit; i++) - s[i] = toupper(s[i]); - return s; -} diff --git a/main.c b/main.c index 91125af..a586287 100644 --- a/main.c +++ b/main.c @@ -1,26 +1,37 @@ -#include "arch/arch.h" -#include "io/log.h" -#include "mem/memory.h" -#include "mem/zone.h" -#include "boot/cmdline.h" -#include "ird/initrd.h" -#include "usr/tasking.h" -#include "usr/umode.h" -#include "lib/jove.h" +#include "device/serial.h" +#include "arch/processor.h" +#include "arch/cpu.h" +#include "memory.h" +#include "commandline.h" +#include "tasking.h" +#include "initrd.h" +#include "print.h" +/**Setup datastructures and other fields required for the execution manager + * and interfaces used by init.*/ void kernel_main(void) { serial_setup(); - arch_tables_setup(); - mem_setup(); + cpu_setup(); + processor_setup(proc_bsp); - cmdline_kernel_setup(); - initrd_setup(); + mm_setup_early(); + mm_setup(); tasking_setup(); - umode_setup(); + kpanic("Reached end of kernel_main\n"); +} + +/**Kernel execution context that sets up init.*/ +void +kernel_stage2(void) +{ + cmdline_kernel_setup(); + + initrd_setup(); - kpanic("Reached end of kernel main\n"); + extern void kinit(void); + kinit(); } diff --git a/mem/memory.c b/mem/memory.c deleted file mode 100644 index 26bbbd8..0000000 --- a/mem/memory.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "memory.h" -#include "zone.h" - -void -mem_setup(void) -{ - mem_zone_setup_standard(); - mem_paging_setup(); - mem_slab_setup(); -} diff --git a/mem/memory.h b/mem/memory.h deleted file mode 100644 index 251c6f5..0000000 --- a/mem/memory.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef JOVE_MEM_H -#define JOVE_MEM_H 1 - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (1 << PAGE_SHIFT) -#define PAGE_MASK (PAGE_SIZE - 1) - -#define KiB 1024ULL -#define MiB (KiB * KiB) -#define GiB (MiB * KiB) -#define TiB (GiB * KiB) - -#include "lib/spinlock.h" -#include "sys/types.h" - -typedef struct page_directory -{ - spinlock_t lock; - size_t id; - size_t ref; - physptr_t phys; - void *virt; -} page_directory_t; - -#include "slab.h" - -extern page_directory_t *current_page_directory; - -/**Setup the kernel structures responsible for handling physical memory translation.*/ -void mem_paging_setup(void); - -/**Check if a given pointer is valid. - * @param ptr pointer to check. - * @return if the pointer is valid.*/ -bool mem_check_ptr(const void *ptr); - -/** Return the physical memory mapping for the given address. - * @param pd page directory to get mapping in. - * @param addr address to get mapping for. - * @return HAL compliant page mapping.*/ -page_mapping_t mem_get_mapping_as(page_directory_t *pd, uintptr_t addr); - -/** Return the physical memory mapping for the given address. - * @param addr address to get mapping for. - * @return HAL compliant page mapping.*/ -page_mapping_t mem_get_mapping(uintptr_t addr); - -/** Map a page mapping to a given virtual address. - * @param pd pointer to the page directory to edit. - * @param mapping mapping to apply. - * @param virt virtual address to map to. */ -void mem_set_mapping_as(page_directory_t *pd, page_mapping_t mapping, uintptr_t virt); - -/** Map a page mapping to a given virtual address. - * @param pd pointer to the page directory to edit. - * @param mapping mapping to apply. - * @param virt virtual address to map to. */ -void mem_set_mapping(page_mapping_t mapping, uintptr_t virt); - -/** Make sure the range indicated is available in memory for specified pd - * If necessary, allocate new pages using the passed flags - * @param pd pointer to page directory to edit - * @param from start of the range - * @param to end of the range - * @param rw flag to mark page is writeable - * @param user flag to mark page as user accessable*/ -void mem_ensure_range_as(page_directory_t *pd, uintptr_t from, uintptr_t to, page_flags_t flg); - -/**Make sure the range indicated is available in memory - * If necessary, allocate new pages using the passed flags - * @param from start of the range. - * @param to end of the range. - * @param rw flag to mark page is writeable. - * @param user flag to mark page as user accessable*/ -void mem_ensure_range(uintptr_t from, uintptr_t to, page_flags_t flg); - -void mem_slab_setup(void); -void mem_slabcache_new(struct SlabCache *cache, char *name, size_t objsize); - -void* mem_slab_alloc(struct SlabCache *cache); -void mem_slab_free(struct SlabCache *cache, void *ptr); - -void* mem_alloc(size_t width); -void mem_free(void *ptr); - -/*Physical*/ - -physptr_t mem_phys_alloc(size_t pages); -void mem_phys_reserve(physptr_t start, physptr_t end); -void mem_phys_release(physptr_t start, physptr_t end); - -void mem_setup(void); - -#endif diff --git a/mem/phys.c b/mem/phys.c deleted file mode 100644 index bf56b77..0000000 --- a/mem/phys.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "memory.h" -#include "zone.h" -#include "lib/jove.h" - -void -mem_phys_reserve(physptr_t start, physptr_t end) -{ - size_t zone = mem_zone_for(start); - size_t limit = mem_zone_bound_upper(zone); - - if(end > limit) { - mem_phys_reserve(limit, end); - end = limit; - } - mem_zone_resv(MEM_ZONE_STANDARD, start, end); -} - -void -mem_phys_release(physptr_t start, physptr_t end) -{ - size_t zone = mem_zone_for(start); - size_t limit = mem_zone_bound_upper(zone); - - if(end > limit) { - mem_phys_release(limit, end); - end = limit; - } - mem_zone_free(MEM_ZONE_STANDARD, start, end); -} - -physptr_t -mem_phys_alloc(size_t pages) -{ - if(mem_zone_pages_free(MEM_ZONE_HIGHER) >= pages) - return mem_zone_alloc(MEM_ZONE_HIGHER, pages); - if(mem_zone_pages_free(MEM_ZONE_STANDARD) >= pages) - return mem_zone_alloc(MEM_ZONE_STANDARD, pages); - kpanic("Kernel ran out of physical memory!\n"); -} diff --git a/mem/slab.c b/mem/slab.c deleted file mode 100644 index 30bc23a..0000000 --- a/mem/slab.c +++ /dev/null @@ -1,209 +0,0 @@ -#include "slab.h" -#include "memory.h" -#include "lib/format.h" -#include "lib/string.h" -#include "lib/jove.h" -#include "io/log.h" - -extern void *_kernel_end; - -static uintptr_t s_addr_next_free; - -#define GENERIC_CACHEC 8 -static struct SlabCache s_generic_caches[GENERIC_CACHEC]; - -static uintptr_t -s_next_free(size_t width) -{ - uintptr_t ret = s_addr_next_free; - s_addr_next_free += width; - mem_ensure_range( - ret, - s_addr_next_free, - (page_flags_t) { - .present = true, - .writeable = true, - .useraccess = false, - .executable = false - }); - return ret; -} - -static int -s_get_free_listw(size_t slabw, size_t objw) -{ - int freelistc = 1; - while(freelistc < 256) { - int maxobjc = (slabw - (freelistc * sizeof(uintptr_t))) / objw; - if(maxobjc <= freelistc) return maxobjc; - freelistc++; - } - return freelistc; -} - -static struct SlabDescriptor -*s_slab_new(struct SlabCache *cache, struct SlabDescriptor *last) -{ - size_t slab_width = (cache->slab_pages << PAGE_SHIFT); - uintptr_t descr_base = s_next_free(slab_width); - struct SlabDescriptor *descr = (struct SlabDescriptor*)descr_base; - - size_t free_listc = s_get_free_listw( - slab_width - sizeof(struct SlabDescriptor), - cache->obj_size); - size_t descriptor_width = sizeof(struct SlabDescriptor) - + (free_listc * sizeof(uintptr_t)); - uintptr_t obj_base = descr_base + descriptor_width; - - if(free_listc < 8) { - free_listc = ((slab_width - sizeof(struct SlabDescriptor)) / cache->obj_size); - descr = mem_alloc(sizeof(struct SlabDescriptor) + (free_listc * sizeof(uintptr_t))); - obj_base = descr_base; - } - - *descr = (struct SlabDescriptor) { - .prev = last, - .next = (last == NULL ? NULL : last->next), - .slab_base = (void*)descr_base, - .obj_base = (void*)obj_base, - .free_count = free_listc, - .free_index = free_listc - 1 - }; - for(size_t i = 0; i < free_listc; i++) { - descr->free[i] = obj_base + (i * cache->obj_size); - } - - return descr; -} - -void -mem_slabcache_new(struct SlabCache *cache, char *name, size_t objsize) -{ - if(objsize % 8 > 0) objsize += (8 - (objsize % 8)); - size_t pages = objsize > 512 ? (objsize >> 9) : 1; - *cache = (struct SlabCache){ - .obj_size = objsize, - .slab_pages = pages, - .list_free = NULL, - .list_partial = NULL, - .list_full = NULL - }; - size_t namelen = strlen(name); - namelen = namelen > 32 ? 32 : namelen; - memcpy(cache->name, name, namelen); - - //Allocate the first slab - cache->list_free = s_slab_new(cache, NULL); -} - -void* -mem_slab_alloc(struct SlabCache *cache) -{ - // Get a free slab - struct SlabDescriptor *slab = NULL; - if(cache->list_partial != NULL) slab = cache->list_partial; - if(slab == NULL && cache->list_free != NULL) { - slab = cache->list_free; - cache->list_free = slab->next; - } - if(slab == NULL) slab = s_slab_new(cache, cache->list_free); - cache->list_partial = slab; - - // Take an object from the slab. - uintptr_t objaddr = slab->free[slab->free_index]; - slab->free_index -= 1; - - if(slab->free_index < 0) { - slab->next = cache->list_full; - cache->list_full = slab; - } - return (void*)objaddr; -} - -void -mem_slab_free(struct SlabCache *cache, void *ptr) -{ - uintptr_t addr = (uintptr_t)ptr; - //Look for the pointer in the bounds of every slab - for(struct SlabDescriptor *slab = cache->list_full; - slab != NULL; slab = slab->next) - { - uintptr_t base = (uintptr_t)slab->obj_base; - uintptr_t limit = ((uintptr_t)slab->slab_base) - + (cache->slab_pages << PAGE_SHIFT); - if(addr > limit || addr < base) continue; - if((addr - base) % cache->obj_size != 0) { - klogf("Tried to free offset pointer %#016X in slab %s\n", - addr, cache->name); - return; - } - slab->free_index++; - slab->free[slab->free_index] = addr; - - cache->list_full = slab->next; - slab->next = cache->list_partial; - cache->list_partial = slab; - return; - } - for(struct SlabDescriptor *slab = cache->list_partial; - slab != NULL; slab = slab->next) - { - uintptr_t base = (uintptr_t)slab->obj_base; - uintptr_t limit = ((uintptr_t)slab->slab_base) - + (cache->slab_pages << PAGE_SHIFT); - if(addr > limit || addr < base) continue; - if((addr - base) % cache->obj_size != 0) { - klogf("Tried to free offset pointer %#016X in slab %s\n", - addr, cache->name); - return; - } - slab->free_index++; - slab->free[slab->free_index] = addr; - - if(slab->free_index == (slab->free_count - 1)) { - cache->list_partial = slab->next; - slab->next = cache->list_free; - cache->list_free = slab; - } - return; - } -} - -void* -mem_alloc(size_t width) -{ - size_t width_log2 = (__builtin_clz(width) ^ 31) + 1; - if(width_log2 < 6) width_log2 = 6; - width_log2 -= 6; - if(width_log2 >= GENERIC_CACHEC) { - klogf("Allocation size %i too big for generic caches!\n", width); - return NULL; - } - - struct SlabCache *generic_cache = &s_generic_caches[width_log2]; - return mem_slab_alloc(generic_cache); -} - -void -mem_free(void *ptr) -{ - for(int i = 0; i < GENERIC_CACHEC; i++) { - mem_slab_free(&s_generic_caches[i], ptr); - } -} - -void -mem_slab_setup(void) -{ - s_addr_next_free = (uintptr_t)&_kernel_end; - s_addr_next_free = ((s_addr_next_free >> 12) + 1) << 12; - s_get_free_listw(PAGE_SIZE - sizeof(struct SlabDescriptor), 32); - - for(int i = 0; i < GENERIC_CACHEC; i++) - { - size_t objsize = 1 << (i + 6); - char slab_name[SLABCACHE_NAME_LIMIT]; - sfmt(slab_name, SLABCACHE_NAME_LIMIT, "generic_%i", 1 << (i + 6)); - mem_slabcache_new(&s_generic_caches[i], slab_name, objsize); - } -} diff --git a/mem/slab.h b/mem/slab.h deleted file mode 100644 index 074d278..0000000 --- a/mem/slab.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef JOVE_MEMORY_SLAB_H -#define JOVE_MEMORY_SLAB_H 1 - -#include -#include -#include - -#define SLABCACHE_NAME_LIMIT 32 -struct SlabCache -{ - char name[SLABCACHE_NAME_LIMIT]; - - struct SlabDescriptor *list_free; - struct SlabDescriptor *list_partial; - struct SlabDescriptor *list_full; - - size_t obj_size; - size_t slab_pages; -}; - -struct SlabDescriptor -{ - struct SlabDescriptor *prev; - struct SlabDescriptor *next; - void *slab_base; - void *obj_base; - - size_t free_count; - int free_index; - uintptr_t free[]; -}; - -#endif diff --git a/mem/zone.c b/mem/zone.c deleted file mode 100644 index 42a056e..0000000 --- a/mem/zone.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "zone.h" -#include "memory.h" -#include "boot/boot.h" -#include "lib/string.h" -#include "lib/jove.h" -#include "sys/errno.h" -#include "io/log.h" - -#define MEM_ZONE_STANDARD_PAGES (MEM_ZONE_STANDARD_LIMIT >> PAGE_SHIFT) - -static uintmax_t - s_zone_standard_freemap_blocks_flat[BUDDY_BLOCKS_FOR(MEM_ZONE_STANDARD_PAGES)]; -static uintmax_t* - s_zone_standard_freemap_blocks[MEM_BUDDY_ORDERS]; - -static struct PhysicalMemoryZone s_zones[MEM_ZONE_COUNT] = -{ - { - .name = "Standard", - .base = MEM_ZONE_STANDARD_BASE, - .limit = MEM_ZONE_STANDARD_LIMIT, - .freemap = { - .orders = MEM_BUDDY_ORDERS, - .bits = MEM_ZONE_STANDARD_PAGES, - .free = 0, - .blocks = s_zone_standard_freemap_blocks - } - }, - { - .name = "Higher", - .base = MEM_ZONE_HIGHER_BASE, - .limit = -1, - .freemap = { - .orders = MEM_BUDDY_ORDERS - } - } -}; - -int -mem_zone_for(uintptr_t addr) -{ - addr &= ~PAGE_MASK; - for(size_t zonei = 0; zonei < MEM_ZONE_COUNT; zonei++) - { - struct PhysicalMemoryZone *pmz = &s_zones[zonei]; - if(addr >= pmz->base && addr < pmz->limit) return zonei; - } - return -ENOTFOUND; -} - -uintptr_t -mem_zone_bound_lower(size_t zone) -{ - if(zone >= MEM_ZONE_COUNT) return 0; - return s_zones[zone].base; -} - -uintptr_t -mem_zone_bound_upper(size_t zone) -{ - if(zone >= MEM_ZONE_COUNT) return 0; - return s_zones[zone].limit; -} - -size_t -mem_zone_pages_free(size_t zone) -{ - if(zone >= MEM_ZONE_COUNT) return 0; - return s_zones[zone].freemap.free; -} - -void -_zone_resv(struct PhysicalMemoryZone *zone, uintptr_t base, uintptr_t limit) -{ - buddy_mark_range(&zone->freemap, base >> PAGE_SHIFT, limit >> PAGE_SHIFT); -} - -void -_zone_free(struct PhysicalMemoryZone *zone, uintptr_t base, uintptr_t limit) -{ - buddy_free_range(&zone->freemap, base >> PAGE_SHIFT, limit >> PAGE_SHIFT); -} - -int -mem_zone_resv(size_t zone, uintptr_t base, uintptr_t limit) -{ - if(zone >= MEM_ZONE_COUNT) return -EINVAL; - - size_t base_off = base % PAGE_SIZE; - - size_t base_real = (base & ~PAGE_MASK) + (base_off > 0 ? PAGE_SIZE : 0); - size_t limit_real = limit & ~PAGE_MASK; - _zone_resv(&s_zones[zone], base_real, limit_real); - return 0; -} - -int -mem_zone_free(size_t zone, uintptr_t base, uintptr_t limit) -{ - if(zone >= MEM_ZONE_COUNT) return -EINVAL; - - size_t base_off = base % PAGE_SIZE; - - size_t base_real = (base & ~PAGE_MASK) + (base_off > 0 ? PAGE_SIZE : 0); - size_t limit_real = limit & ~PAGE_MASK; - _zone_free(&s_zones[zone], base_real, limit_real); - return 0; -} - -uintptr_t -mem_zone_alloc(size_t zone, size_t pages) -{ - if(zone >= MEM_ZONE_COUNT) return 0; - - struct PhysicalMemoryZone *pmz = &s_zones[zone]; - intmax_t pagei = buddy_alloc(&pmz->freemap, pages); - if(pagei < 0) { - return 0; - } - - return (((uintmax_t)pagei) << PAGE_SHIFT) + pmz->base; -} - -void -mem_zone_setup_standard(void) -{ - struct PhysicalMemoryZone *standard_zone = &s_zones[MEM_ZONE_STANDARD]; - uintmax_t *map_block_layer_base = s_zone_standard_freemap_blocks_flat; - for(size_t i = 0; i < MEM_BUDDY_ORDERS; i++) { - size_t layer_entries = (standard_zone->freemap.bits / BUDDY_BLOCK_BITS) >> i; - standard_zone->freemap.blocks[i] = map_block_layer_base; - memset(map_block_layer_base, 0xFF, layer_entries * sizeof(uintmax_t)); - map_block_layer_base = &map_block_layer_base[layer_entries]; - } - - for(int i = 0; i < boot_memorymap.count; i++) { - struct MemoryMapEntry *entry = &boot_memorymap.entries[i]; - klogf("%2i\t%#016X -> %#016X (%i)\n", - i, entry->base, entry->base + entry->length, entry->usable); - if(entry->base > MEM_ZONE_STANDARD_LIMIT) continue; - size_t limit = entry->base + entry->length; - if(limit > MEM_ZONE_STANDARD_LIMIT) limit = MEM_ZONE_STANDARD_LIMIT; - if(entry->usable) - mem_zone_free(MEM_ZONE_STANDARD, entry->base, limit); - } -} diff --git a/mem/zone.h b/mem/zone.h deleted file mode 100644 index c0b0f52..0000000 --- a/mem/zone.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef JOVE_MEM_ZONE_H -#define JOVE_MEM_ZONE_H 1 - -#include -#include "lib/buddymap.h" - -enum { - MEM_ZONE_STANDARD = 0, /* First GiB of physical memory. */ - MEM_ZONE_HIGHER, - MEM_ZONE_COUNT -}; - -#define MEM_ZONE_STANDARD_BASE 0 -#define MEM_ZONE_STANDARD_LIMIT (1 * GiB) -#define MEM_ZONE_HIGHER_BASE MEM_ZONE_STANDARD_LIMIT - -#define MEM_BUDDY_ORDERS 12 -struct PhysicalMemoryZone -{ - const char *name; - - uintptr_t base; - uintptr_t limit; - - struct BuddyMap freemap; -}; - -/**Return the zone index for the given address - * @param addr address to look up - * @return zone index*/ -int mem_zone_for(uintptr_t addr); - -/**Return the lower bound for the given zone index. - * @param zone index into zones. - * @return lower bound.*/ -uintptr_t mem_zone_bound_lower(size_t zone); - -/**Return the upper bound for the given zone index. - * @param zone index into zones. - * @return upper bound.*/ -uintptr_t mem_zone_bound_upper(size_t zone); - -/**Return the number of pages free in the given zone. - * @param zone index into zones. - * @return number of free pages.*/ -size_t mem_zone_pages_free(size_t zone); - -/** Using a given zone, reserve a range of physical addresses - * @param zone identifier of zone to modify - * @param base starting address to reserve - * @param limit ending address to reserve - * @return error code or 0 if success */ -int mem_zone_resv(size_t zone, uintptr_t base, uintptr_t limit); - -/** Using a given zone, free a range of physical addresses - * @param zone identifier of zone to modify - * @param base starting address to free - * @param limit ending address to free - * @return error code or 0 if success*/ -int mem_zone_free(size_t zone, uintptr_t base, uintptr_t limit); - -/** Allocate a number of pages from the given zone - * @param zone identifier of the zone to modify - * @param pages number of pages to allocate - * @return physical memory address of allocation - * zero if allocation failed*/ -uintptr_t mem_zone_alloc(size_t zone, size_t pages); - -void mem_zone_setup_standard(void); - -#endif diff --git a/memory/alloc/calloc.c b/memory/alloc/calloc.c new file mode 100644 index 0000000..cd272af --- /dev/null +++ b/memory/alloc/calloc.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) Jon Santmyer. + * This source file is released under the LGPL Version 3 as detailed in + * the LICENSE file provided in the following repository: + * https://git.jonsantmyer.com/heap/ + * */ + +#include "malloc.h" +#include + +void* +__calloc_impl(heap_cache_t *cache, size_t nmemb, size_t w) +{ + w = REALW(w); + void *ptr = __malloc_impl(cache, w * nmemb); + if(ptr == NULL) return NULL; + + /* Zero newly allocated memory as per spec.*/ + memset(ptr, 0, w * nmemb); + return ptr; +} diff --git a/memory/alloc/free.c b/memory/alloc/free.c new file mode 100644 index 0000000..e2cc060 --- /dev/null +++ b/memory/alloc/free.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) Jon Santmyer. + * This source file is released under the LGPL Version 3 as detailed in + * the LICENSE file provided in the following repository: + * https://git.jonsantmyer.com/heap/ + * */ + +#include "malloc.h" +#include "assert.h" + +bucket_t* +__bucket_from_obj(heap_cache_t *cache, bucket_obj_t *obj) +{ + assert(cache != NULL); + assert(cache->head != NULL); + /* Buckets are always aligned to the nearest page boundary, and that the + * metadata is always below the object. We use this fact to quickly find + * owning buckets.*/ + uintptr_t objptr = (uintptr_t)obj; + uintptr_t bktptr = objptr & ~0xFFF; + while(1) { + /* If the page boundary is below the head, we are below the heap memory + * region and can stop.*/ + if(bktptr < (uintptr_t)cache->head) return NULL; + + /* At each page boundary below the object, check for the heap checksum. + * If it is found, we can assume that we found a bucket.*/ + bucket_t *bucket = (bucket_t*)bktptr; + if(OBJ_VALID(bucket)) { + if(bucket->limit > objptr) return NULL; + return bucket; + } + + bktptr -= BUCKET_ALIGN; + } +} + +void +__free_impl(heap_cache_t *cache, void *ptr) +{ + DBGPRINT("free: asking to free ptr %p\n", ptr); + assert(cache != NULL); + /* free(NULL) does nothing.*/ + if(ptr == NULL) return; + + /* Make sure the pointer actually comes from the heap.*/ + assert((uintptr_t)ptr < (uintptr_t)cache->tail); + assert((uintptr_t)ptr > (uintptr_t)cache->head); + bucket_obj_t *obj = OBJ_FROM_PTR(ptr); + assert(OBJ_VALID(obj)); + + /* Mask the taken bit in the object to mark it free.*/ + DBGPRINT("free: masking taken bit in object %p (was %i, now ", + obj, obj->size_taken); + obj->size_taken &= ~1; + DBGPRINT("%i)\n", obj->size_taken); + + /* If the buckets' lastfree is greater than this new free object, this + * object will be the lastfree.*/ + bucket_t *bucket = __bucket_from_obj(cache, obj); + if(bucket != NULL && bucket->firstfree > obj) + bucket->firstfree = obj; + + /* Start trying to merge this free object with the next object. + * If the object after is taken, do nothing.*/ + bucket_obj_t *after = OBJ_AFTER(obj); + if((uintptr_t)after > bucket->limit) return; + assert(OBJ_VALID(after)); + if(OBJ_TAKEN(after)) return; + + /* Merge with the next object. + * from: + * [meta| -objw-][meta| -afterw-] + * to: + * [meta| ---------objw---------]*/ + DBGPRINT("free: obj %p merging with adjacent free object %p (was %i, now \n", + obj, after, obj->size_taken); + obj->size_taken += sizeof(bucket_obj_t) + after->size_taken; + DBGPRINT("%i)\n", obj->size_taken); +} diff --git a/memory/alloc/malloc.c b/memory/alloc/malloc.c new file mode 100644 index 0000000..ba1e2d2 --- /dev/null +++ b/memory/alloc/malloc.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) Jon Santmyer. + * This source file is released under the LGPL Version 3 as detailed in + * the LICENSE file provided in the following repository: + * https://git.jonsantmyer.com/heap/ + * */ + +#include "malloc.h" +#include "assert.h" +#include "jove.h" +#include "memory/bump.h" + +/**Allocate memory for a new bucket in the heap. + * Automatically aligns new memory to BUCKET_ALIGN. + * Instantiates a new free object spanning the entire bucket. + * Then adds the new bucket to the heap cache. + * If sbrk encounters an error, pass through errno and return NULL. + * @param cache to allocate for. + * @param objw width of the object the bucket is assumed to hold. + * @return bucket created by this function.*/ +bucket_t* +s_bucket_new(heap_cache_t *cache, size_t objw) +{ + DBGPRINT("malloc: ask for new bucket for cache %p with objw %i\n", cache, objw); + size_t bucketw = BUCKET_WIDTH(objw); + /* Assuming sbrk allocates memory for after the program break, make sure + * we allocate enough for the requested bucket width and any adjustments + * to ensure page alignment.*/ + uintptr_t pbrk = (uintptr_t)bump_where(); + uintptr_t brko = pbrk % BUCKET_ALIGN; + uintptr_t nbrk = (uintptr_t)bump_alloc(bucketw + brko); + + bucket_t *bucket = (bucket_t*)(nbrk + brko); + DBGPRINT("malloc: got new bucket at %p\n", bucket); + + *bucket = (bucket_t){ + .checksum = OBJ_CHECKSUM, + .next = NULL, + .limit = (uintptr_t)bucket + bucketw, + }; + /* Create a new object spanning the entire bucket. This new object will + * be the first free.*/ + bucket_obj_t *obj0 = (bucket_obj_t*)bucket->objs; + *obj0 = (bucket_obj_t) { + .checksum = OBJ_CHECKSUM, + .size_taken = bucketw - sizeof(bucket_t) - sizeof(bucket_obj_t) + }; + bucket->firstfree = obj0; + + /* If the cache is empty, this will be the first and last bucket.*/ + if(cache->head == NULL) { + cache->head = cache->tail = bucket; + return bucket; + } + /* Add the bucket to the heap cache bucket list.*/ + cache->tail->next = bucket; + cache->tail = bucket; + return bucket; +} + +/**Given an existing object and a size, split the object so that the original + * has size w. + * If the object is smaller than or is already the correct size, do nothing. + * Space after the split is allocated to a new free object after the resized + * original. + * If the original == bucket->firstfree, the new object is assigned to + * that variable. + * If the heap is corrupted, assert fail. + * @param bucket object's parent bucket. + * @param parent object to split. + * @param w requested size for original object. */ +void +s_obj_take_split(bucket_t *bucket, bucket_obj_t *parent, size_t w) +{ + DBGPRINT("malloc: requesting to split object %p (last %p) for size %i (was %i)\n", + bucket, parent, w, parent->size_taken); + + /* Assert fail on corrupted heap.*/ + assert(OBJ_VALID(bucket)); + assert(OBJ_VALID(parent)); + assert(w >= OBJ_SIZE_MIN); + + size_t objw = OBJ_WIDTH(parent); + if(w == objw) { /* Obj is already correct size, take and ignore.*/ + if(bucket->firstfree == parent) + bucket->firstfree = OBJ_AFTER(parent); + /* Ensure that firstfree does not exceed bucket limits.*/ + if((uintptr_t)bucket->firstfree > bucket->limit) + bucket->firstfree = NULL; + DBGPRINT("malloc: Object is already right size, ignoring\n"); + + /* Mark object as taken.*/ + parent->size_taken = w | 1; + return; + } + /* New object created by split will be the original width minus the new + * width and metadata size. + * + * from: + * [meta| --------objw-------- ] + * + * to: + * [meta| -w- ][meta| -afterw- ]*/ + size_t afterw = objw - sizeof(bucket_obj_t) - w; + + parent->size_taken = w | 1; + bucket_obj_t *obj = OBJ_AFTER(parent); + DBGPRINT("malloc: New object created inplace at %p with size %i\n", + obj, afterw); + + /* In-place allocate after obj.*/ + *obj = (bucket_obj_t){ + .checksum = OBJ_CHECKSUM, + .size_taken = afterw, + }; + if(bucket->firstfree == parent) + bucket->firstfree = obj; +} + +/* Look for a free object in the given bucket that closest matches size w. + * Uses bucket->firstfree as a starting point to save checks against taken + * objects. + * If the heap is corrupted, assert fail. + * If there are no good objects in this bucket, return NULL. + * @param bucket to search in. + * @param w to search for. + * @return best-fitting object or NULL if none are found. + * */ +bucket_obj_t* +s_obj_bestfit(bucket_t *bucket, size_t w) +{ + assert(bucket != NULL); + assert(OBJ_VALID(bucket)); + + bucket_obj_t *best = NULL; + bucket_obj_t *obj = bucket->firstfree; + if(obj == NULL) return NULL; + for(; (uintptr_t)obj < bucket->limit; obj = OBJ_AFTER(obj)) + { + assert(OBJ_VALID(obj)); + if(OBJ_TAKEN(obj)) continue; + size_t objw = OBJ_WIDTH(obj); + if(objw < w) continue; + if(best == NULL) best = obj; + + size_t bestw = OBJ_WIDTH(best); + if(objw < bestw) best = obj; + } + + DBGPRINT("malloc: Bucket %p returns best fit at %p for size %i ", + bucket, best, w); + if(best != NULL) { DBGPRINT("(size %i)\n", best->size_taken); } + else { DBGPRINT("(is NULL)\n"); } + + return best; +} + +/**Searching through the entire heap, or until an object is found, find a + * free object that best fits the requested width and place the resulting + * bucket in the passed pointer. + * If the heap is corrupted, assert fail. + * If no object is found in any of the buckets, return NULL. + * @param cache heap to search through. + * @param w object width to search for. + * @param bucket pointer to bucket pointer owning the returned bucket. + * If no object is found, variable is untouched. + * @return object that fits the given width.*/ +bucket_obj_t* +s_bucket_bestfit(heap_cache_t *cache, size_t w, bucket_t **bucket) +{ + *bucket = cache->head; + for(; *bucket != NULL; *bucket = (*bucket)->next) + { + bucket_obj_t *obj = s_obj_bestfit(*bucket, w); + /* Object is already found, don't waste cycles searching through + * the entire heap.*/ + if(obj != NULL) return obj; + } + return NULL; +} + +void* +__malloc_impl(heap_cache_t *cache, size_t w) +{ + assert(cache != NULL); + /* w == 0 is ub, just return NULL.*/ + if(w == 0) return NULL; + /* Ensure that w is valid.*/ + w = REALW(w); + + DBGPRINT("malloc: Asking to malloc for size %i\n", w); + + bucket_t *bucket = NULL; + bucket_obj_t *obj = s_bucket_bestfit(cache, w, &bucket); + if(obj == NULL) { + /* No bucket in the heap has an appropriate space. + * Allocate a new bucket and take the first object. + * If the bucket allocation fails, return -1 and pass errno through.*/ + bucket = s_bucket_new(cache, w); + if(bucket == NULL) return (void*)(-1); + obj = (bucket_obj_t*)bucket->objs; + } + /* Split the bucket to make the object bestfit.*/ + s_obj_take_split(bucket, obj, w); + return obj->data; +} diff --git a/memory/alloc/malloc.h b/memory/alloc/malloc.h new file mode 100644 index 0000000..abe87ff --- /dev/null +++ b/memory/alloc/malloc.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) Jon Santmyer. + * This source file is released under the LGPL Version 3 as detailed in + * the LICENSE file provided in the following repository: + * https://git.jonsantmyer.com/heap/ + * */ + +#ifndef _MALLOC_H +#define _MALLOC_H 1 + +/* A bucket-based malloc implementation for 2^n sized objects. + * Allocates memory at pbrk for use in dynamic allocations, called "objects". + * Each object is pre-empted by metadata, which stores a checksum, the width, + * and a bit to mark it as taken. + * + * Each alloc-able region is pre-empted by a "bucket", which stores metadata + * about the bucket's state, the width, the first free object, and the next + * bucket in the chain. + * + * Buckets are allocated when needed. The width of the new bucket is determined + * by the object that needs the bucket. + * Buckets are always page aligned, and the size is a multiple of a page width. + * + * Dependencies: + * stddef.h + * stdint.h + * errno.h + * assert.h + * assert + * string.h + * memset + * memcpy + * unistd.h + * sbrk + * brk + * + * with MALLOC_DBG: + * stdio.h + * printf*/ + +#include +#include + +#define DBGPRINT(...) +#ifdef MALLOC_DBG +#include "io/log.h" +#undef DBGPRINT +#define DBGPRINT(...) klogf(__VA_ARGS__) +#endif + +/* Bucket checksum is a 64-bit value containing the string "BUCKET\0\0"*/ +#define OBJ_CHECKSUM \ + (((uintmax_t)'B') | \ + ((uintmax_t)'U' << 8) | \ + ((uintmax_t)'C' << 16) | \ + ((uintmax_t)'K' << 24) | \ + ((uintmax_t)'E' << 32) | \ + ((uintmax_t)'T' << 40)) + +/* For an object to be valid, the object must have the correct checksum.*/ +#define OBJ_VALID(obj) (obj->checksum == OBJ_CHECKSUM) + +/* Object width is assumed to be a multiple of two. The first bit is reserved + * for the taken flag.*/ +#define OBJ_WIDTH(obj) (obj->size_taken & ~1) +#define OBJ_TAKEN(obj) (obj->size_taken & 1) + +/* Gets the object struct after this object. + * Since objects are allocated in-place, we can get the next object using + * the object's size and it's pointer to the start of data. + * + * The same is true for getting the metadata for any given data pointer. + * We take the pointer and subtract the size of the object struct from it + * since the metadata is behind the actual data.*/ +#define OBJ_AFTER(obj) \ + ((bucket_obj_t*)(((uintptr_t)obj->data) + OBJ_WIDTH(obj))) +#define OBJ_FROM_PTR(ptr) ((bucket_obj_t*)((uintptr_t)ptr - sizeof(bucket_obj_t))); + +typedef struct bucket_obj +{ + uintmax_t checksum; + size_t size_taken; + char data[]; +} bucket_obj_t; + +#define LOG2(n) ((31) - __builtin_clz(n)) +/* Buckets are always aligned to the page boundary for cache friendliness.*/ +#define BUCKET_ALIGN (4096) +/* Buckets should always be a multiple of the page width, expanding with the + * initial object size.*/ +#define BUCKET_WIDTH(w) \ + (1UL << (12 + (w < BUCKET_ALIGN ? 0 : LOG2(w + 1) - 11))) + +/* Bucket metadata is stored behind the object metadata.*/ +typedef struct bucket +{ + size_t checksum; + struct bucket *next; + + uintptr_t limit; + bucket_obj_t *firstfree; /* Helpful for fast object allocations.*/ + char objs[]; +} bucket_t; + +/* The overall size of an object (data + metadata) should be 2*metadata.*/ +#define OBJ_SIZE_MIN (sizeof(bucket_obj_t)) +/* Data width is always a power of two.*/ +#define REALW(n) \ + (n < OBJ_SIZE_MIN ? OBJ_SIZE_MIN : (1UL << (LOG2(n) + 1))) + +typedef struct heap_cache +{ + bucket_t *head; + bucket_t *tail; +} heap_cache_t; + +/**Given the heap cache and an object, find the bucket to which the object + * belongs. + * Since buckets are always page aligned, we can check each page boundary + * for the checksum until we find it, then check the limit. + * Since we also know the first bucket in the cache, we can also check if the + * passed object is invalid and return NULL. + * @param heap cache. + * @param obj to find the bucket for. + * @return bucket owning obj, or NULL if obj is invalid.*/ +bucket_t *__bucket_from_obj(heap_cache_t *heap, bucket_obj_t *obj); + +/**Allocate w bytes into the given heap. + * If w == 0, returns NULL. + * If w is not a power of 2, rounds to the nearest pow2. + * If the heap is corrupted, assert fail. + * If the program is OOM, errno is assumed to be set and returns (void*)-1 + * @param heap cache. + * @param w n-bytes to allocate. + * @return pointer to allocated memory.*/ +void* __malloc_impl(heap_cache_t *heap, size_t w); + +/**Allocate a contiguous array of nmemb members each w wide. + * Newly allocated memory is zero'd. + * If w == 0 || nmemb == 0, returns NULL + * If w is not a power of 2, rounds to nearest pow2 + * If the heap is corrupted, assert fail + * If the program is OON, ernno is assumed to be set and returns (void*)-1 + * @param heap cache. + * @param nmemb number of members. + * @param w number of bytes per member. + * @return pointer to allocated memory.*/ +void* __calloc_impl(heap_cache_t *heap, size_t nmemb, size_t w); + +/**Resize the given allocated memory region to fit w. + * If w is less than the original width, does nothing. + * If w == 0, frees p + * If the heap is corrupted, assert fail. + * If the heap is OOM, errno is assumed to be set and returns (void*)-1 + * @param heap cache. + * @param p pointer to reallocate. + * @param w width to fit p to. + * @return pointer to memory allocated to fit w.*/ +void* __realloc_impl(heap_cache_t *heap, void *p, size_t w); + +/**Resize the given allocated contiguous array to fit nmemb members of w width + * objects. + * Zeros the new members excluding already existing data. + * If w * nmemb is less than the original width, does nothing. + * If w == 0 || nmemb == 0, frees p + * If the heap is corrupted, assert fail. + * If the heap is OOM, errno is assumed to be set and returns (void*)-1 + * @param heap cache. + * @param p pointer to reallocate. + * @param nmemb number of members. + * @param w width to fit p to. + * @return pointer to memory allocated to fit w * nmemb.*/ +void* __reallocarray_impl(heap_cache_t *heap, void *p, size_t nmemb, size_t w); + +/**Free a pointer in the given heap. + * If p == NULL, do nothing. + * If p does not fall in the range of heap, assert fail. + * If the heap is corrupted, assert fail. + * @param heap cache. + * @param p pointer to free.*/ +void __free_impl(heap_cache_t *heap, void *p); + +#endif diff --git a/memory/alloc/realloc.c b/memory/alloc/realloc.c new file mode 100644 index 0000000..1b90e8c --- /dev/null +++ b/memory/alloc/realloc.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) Jon Santmyer. + * This source file is released under the LGPL Version 3 as detailed in + * the LICENSE file provided in the following repository: + * https://git.jonsantmyer.com/heap/ + * */ + +#include "malloc.h" +#include "assert.h" +#include "string.h" + +void* +__realloc_impl(heap_cache_t *cache, void *ptr, size_t w) +{ + if(w == 0) { + DBGPRINT("realloc: called with w == 0, freeing %p\n", ptr); + __free_impl(cache, ptr); + return NULL; + } + if(ptr == NULL) { + DBGPRINT("realloc: called with NULL ptr, alloc %i\n", w); + return __malloc_impl(cache, w); + } + + w = REALW(w); + bucket_obj_t *obj = OBJ_FROM_PTR(ptr); + + assert(OBJ_VALID(obj)); + size_t objw = OBJ_WIDTH(obj); + if(objw > w) return ptr; + + size_t wdiff = w - objw; + DBGPRINT("realloc: ptr %p needs %i new bytes\n", ptr, wdiff); + + bucket_obj_t *after = OBJ_AFTER(obj); + size_t afterw = 0; + bucket_t *bucket = __bucket_from_obj(cache, obj); + void *newptr = NULL; + + if(bucket == NULL) + goto resize_fail; + + if((uintptr_t)after > bucket->limit) goto resize_fail; + assert(OBJ_VALID(after)); + afterw = OBJ_WIDTH(after); + + if(OBJ_TAKEN(after)) + goto resize_fail; + + DBGPRINT("realloc: obj %p after obj %p is free (w %i)\n", after, obj, afterw); + if(objw + sizeof(bucket_obj_t) + afterw < w) + goto resize_fail; + + obj->size_taken = w | 1; + if(bucket->firstfree == after) + bucket->firstfree = OBJ_AFTER(obj); + + after = OBJ_AFTER(obj); + *after = (bucket_obj_t){ + .checksum = OBJ_CHECKSUM, + .size_taken = afterw - wdiff + }; + DBGPRINT("realloc: moved obj %p (%i) to resize obj %p (%i)\n", + after, after->size_taken, obj, obj->size_taken); + return ptr; + +resize_fail: + DBGPRINT("realloc: could not resize existing object, calling malloc\n"); + newptr = __malloc_impl(cache, w); + memcpy(newptr, ptr, obj->size_taken & ~1); + __free_impl(cache, ptr); + return newptr; +} diff --git a/memory/alloc/reallocarray.c b/memory/alloc/reallocarray.c new file mode 100644 index 0000000..c58dfe9 --- /dev/null +++ b/memory/alloc/reallocarray.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) Jon Santmyer. + * This source file is released under the LGPL Version 3 as detailed in + * the LICENSE file provided in the following repository: + * https://git.jonsantmyer.com/heap/ + * */ + +#include "malloc.h" +#include "assert.h" +#include "string.h" + +void* +__reallocarray_impl(heap_cache_t *cache, void *ptr, size_t nmemb, size_t w) +{ + /* Free if w == nmemb == 0*/ + if(w == 0 || nmemb == 0) { + __free_impl(cache, ptr); + return NULL; + } + + if(ptr == NULL) + return __calloc_impl(cache, nmemb, w); + + size_t allocw = w * nmemb; + w = REALW(w); + + bucket_obj_t *obj = OBJ_FROM_PTR(ptr); + assert(OBJ_VALID(obj)); + size_t oldw = OBJ_WIDTH(obj); + if(allocw < oldw) return ptr; + + ptr = __realloc_impl(cache, ptr, allocw); + size_t wdiff = allocw - oldw; + void *zeroat = (void*)(((uintptr_t)ptr) + oldw); + memset(zeroat, 0, wdiff); + return ptr; +} diff --git a/memory/bump.c b/memory/bump.c new file mode 100644 index 0000000..a6b0228 --- /dev/null +++ b/memory/bump.c @@ -0,0 +1,33 @@ +#include "bump.h" +#include "memory.h" + +static void *s_next_free; + +void* +bump_where(void) +{ + return s_next_free; +} + +void *bump_alloc(size_t size) +{ + void *ret = s_next_free; + s_next_free = (void*)((uintptr_t)s_next_free + size); + vm_ensure( + (uintptr_t)ret, + (uintptr_t)s_next_free, + (page_flags_t) { + .present = true, + .writeable = true, + .useraccess = false, + .executable = false + }); + return ret; +} + +void +bump_setup(void) +{ + extern void *_kernel_end; + s_next_free = (void*)&_kernel_end; +} diff --git a/memory/bump.h b/memory/bump.h new file mode 100644 index 0000000..5b1c2b7 --- /dev/null +++ b/memory/bump.h @@ -0,0 +1,10 @@ +#ifndef JOVE_MEMORY_BUMP_H +#define JOVE_MEMORY_BUMP_H 1 + +#include + +void *bump_where(void); +void *bump_alloc(size_t size); +void bump_setup(void); + +#endif diff --git a/memory/memory.c b/memory/memory.c new file mode 100644 index 0000000..2a0e8f2 --- /dev/null +++ b/memory/memory.c @@ -0,0 +1,39 @@ +#include "memory.h" +#include "alloc/malloc.h" +#include "zone.h" +#include "bump.h" + +heap_cache_t heap_cache; + +void* +kmalloc(size_t width) +{ + return __malloc_impl(&heap_cache, width); +} + +void* +krealloc(void *ptr, size_t width) +{ + return __realloc_impl(&heap_cache, ptr, width); +} + +void +kfree(void *ptr) +{ + __free_impl(&heap_cache, ptr); +} + +void +mm_setup_early(void) +{ + pm_zone_setup(); + vm_setup_early(); +} + +void +mm_setup(void) +{ + heap_cache = (heap_cache_t) { NULL, NULL }; + bump_setup(); + vm_setup(); +} diff --git a/memory/phys.c b/memory/phys.c new file mode 100644 index 0000000..4d9dbc1 --- /dev/null +++ b/memory/phys.c @@ -0,0 +1,39 @@ +#include "memory.h" +#include "zone.h" +#include "jove.h" + +void +pm_reserve(physptr_t start, physptr_t end) +{ + size_t zone = pm_zone_for(start); + size_t limit = pm_zone_bound_upper(zone); + + if(end > limit) { + pm_reserve(limit, end); + end = limit; + } + pm_zone_resv(MEM_ZONE_STANDARD, start, end); +} + +void +pm_release(physptr_t start, physptr_t end) +{ + size_t zone = pm_zone_for(start); + size_t limit = pm_zone_bound_upper(zone); + + if(end > limit) { + pm_release(limit, end); + end = limit; + } + pm_zone_free(MEM_ZONE_STANDARD, start, end); +} + +physptr_t +pm_alloc(size_t pages) +{ + if(pm_zone_pages_free(MEM_ZONE_HIGHER) >= pages) + return pm_zone_alloc(MEM_ZONE_HIGHER, pages); + if(pm_zone_pages_free(MEM_ZONE_STANDARD) >= pages) + return pm_zone_alloc(MEM_ZONE_STANDARD, pages); + kpanic("Kernel ran out of physical memory!\n"); +} diff --git a/memory/slab.c b/memory/slab.c new file mode 100644 index 0000000..dc8aeda --- /dev/null +++ b/memory/slab.c @@ -0,0 +1,148 @@ +#include "slab.h" +#include "bump.h" +#include "memory.h" +#include "string.h" +#include "jove.h" +#include "print.h" +#include "klib/format.h" + +static int +s_get_free_listw(size_t slabw, size_t objw) +{ + int freelistc = 1; + while(freelistc < 256) { + int maxobjc = (slabw - (freelistc * sizeof(uintptr_t))) / objw; + if(maxobjc <= freelistc) return maxobjc; + freelistc++; + } + return freelistc; +} + +static slab_t +*s_slab_new(slab_cache_t *cache, slab_t *last) +{ + size_t slab_width = (cache->slab_pages << PAGE_SHIFT); + uintptr_t descr_base = (uintptr_t)bump_alloc(slab_width); + slab_t *descr = (slab_t*)descr_base; + + size_t free_listc = s_get_free_listw( + slab_width - sizeof(slab_t), + cache->obj_size); + size_t descriptor_width = sizeof(slab_t) + + (free_listc * sizeof(uintptr_t)); + uintptr_t obj_base = descr_base + descriptor_width; + + if(free_listc < 8) { + free_listc = ((slab_width - sizeof(slab_t)) / cache->obj_size); + descr = kmalloc(sizeof(slab_t) + (free_listc * sizeof(uintptr_t))); + obj_base = descr_base; + } + cache->obj_capacity += free_listc; + + *descr = (slab_t) { + .prev = last, + .next = (last == NULL ? NULL : last->next), + .slab_base = (void*)descr_base, + .obj_base = (void*)obj_base, + .free_count = free_listc, + .free_index = free_listc - 1 + }; + for(size_t i = 0; i < free_listc; i++) { + descr->free[i] = obj_base + (i * cache->obj_size); + } + + return descr; +} + +void +slabcache_new(slab_cache_t *cache, char *name, size_t objsize) +{ + if(objsize % 8 > 0) objsize += (8 - (objsize % 8)); + size_t pages = objsize > 512 ? (objsize >> 9) : 1; + *cache = (slab_cache_t){ + .obj_size = objsize, + .slab_pages = pages, + .list_free = NULL, + .list_partial = NULL, + .list_full = NULL + }; + size_t namelen = strlen(name); + namelen = namelen > 32 ? 32 : namelen; + memcpy(cache->name, name, namelen); + + //Allocate the first slab + cache->list_free = s_slab_new(cache, NULL); +} + +void* +slab_alloc(slab_cache_t *cache) +{ + // Get a free slab + slab_t *slab = NULL; + if(cache->list_partial != NULL) slab = cache->list_partial; + if(slab == NULL && cache->list_free != NULL) { + slab = cache->list_free; + cache->list_free = slab->next; + } + if(slab == NULL) slab = s_slab_new(cache, cache->list_free); + cache->list_partial = slab; + + // Take an object from the slab. + uintptr_t objaddr = slab->free[slab->free_index]; + slab->free_index -= 1; + + if(slab->free_index < 0) { + slab->next = cache->list_full; + cache->list_full = slab; + } + return (void*)objaddr; +} + +void +slab_free(slab_cache_t *cache, void *ptr) +{ + uintptr_t addr = (uintptr_t)ptr; + //Look for the pointer in the bounds of every slab + for(slab_t *slab = cache->list_full; + slab != NULL; slab = slab->next) + { + uintptr_t base = (uintptr_t)slab->obj_base; + uintptr_t limit = ((uintptr_t)slab->slab_base) + + (cache->slab_pages << PAGE_SHIFT); + if(addr > limit || addr < base) continue; + if((addr - base) % cache->obj_size != 0) { + klogf("Tried to free offset pointer %#016X in slab %s\n", + addr, cache->name); + return; + } + slab->free_index++; + slab->free[slab->free_index] = addr; + + cache->list_full = slab->next; + slab->next = cache->list_partial; + cache->list_partial = slab; + return; + } + for(slab_t *slab = cache->list_partial; + slab != NULL; slab = slab->next) + { + uintptr_t base = (uintptr_t)slab->obj_base; + uintptr_t limit = ((uintptr_t)slab->slab_base) + + (cache->slab_pages << PAGE_SHIFT); + if(addr > limit || addr < base) continue; + if((addr - base) % cache->obj_size != 0) { + klogf("Tried to free offset pointer %#016X in slab %s\n", + addr, cache->name); + return; + } + slab->free_index++; + slab->free[slab->free_index] = addr; + + if(slab->free_index == ((int)slab->free_count - 1)) { + cache->list_partial = slab->next; + slab->next = cache->list_free; + cache->list_free = slab; + } + return; + } +} diff --git a/memory/zone.c b/memory/zone.c new file mode 100644 index 0000000..4201cee --- /dev/null +++ b/memory/zone.c @@ -0,0 +1,145 @@ +#include "zone.h" +#include "boot.h" +#include "memory.h" +#include "jove.h" +#include "string.h" +#include "print.h" + +#define MEM_ZONE_STANDARD_PAGES (MEM_ZONE_STANDARD_LIMIT >> PAGE_SHIFT) + +static uintmax_t + s_zone_standard_freemap_blocks_flat[BUDDY_BLOCKS_FOR(MEM_ZONE_STANDARD_PAGES)]; +static uintmax_t* + s_zone_standard_freemap_blocks[MEM_BUDDY_ORDERS]; + +static struct PhysicalMemoryZone s_zones[MEM_ZONE_COUNT] = +{ + { + .name = "Standard", + .base = MEM_ZONE_STANDARD_BASE, + .limit = MEM_ZONE_STANDARD_LIMIT, + .freemap = { + .orders = MEM_BUDDY_ORDERS, + .bits = MEM_ZONE_STANDARD_PAGES, + .free = 0, + .blocks = s_zone_standard_freemap_blocks + } + }, + { + .name = "Higher", + .base = MEM_ZONE_HIGHER_BASE, + .limit = -1, + .freemap = { + .orders = MEM_BUDDY_ORDERS + } + } +}; + +int +pm_zone_for(uintptr_t addr) +{ + addr &= ~PAGE_MASK; + for(size_t zonei = 0; zonei < MEM_ZONE_COUNT; zonei++) + { + struct PhysicalMemoryZone *pmz = &s_zones[zonei]; + if(addr >= pmz->base && addr < pmz->limit) return zonei; + } + return -1; +} + +uintptr_t +pm_zone_bound_lower(size_t zone) +{ + if(zone >= MEM_ZONE_COUNT) return 0; + return s_zones[zone].base; +} + +uintptr_t +pm_zone_bound_upper(size_t zone) +{ + if(zone >= MEM_ZONE_COUNT) return 0; + return s_zones[zone].limit; +} + +size_t +pm_zone_pages_free(size_t zone) +{ + if(zone >= MEM_ZONE_COUNT) return 0; + return s_zones[zone].freemap.free; +} + +void +_zone_resv(struct PhysicalMemoryZone *zone, uintptr_t base, uintptr_t limit) +{ + buddy_mark_range(&zone->freemap, base >> PAGE_SHIFT, limit >> PAGE_SHIFT); +} + +void +_zone_free(struct PhysicalMemoryZone *zone, uintptr_t base, uintptr_t limit) +{ + buddy_free_range(&zone->freemap, base >> PAGE_SHIFT, limit >> PAGE_SHIFT); +} + +int +pm_zone_resv(size_t zone, uintptr_t base, uintptr_t limit) +{ + assert(zone < MEM_ZONE_COUNT); + + size_t base_off = base % PAGE_SIZE; + + size_t base_real = (base & ~PAGE_MASK) + (base_off > 0 ? PAGE_SIZE : 0); + size_t limit_real = limit & ~PAGE_MASK; + _zone_resv(&s_zones[zone], base_real, limit_real); + return 0; +} + +int +pm_zone_free(size_t zone, uintptr_t base, uintptr_t limit) +{ + assert(zone < MEM_ZONE_COUNT); + + size_t base_off = base % PAGE_SIZE; + + size_t base_real = (base & ~PAGE_MASK) + (base_off > 0 ? PAGE_SIZE : 0); + size_t limit_real = limit & ~PAGE_MASK; + _zone_free(&s_zones[zone], base_real, limit_real); + return 0; +} + +uintptr_t +pm_zone_alloc(size_t zone, size_t pages) +{ + if(zone >= MEM_ZONE_COUNT) return 0; + + struct PhysicalMemoryZone *pmz = &s_zones[zone]; + intmax_t pagei = buddy_alloc(&pmz->freemap, pages); + if(pagei < 0) { + return 0; + } + + return (((uintmax_t)pagei) << PAGE_SHIFT) + pmz->base; +} + +void +pm_zone_setup(void) +{ + struct PhysicalMemoryZone *standard_zone = &s_zones[MEM_ZONE_STANDARD]; + uintmax_t *map_block_layer_base = s_zone_standard_freemap_blocks_flat; + for(size_t i = 0; i < MEM_BUDDY_ORDERS; i++) { + size_t layer_entries = (standard_zone->freemap.bits / BUDDY_BLOCK_BITS) >> i; + standard_zone->freemap.blocks[i] = map_block_layer_base; + memset(map_block_layer_base, 0xFF, layer_entries * sizeof(uintmax_t)); + map_block_layer_base = &map_block_layer_base[layer_entries]; + } + + for(int i = 0; i < boot_memorymap.count; i++) { + struct MemoryMapEntry *entry = &boot_memorymap.entries[i]; + kdbgf("%2i\t%#016X -> %#016X (%i)\n", + i, entry->base, entry->base + entry->length, entry->usable); + if(entry->base > MEM_ZONE_STANDARD_LIMIT) continue; + size_t limit = entry->base + entry->length; + if(limit > MEM_ZONE_STANDARD_LIMIT) limit = MEM_ZONE_STANDARD_LIMIT; + if(entry->usable) + pm_zone_free(MEM_ZONE_STANDARD, entry->base, limit); + } +} diff --git a/print.c b/print.c new file mode 100644 index 0000000..dc5597b --- /dev/null +++ b/print.c @@ -0,0 +1,40 @@ +#include "print.h" +#include "jove.h" +#include "string.h" +#include "device/serial.h" +#include "klib/format.h" +#include "klib/spinlock.h" + +static spinlock_t s_print_lock; +static char s_print_buffer[PRINT_BUFFERW]; + +static char *s_print_level_str[PRINT_ERROR + 1] = { + "[D] %s/%s:%i | ", + "[I] ", + "[W] %s/%s:%i | ", + "[!!E!!] %s/%s:%i | " +}; + +void +_plogvf(const char *file, const char *func, int line, int lvl, const char *fmt, va_list ap) +{ + spinlock_acquire(s_print_lock); + + char *buf = sfmt(s_print_buffer, PRINT_BUFFERW, s_print_level_str[lvl], + file, func, line); + size_t prew = strlen(buf); + + svfmt(&buf[prew], PRINT_BUFFERW - 128, fmt, ap); + serial_write(&COM1, buf, strlen(buf)); + + spinlock_release(s_print_lock); +} + +void +_plogf(const char *file, const char *func, int line, int lvl, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _plogvf(file, func, line, lvl, fmt, ap); + va_end(ap); +} diff --git a/sys/errno.h b/sys/errno.h deleted file mode 100644 index 8d0c980..0000000 --- a/sys/errno.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _SYS_ERRNO_H -#define _SYS_ERRNO_H 1 - -#define ENOPERM 1 -#define EFAULT 2 -#define EINVAL 3 -#define ENOSYS 4 -#define ENOTFOUND 5 - -#endif diff --git a/sys/permission.h b/sys/permission.h deleted file mode 100644 index 08bb765..0000000 --- a/sys/permission.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _SYS_PERMISSION_H -#define _SYS_PERMISSION_H 1 - -#define PERM_MEM_PHYS_RESV 1 /* Reserve physical memory. */ -#define PERM_MEM_PHYS_FREE 2 /* Free physical memory. */ -#define PERM_MEM_PHYS_ALLOC 4 /* Allocate physical memory. */ - -#define PERM_MEM_VIRT_PD 8 /* Work on any PD. */ -#define PERM_MEM_VIRT_MAP 0x10 /* Map physical memory to virtual memory. */ - -#endif diff --git a/sys/syscall.h b/sys/syscall.h deleted file mode 100644 index d8b64bb..0000000 --- a/sys/syscall.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _SYS_SYSCALL_H -#define _SYS_SYSCALL_H 1 - -#include -#include -#include "types.h" - -typedef struct syscall { - int id; -} syscall_t; - -struct syscall_log { - syscall_t syscall; - const char *message; -}; - -struct syscall_mem_phys_range_op { - syscall_t syscall; - uintptr_t base; - uintptr_t limit; -}; - -struct syscall_mem_phys_alloc { - syscall_t syscall; - size_t npages; - uintptr_t *result; -}; - -struct syscall_mem_virt_mapping { - syscall_t syscall; - linear_address_t addr; - page_mapping_t *result; -}; - -struct syscall_mem_virt_map { - syscall_t syscall; - linear_address_t addr; - page_mapping_t map; -}; - -struct syscall_mem_virt_alloc { - syscall_t syscall; - linear_address_t from; - uintptr_t to; - page_flags_t flg; -}; - -enum -{ - SYSCALL_LOG = 0, - SYSCALL_TID, - - SYSCALL_MEM_PHYS_RESV, - SYSCALL_MEM_PHYS_FREE, - SYSCALL_MEM_PHYS_ALLOC, - - SYSCALL_MEM_VIRT_MAPPING, - SYSCALL_MEM_VIRT_MAP, - SYSCALL_MEM_VIRT_ALLOC, - - SYSCALL_COUNT -}; - -#define _SYSCALL(data) \ - intmax_t ax; \ - __asm__ volatile("movq %0, %%rdi\nsyscall": "=a"(ax): "r"(data): "memory"); \ - return ax - -#endif diff --git a/sys/types.h b/sys/types.h deleted file mode 100644 index 0a519c5..0000000 --- a/sys/types.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _SYS_TYPES_H -#define _SYS_TYPES_H 1 - -#include -#include -#include - -typedef intmax_t tid_t; - -typedef struct { - intmax_t tid; - uintmax_t addr; -} linear_address_t; - -typedef uintptr_t physptr_t; - -typedef struct page_flags -{ - bool present; - bool writeable; - bool useraccess; - bool executable; -} page_flags_t; - -typedef struct page_mapping -{ - physptr_t phys; - page_flags_t pf; -} page_mapping_t; - - -#endif diff --git a/syscall/dbg_log.c b/syscall/dbg_log.c new file mode 100644 index 0000000..9055498 --- /dev/null +++ b/syscall/dbg_log.c @@ -0,0 +1,19 @@ +#include "handler.h" +#include "print.h" +#include "umode_vma.h" +#include "api/errno.h" + +int +_handler_dbg_log(struct sc_dbg_log *u_sc) +{ + struct sc_dbg_log sc; + if(user_vma_read(&sc, u_sc, sizeof(struct sc_dbg_log)) != 0) + return -EFAIL; + + char buf[sc.w]; + if(user_vma_read(buf, sc.s, sc.w) != 0) + return -EFAIL; + + klogf("%s", buf); + return 0; +} diff --git a/syscall/exit.c b/syscall/exit.c new file mode 100644 index 0000000..307ea7a --- /dev/null +++ b/syscall/exit.c @@ -0,0 +1,17 @@ +#include "api/syscall.h" +#include "api/errno.h" +#include "umode_vma.h" +#include "arch/processor.h" +#include "handler.h" + +int +_handler_exit(struct sc_exit *sc) +{ + int exit_code = 0; + if(user_vma_read(&exit_code, &sc->exit_code, sizeof(int)) != 0) + return -EFAIL; + + tcb_t *tcb = tcb_current(); + tcb_kill(tcb, exit_code); + return 0; +} diff --git a/syscall/handler.c b/syscall/handler.c new file mode 100644 index 0000000..5cafdc6 --- /dev/null +++ b/syscall/handler.c @@ -0,0 +1,23 @@ +#include "handler.h" +#include "print.h" +#include "umode_vma.h" +#include "api/errno.h" + +static void *s_handlers[] = { + (void*)_handler_dbg_log, + (void*)_handler_exit +}; +static size_t s_handlers_size = sizeof(s_handlers); + +int +_syscall_handler(void *data) +{ + uintmax_t req_id = 0; + if(user_vma_read(&req_id, data, sizeof(uintmax_t)) != 0) + return -EFAIL; + + if(req_id >= s_handlers_size) return -1; + int (*handle)(void*) = (int (*)(void*))s_handlers[req_id]; + kdbgf("syscall id %i handle %p\n", req_id, handle); + return handle(data); +} diff --git a/syscall/handler.h b/syscall/handler.h new file mode 100644 index 0000000..f746dcc --- /dev/null +++ b/syscall/handler.h @@ -0,0 +1,19 @@ +#ifndef _JOVE_SYSCALL_HANDLER_H +#define _JOVE_SYSCALL_HANDLER_H 1 + +#include "api/syscall.h" +#include "memory.h" + +int _syscall_handler(void *data); + +#define CHECKPTR(p) { \ + page_mapping_t mapping = vm_mapping_get((uintptr_t)p); \ + if(mapping.phys == 0 || /* Mapping must not map to NULL phys page. */ \ + mapping.pf.present == 0 || /* Mapping must be present. */\ + mapping.pf.useraccess == 0 /* Mapping must be useraccess. */) \ + return -1; } + +int _handler_dbg_log(struct sc_dbg_log *sc); +int _handler_exit(struct sc_exit *sc); + +#endif diff --git a/task/exrtab.c b/task/exrtab.c new file mode 100644 index 0000000..82b9e29 --- /dev/null +++ b/task/exrtab.c @@ -0,0 +1,19 @@ +#include "arch/processor.h" +#include "assert.h" + +void +_exrtab_push(void *v) +{ + processor_t *proc = processor_current(); + proc->exrtab[proc->ert_i++] = (uintptr_t)v; +} + +void* +_exrtab_pop(void) +{ + processor_t *proc = processor_current(); + + assert(proc->ert_i != 0); + uintptr_t r = proc->exrtab[--proc->ert_i]; + return (void*)r; +} diff --git a/task/init.c b/task/init.c new file mode 100644 index 0000000..c4c8bad --- /dev/null +++ b/task/init.c @@ -0,0 +1,22 @@ +#include "commandline.h" +#include "jove.h" +#include "initrd.h" +#include "tasking.h" +#include "arch/elf.h" + +__attribute__((noreturn)) void +kinit(void) +{ + const char *init_filepath = cmdline_get("init"); + if(init_filepath == NULL) + kpanic("init filepath not found in kernel commandline\n"); + + initrd_file_t *init_file = ird_getfile(init_filepath); + if(init_file == NULL) + kpanic("init file not found in initrd [filepath=\"%s\"]\n", init_filepath); + + uintptr_t ip = elf_load(init_file->data, init_file->size); + + kexec((void*)ip, 0, NULL, 0, NULL); + kpanic("Reached end of kinit\n"); +} diff --git a/task/stack.c b/task/stack.c new file mode 100644 index 0000000..396ab3e --- /dev/null +++ b/task/stack.c @@ -0,0 +1,14 @@ +#include "tasking.h" +#include "string.h" +#include "assert.h" + +void +tcb_stack_push(tcb_t *tcb, void *data, size_t len) +{ + assert(tcb != NULL); + void *spo = (void*)(tcb->ksp - len); + assert(spo >= tcb->stack); + + memcpy(spo, data, len); + tcb->ksp = (uintptr_t)spo; +} diff --git a/task/tasking.c b/task/tasking.c new file mode 100644 index 0000000..ee57a13 --- /dev/null +++ b/task/tasking.c @@ -0,0 +1,45 @@ +#include "tasking.h" +#include "slab.h" +#include "klib/rbtree.h" +#include "arch/processor.h" + +rbtree_t s_tcbs; +tcbid_t s_tcb_nextid = 0; +slab_cache_t s_kstack_slab; + +void +tasking_setup(void) +{ + rbtree_new(&s_tcbs, tcb_t); + slabcache_new(&s_kstack_slab, "kernel stack", KERNEL_STACKW); + + extern void kernel_stage2(void); + tcb_t *init_tcb = tcb_new((void*)kernel_stage2, pd_current()); + + tcb_switch(init_tcb); +} + +tcb_t* +tcb_new(void *ip, page_directory_t *pd) +{ + void *stack = slab_alloc(&s_kstack_slab); + tcb_t *tcb = rbtree_reserve(&s_tcbs, s_tcb_nextid); + *tcb = (tcb_t) { + .id = s_tcb_nextid++, + .stack = stack, + .ksp = ((uintptr_t)stack) + (KERNEL_STACKW - 1), + .pd = pd, + .state = TCB_RUNNING + }; + + tcb_prepare(tcb, ip); + return tcb; +} + +void +tcb_kill(tcb_t *tcb, int code) +{ + if(tcb->id == 0) kpanic("init thread killed!\n"); + tcb->state = TCB_DEAD; + tcb->exit_code = code; +} diff --git a/task/umode_vma.c b/task/umode_vma.c new file mode 100644 index 0000000..880e047 --- /dev/null +++ b/task/umode_vma.c @@ -0,0 +1,37 @@ +#include "umode_vma.h" +#include "arch/processor.h" +#include "api/errno.h" +#include "print.h" + +__attribute__((naked)) +int +_umode_vma_fail(void) +{ + __asm__ volatile(" \ + movq %%rbp, %%rsp; \ + popq %%rbp; \ + mov $1, %%eax; \ + retq":::); +} + +int +user_vma_read(void *dest, const void *src, size_t w) +{ + if((uintptr_t)src > USERLAND_MEMORY_LIMIT) return -EACCESS; + + _exrtab_push((void*)_umode_vma_fail); + for(size_t i = 0; i < w; i++) ((char*)dest)[i] = ((const char*)src)[i]; + _exrtab_pop(); + return 0; +} + +int +user_vma_write(void *dest, const void *src, size_t w) +{ + if((uintptr_t)dest > USERLAND_MEMORY_LIMIT) return -EACCESS; + + _exrtab_push((void*)_umode_vma_fail); + for(size_t i = 0; i < w; i++) ((char*)dest)[i] = ((const char*)src)[i]; + _exrtab_pop(); + return 0; +} diff --git a/usr/elf.h b/usr/elf.h deleted file mode 100644 index d805e55..0000000 --- a/usr/elf.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef JOVE_USER_ELF_H -#define JOVE_USER_ELF_H 1 - -#include - -/**Load an ELF file into usermode memory. - * @param data pointer to ELF file data buffer - * @param len length of ELF file data buffer - * @return entry point for loaded ELF exec*/ -void *elf_load(const void *data, size_t len); - -#endif diff --git a/usr/syscall.c b/usr/syscall.c deleted file mode 100644 index fbc5fe7..0000000 --- a/usr/syscall.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "syscall.h" -#include "sys/errno.h" -#include "sys/permission.h" -#include "usr/tasking.h" -#include "mem/memory.h" -#include "io/log.h" - -#define ENSURE_ADDR(ptr) \ - if(!mem_check_ptr(ptr)) { klogf("User passed bad address %#016X\n", ptr); return -EFAULT; } - -#define ENSURE_PERM(p) \ - if(!(task_current->perm & p)) return -ENOPERM - -#define PD_FOR_LINEAR_ADDRESS(addr) current_page_directory; \ - if(addr.tid == -1) addr.tid = task_current->id; \ - if(addr.tid != task_current->id) { \ - ENSURE_PERM(PERM_MEM_VIRT_PD); \ - struct Task *task = task_get(addr.tid); \ - if(task == NULL) return -EFAULT; \ - pd = task->pd; \ - } - -int _syscall_handler_log(struct syscall_log *req) -{ - ENSURE_ADDR(req->message); - klogf("%s", req->message); - return 0; -} - -intmax_t _syscall_handler_tid(syscall_t *req) -{ - return task_current->id; -} - -int _syscall_handler_mem_phys_resv(struct syscall_mem_phys_range_op *req) -{ - ENSURE_PERM(PERM_MEM_PHYS_RESV); - mem_phys_reserve(req->base, req->limit); - return 0; -} - -int _syscall_handler_mem_phys_free(struct syscall_mem_phys_range_op *req) -{ - ENSURE_PERM(PERM_MEM_PHYS_FREE); - mem_phys_release(req->base, req->limit); - return 0; -} - -int _syscall_handler_mem_phys_alloc(struct syscall_mem_phys_alloc *req) -{ - ENSURE_ADDR(req->result); - ENSURE_PERM(PERM_MEM_PHYS_ALLOC); - *req->result = mem_phys_alloc(req->npages); - return 0; -} - -int _syscall_handler_mem_virt_mapping(struct syscall_mem_virt_mapping *req) -{ - ENSURE_ADDR(req->result); - ENSURE_PERM(PERM_MEM_VIRT_MAP); - page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->addr); - *req->result = mem_get_mapping_as(pd, req->addr.addr); - return 0; -} - -int _syscall_handler_mem_virt_map(struct syscall_mem_virt_map *req) -{ - ENSURE_PERM(PERM_MEM_VIRT_MAP); - page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->addr); - mem_set_mapping_as(pd, req->map, req->addr.addr); - return 0; -} - -int _syscall_handler_mem_virt_alloc(struct syscall_mem_virt_alloc *req) -{ - ENSURE_PERM(PERM_MEM_VIRT_MAP); - ENSURE_PERM(PERM_MEM_PHYS_ALLOC); - page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->from); - mem_ensure_range_as(pd, req->from.addr, req->to, req->flg); - return 0; -} - -void *_syscall_handlers[SYSCALL_COUNT] = { - _syscall_handler_log, - _syscall_handler_tid, - - _syscall_handler_mem_phys_resv, - _syscall_handler_mem_phys_free, - _syscall_handler_mem_phys_alloc, - - _syscall_handler_mem_virt_mapping, - _syscall_handler_mem_virt_map, - _syscall_handler_mem_virt_alloc, -}; - -int -syscall_handler(syscall_t *req) -{ - ENSURE_ADDR(req); - if(req->id >= SYSCALL_COUNT) return -ENOSYS; - - ENSURE_ADDR(_syscall_handlers[req->id]); - return ((syscall_handler_t)(_syscall_handlers[req->id]))(req); -} diff --git a/usr/syscall.h b/usr/syscall.h deleted file mode 100644 index 5cc82b8..0000000 --- a/usr/syscall.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef JOVE_USER_SYSCALL_H -#define JOVE_USER_SYSCALL_H 1 - -#include "sys/syscall.h" - -typedef int (*syscall_handler_t)(syscall_t*); - -int _syscall_handler_log(struct syscall_log *req); -intmax_t _syscall_handler_tid(syscall_t *req); - -#endif diff --git a/usr/tasking.c b/usr/tasking.c deleted file mode 100644 index cb4df25..0000000 --- a/usr/tasking.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "tasking.h" - -void -task_perm_release(struct Task *task, size_t mask) -{ - task->perm &= ~mask; -} diff --git a/usr/tasking.h b/usr/tasking.h deleted file mode 100644 index 4b11999..0000000 --- a/usr/tasking.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef JOVE_TASKING_H -#define JOVE_TASKING_H 1 - -#include -#include -#include "sys/types.h" -#include "mem/memory.h" - -struct Task -{ - struct Task *next; - tid_t id; - uintptr_t kbp; - size_t perm; - - page_directory_t *pd; -}; - -extern struct Task *task_current; - -void tasking_setup(void); - -struct Task *task_new(struct Task *parent); -struct Task *task_get(tid_t id); - -void task_perm_release(struct Task *task, size_t mask); - -#endif diff --git a/usr/umode.c b/usr/umode.c deleted file mode 100644 index 1105d9e..0000000 --- a/usr/umode.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "umode.h" -#include "elf.h" -#include "boot/cmdline.h" -#include "lib/jove.h" -#include "ird/initrd.h" -#include "mem/memory.h" - -void -umode_setup(void) -{ - extern void syscall_setup_syscall(void); - syscall_setup_syscall(); - - const char *init_path = cmdline_get("init"); - if(init_path == NULL) - kpanic("Missing path to init ELF file / binary\n"); - - struct InitrdFile *init_file = ird_getfile(init_path); - if(init_file == NULL) - kpanic("Missing init file %s in initrd\n", init_path); - - void (*entry_point)(void) = elf_load(init_file->data, init_file->size); - if(entry_point == NULL) - kpanic("Init file %s is incorrectly formatted (want ELF64)\n", init_path); - - void *user_stack = (void*)(0x00007FFFFFFFFFFF); - mem_ensure_range( - (uintptr_t)user_stack & ~0xFFF, - (uintptr_t)user_stack, - (page_flags_t) { - .present = true, - .writeable = true, - .useraccess = true, - .executable = false - }); - - klogf("User entry point %#016X\n", entry_point); - umode_enter(entry_point, user_stack); -} diff --git a/usr/umode.h b/usr/umode.h deleted file mode 100644 index 2755abe..0000000 --- a/usr/umode.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JOVE_UMODE_H -#define JOVE_UMODE_H 1 - -void umode_setup(void); - -void umode_enter(void (*entry)(void), void *stack); - -#endif -- cgit v1.2.1