diff options
| -rw-r--r-- | Makefile | 24 | ||||
| -rw-r--r-- | TODO.txt | 26 | ||||
| -rw-r--r-- | arch/riscv/common/vmem.c | 104 | ||||
| -rw-r--r-- | arch/riscv/conf/apos.its | 2 | ||||
| -rw-r--r-- | arch/riscv/conf/init-link.S | 31 | ||||
| -rw-r--r-- | arch/riscv/conf/kernel-link.S | 4 | ||||
| -rw-r--r-- | arch/riscv/include/csr.h | 36 | ||||
| -rw-r--r-- | arch/riscv/include/vmem.h | 8 | ||||
| -rw-r--r-- | arch/riscv/init/head.S | 7 | ||||
| -rw-r--r-- | arch/riscv/init/init.c | 337 | ||||
| -rw-r--r-- | arch/riscv/kernel/irq.c | 4 | ||||
| -rw-r--r-- | arch/riscv/kernel/main.c | 314 | ||||
| -rw-r--r-- | arch/riscv/kernel/proc.c | 15 | ||||
| -rw-r--r-- | arch/riscv/kernel/vmem.c | 52 | ||||
| -rw-r--r-- | arch/riscv/proc.txt | 3 | ||||
| -rw-r--r-- | arch/riscv/source.mk | 5 | ||||
| -rw-r--r-- | common/elf.c | 9 | ||||
| -rw-r--r-- | common/initrd.c (renamed from kernel/temp.c) | 0 | ||||
| -rw-r--r-- | common/mem_nodes.c | 2 | ||||
| -rw-r--r-- | common/tcb.c | 55 | ||||
| -rw-r--r-- | common/vmem.c | 112 | ||||
| -rw-r--r-- | include/apos/elf.h | 33 | ||||
| -rw-r--r-- | include/apos/init.h | 31 | ||||
| -rw-r--r-- | include/apos/initrd.h | 9 | ||||
| -rw-r--r-- | include/apos/pmem.h | 6 | ||||
| -rw-r--r-- | include/apos/proc.h | 7 | ||||
| -rw-r--r-- | include/apos/tcb.h | 34 | ||||
| -rw-r--r-- | include/apos/vmem.h | 18 | ||||
| -rwxr-xr-x | scripts/gen-deps | 30 |
29 files changed, 649 insertions, 669 deletions
@@ -5,7 +5,7 @@ DEBUGFLAGS != [ $(RELEASE) ] && echo "-flto -O2" || echo "-O0 -ggdb3 -DDEBUG" CFLAGS = -fno-pie -ffreestanding -nostdlib -std=c17 -Wall -Wextra DEPFLAGS = -MT $@ -MMD -MP -MF $@.d -all: apos.bin +all: kernel.bin # default values, overwrite if/when needed ARCH ?= riscv @@ -20,10 +20,8 @@ OBJCOPY ?= objcopy # This makes sure .bss is loaded into the binary OBJCOPY_FLAGS ?= -Obinary --set-section-flags .bss=alloc,load,contents -COMMON_SOURCES != echo common/*.c lib/fdt*.c -KERNEL_SOURCES != echo kernel/*.c $(COMMON_SOURCES) -INIT_SOURCES := $(COMMON_SOURCES) -CLEANUP := build deps.mk kernel.* init.* apos.bin +KERNEL_SOURCES != echo common/*.c lib/*.c +CLEANUP := build deps.mk kernel.* apos.bin CLEANUP_CMD := include arch/$(ARCH)/source.mk @@ -43,32 +41,20 @@ KERN_SIZE = wc -c kernel.bin | cut -d ' ' -f 1 KERN_INFO = sed "s/<KERNEL_SIZE>/$$($(KERN_SIZE))/" KERNEL_LINK := arch/$(ARCH)/conf/kernel-link -INIT_LINK := arch/$(ARCH)/conf/init-link -KERNEL_OBJECTS != ./scripts/gen-deps --kern "$(KERNEL_SOURCES)" -INIT_OBJECTS != ./scripts/gen-deps --init "$(INIT_SOURCES)" -KERNEL_LD != ./scripts/gen-deps --kern-link "$(KERNEL_LINK).S" -INIT_LD != ./scripts/gen-deps --init-link "$(INIT_LINK).S" +KERNEL_OBJECTS != ./scripts/gen-deps --compile "$(KERNEL_SOURCES)" +KERNEL_LD != ./scripts/gen-deps --link "$(KERNEL_LINK).S" include deps.mk -apos.bin: kernel.bin init.bin - cat init.bin kernel.bin > $@ - kernel.elf: $(KERNEL_OBJECTS) $(KERNEL_LD) $(GENELF) -T $(KERNEL_LD) $(KERNEL_OBJECTS) -o $@ $(INIT_LD): kernel.bin -init.elf: $(INIT_OBJECTS) $(INIT_LD) - $(GENELF) -T $(INIT_LD) $(INIT_OBJECTS) -o $@ - kernel.bin: kernel.elf $(CROSS_COMPILE)$(OBJCOPY) $(OBJCOPY_FLAGS) $< $@ -init.bin: init.elf - $(CROSS_COMPILE)$(OBJCOPY) $(OBJCOPY_FLAGS) $< $@ - clean: $(RM) -r $(CLEANUP) @@ -1,22 +1,6 @@ -+ Add in sensible defines (uint64_t etc.) x -+ Improve build process (Kbuild? nah, regular config.h files) -+ Automate booting and starting qemu etc. (make run) (sort of) -+ Add in pmem/vmem routines (both .init and .text!) - -+ Test string.c -+ Write the kernel lol -+ Test libfdt and see if it can be used to read memory geometry etc. - -+ Jump to vmem x -+ Mark fdt, reserved mem, kernel, init and initrd in vmem. Remember to remove -init from vmem when jumping to vmem -+ Figure out best way to tell the init how large out kernel is x~ -+ Make code more robust, error checking etc -+ Make all physical memory addresses use the same typedef x - -+ should I consider passing more pointers around rather than return structures? -+ should probably come up with some kind of general error handling scheme? - -+ Fix unmap/map_vmem when called from virtual memory - + Investigate GCC/Clang builtin atomic operations? + ++ Add in mapping the same memory to two different processes ++ Create sensible thread handling ++ Add in init process loading ++ Make sure vmap is in 4K increments or whatever diff --git a/arch/riscv/common/vmem.c b/arch/riscv/common/vmem.c deleted file mode 100644 index 6b022e1..0000000 --- a/arch/riscv/common/vmem.c +++ /dev/null @@ -1,104 +0,0 @@ -#include <apos/string.h> -#include <apos/pmem.h> -#include <apos/vmem.h> -#include <apos/mem.h> -#include <apos/debug.h> -#include <pages.h> - -#define pte_ppn(pte) (((pm_t)(pte)) >> 10) -#define pte_flags(pte) (((pm_t)(pte)) & 0xff) -#define to_pte(p, f) ((pm_to_pnum(p) << 10) + (f)) -#define pte_addr(pte) (pnum_to_paddr(pte_ppn(pte))) -#define vm_to_index(a, o) (pm_to_index(a, o)) - -#if defined(KERNEL) - -static vm_t *tmp_pte = 0; -void arch_init_vmem(struct vm_branch_t *branch, vm_t pte) -{ - (void)branch; - tmp_pte = (vm_t *)pte; -} - -/* this seems like an awful idea, should probably try to come up with a smarter - * approach? flushing the cache every time is probably pretty slow and also - * this code doesn't take into account the cpu ASID, although that's probably - * not relevant here */ - -/* what I probably should do is something like Linux, where the kernel has a - * direct (or linear, I suppose?) so that all direct memory accesses are also - * accessible from virtual memory. Not entirely sure how I should do that, - * wouldn't there be situations where the RAM is larger than the allocated - * memory region? - * - * Or maybe some kind of walker, where I maintain a virtual page table that - * mirrors the physical page table? Not sure yet, but this seems to work for - * _now_. - */ -#define QUOTE2(x) #x -#define QUOTE(x) QUOTE2(x) -static void *set_vptr(uint8_t flags, pm_t a) -{ - *tmp_pte = to_pte(a, flags); - __asm__ ("sfence.vma %0, %1" - :: "rk" (0), "rK" (TMP_PTE) - : "memory"); - - return (void *)TMP_PTE; -} - -#else -struct vm_branch_t *arch_get_tmp_pte(struct vm_branch_t *branch) -{ - enum mm_order_t top = __mm_max_order; - while(top){ - size_t idx = vm_to_index(TMP_PTE, top); - branch = (struct vm_branch_t *)pte_addr(branch->leaf[idx]); - top--; - } - - return branch; -} - -#define set_vptr(flags, a) (a) -#endif - -void map_vmem(struct vm_branch_t *branch, - pm_t paddr, vm_t vaddr, uint8_t flags, enum mm_order_t order) -{ - enum mm_order_t top = __mm_max_order; - while (top != order) { - size_t idx = vm_to_index(vaddr, top); - - if (!branch->leaf[idx]) { - pm_t new_leaf = alloc_page(MM_KPAGE, 0); - branch->leaf[idx] = - (struct vm_branch_t *)to_pte(new_leaf, VM_V); - - void *leaf_ptr = (void *)set_vptr(VM_R | VM_W | VM_V, new_leaf); - memset(leaf_ptr, 0, sizeof(struct vm_branch_t)); - } - - pm_t pte = (pm_t)branch->leaf[idx]; - pm_t branch_pptr = (pm_t)pte_addr(pte); - branch = (struct vm_branch_t *)set_vptr(VM_R | VM_W | VM_V, branch_pptr); - top--; - } - - size_t idx = vm_to_index(vaddr, top); - branch->leaf[idx] = (struct vm_branch_t *)to_pte(paddr, flags); -} - -void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr, enum mm_order_t order) -{ - while (order) { - size_t idx = pm_to_index(vaddr, order); - branch = (struct vm_branch_t *)pte_addr(branch->leaf[idx]); - } - - size_t idx = pm_to_index(vaddr, order); - if (branch->leaf[idx]) - free_page(order, pte_addr(branch->leaf[idx])); - - branch->leaf[idx] = 0; -} diff --git a/arch/riscv/conf/apos.its b/arch/riscv/conf/apos.its index 7c05044..1581025 100644 --- a/arch/riscv/conf/apos.its +++ b/arch/riscv/conf/apos.its @@ -7,7 +7,7 @@ images { kernel { description = "Garbaggio"; - data = /incbin/("../../../apos.bin"); + data = /incbin/("../../../kernel.bin"); type = "kernel"; arch = "riscv"; os = "apos"; diff --git a/arch/riscv/conf/init-link.S b/arch/riscv/conf/init-link.S deleted file mode 100644 index c9a6da2..0000000 --- a/arch/riscv/conf/init-link.S +++ /dev/null @@ -1,31 +0,0 @@ -OUTPUT_ARCH(riscv) -ENTRY(_start) - -SECTIONS { - . = ABSOLUTE(PM_KERN); - __init_start = .; - - /* objcopy only copies these three sections (as far as I'm aware) into the - produces binary, so __init_end should point to the correct location in the - final binary - */ - .text ALIGN(4K) : AT(0) { - *(.init.start) - *(.text*); - } - - .rodata : { - *(.rodata*) - } - - .data : { - *(.data*) - } - - .bss : { - *(.bss*) *(COMMON) - } - - __kernel_size = <KERNEL_SIZE>; - __init_end = . ; -} diff --git a/arch/riscv/conf/kernel-link.S b/arch/riscv/conf/kernel-link.S index d3b1223..bf0ad28 100644 --- a/arch/riscv/conf/kernel-link.S +++ b/arch/riscv/conf/kernel-link.S @@ -2,10 +2,10 @@ OUTPUT_ARCH(riscv) ENTRY(main) SECTIONS { - . = ABSOLUTE(VM_KERN); + . = ABSOLUTE(PM_KERN); __kernel_start = .; - .text ALIGN(4K) : AT(0) { + .text : AT(0) { *(.kernel.start); *(.text*); } diff --git a/arch/riscv/include/csr.h b/arch/riscv/include/csr.h index ab25bdd..70e60bb 100644 --- a/arch/riscv/include/csr.h +++ b/arch/riscv/include/csr.h @@ -3,11 +3,39 @@ #include <apos/utils.h> -#define SATP_MODE_Sv32 0x80000000 -#define SATP_MODE_Sv39 0x8000000000000000 -#define SATP_MODE_Sv48 0x9000000000000000 +#define SATP_MODE_Sv32 0x80000000 +#define SATP_MODE_Sv39 0x8000000000000000 +#define SATP_MODE_Sv48 0x9000000000000000 -#define CSR_SATP 0x180 + +/* supervisor CSR registers */ +#define CSR_SSTATUS 0x100 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 + +#define CSR_SENVCFG 0x10A + +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 + +#define CSR_SATP 0x180 + +#define CSR_SCONTEXT 0x5A8 + +/* Exception causes */ +#define EXC_INST_MISALIGNED 0 +#define EXC_INST_ACCESS 1 +#define EXC_BREAKPOINT 3 +#define EXC_LOAD_ACCESS 5 +#define EXC_STORE_ACCESS 7 +#define EXC_SYSCALL 8 +#define EXC_INST_PAGE_FAULT 12 +#define EXC_LOAD_PAGE_FAULT 13 +#define EXC_STORE_PAGE_FAULT 15 /* directly lifted from Linux:/arch/riscv/include/asm/asm.h:9-13 */ #ifdef __ASSEMBLY__ diff --git a/arch/riscv/include/vmem.h b/arch/riscv/include/vmem.h index d17aaf1..2cd3ac7 100644 --- a/arch/riscv/include/vmem.h +++ b/arch/riscv/include/vmem.h @@ -3,6 +3,7 @@ #include <apos/types.h> #include <apos/attrs.h> +#include <apos/pmem.h> #define VM_V (1 << 0) #define VM_R (1 << 1) @@ -24,4 +25,11 @@ struct __packed vm_branch_t { struct vm_branch_t *leaf[512]; }; + +void map_vmem(struct vm_branch_t *b, + pm_t paddr, vm_t vaddr, uint8_t flags, enum mm_order_t order); + +void unmap_vmem(struct vm_branch_t *b, + vm_t vaddr, enum mm_order_t order); + #endif /* APOS_RISCV_VMAP_H */ diff --git a/arch/riscv/init/head.S b/arch/riscv/init/head.S deleted file mode 100644 index 3589ead..0000000 --- a/arch/riscv/init/head.S +++ /dev/null @@ -1,7 +0,0 @@ -.section .init.start -.global _start -.type _start, @function -_start: - li sp, PM_STACK_TOP - /* go to proper init */ - j init diff --git a/arch/riscv/init/init.c b/arch/riscv/init/init.c deleted file mode 100644 index 721712c..0000000 --- a/arch/riscv/init/init.c +++ /dev/null @@ -1,337 +0,0 @@ -/* TODO: cleanup :P */ - -#include <apos/init.h> -#include <apos/sizes.h> -#include <apos/types.h> -#include <apos/string.h> -#include <apos/debug.h> -#include <apos/pmem.h> -#include <apos/vmem.h> -#include <apos/utils.h> -#include <libfdt.h> -#include <pages.h> -#include <csr.h> - -struct pm_layout_t { - pm_t base; - pm_t top; -}; - -struct pm_orders_t { - size_t max_order; - size_t bits[10]; - size_t page_shift; -}; - -static struct pm_layout_t get_memlayout(void *fdt) -{ - struct cell_info_t ci = get_reginfo(fdt, "/memory"); - int mem_offset = fdt_path_offset(fdt, "/memory"); - uint8_t *mem_reg = - (uint8_t *) fdt_getprop(fdt, mem_offset, "reg", NULL); - - /* if riscv128 comes around we will probably see addr_cells == 4, but - * I'm not too concerned about it at the moment */ - pm_t base = (pm_t)fdt_load_int_ptr(ci.addr_cells, mem_reg); - - if(ci.addr_cells == 2) - mem_reg += sizeof(fdt64_t); - else - mem_reg += sizeof(fdt32_t); - - /* -1 because base is a legitimate memory address */ - pm_t top = (pm_t)fdt_load_int_ptr(ci.size_cells, mem_reg) + base - 1; - return (struct pm_layout_t){base, top}; -} - -#ifdef DEBUG - -static void init_debug(void *fdt) -{ - struct dbg_info_t dbg = dbg_from_fdt(fdt); - dbg_init(dbg.dbg_ptr, dbg.dev); -} - -#else -#define init_debug(...) -#endif - -static pm_t get_kerneltop() -{ - /* interesting, for some reason if I define these to be just char - * pointers I get some wacky values. Not sure why that would be, but - * this works. */ - extern char __init_end, __kernel_size; - return (pm_t)&__init_end + (pm_t)&__kernel_size; -} - -static pm_t get_initrdtop(void *fdt) -{ - int chosen_offset = fdt_path_offset(fdt, "/chosen"); - struct cell_info_t ci = get_cellinfo(fdt, chosen_offset); - - void *initrd_end_ptr = (void *)fdt_getprop(fdt, chosen_offset, - "linux,initrd-end", NULL); - - return (pm_t)fdt_load_int_ptr(ci.addr_cells, initrd_end_ptr); -} - -static pm_t get_initrdbase(void *fdt) -{ - int chosen_offset = fdt_path_offset(fdt, "/chosen"); - struct cell_info_t ci = get_cellinfo(fdt, chosen_offset); - - void *initrd_base_ptr = (void *)fdt_getprop(fdt, chosen_offset, - "linux,initrd-start", NULL); - - return (pm_t)fdt_load_int_ptr(ci.addr_cells, initrd_base_ptr); -} - -static pm_t get_fdttop(void *fdt) -{ - const char *b = (const char *)fdt; - return (pm_t)(b + fdt_totalsize(fdt)); -} - -static pm_t get_fdtbase(void *fdt) -{ - /* lol */ - return (pm_t)fdt; -} - -static void mark_area_used(pm_t base, pm_t top) -{ - size_t area_left = top - base; - /* TODO: add in a method to make sure that we use as large mappings as - * possible. */ - while(area_left >= MM_KPAGE_SIZE){ - mark_used(base, MM_KPAGE); - area_left -= MM_KPAGE_SIZE; - base += MM_KPAGE_SIZE; - } - - if(area_left != 0) - mark_used(base, MM_KPAGE_SIZE); -} - -static void mark_reserved_mem(void *fdt) -{ - int rmem_offset = fdt_path_offset(fdt, "/reserved-memory/mmode_resv0"); - struct cell_info_t ci = get_reginfo(fdt, "/reserved-memory/mmode_resv0"); - uint8_t *rmem_reg = (uint8_t *)fdt_getprop(fdt, rmem_offset, "reg", NULL); - - pm_t base = (pm_t)fdt_load_int_ptr(ci.addr_cells, rmem_reg); - - if(ci.addr_cells == 2) - rmem_reg += sizeof(fdt64_t); - else - rmem_reg += sizeof(fdt32_t); - - pm_t top = (pm_t)fdt_load_int_ptr(ci.size_cells, rmem_reg) + base - 1; - mark_area_used(base, top); -} - -static struct pm_orders_t init_pmem(void *fdt) -{ - enum mm_mode_t mmode = get_mmode(fdt); - - size_t max_order = 0; - size_t order_bits = 9; - switch(mmode){ - case Sv32: - max_order = 1; - order_bits = 10; - break; - - case Sv39: - max_order = 2; - break; - - case Sv48: - max_order = 3; - break; - }; - - size_t bits[10] = {0}; - for(size_t i = 0; i <= max_order; ++i) - bits[i] = order_bits; - - init_mem(max_order, bits, 12); - - struct pm_orders_t ret = {max_order, {0}, 12}; - for(size_t i = 0; i <= __mm_max_order; ++i) - ret.bits[i] = bits[i]; - - return ret; -} - -static struct pm_layout_t setup_pmem(void *fdt) -{ - struct pm_layout_t pmem = get_memlayout(fdt); - - pm_t initrd_top = get_initrdtop(fdt); - pm_t kernel_top = get_kerneltop(); - pm_t fdt_top = get_fdttop(fdt); - - pm_t top = MAX3(kernel_top, initrd_top, fdt_top); - dbg("initrd_top:\t%#lx\n", initrd_top); - dbg("kernel_top:\t%#lx\n", kernel_top); - dbg("fdt_top:\t%#lx\n", fdt_top); - - /* TODO: check that pmap placement doesn't overwrite anything, such as - * stack or go over top address of memory */ - size_t probe_size = probe_pmap(pmem.base, pmem.top - pmem.base); - /* riscv handles two byte boundaries better than one byte, so align - * upwards */ - pm_t pmap_base = align_up(top + 1, 2); - size_t actual_size = populate_pmap(pmem.base, pmem.top - pmem.base, - pmap_base); - - /* TODO: not entirely sure what to do about this, probably give up trying to - * boot? */ - if(probe_size != actual_size){ - dbg("BUG! probe_size (%#lx) != actual_size (%#lx)\n", - probe_size, actual_size); - } - - /* mark init stack, at the moment always mapped to 2M */ - mark_used(PM_STACK_BASE, MM_MPAGE); - - /* mark kernel, at the moment it is always mapped to a 2M partition */ - mark_used(PM_KERN, MM_MPAGE); - - /* mark fdt and initrd */ - mark_area_used(get_initrdbase(fdt), initrd_top); - mark_area_used(get_fdtbase(fdt), fdt_top); - - /* mark pmap */ - mark_area_used(pmap_base, pmap_base + actual_size); - - /* mark reserved mem */ - mark_reserved_mem(fdt); - - return (struct pm_layout_t){.base = pmap_base, .top = actual_size + pmap_base}; -} - -pm_t move_kernel() -{ - extern char __init_end, __kernel_size; - pm_t dst = alloc_page(MM_MPAGE, 0); - memmove((void *)dst, &__init_end, (size_t)&__kernel_size); - - return dst; -} - -struct vm_branch_t *prepare_vmem() -{ - pm_t kernel_dst = move_kernel(); - - /* TODO: check if this actually works */ - struct vm_branch_t *branch = (struct vm_branch_t *)alloc_page(MM_KPAGE, 0); - memset(branch, 0, sizeof(struct vm_branch_t)); - - /* TODO: check mapping flags, also iron out possible bugs etc in - * map_vmem */ - /* map kernel */ - map_vmem(branch, kernel_dst, VM_KERN, VM_R | VM_W | VM_G | VM_X | VM_V, MM_MPAGE); - - /* map init */ - map_vmem(branch, PM_KERN, PM_KERN, VM_R | VM_W | VM_X | VM_V, MM_MPAGE); - - /* map stack */ - map_vmem(branch, PM_STACK_BASE, PM_STACK_BASE, VM_R | VM_W | VM_V, MM_MPAGE); - - /* map root pte */ - map_vmem(branch, (pm_t)branch, ROOT_PTE, VM_R | VM_W | VM_V, MM_KPAGE); - - /* TODO: map more stuff? */ - return branch; -} - -static vm_t prepare_tmp_pte(struct vm_branch_t *branch) -{ - /* make sure the TMP_PTE is mapped to *something* */ - map_vmem(branch, 0, TMP_PTE, VM_R | VM_W | VM_V, MM_KPAGE); - - struct vm_branch_t *tmp_pte = arch_get_tmp_pte(branch); - - vm_t addr = TMP_PTE + MM_KPAGE_SIZE; - map_vmem(branch, (vm_t)tmp_pte, addr, VM_R | VM_W | VM_V, MM_KPAGE); - return addr; -} - -void start_vmem(void *fdt, struct vm_branch_t *branch) -{ - /* TODO: get ASID from CPU id */ - - /* TODO: probably unnecessary optimisations but this could be cached? */ - enum mm_mode_t m = get_mmode(fdt); - - if(m == Sv32) - csr_write(CSR_SATP, SATP_MODE_Sv32 | pm_to_pnum((pm_t)(branch))); - else if (m == Sv39) - csr_write(CSR_SATP, SATP_MODE_Sv39 | pm_to_pnum((pm_t)(branch))); - else - csr_write(CSR_SATP, SATP_MODE_Sv48 | pm_to_pnum((pm_t)(branch))); - - __asm__ ("sfence.vma" : : : "memory"); - /* Sv57 && Sv64 in the future? */ -} - -struct init_data_t populate_initdata(void *fdt, struct pm_orders_t o, - struct pm_layout_t p, - struct vm_branch_t *b, - vm_t v) -{ - extern char __init_start, __init_end; - - struct init_data_t d = {0}; - d.init_base = (pm_t)&__init_start; - d.init_top = (pm_t)&__init_end; - - d.initrd_base = get_initrdbase(fdt); - d.initrd_top = get_initrdtop(fdt); - - d.pmap_base = p.base; - d.pmap_top = p.top; - - d.fdt_base = get_fdtbase(fdt); - d.fdt_top = get_fdttop(fdt); - - d.stack_base = PM_STACK_BASE; - d.stack_top = PM_STACK_TOP; - - d.kernel_vm_base = b; - d.tmp_pte = v; - - d.max_order = o.max_order; - for(size_t i = 0; i <= __mm_max_order; ++i) - d.bits[i] = o.bits[i]; - d.page_shift = o.page_shift; - - /* initialize pmap in vmem */ - pm_t addr = p.base; - while(addr < p.top){ - map_vmem(b, addr, addr, VM_R | VM_W | VM_V, MM_MPAGE); - addr += MM_MPAGE_SIZE; - } - - return d; -} - -void init(void *fdt) -{ - init_debug(fdt); - dbg_fdt(fdt); - - struct pm_orders_t o = init_pmem(fdt); - struct pm_layout_t p = setup_pmem(fdt); - struct vm_branch_t *b = prepare_vmem(); - vm_t v = prepare_tmp_pte(b); - struct init_data_t d = populate_initdata(fdt, o, p, b, v); - start_vmem(fdt, b); - - /* update_pmap(TODO: figure out where to place pmap in vmem); */ - void (*main)(struct init_data_t) = (void (*)(struct init_data_t))VM_KERN; - main(d); -} diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c new file mode 100644 index 0000000..f015411 --- /dev/null +++ b/arch/riscv/kernel/irq.c @@ -0,0 +1,4 @@ +void irq_handler() +{ + +} diff --git a/arch/riscv/kernel/main.c b/arch/riscv/kernel/main.c index 3f524bc..c7a1290 100644 --- a/arch/riscv/kernel/main.c +++ b/arch/riscv/kernel/main.c @@ -1,51 +1,305 @@ #include <apos/debug.h> -#include <apos/init.h> #include <apos/vmem.h> +#include <apos/pmem.h> +#include <apos/types.h> #include <apos/mem.h> #include <apos/lock.h> +#include <apos/tcb.h> +#include <apos/string.h> +#include <apos/proc.h> +#include <apos/mem_nodes.h> +#include <apos/elf.h> +#include <apos/initrd.h> +#include <libfdt.h> +#include <csr.h> + +struct pm_layout_t { + pm_t base; + pm_t top; +}; + +struct pm_orders_t { + size_t max_order; + size_t bits[10]; + size_t page_shift; +}; #ifdef DEBUG -static void kernel_dbg(void *fdt) +static void init_dbg(void *fdt) { struct dbg_info_t dbg = dbg_from_fdt(fdt); - map_vmem(ROOT_PTE, (pm_t)dbg.dbg_ptr, (vm_t)dbg.dbg_ptr, - VM_R | VM_W | VM_V, MM_KPAGE); dbg_init(dbg.dbg_ptr, dbg.dev); } #else -#define kernel_dbg(...) +#define init_dbg(...) #endif -static void map_fdt(struct vm_branch_t *branch, vm_t fdt_base, vm_t fdt_top) +static struct pm_layout_t get_memlayout(void *fdt) +{ + struct cell_info_t ci = get_reginfo(fdt, "/memory"); + int mem_offset = fdt_path_offset(fdt, "/memory"); + uint8_t *mem_reg = + (uint8_t *) fdt_getprop(fdt, mem_offset, "reg", NULL); + + /* if riscv128 comes around we will probably see addr_cells == 4, but + * I'm not too concerned about it at the moment */ + pm_t base = (pm_t)fdt_load_int_ptr(ci.addr_cells, mem_reg); + + if(ci.addr_cells == 2) + mem_reg += sizeof(fdt64_t); + else + mem_reg += sizeof(fdt32_t); + + /* -1 because base is a legitimate memory address */ + pm_t top = (pm_t)fdt_load_int_ptr(ci.size_cells, mem_reg) + base - 1; + return (struct pm_layout_t){base, top}; +} + +static pm_t get_kerneltop() +{ + /* interesting, for some reason if I define these to be just char + * pointers I get some wacky values. Not sure why that would be, but + * this works. */ + extern char __kernel_end; + return (pm_t)&__kernel_end; +} + +static pm_t get_initrdtop(void *fdt) +{ + int chosen_offset = fdt_path_offset(fdt, "/chosen"); + struct cell_info_t ci = get_cellinfo(fdt, chosen_offset); + + void *initrd_end_ptr = (void *)fdt_getprop(fdt, chosen_offset, + "linux,initrd-end", NULL); + + return (pm_t)fdt_load_int_ptr(ci.addr_cells, initrd_end_ptr); +} + +static pm_t get_initrdbase(void *fdt) +{ + int chosen_offset = fdt_path_offset(fdt, "/chosen"); + struct cell_info_t ci = get_cellinfo(fdt, chosen_offset); + + void *initrd_base_ptr = (void *)fdt_getprop(fdt, chosen_offset, + "linux,initrd-start", NULL); + + return (pm_t)fdt_load_int_ptr(ci.addr_cells, initrd_base_ptr); +} + +static pm_t get_fdttop(void *fdt) +{ + const char *b = (const char *)fdt; + return (pm_t)(b + fdt_totalsize(fdt)); +} + +static pm_t get_fdtbase(void *fdt) +{ + /* lol */ + return (pm_t)fdt; +} + + +static void mark_area_used(pm_t base, pm_t top) +{ + size_t area_left = top - base; + /* TODO: add in a method to make sure that we use as large mappings as + * possible. */ + while(area_left >= MM_KPAGE_SIZE){ + mark_used(base, MM_KPAGE); + area_left -= MM_KPAGE_SIZE; + base += MM_KPAGE_SIZE; + } + + if(area_left != 0) + mark_used(base, MM_KPAGE_SIZE); +} + +static void mark_reserved_mem(void *fdt) +{ + int rmem_offset = fdt_path_offset(fdt, "/reserved-memory/mmode_resv0"); + struct cell_info_t ci = get_reginfo(fdt, "/reserved-memory/mmode_resv0"); + uint8_t *rmem_reg = (uint8_t *)fdt_getprop(fdt, rmem_offset, "reg", NULL); + + pm_t base = (pm_t)fdt_load_int_ptr(ci.addr_cells, rmem_reg); + + if(ci.addr_cells == 2) + rmem_reg += sizeof(fdt64_t); + else + rmem_reg += sizeof(fdt32_t); + + pm_t top = (pm_t)fdt_load_int_ptr(ci.size_cells, rmem_reg) + base - 1; + mark_area_used(base, top); +} + +static struct pm_layout_t setup_pmem(void *fdt) +{ + struct pm_layout_t pmem = get_memlayout(fdt); + + pm_t initrd_top = get_initrdtop(fdt); + pm_t kernel_top = get_kerneltop(); + pm_t fdt_top = get_fdttop(fdt); + + pm_t top = MAX3(kernel_top, initrd_top, fdt_top); + dbg("initrd_top:\t%#lx\n", initrd_top); + dbg("kernel_top:\t%#lx\n", kernel_top); + dbg("fdt_top:\t%#lx\n", fdt_top); + + /* TODO: check that pmap placement doesn't overwrite anything, such as + * stack or go over top address of memory */ + size_t probe_size = probe_pmap(pmem.base, pmem.top - pmem.base); + /* riscv handles two byte boundaries better than one byte, so align + * upwards */ + pm_t pmap_base = align_up(top + 1, 2); + size_t actual_size = populate_pmap(pmem.base, pmem.top - pmem.base, + pmap_base); + + /* TODO: not entirely sure what to do about this, probably give up trying to + * boot? */ + if(probe_size != actual_size){ + dbg("BUG! probe_size (%#lx) != actual_size (%#lx)\n", + probe_size, actual_size); + } + + /* mark init stack, at the moment always mapped to 2M */ + mark_used(PM_STACK_BASE, MM_MPAGE); + + /* mark kernel, at the moment it is always mapped to a 2M partition */ + mark_used(PM_KERN, MM_MPAGE); + + /* mark fdt and initrd */ + mark_area_used(get_initrdbase(fdt), initrd_top); + mark_area_used(get_fdtbase(fdt), fdt_top); + + /* mark pmap */ + mark_area_used(pmap_base, pmap_base + actual_size); + + /* mark reserved mem */ + mark_reserved_mem(fdt); + + return (struct pm_layout_t){.base = pmap_base, .top = actual_size + pmap_base}; +} + +static struct pm_orders_t init_pmem(void *fdt) { - /* TODO: fix this shit */ - map_vregion(branch, fdt_base, fdt_base, fdt_top - fdt_base, VM_R | VM_W |VM_V); + enum mm_mode_t mmode = get_mmode(fdt); + + size_t max_order = 0; + size_t order_bits = 9; + switch(mmode){ + case Sv32: + max_order = 1; + order_bits = 10; + break; + + case Sv39: + max_order = 2; + break; + + case Sv48: + max_order = 3; + break; + }; + + size_t bits[10] = {0}; + for(size_t i = 0; i <= max_order; ++i) + bits[i] = order_bits; + + init_mem(max_order, bits, 12); + + struct pm_orders_t ret = {max_order, {0}, 12}; + for(size_t i = 0; i <= __mm_max_order; ++i) + ret.bits[i] = bits[i]; + + return ret; +} + +static void populate_root_branch(struct vm_branch_t *b, size_t mul) +{ + for(size_t i = 0; i <= (MM_KPAGE_SIZE / sizeof(size_t))/2; ++i) + b->leaf[i] = (struct vm_branch_t *)(mul * i | VM_V | VM_R | VM_W | VM_X | VM_G); +} + +static void start_vmem(struct vm_branch_t *branch, enum mm_mode_t m) +{ + /* TODO: get ASID from CPU id */ + + if(m == Sv32) + csr_write(CSR_SATP, SATP_MODE_Sv32 | pm_to_pnum((pm_t)(branch))); + else if (m == Sv39) + csr_write(CSR_SATP, SATP_MODE_Sv39 | pm_to_pnum((pm_t)(branch))); + else + csr_write(CSR_SATP, SATP_MODE_Sv48 | pm_to_pnum((pm_t)(branch))); + + __asm__ ("sfence.vma" : : : "memory"); + /* Sv57 && Sv64 in the future? */ +} + +static struct vm_branch_t *init_vmem(void *fdt) +{ + struct pm_orders_t o = init_pmem(fdt); + setup_pmem(fdt); + + struct vm_branch_t *b = (struct vm_branch_t *)alloc_page(MM_KPAGE, 0); + memset(b, 0, sizeof(struct vm_branch_t)); + + enum mm_mode_t mm = Sv48; + size_t mul = 0; + switch(o.max_order){ + case 3: /* Sv48 */ + mm = Sv48; + mul = 1UL << 37; + break; + + case 2: /* Sv39 */ + mm = Sv39; + mul = 1UL << 28; + break; + + case 1: /* Sv32 */ + mm = Sv32; + mul = 1UL << 20; + break; + } + + set_uvmem_size(mul); + populate_root_branch(b, uvmem_size()); + /* jump to vmem */ + start_vmem(b, mm); + return b; +} + +static void init_irq(void *fdt) +{ +} + +static void init_proc(void *fdt, struct vm_branch_t *b) +{ + struct tcb *t = (struct tcb *)alloc_page(MM_KPAGE, 0); + t->b_r = b; + t->pid = 0; + t->tid = 0; + threads_insert(t); + sp_mem_init(&t->sp_r, uvmem_size()); + + /* binary itself */ + size_t sz = align_up(get_init_size(fdt), BASE_PAGE_SIZE); + t->bin = alloc_uvmem(t, sz, VM_V | VM_X); + /* stack */ + t->stack = alloc_uvmem(t, SZ_2M, VM_V | VM_R | VM_W); + /* if it needs heap, it'll ask for it */ + + move_init(fdt, (void *)t->bin, sz); + jump_to_userspace(t, 0, 0); } -void __main main(struct init_data_t d) +void __main main(void *fdt) { - init_pmap((void *)d.pmap_base); - init_mem(d.max_order, d.bits, d.page_shift); - init_vmem(ROOT_PTE, d.tmp_pte); - /* TODO: move pmap into vmem somewhere */ - /* TODO: mark kernel area as used */ - map_fdt(ROOT_PTE, d.fdt_base, d.fdt_top); - kernel_dbg((void *)d.fdt_base); - dbg("test\n"); - /* TODO: approximate order of business: - * setup debugging in vmem (requires mapping fdt) - * free unnecessary init - * setup interrupts (should this be done in init?) - * load init from initrd - * setup init environment (thread control blocks etc.) - * jumpstart init (free stack init setup) - */ + init_dbg(fdt); + struct vm_branch_t *b = init_vmem(fdt); - /* functionality that should be implemented: - * figure out best continuous run of memory (pmap etc) - * arbitrary user and kernel mapping (memory) - * vm to pm - */ + init_mem_blocks(); + init_irq(fdt); + init_proc(fdt, b); } diff --git a/arch/riscv/kernel/proc.c b/arch/riscv/kernel/proc.c new file mode 100644 index 0000000..3a39dd3 --- /dev/null +++ b/arch/riscv/kernel/proc.c @@ -0,0 +1,15 @@ +#include <apos/tcb.h> +#include <apos/elf.h> +#include <csr.h> + +void jump_to_userspace(struct tcb *t, char **argv, int argc) +{ + csr_write(CSR_SEPC, bin_entry(t->bin)); + __asm__("mv sp, %0\n" : "=r" (t->stack) :: "memory"); + __asm__("sret\n" ::: "memory"); +} + +void return_to_userspace(struct tcb *t) +{ + /* lol */ +} diff --git a/arch/riscv/kernel/vmem.c b/arch/riscv/kernel/vmem.c new file mode 100644 index 0000000..ffe8731 --- /dev/null +++ b/arch/riscv/kernel/vmem.c @@ -0,0 +1,52 @@ +#include <apos/string.h> +#include <apos/pmem.h> +#include <apos/vmem.h> +#include <apos/mem.h> +#include <apos/debug.h> +#include <pages.h> + +#define pte_ppn(pte) (((pm_t)(pte)) >> 10) +#define pte_flags(pte) (((pm_t)(pte)) & 0xff) +#define to_pte(p, f) ((pm_to_pnum(p) << 10) + (f)) +#define pte_addr(pte) (pnum_to_paddr(pte_ppn(pte))) +#define vm_to_index(a, o) (pm_to_index(a, o)) + +void map_vmem(struct vm_branch_t *branch, + pm_t paddr, vm_t vaddr, uint8_t flags, enum mm_order_t order) +{ + enum mm_order_t top = __mm_max_order; + while (top != order) { + size_t idx = vm_to_index(vaddr, top); + + if (!branch->leaf[idx]) { + pm_t new_leaf = alloc_page(MM_KPAGE, 0); + branch->leaf[idx] = + (struct vm_branch_t *)to_pte(new_leaf, VM_V); + + void *leaf_ptr = (void *)new_leaf; + memset(leaf_ptr, 0, sizeof(struct vm_branch_t)); + } + + pm_t pte = (pm_t)branch->leaf[idx]; + pm_t branch_pptr = (pm_t)pte_addr(pte); + branch = (struct vm_branch_t *)branch_pptr; + top--; + } + + size_t idx = vm_to_index(vaddr, top); + branch->leaf[idx] = (struct vm_branch_t *)to_pte(paddr, flags); +} + +void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr, enum mm_order_t order) +{ + while (order) { + size_t idx = pm_to_index(vaddr, order); + branch = (struct vm_branch_t *)pte_addr(branch->leaf[idx]); + } + + size_t idx = pm_to_index(vaddr, order); + if (branch->leaf[idx]) + free_page(order, pte_addr(branch->leaf[idx])); + + branch->leaf[idx] = 0; +} diff --git a/arch/riscv/proc.txt b/arch/riscv/proc.txt new file mode 100644 index 0000000..29b2e92 --- /dev/null +++ b/arch/riscv/proc.txt @@ -0,0 +1,3 @@ +Each thread should obviously have a thread control block (tcb) which lives in +kernelspace and has pointers to virtual memory allocations, along with PID and +other required data. That's about what I can come up with at the moment. diff --git a/arch/riscv/source.mk b/arch/riscv/source.mk index b1dd361..ecc22bd 100644 --- a/arch/riscv/source.mk +++ b/arch/riscv/source.mk @@ -1,9 +1,6 @@ -KERNEL_LOCAL != echo arch/riscv/kernel/*.[cS] arch/riscv/common/*.[cS] +KERNEL_LOCAL != echo arch/riscv/kernel/*.[cS] KERNEL_SOURCES += $(KERNEL_LOCAL) -INIT_LOCAL != echo arch/riscv/init/*.[cS] arch/riscv/common/*.[cS] -INIT_SOURCES += $(INIT_LOCAL) - CLEANUP_CMD := ./arch/riscv/conf/rmimage.sh ARCH_FLAGS := -mcmodel=medany diff --git a/common/elf.c b/common/elf.c new file mode 100644 index 0000000..7531bd1 --- /dev/null +++ b/common/elf.c @@ -0,0 +1,9 @@ +#include <apos/elf.h> +#include <apos/vmem.h> + +vm_t bin_entry(vm_t bin) +{ + struct elf_header *e = (struct elf_header *)bin; + /* TODO: check that address points to a valid ELF executable */ + return (vm_t)e->e_entry; +} diff --git a/kernel/temp.c b/common/initrd.c index e69de29..e69de29 100644 --- a/kernel/temp.c +++ b/common/initrd.c diff --git a/common/mem_nodes.c b/common/mem_nodes.c index 1779276..dba714f 100644 --- a/common/mem_nodes.c +++ b/common/mem_nodes.c @@ -138,7 +138,7 @@ struct sp_mem *get_mem_node() return __find_free_block(r); } - n = n->left; + n = sp_left(n); } /* we need to allocate a new region */ diff --git a/common/tcb.c b/common/tcb.c new file mode 100644 index 0000000..5b00524 --- /dev/null +++ b/common/tcb.c @@ -0,0 +1,55 @@ +#include <apos/tcb.h> +#include <apos/utils.h> +#include <apos/sp_tree.h> + +static struct sp_root t_root = (struct sp_root){0}; + +#define tcb_container(x) \ + container_of(x, struct tcb, sp_n) + +void threads_insert(struct tcb *t) +{ + if(!sp_root(t_root)){ + sp_root(t_root) = &t->sp_n; + return; + } + + struct sp_node *n = sp_root(t_root), *p = NULL; + enum sp_dir d = LEFT; + + while(n){ + struct tcb *tc = tcb_container(n); + p = n; + + if(t->tid < tc->tid){ + n = sp_left(n); + d = LEFT; + } + + else { + n = sp_right(n); + d = RIGHT; + } + } + + sp_insert(&sp_root(t_root), p, &t->sp_n, d); +} + +struct tcb *threads_find(id_t tid) +{ + struct sp_node *n = sp_root(t_root); + + while(n){ + struct tcb *t = tcb_container(n); + + if(t->tid == tid) + return t; + + if(t->tid < tid) + n = sp_left(n); + else + n = sp_right(n); + } + + return 0; +} diff --git a/common/vmem.c b/common/vmem.c index 267fbb7..25a8617 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -1,3 +1,4 @@ +#include <vmem.h> #include <apos/vmem.h> #include <apos/mem_nodes.h> @@ -5,8 +6,7 @@ #define mark_region_unused(r) ((r) = 0) #define is_region_used(r) (r) -static struct sp_root free_regions = (struct sp_root){0}; -static struct sp_root used_regions = (struct sp_root){0}; +static size_t __uvmem_size = 0; /* pretty major slowdown when we get to some really massive numbers, not * entirely sure why. Will need to check up on this at some point, have I @@ -24,9 +24,9 @@ static struct sp_root used_regions = (struct sp_root){0}; * maybe not even anything with sp_trees but more a weakness of binary trees in * general? */ -static struct sp_mem *sp_free_insert_region(struct sp_mem *m) +static struct sp_mem *sp_free_insert_region(struct sp_reg_root *r, struct sp_mem *m) { - struct sp_node *n = sp_root(free_regions), *p = NULL; + struct sp_node *n = sp_root(r->free_regions), *p = NULL; size_t start = m->start; size_t size = m->end - m->start; enum sp_dir d = LEFT; @@ -59,17 +59,17 @@ static struct sp_mem *sp_free_insert_region(struct sp_mem *m) } } - if(sp_root(free_regions)) - sp_insert(&sp_root(free_regions), p, &m->sp_n, d); + if(sp_root(r->free_regions)) + sp_insert(&sp_root(r->free_regions), p, &m->sp_n, d); else - sp_root(free_regions) = &m->sp_n; + sp_root(r->free_regions) = &m->sp_n; return m; } -static struct sp_mem *sp_used_insert_region(struct sp_mem *m) +static struct sp_mem *sp_used_insert_region(struct sp_reg_root *r, struct sp_mem *m) { - struct sp_node *n = sp_root(used_regions), *p = NULL; + struct sp_node *n = sp_root(r->used_regions), *p = NULL; vm_t start = m->start; enum sp_dir d = LEFT; @@ -93,19 +93,19 @@ static struct sp_mem *sp_used_insert_region(struct sp_mem *m) } } - if(sp_root(used_regions)) - sp_insert(&sp_root(used_regions), p, &m->sp_n, d); + if(sp_root(r->used_regions)) + sp_insert(&sp_root(r->used_regions), p, &m->sp_n, d); else - sp_root(used_regions) = &m->sp_n; + sp_root(r->used_regions) = &m->sp_n; return m; } -int sp_mem_init(size_t arena_size) +int sp_mem_init(struct sp_reg_root *r, size_t arena_size) { struct sp_mem *m = get_mem_node(); m->end = arena_size; - sp_free_insert_region(m); + sp_free_insert_region(r, m); return 0; } @@ -122,10 +122,10 @@ static void __sp_mem_destroy(struct sp_node *n) free_mem_node(m); } -void sp_mem_destroy() +void sp_mem_destroy(struct sp_reg_root *r) { - __sp_mem_destroy(sp_root(free_regions)); - __sp_mem_destroy(sp_root(used_regions)); + __sp_mem_destroy(sp_root(r->free_regions)); + __sp_mem_destroy(sp_root(r->used_regions)); } /* interestingly this is now the main bottleneck :D @@ -133,9 +133,9 @@ void sp_mem_destroy() * eh, it's not a massive thing I guess, maybe the code could be a bit quicker * but I mean 10 000 000 memory allocations in 20 s is good enough for now * */ -static struct sp_mem *sp_used_find(vm_t start) +static struct sp_mem *sp_used_find(struct sp_reg_root *r, vm_t start) { - struct sp_node *n = sp_root(used_regions); + struct sp_node *n = sp_root(r->used_regions); while(n){ struct sp_mem *t = mem_container(n); if(start == t->start) @@ -161,9 +161,9 @@ static struct sp_mem *sp_mem_create_region(vm_t start, vm_t end, return m; } -static struct sp_mem *sp_free_find_first(size_t size, size_t alignment) +static struct sp_mem *sp_free_find_first(struct sp_reg_root *r, size_t size, size_t alignment) { - struct sp_node *n = sp_root(free_regions); + struct sp_node *n = sp_root(r->free_regions); while(n){ struct sp_mem *t = mem_container(n); size_t nsize = t->end - align_up(t->start, alignment); @@ -181,13 +181,13 @@ static struct sp_mem *sp_free_find_first(size_t size, size_t alignment) * just ignore them for now. Note that alloc_region should only be used when * mmap is called with MAP_ANON, all other situations should be handled in some * fs server */ -vm_t alloc_region(size_t size, size_t alignment) +vm_t alloc_region(struct sp_reg_root *r, size_t size, size_t alignment) { - struct sp_mem *m = sp_free_find_first(size, alignment); + struct sp_mem *m = sp_free_find_first(r, size, alignment); if(!m) return 0; - sp_remove(&sp_root(free_regions), &m->sp_n); + sp_remove(&sp_root(r->free_regions), &m->sp_n); vm_t aligned_start = align_up(m->start, alignment); @@ -206,7 +206,7 @@ vm_t alloc_region(size_t size, size_t alignment) if(n->prev) n->prev->next = n; - sp_free_insert_region(n); + sp_free_insert_region(r, n); } if(post_start != post_end){ @@ -215,17 +215,17 @@ vm_t alloc_region(size_t size, size_t alignment) if(n->next) n->next->prev = n; - sp_free_insert_region(n); + sp_free_insert_region(r, n); } m->end = end; m->start = start; mark_region_used(m->flags); - sp_used_insert_region(m); + sp_used_insert_region(r, m); return start; } -static void __sp_try_coalesce_prev(struct sp_mem *m) +static void __sp_try_coalesce_prev(struct sp_reg_root *r, struct sp_mem *m) { while(m){ if(!m || is_region_used(m->flags)) @@ -241,14 +241,14 @@ static void __sp_try_coalesce_prev(struct sp_mem *m) if(m->prev) m->prev->next = m; - sp_remove(&sp_root(free_regions), &p->sp_n); + sp_remove(&sp_root(r->free_regions), &p->sp_n); free_mem_node(p); m = m->prev; } } -static void __sp_try_coalesce_next(struct sp_mem *m) +static void __sp_try_coalesce_next(struct sp_reg_root *r, struct sp_mem *m) { while(m){ if(!m || is_region_used(m->flags)) @@ -264,28 +264,62 @@ static void __sp_try_coalesce_next(struct sp_mem *m) if(m->next) m->next->prev = m; - sp_remove(&sp_root(free_regions), &n->sp_n); + sp_remove(&sp_root(r->free_regions), &n->sp_n); free_mem_node(n); m = m->next; } } -static void sp_mem_try_coalesce(struct sp_mem *m) +static void sp_mem_try_coalesce(struct sp_reg_root *r, struct sp_mem *m) { - __sp_try_coalesce_prev(m); - __sp_try_coalesce_next(m); + __sp_try_coalesce_prev(r, m); + __sp_try_coalesce_next(r, m); } -void free_region(vm_t start) +void free_region(struct sp_reg_root *r, vm_t start) { - struct sp_mem *m = sp_used_find(start); + struct sp_mem *m = sp_used_find(r, start); if(!m) return; - sp_remove(&sp_root(used_regions), &m->sp_n); + sp_remove(&sp_root(r->used_regions), &m->sp_n); mark_region_unused(m->flags); - sp_mem_try_coalesce(m); - sp_free_insert_region(m); + sp_mem_try_coalesce(r, m); + sp_free_insert_region(r, m); +} + +void set_uvmem_size(size_t s) +{ + __uvmem_size = s; +} + +size_t uvmem_size() +{ + return __uvmem_size; +} + +vm_t map_fill_region(struct vm_branch_t *b, vm_t start, size_t bytes, uint8_t flags) +{ + size_t pages = bytes / BASE_PAGE_SIZE; + pm_t offset = 0; + for(size_t i = 0; i < pages; ++i){ + offset = alloc_page(BASE_PAGE, offset); + map_vmem(b, offset, start + i * BASE_PAGE_SIZE, flags, BASE_PAGE); + } + + return start; +} + +vm_t alloc_uvmem(struct tcb *t, size_t s, uint8_t flags) +{ + size_t sa = align_up(s, BASE_PAGE_SIZE); + vm_t v = alloc_region(&t->sp_r, sa, 0); + return map_fill_region(t->b_r, v, sa, flags); +} + +void free_uvmem(struct tcb *t, vm_t a) +{ + free_region(&t->sp_r, a); } diff --git a/include/apos/elf.h b/include/apos/elf.h new file mode 100644 index 0000000..492c414 --- /dev/null +++ b/include/apos/elf.h @@ -0,0 +1,33 @@ +#ifndef APOS_ELF_H +#define APOS_ELF_H + +#include <apos/attrs.h> +#include <apos/types.h> +#include <apos/vmem.h> + +__packed struct elf_header { + uint64_t ei_magic; + uint8_t ei_class; + uint8_t ei_data; + uint8_t ei_version; + uint8_t ei_osabi; + uint8_t ei_abiversion; + uint8_t e_pad; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + void *e_entry; + void *e_phoff; + void *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; +}; + +vm_t bin_entry(vm_t bin); + +#endif /* APOS_ELF_H */ diff --git a/include/apos/init.h b/include/apos/init.h deleted file mode 100644 index 2dd8a27..0000000 --- a/include/apos/init.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef APOS_INIT_H -#define APOS_INIT_H - -#include <apos/pmem.h> -#include <apos/vmem.h> - -struct init_data_t { - pm_t init_base; - pm_t init_top; - - pm_t initrd_base; - pm_t initrd_top; - - pm_t pmap_base; - pm_t pmap_top; - - pm_t fdt_base; - pm_t fdt_top; - - pm_t stack_base; - pm_t stack_top; - - struct vm_branch_t *kernel_vm_base; - vm_t tmp_pte; - - size_t max_order; - size_t bits[10]; - size_t page_shift; -}; - -#endif /* APOS_INIT_H */ diff --git a/include/apos/initrd.h b/include/apos/initrd.h new file mode 100644 index 0000000..942875f --- /dev/null +++ b/include/apos/initrd.h @@ -0,0 +1,9 @@ +#ifndef APOS_INITRD_H +#define APOS_INITRD_H + +#include <apos/types.h> + +size_t get_init_size(void *fdt); +void move_init(void *fdt, void *target, size_t sz); + +#endif /* APOS_INITRD_H */ diff --git a/include/apos/pmem.h b/include/apos/pmem.h index 38dd670..01d89ce 100644 --- a/include/apos/pmem.h +++ b/include/apos/pmem.h @@ -25,13 +25,7 @@ void free_page(enum mm_order_t order, pm_t paddr); void mark_used(enum mm_order_t order, pm_t paddr); pm_t alloc_page(enum mm_order_t order, pm_t offset); -#if defined(INIT) pm_t populate_pmap(pm_t ram_base, size_t ram_size, pm_t cont); pm_t probe_pmap(pm_t ram_base, size_t ram_size); -#endif - -#if defined(KERNEL) -void init_pmap(void *p); -#endif #endif /* APOS_PMEM_H */ diff --git a/include/apos/proc.h b/include/apos/proc.h new file mode 100644 index 0000000..7506b10 --- /dev/null +++ b/include/apos/proc.h @@ -0,0 +1,7 @@ +#ifndef APOS_PROC_H +#define APOS_PROC_H + +#include <apos/tcb.h> +void jump_to_userspace(struct tcb *t, char **argv, int argc); + +#endif /* APOS_PROC_H */ diff --git a/include/apos/tcb.h b/include/apos/tcb.h new file mode 100644 index 0000000..9cef386 --- /dev/null +++ b/include/apos/tcb.h @@ -0,0 +1,34 @@ +#ifndef APOS_TCB_H +#define APOS_TCB_H + +struct tcb; +struct sp_reg_root; + +#include <vmem.h> +#include <apos/vmem.h> +#include <apos/types.h> +#include <apos/sp_tree.h> + +typedef size_t id_t; + +struct sp_reg_root { + struct sp_root free_regions; + struct sp_root used_regions; +}; + +struct tcb { + struct sp_node sp_n; + + id_t pid; + id_t tid; + + vm_t stack; + vm_t bin; + + struct vm_branch_t *b_r; + struct sp_reg_root sp_r; +}; + +void threads_insert(struct tcb *t); + +#endif /* APOS_TCB_H */ diff --git a/include/apos/vmem.h b/include/apos/vmem.h index eb7ad17..fe2a76f 100644 --- a/include/apos/vmem.h +++ b/include/apos/vmem.h @@ -1,11 +1,14 @@ #ifndef APOS_VMEM_H #define APOS_VMEM_H +struct sp_mem; + /* arch-specific data */ #include <vmem.h> /* common */ #include <apos/pmem.h> +#include <apos/tcb.h> #include <apos/sp_tree.h> struct sp_mem { @@ -24,6 +27,7 @@ struct sp_mem { container_of(ptr, struct sp_mem, sp_n) + /* general overview of the different functions: * (un)map_vmem: map one known page of physical memory to one known page of * virtual memory @@ -35,16 +39,14 @@ struct sp_mem { */ /* defined by arch */ -void map_vmem(struct vm_branch_t *branch, - pm_t paddr, vm_t vaddr, - uint8_t flags, enum mm_order_t order); +int sp_mem_init(struct sp_reg_root *r, size_t nums); -void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr, enum mm_order_t order); +vm_t alloc_uvmem(struct tcb *r, size_t s, uint8_t flags); +void free_uvmem(struct tcb *r, vm_t a); +vm_t map_fill_region(struct vm_branch_t *b, vm_t start, size_t bytes, uint8_t flags); -vm_t map_vregion(struct vm_branch_t *branch, pm_t base, vm_t start, size_t size, - uint8_t flags); -void unmap_vregion(struct vm_branch_t *branch, vm_t start); +size_t uvmem_size(); +void set_uvmem_size(size_t s); -void init_vmem(struct vm_branch_t *branch, vm_t tmp_pte); #endif /* APOS_VMEM_H */ diff --git a/scripts/gen-deps b/scripts/gen-deps index 7a468d3..ee64022 100755 --- a/scripts/gen-deps +++ b/scripts/gen-deps @@ -11,43 +11,25 @@ gencommon () { echo "${obj}: ${s}" >> deps.mk } + genlink () { gencommon ".ld" - if [ "${init}" = "0" ] ; then - echo " \$(GENLINK) $< | \$(STRIPLINK) > \$@"\ - >> deps.mk; - else - echo " \$(GENLINK) $< | \$(STRIPLINK) | \$(KERN_INFO) > \$@"\ + echo " \$(GENLINK) $< | \$(STRIPLINK) | \$(KERN_INFO) > \$@"\ >> deps.mk; - fi - } genrule () { gencommon "${1}" - echo " \$(COMPILE) ${defs} -c \$< -o \$@" >> deps.mk + echo " \$(COMPILE) -c \$< -o \$@" >> deps.mk } case "${1}" in - --kern) - suffix=.k.o - defs=-DKERNEL - func=genrule - ;; - --init) - suffix=.i.o - defs=-DINIT + --compile) + suffix=.o func=genrule ;; - --init-link) - suffix=.ld - init=1 - func=genlink - ;; - - --kern-link) + --link) suffix=.ld - init=0 func=genlink esac |
