aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv/kernel/vmem.c109
-rw-r--r--common/vmem.c17
-rw-r--r--include/apos/vmem.h6
3 files changed, 91 insertions, 41 deletions
diff --git a/arch/riscv/kernel/vmem.c b/arch/riscv/kernel/vmem.c
index 744f633..d1d77a1 100644
--- a/arch/riscv/kernel/vmem.c
+++ b/arch/riscv/kernel/vmem.c
@@ -10,11 +10,84 @@
#define pte_flags(pte) (((pm_t)(pte)) & 0xff)
#define to_pte(p, f) ((pm_to_pnum((pm_t)__pa(p)) << 10) | (f))
#define pte_addr(pte) __va(pnum_to_paddr(pte_ppn(pte)))
+#define pte_paddr(pte) (pnum_to_paddr(pte_ppn(pte)))
#define vm_to_index(a, o) (pm_to_index(a, o))
+#define is_active(pte) (pte_flags(pte) & VM_V)
+#define is_leaf(pte) (is_active(pte) && (pte_flags(pte) & ~VM_V))
+#define is_branch(pte) (is_active(pte) && !(pte_flags(pte) & ~VM_V))
-void mod_vmem(struct vm_branch_t *branch, vm_t vaddr, uint8_t flags, enum mm_order_t order)
+static pm_t *__find_vmem(struct vm_branch_t *b, vm_t v, enum mm_order_t *o)
{
- /* todo */
+ enum mm_order_t top = __mm_max_order;
+ *o = MM_O0;
+ do {
+ size_t idx = vm_to_index(v, top);
+ pm_t pte = (pm_t)b->leaf[idx];
+
+ if(!pte)
+ return 0;
+
+ if(is_leaf(pte)){
+ if(o)
+ *o = top;
+
+ return (pm_t *)&b->leaf[idx];
+ }
+
+ b = (struct vm_branch_t *)pte_addr(pte);
+ } while (top--);
+
+ return 0;
+}
+
+int mod_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t paddr, uint8_t flags)
+{
+ pm_t *pte = __find_vmem(branch, vaddr, 0);
+ if(pte){
+ *pte = to_pte(paddr, flags);
+ return 0;
+ }
+
+ return -1;
+}
+
+/* huh, should probably add status flags etc. to all my API functions. Damn, I'm
+ * lazy. */
+int stat_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t *paddr,
+ enum mm_order_t *order, uint8_t *flags)
+{
+ pm_t *pte = __find_vmem(branch, vaddr, order);
+ if(pte){
+ if(paddr)
+ *paddr = pte_paddr(*pte);
+
+ if(flags)
+ *flags = pte_flags(*pte);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static struct vm_branch_t *__create_leaf()
+{
+ pm_t new_leaf = alloc_page(MM_KPAGE, 0);
+ memset((void *)new_leaf, 0, sizeof(struct vm_branch_t));
+ return (struct vm_branch_t *)to_pte(new_leaf, VM_V);
+}
+
+static void __destroy_branch(struct vm_branch_t *b)
+{
+ if(!b)
+ return;
+
+ for(size_t i = 0; i < BASE_PAGE_SIZE / sizeof(pm_t); ++i){
+ if(is_branch(b->leaf[i]));
+ __destroy_branch((struct vm_branch_t *)pte_addr(b->leaf[i]));
+
+ free_page(MM_KPAGE, (pm_t)pte_addr(b->leaf[i]));
+ }
}
void map_vmem(struct vm_branch_t *branch,
@@ -24,18 +97,16 @@ void map_vmem(struct vm_branch_t *branch,
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));
+ if (is_branch(branch->leaf[idx])){
+ __destroy_branch(branch->leaf[idx]);
+ branch->leaf[idx] = 0;
}
- pm_t pte = (pm_t)branch->leaf[idx];
- pm_t branch_pptr = (pm_t)pte_addr(pte);
- branch = (struct vm_branch_t *)branch_pptr;
+ if (!branch->leaf[idx])
+ branch->leaf[idx] = __create_leaf();
+
+
+ branch = (struct vm_branch_t *)pte_addr(branch->leaf[idx]);
top--;
}
@@ -43,16 +114,10 @@ void map_vmem(struct vm_branch_t *branch,
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)
+void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr)
{
- 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, (pm_t)pte_addr(branch->leaf[idx]));
- branch->leaf[idx] = 0;
+ pm_t *pte = __find_vmem(branch, vaddr, 0);
+ if(pte)
+ *pte = 0;
}
diff --git a/common/vmem.c b/common/vmem.c
index 865ffdc..eee85a0 100644
--- a/common/vmem.c
+++ b/common/vmem.c
@@ -165,23 +165,6 @@ static struct sp_mem *sp_mem_create_region(vm_t start, vm_t end,
return m;
}
-static struct sp_mem *sp_free_find_first(struct sp_reg_root *r, size_t size, size_t *align)
-{
- *align = 0;
- struct sp_node *n = sp_root(r->free_regions);
- while(n){
- struct sp_mem *t = mem_container(n);
- size_t nsize = t->end - t->start;
-
- if(size <= nsize)
- return t;
-
- n = sp_right(n);
- }
-
- return 0;
-}
-
/* TODO: should probably check if this actually works :D seems to do, but that's
* just from really quick checking */
static size_t po_align(size_t s)
diff --git a/include/apos/vmem.h b/include/apos/vmem.h
index 6918ba4..fd1a165 100644
--- a/include/apos/vmem.h
+++ b/include/apos/vmem.h
@@ -40,8 +40,10 @@ struct sp_mem {
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);
+void unmap_vmem(struct vm_branch_t *branch, vm_t vaddr);
+int mod_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t paddr, uint8_t flags);
+int stat_vmem(struct vm_branch_t *branch, vm_t vaddr, pm_t *paddr,
+ enum mm_order_t *order, uint8_t *flags);
int sp_mem_init(struct sp_reg_root *r, vm_t start, size_t nums);