aboutsummaryrefslogtreecommitdiff
path: root/arch/riscv
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2021-10-25 19:40:53 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2021-10-25 19:44:11 +0300
commit7f7b3d61baf46fe358d3f1bd1cb584e0daed3a81 (patch)
tree51ded3e49cb467915a6e2b0e570b5d9973515553 /arch/riscv
parent59a374b0eed4313d1a67e2cdb673a295e79a6494 (diff)
downloadkmi-7f7b3d61baf46fe358d3f1bd1cb584e0daed3a81.tar.gz
kmi-7f7b3d61baf46fe358d3f1bd1cb584e0daed3a81.zip
Some minor changes to virtual memory handling
+ Should start to think about how virtual memory should be handled efficiently, I'm sort of flailing around and not actually doing anything beneficial. The mapping system I've so far implemented _works_, but it's not good and I'm not happy with it. I might come back and fix/improve it, but I think I'll go ahead and do other things for a while, might give me a better overhead view of what the virtual memory system should do. + TODO: should probably document the memory layout I'm going with at the moment.
Diffstat (limited to 'arch/riscv')
-rw-r--r--arch/riscv/common/vmem.c68
-rw-r--r--arch/riscv/config.h3
-rw-r--r--arch/riscv/init/init.c80
-rw-r--r--arch/riscv/kernel/main.c28
4 files changed, 159 insertions, 20 deletions
diff --git a/arch/riscv/common/vmem.c b/arch/riscv/common/vmem.c
index 7b2d66b..6b022e1 100644
--- a/arch/riscv/common/vmem.c
+++ b/arch/riscv/common/vmem.c
@@ -1,33 +1,91 @@
#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
-/* probably not actually this simple, right? */
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 = pm_to_index(vaddr, top);
+ 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);
- memset((void *)new_leaf, 0, sizeof(struct vm_branch_t));
+
+ void *leaf_ptr = (void *)set_vptr(VM_R | VM_W | VM_V, new_leaf);
+ memset(leaf_ptr, 0, sizeof(struct vm_branch_t));
}
- branch = (struct vm_branch_t *)pte_addr(branch->leaf[idx]);
+ 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 = pm_to_index(vaddr, top);
+ size_t idx = vm_to_index(vaddr, top);
branch->leaf[idx] = (struct vm_branch_t *)to_pte(paddr, flags);
}
diff --git a/arch/riscv/config.h b/arch/riscv/config.h
index 75c898f..fa3c178 100644
--- a/arch/riscv/config.h
+++ b/arch/riscv/config.h
@@ -10,3 +10,6 @@
#define PM_STACK_BASE (PM_KERN + SZ_2M)
#define PM_STACK_TOP (PM_STACK_BASE + SZ_2M - 2)
#define VM_KERN (-SZ_1G)
+#define TMP_PTE (-SZ_2G)
+#define ROOT_PTE (0)
+#define ROOT_REGION (SZ_4K)
diff --git a/arch/riscv/init/init.c b/arch/riscv/init/init.c
index 48fa661..9b7d371 100644
--- a/arch/riscv/init/init.c
+++ b/arch/riscv/init/init.c
@@ -17,6 +17,12 @@ struct pm_layout_t {
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");
@@ -125,16 +131,16 @@ static void mark_reserved_mem(void *fdt)
mark_area_used(base, top);
}
-static void init_pmem(void *fdt)
+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_width = 9;
+ size_t order_bits = 9;
switch(mmode){
case Sv32:
max_order = 1;
- order_width = 10;
+ order_bits = 10;
break;
case Sv39:
@@ -146,17 +152,21 @@ static void init_pmem(void *fdt)
break;
};
- size_t widths[10] = {0};
+ size_t bits[10] = {0};
for(size_t i = 0; i <= max_order; ++i)
- widths[i] = order_width;
+ bits[i] = order_bits;
+
+ init_mem(max_order, bits, 12);
- init_mem(max_order, widths, 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 setup_pmem(void *fdt)
+static struct pm_layout_t setup_pmem(void *fdt)
{
- init_pmem(fdt);
-
struct pm_layout_t pmem = get_memlayout(fdt);
pm_t initrd_top = get_initrdtop(fdt);
@@ -199,6 +209,8 @@ static void setup_pmem(void *fdt)
/* mark reserved mem */
mark_reserved_mem(fdt);
+
+ return (struct pm_layout_t){.base = pmap_base, .top = actual_size + pmap_base};
}
pm_t move_kernel()
@@ -229,10 +241,27 @@ struct vm_branch_t *prepare_vmem()
/* 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);
+
+ map_vmem(branch, 0x10000000, 0x10000000, 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 */
@@ -250,7 +279,10 @@ void start_vmem(void *fdt, struct vm_branch_t *branch)
/* Sv57 && Sv64 in the future? */
}
-struct init_data_t populate_initdata(void *fdt, struct vm_branch_t *branch)
+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;
@@ -261,13 +293,29 @@ struct init_data_t populate_initdata(void *fdt, struct vm_branch_t *branch)
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 = branch;
+ 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;
}
@@ -276,11 +324,13 @@ void init(void *fdt)
{
init_debug(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(fdt, branch);
+ 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;
diff --git a/arch/riscv/kernel/main.c b/arch/riscv/kernel/main.c
index c8eca26..d4fa7b8 100644
--- a/arch/riscv/kernel/main.c
+++ b/arch/riscv/kernel/main.c
@@ -1,9 +1,37 @@
#include <apos/debug.h>
#include <apos/init.h>
#include <apos/vmem.h>
+#include <apos/mem.h>
+
+#ifdef DEBUG
+
+static void kernel_dbg(void *fdt)
+{
+ struct dbg_info_t dbg = dbg_from_fdt(fdt);
+ dbg_init(dbg.dbg_ptr, dbg.dev);
+}
+
+#else
+#define kernel_dbg(...)
+#endif
+
+static void map_fdt(struct vm_branch_t *branch, vm_t fdt_base, vm_t fdt_top)
+{
+ map_vregion(branch, fdt_base, 0, fdt_top - fdt_base, VM_R | VM_W |VM_V);
+}
void __main main(struct init_data_t d)
{
+ /* feck */
+ dbg_init(0x10000000, NS16550A);
+ dbg("test\n");
+ 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);
/* TODO: approximate order of business:
* setup debugging in vmem (requires mapping fdt)
* free unnecessary init