From 7237d673904d8568a2f9c290a0247c9d1a07c5d2 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 11 Oct 2021 23:18:47 +0300 Subject: Start designing vmem framework --- Makefile | 1 + TODO.txt | 9 ++-- arch/riscv/common/vmem.c | 30 ++++++++++- arch/riscv/config.h | 14 +++--- arch/riscv/include/csr.h | 7 ++- arch/riscv/include/vmem.h | 8 --- arch/riscv/init/init.c | 55 ++++++++++++++++---- arch/riscv/kernel/main.c | 4 +- common/mem.c | 81 +++++++++++++++-------------- common/pmem.c | 26 +++++----- include/apos/bytes.h | 1 + include/apos/mem.h | 126 +++++++--------------------------------------- include/apos/types.h | 2 - include/apos/utils.h | 3 ++ include/apos/vmem.h | 32 ++++++++++++ 15 files changed, 208 insertions(+), 191 deletions(-) create mode 100644 include/apos/vmem.h diff --git a/Makefile b/Makefile index 1598ed8..9e1b5d3 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ DEPFLAGS = -MT $@ -MMD -MP -MF $@.d all: apos.bin +# default values, overwrite if/when needed ARCH ?= riscv CROSS_COMPILE ?= riscv64-unknown-elf- diff --git a/TODO.txt b/TODO.txt index 5176f0a..0d65372 100644 --- a/TODO.txt +++ b/TODO.txt @@ -7,9 +7,12 @@ + Write the kernel lol + Test libfdt and see if it can be used to read memory geometry etc. -+ Jump to vmem ++ 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 ++ 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 ++ 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? diff --git a/arch/riscv/common/vmem.c b/arch/riscv/common/vmem.c index ef89ec3..207df34 100644 --- a/arch/riscv/common/vmem.c +++ b/arch/riscv/common/vmem.c @@ -1,7 +1,7 @@ #include #include +#include #include -#include #define pte_ppn(pte) (((pm_t)(pte)) >> 10) #define pte_flags(pte) (((pm_t)(pte)) & 0xff) @@ -13,7 +13,7 @@ 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 = MAX_ORDER; + enum mm_order_t top = __mm_max_order; while(top != order){ size_t idx = pm_to_index(vaddr, top); @@ -45,3 +45,29 @@ void unmap_vmem(struct vm_branch_t *branch, branch->leaf[idx] = 0; } + +vm_t map_vregion(struct vm_branch_t *branch, pm_t base, pm_t top, vm_t start, vm_t end) +{ + /* TODO: figure out how to find first suitable memory region */ + + /* find first free page, iterate forward until we either fit the whole + * physical region or hit a used page + * + * continue until we hit end? + */ +} + +void unmap_vregion(struct vm_branch_t *branch, pm_t base, pm_t top) +{ + /* TODO */ +} + +vm_t map_vsize(struct vm_branch_t *branch, size_t size) +{ + /* TODO */ +} + +void unmap_vsize(struct vm_branch_t *branch, size_t size) +{ + /* TODO */ +} diff --git a/arch/riscv/config.h b/arch/riscv/config.h index f223ee7..75c898f 100644 --- a/arch/riscv/config.h +++ b/arch/riscv/config.h @@ -1,12 +1,12 @@ #include + +/* --- START ARCH USER CONFIG VALUES --- */ +/* physical address to which the kernel will be loaded */ #define PM_KERN 0x83800000 +/* --- END ARCH USER CONFIG VALUES --- */ + +/* don't touch >:( */ + #define PM_STACK_BASE (PM_KERN + SZ_2M) #define PM_STACK_TOP (PM_STACK_BASE + SZ_2M - 2) #define VM_KERN (-SZ_1G) - -#define MAX_ORDER 3 -#define PAGE_SHIFT 12 -#define O0_WIDTH 9 -#define O1_WIDTH 9 -#define O2_WIDTH 9 -#define O3_WIDTH 9 diff --git a/arch/riscv/include/csr.h b/arch/riscv/include/csr.h index 5da0882..ab25bdd 100644 --- a/arch/riscv/include/csr.h +++ b/arch/riscv/include/csr.h @@ -1,8 +1,11 @@ #ifndef APOS_CSR_H #define APOS_CSR_H -#define SATP_MODE_39 0x8000000000000000 -#define SATP_MODE_48 0x9000000000000000 +#include + +#define SATP_MODE_Sv32 0x80000000 +#define SATP_MODE_Sv39 0x8000000000000000 +#define SATP_MODE_Sv48 0x9000000000000000 #define CSR_SATP 0x180 diff --git a/arch/riscv/include/vmem.h b/arch/riscv/include/vmem.h index 0aad780..ec2a3ba 100644 --- a/arch/riscv/include/vmem.h +++ b/arch/riscv/include/vmem.h @@ -1,7 +1,6 @@ #ifndef APOS_RISCV_VMAP_H #define APOS_RISCV_VMAP_H -#include #include #include @@ -19,11 +18,4 @@ struct __packed vm_branch_t { struct vm_branch_t *leaf[512]; }; -void map_vmem(struct vm_branch_t *branch, - pm_t paddr, vm_t vaddr, - uint8_t flags, enum mm_order_t order); - -void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr, enum mm_order_t order); - - #endif /* APOS_RISCV_VMAP_H */ diff --git a/arch/riscv/init/init.c b/arch/riscv/init/init.c index a64bdf5..48fa661 100644 --- a/arch/riscv/init/init.c +++ b/arch/riscv/init/init.c @@ -6,10 +6,10 @@ #include #include #include +#include #include #include #include -#include #include struct pm_layout_t { @@ -125,8 +125,38 @@ static void mark_reserved_mem(void *fdt) mark_area_used(base, top); } +static void init_pmem(void *fdt) +{ + enum mm_mode_t mmode = get_mmode(fdt); + + size_t max_order = 0; + size_t order_width = 9; + switch(mmode){ + case Sv32: + max_order = 1; + order_width = 10; + break; + + case Sv39: + max_order = 2; + break; + + case Sv48: + max_order = 3; + break; + }; + + size_t widths[10] = {0}; + for(size_t i = 0; i <= max_order; ++i) + widths[i] = order_width; + + init_mem(max_order, widths, 12); +} + static void setup_pmem(void *fdt) { + init_pmem(fdt); + struct pm_layout_t pmem = get_memlayout(fdt); pm_t initrd_top = get_initrdtop(fdt); @@ -203,13 +233,21 @@ struct vm_branch_t *prepare_vmem() return branch; } -void start_vmem(struct vm_branch_t *branch) +void start_vmem(void *fdt, struct vm_branch_t *branch) { - /* assume Sv48 and ASID 0*/ - /* TODO: get ASID from CPU id - * TODO: more cores lol - */ - csr_write(CSR_SATP, SATP_MODE_48 | (((pm_t)(branch)) >> 12)); + /* 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))); + + /* Sv57 && Sv64 in the future? */ } struct init_data_t populate_initdata(void *fdt, struct vm_branch_t *branch) @@ -240,10 +278,9 @@ void init(void *fdt) dbg_fdt(fdt); setup_pmem(fdt); - struct vm_branch_t *branch = prepare_vmem(); struct init_data_t d = populate_initdata(fdt, branch); - start_vmem(branch); + start_vmem(fdt, branch); /* update_pmap(TODO: figure out where to place pmap in vmem); */ void (*main)(struct init_data_t) = (void (*)(struct init_data_t))VM_KERN; diff --git a/arch/riscv/kernel/main.c b/arch/riscv/kernel/main.c index 5566d63..c8eca26 100644 --- a/arch/riscv/kernel/main.c +++ b/arch/riscv/kernel/main.c @@ -1,5 +1,6 @@ #include #include +#include void __main main(struct init_data_t d) { @@ -14,6 +15,7 @@ void __main main(struct init_data_t d) /* functionality that should be implemented: * figure out best continuous run of memory (pmap etc) - * arbitrary mapping and kernel mapping (memory) + * arbitrary user and kernel mapping (memory) + * vm to pm */ } diff --git a/common/mem.c b/common/mem.c index 420f6f4..445748c 100644 --- a/common/mem.c +++ b/common/mem.c @@ -1,40 +1,47 @@ #include #include +#include -const size_t mm_shifts[10] = { - MM_O0_SHIFT, - MM_O1_SHIFT, - MM_O2_SHIFT, - MM_O3_SHIFT, - MM_O4_SHIFT, - MM_O6_SHIFT, - MM_O7_SHIFT, - MM_O8_SHIFT, - MM_O9_SHIFT, -}; - -const size_t mm_widths[10] = { - MM_O0_WIDTH, - MM_O1_WIDTH, - MM_O2_WIDTH, - MM_O3_WIDTH, - MM_O4_WIDTH, - MM_O5_WIDTH, - MM_O6_WIDTH, - MM_O7_WIDTH, - MM_O8_WIDTH, - MM_O9_WIDTH, -}; - -const size_t mm_sizes[10] = { - MM_O0_SIZE, - MM_O1_SIZE, - MM_O2_SIZE, - MM_O3_SIZE, - MM_O4_SIZE, - MM_O5_SIZE, - MM_O6_SIZE, - MM_O7_SIZE, - MM_O8_SIZE, - MM_O9_SIZE, -}; +size_t __mm_shifts[10]; +size_t __mm_widths[10]; +size_t __mm_sizes[10]; +size_t __mm_page_shift; +size_t __mm_max_order; + +void init_mem(size_t max_order, size_t widths[10], size_t page_shift) +{ + __mm_max_order = max_order; + __mm_page_shift = page_shift; + + __mm_shifts[0] = 0; + __mm_widths[0] = 1 << widths[0]; + __mm_sizes[0] = 1 << __mm_page_shift; + + for(size_t i = 0; i <= __mm_max_order; ++i){ + __mm_widths[i] = 1 << widths[i]; + __mm_shifts[i] = __mm_shifts[i - 1] + __mm_widths[i - 1]; + __mm_sizes[i] = 1 << __mm_shifts[i] << __mm_page_shift; + } +} + +enum mm_mode_t get_mmode(void *fdt) +{ + int mmu_offset = fdt_path_offset(fdt, "/cpus/cpu"); + const char *mmu = fdt_getprop(fdt, mmu_offset, "mmu-type", NULL); + + if(strncmp("riscv,sv48", mmu, 10) == 0) + return Sv48; + + if(strncmp("riscv,sv39", mmu, 10) == 0) + return Sv39; + + if(strncmp("riscv,sv32", mmu, 10) == 0) + return Sv32; + + /* fdt is missing mmu-type for some reason, but we can probably use + * these values as fallback */ + if(__riscv_xlen == 32) + return Sv32; + else + return Sv39; +} diff --git a/common/pmem.c b/common/pmem.c index 4546e00..e40d160 100644 --- a/common/pmem.c +++ b/common/pmem.c @@ -71,7 +71,7 @@ static void __mark_free(mm_node_t * op, pnum_t pnum, enum mm_order_t tgt, void free_page(enum mm_order_t order, pm_t paddr) { - for (ssize_t i = MM_O0; i <= MAX_ORDER; ++i) { + for (size_t i = MM_O0; i <= __mm_max_order; ++i) { if (!pmap->omap[i]) continue; @@ -125,7 +125,7 @@ static bool __mark_used(mm_node_t * op, pnum_t pnum, enum mm_order_t tgt, void mark_used(enum mm_order_t order, pm_t paddr) { - for (ssize_t i = MM_O0; i <= MAX_ORDER; ++i) { + for (size_t i = MM_O0; i <= __mm_max_order; ++i) { if (!pmap->omap[i]) continue; @@ -175,13 +175,13 @@ static pnum_t __enum_order(mm_node_t * op, pnum_t offset, pm_t alloc_page(enum mm_order_t order, pm_t offset) { - if (order > MAX_ORDER) + if (order > __mm_max_order) return 0; pnum_t pnum = -1; pm_t base = 0; struct mm_omap_t *omap; - for (size_t i = order; i <= MAX_ORDER; ++i) { + for (size_t i = order; i <= __mm_max_order; ++i) { if (!pmap->omap[i]) continue; @@ -240,7 +240,7 @@ static void __update_omap(struct mm_omap_t *omap, pm_t base, pm_t offset) void update_pmap(pm_t offset) { pm_t base = (pm_t) pmap; - for (size_t i = 0; i <= MAX_ORDER; ++i) { + for (size_t i = 0; i <= __mm_max_order; ++i) { if (!pmap->omap[i]) continue; @@ -347,16 +347,16 @@ pm_t populate_pmap(pm_t ram_base, size_t ram_size, pm_t cont) pm_t ram_region = ram_base; size_t ram_left = ram_size; - for (ssize_t i = MAX_ORDER; i >= MM_O0; --i) { - size_t entries = ram_left / mm_sizes[i]; + for (ssize_t i = __mm_max_order; i >= MM_O0; --i) { + size_t entries = ram_left / __mm_sizes[i]; if (entries == 0) continue; cont = __populate_omap(&pmap->omap[i], cont, ram_region, entries, i); - ram_left -= mm_sizes[i] * entries; - ram_region += (mm_sizes[i] * entries); + ram_left -= __mm_sizes[i] * entries; + ram_region += (__mm_sizes[i] * entries); } return cont - start; @@ -374,15 +374,15 @@ pm_t probe_pmap(pm_t ram_base, size_t ram_size) pm_t ram_region = ram_base; size_t ram_left = ram_size; - for(ssize_t i = MAX_ORDER; i >= MM_O0; --i){ - size_t entries = ram_left / mm_sizes[i]; + for(ssize_t i = __mm_max_order; i >= MM_O0; --i){ + size_t entries = ram_left / __mm_sizes[i]; if(entries == 0) continue; cont = __probe_omap(cont, entries, i); - ram_left -= mm_sizes[i] * entries; - ram_region += (mm_sizes[i] * entries); + ram_left -= __mm_sizes[i] * entries; + ram_region += (__mm_sizes[i] * entries); } return cont; diff --git a/include/apos/bytes.h b/include/apos/bytes.h index da0ab67..37fe084 100644 --- a/include/apos/bytes.h +++ b/include/apos/bytes.h @@ -2,6 +2,7 @@ #define APOS_BYTES_H #include +#include uint16_t __bswap16(uint16_t u); uint32_t __bswap32(uint32_t u); diff --git a/include/apos/mem.h b/include/apos/mem.h index 5e33e28..630fcd9 100644 --- a/include/apos/mem.h +++ b/include/apos/mem.h @@ -4,112 +4,18 @@ #include #include -#if defined(O0_WIDTH) -#define MM_O0_SHIFT (0) -#define MM_O0_WIDTH (1UL << (O0_WIDTH)) -#define MM_O0_SIZE (1UL << MM_O0_SHIFT << PAGE_SHIFT) -#else -#define MM_O0_SHIFT 0 -#define MM_O0_WIDTH 0 -#define MM_O0_SIZE 0 -#endif - -#if defined(O1_WIDTH) -#define MM_O1_SHIFT (MM_O0_SHIFT + (O0_WIDTH)) -#define MM_O1_WIDTH (1UL << (O1_WIDTH)) -#define MM_O1_SIZE (1UL << MM_O1_SHIFT << PAGE_SHIFT) -#else -#define MM_O1_SHIFT 0 -#define MM_O1_SHIFT 0 -#define MM_O1_SIZE 0 -#endif - -#if defined(O2_WIDTH) -#define MM_O2_SHIFT (MM_O1_SHIFT + (O1_WIDTH)) -#define MM_O2_WIDTH (1UL << (O2_WIDTH)) -#define MM_O2_SIZE (1UL << MM_O2_SHIFT << PAGE_SHIFT) -#else -#define MM_O2_SHIFT 0 -#define MM_O2_WIDTH 0 -#define MM_O2_SIZE 0 -#endif - -#if defined(O3_WIDTH) -#define MM_O3_SHIFT (MM_O2_SHIFT + (O2_WIDTH)) -#define MM_O3_WIDTH (1UL << (O3_WIDTH)) -#define MM_O3_SIZE (1UL << MM_O3_SHIFT << PAGE_SHIFT) -#else -#define MM_O3_SHIFT 0 -#define MM_O3_WIDTH 0 -#define MM_O3_SIZE 0 -#endif - -#if defined(O4_WIDTH) -#define MM_O4_SHIFT (MM_O3_SHIFT + (O3_WIDTH)) -#define MM_O4_SHIFT (1UL << (O4_WIDTH)) -#define MM_O4_SIZE (1UL << MM_O4_SHIFT << PAGE_SHIFT) -#else -#define MM_O4_SHIFT 0 -#define MM_O4_WIDTH 0 -#define MM_O4_SIZE 0 -#endif - -#if defined(O5_WIDTH) -#define MM_O5_SHIFT (MM_O4_SHIFT + (O4_WIDTH)) -#define MM_O5_WIDTH (1UL << (O5_WIDTH)) -#define MM_O5_SIZE (1UL << MM_O5_SHIFT << PAGE_SHIFT) -#else -#define MM_O5_SHIFT 0 -#define MM_O5_WIDTH 0 -#define MM_O5_SIZE 0 -#endif - -#if defined(O6_WIDTH) -#define MM_O6_SHIFT (MM_O5_SHIFT + (O5_WIDTH)) -#define MM_O6_WIDTH (1UL << (O6_WIDTH)) -#define MM_O6_SIZE (1UL << MM_O6_SHIFT << PAGE_SHIFT) -#else -#define MM_O6_SHIFT 0 -#define MM_O6_WIDTH 0 -#define MM_O6_SIZE 0 -#endif - -#if defined(O7_WIDTH) -#define MM_O7_SHIFT (MM_O6_SHIFT + (O6_WIDTH)) -#define MM_O7_WIDTH (1UL << (O7_WIDTH)) -#define MM_O7_SIZE (1UL << MM_O7_SHIFT << PAGE_SHIFT) -#else -#define MM_O7_SHIFT 0 -#define MM_O7_WIDTH 0 -#define MM_O7_SIZE 0 -#endif - -#if defined(O8_WIDTH) -#define MM_O8_SHIFT (MM_O7_SHIFT + (O7_WIDTH)) -#define MM_O8_WIDTH (1UL << (O8_WIDTH)) -#define MM_O8_SIZE (1UL << MM_O8_SHIFT << PAGE_SHIFT) -#else -#define MM_O8_SHIFT 0 -#define MM_O8_WIDTH 0 -#define MM_O8_SIZE 0 -#endif - -#if defined(O9_WIDTH) -#define MM_O9_SHIFT (MM_O8_SHIFT + (O8_WIDTH)) -#define MM_O9_WIDTH (1UL << (O9_WIDTH)) -#define MM_O9_SIZE (1UL << MM_O9_SHIFT << PAGE_SHIFT) -#else -#define MM_O9_SHIFT 0 -#define MM_O9_WIDTH 0 -#define MM_O9_SIZE 0 -#endif +enum mm_mode_t { + Sv48, + Sv39, + Sv32, +}; #define MM_OINFO_WIDTH (sizeof(mm_info_t) * 8) #define pnum_to_index(pnum, order) (((pnum) >> __o_offset(order)) & (__o_width(order) - 1)) #define pm_to_index(paddr, order) (pnum_to_index(pm_to_pnum(paddr), (order))) -#define pm_to_pnum(paddr) ((paddr) >> PAGE_SHIFT) -#define pnum_to_paddr(pnum) ((pnum) << PAGE_SHIFT) +#define pm_to_pnum(paddr) ((paddr) >> __mm_page_shift) +#define pnum_to_paddr(pnum) ((pnum) << __mm_page_shift) #define move_forward(var, num) (((var) += (num)) - (num)) @@ -121,15 +27,21 @@ #define next_elems(num) (sizeof(void *) * (num)) #define max_index(order) (__o_width(order) - 1) -#define __o_offset(order) (mm_shifts[order]) -#define __o_width(order) (mm_widths[order]) -#define __o_elems(order) (mm_widths[order] / MM_OINFO_WIDTH) +#define __o_offset(order) (__mm_shifts[order]) +#define __o_width(order) (__mm_widths[order]) +#define __o_elems(order) (__mm_widths[order] / MM_OINFO_WIDTH) #define __o_container(idx) ((idx) / MM_OINFO_WIDTH) #define __o_bit(idx) ((idx) & (MM_OINFO_WIDTH - 1)) -extern const size_t mm_shifts[10]; -extern const size_t mm_widths[10]; -extern const size_t mm_sizes[10]; +extern size_t __mm_shifts[10]; +extern size_t __mm_widths[10]; +extern size_t __mm_sizes[10]; + +extern size_t __mm_page_shift; +extern size_t __mm_max_order; + +void init_mem(size_t max_order, size_t shifts[10], size_t page_shift); +enum mm_mode_t get_mmode(void *fdt); #endif /* APOS_MEM_H */ diff --git a/include/apos/types.h b/include/apos/types.h index 791c394..7cc4e28 100644 --- a/include/apos/types.h +++ b/include/apos/types.h @@ -1,8 +1,6 @@ #ifndef APOS_TYPES_H #define APOS_TYPES_H -#include - typedef _Bool bool; #define true 1 #define false 0 diff --git a/include/apos/utils.h b/include/apos/utils.h index 3855a37..39d5b83 100644 --- a/include/apos/utils.h +++ b/include/apos/utils.h @@ -11,6 +11,9 @@ #define MIN4(a, b, c, d) (MIN3(a, b, c) <= MIN3(b, c, d) ? MIN3(a, b, c) : MIN3(b, c, d)) /* etc... */ +#define GLUE2(x, y) x##y +#define GLUE(x, y) GLUE2(x, y) + #include static inline size_t align_up(size_t val, size_t a) diff --git a/include/apos/vmem.h b/include/apos/vmem.h new file mode 100644 index 0000000..589e814 --- /dev/null +++ b/include/apos/vmem.h @@ -0,0 +1,32 @@ +#ifndef APOS_VMEM_H +#define APOS_VMEM_H + +/* arch-specific data */ +#include + +/* general overview of the different functions: + * (un)map_vmem: map one known page of physical memory to one known page of + * virtual memory + * + * (un)map_vregion: map known physical region to unknown virtual region within + * start and end + * + * (un)map_vsize: map unknown physical region to unknown virtual region + */ + +void map_vmem(struct vm_branch_t *branch, + pm_t paddr, vm_t vaddr, + uint8_t flags, enum mm_order_t order); + +void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr, enum mm_order_t order); + +#define map_kvregion(b, pb, pt) map_vregion(b, pb, pt, VMEM_BASE, VMEM_TOP); +#define map_uvregion(b, pb, pt) map_vregion(b, pb, pt, UMEM_BASE, UMEM_TOP); + +vm_t map_vregion(struct vm_branch_t *branch, pm_t base, pm_t top, vm_t start, vm_t end); +void unmap_vregion(struct vm_branch_t *branch, pm_t base, pm_t top); + +vm_t map_vsize(struct vm_branch_t *branch, size_t size); +void unmap_vsize(struct vm_branch_t *branch, size_t size); + +#endif /* APOS_VMEM_H */ -- cgit v1.3