sweep through entire page table to free up intermediate tables
[lunaix-os.git] / lunaix-os / kernel / mm / vmap.c
index deb18d30a05577333e824f3c7c8d7ded5e093b55..349f1fb1ef3def73cdc410e8a1645946bfdab0b6 100644 (file)
@@ -1,64 +1,94 @@
-#include <lunaix/mm/pmm.h>
-#include <lunaix/mm/vmm.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/spike.h>
+#include <lunaix/syslog.h>
 
-#define VMAP_START PG_MOUNT_BASE + MEM_4MB
-#define VMAP_END PD_REFERENCED
+#include <asm/mempart.h>
 
-static uintptr_t start = VMAP_START;
+static ptr_t start = VMAP;
+static volatile ptr_t prev_va = 0;
 
-void*
-vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr)
+void
+vmap_set_start(ptr_t start_addr) {
+    start = start_addr;
+}
+
+static pte_t*
+__alloc_contig_ptes(pte_t* ptep, size_t base_sz, int n)
 {
-    // next fit
-    assert_msg((paddr & 0xfff) == 0, "vmap: bad alignment");
-    size = ROUNDUP(size, PG_SIZE);
-
-    uintptr_t current_addr = start;
-    size_t examed_size = 0, wrapped = 0;
-    x86_page_table* pd = (x86_page_table*)L1_BASE_VADDR;
-
-    while (!wrapped || current_addr >= start) {
-        size_t l1inx = L1_INDEX(current_addr);
-        if (!(pd->entry[l1inx])) {
-            // empty 4mb region
-            examed_size += MEM_4MB;
-            current_addr = (current_addr & 0xffc00000) + MEM_4MB;
-        } else {
-            x86_page_table* ptd = (x86_page_table*)(L2_VADDR(l1inx));
-            size_t i = L2_INDEX(current_addr);
-            for (; i < PG_MAX_ENTRIES && examed_size < size; i++) {
-                if (!ptd->entry[i]) {
-                    examed_size += PG_SIZE;
-                } else if (examed_size) {
-                    // found a discontinuity, start from beginning
-                    examed_size = 0;
-                    i++;
-                    break;
-                }
-            }
-            current_addr += i << 12;
-        }
+    int _n     = 0;
+    size_t sz  = L0T_SIZE;
+    ptr_t va   = page_addr(ptep_pfn(ptep));
 
-        if (examed_size >= size) {
-            goto done;
+    ptep = mkl0tep(ptep);
+
+    while (_n < n && va < VMAP_END) {
+        pte_t pte = *ptep;
+        if (pte_isnull(pte)) {
+            _n += sz / base_sz;
+        } 
+        else if ((sz / LEVEL_SIZE) < base_sz) {
+            _n = 0;
+        }
+        else {
+            sz = sz / LEVEL_SIZE;
+            ptep = ptep_step_into(ptep);
+            continue;
         }
 
-        if (current_addr >= VMAP_END) {
-            wrapped = 1;
-            current_addr = VMAP_START;
+        if (ptep_vfn(ptep) + 1 == LEVEL_SIZE) {
+            ptep = ptep_step_out(++ptep);
+            va += sz;
+            
+            sz = sz * LEVEL_SIZE;
+            continue;
         }
+        
+        va += sz;
+        ptep++;
     }
-    panick("vmm: out of memory");
-
-done:
-    uintptr_t alloc_begin = current_addr - examed_size;
-    for (size_t i = 0; i < size; i += PG_SIZE) {
-        vmm_set_mapping(
-          PD_REFERENCED, alloc_begin + i, paddr + i, PG_PREM_RW, 0);
-        pmm_ref_page(KERNEL_PID, paddr + i);
+
+    if (va >= VMAP_END) {
+        return NULL;
     }
-    start = alloc_begin + size;
 
-    return (void*)alloc_begin;
+    va -= base_sz * _n;
+    
+    prev_va = va;
+    return mkptep_va(ptep_vm_mnt(ptep), va);
+}
+
+ptr_t
+vmap_ptes_at(pte_t pte, size_t lvl_size, int n)
+{
+    pte_t* ptep = mkptep_va(VMS_SELF, start);
+    ptep = __alloc_contig_ptes(ptep, lvl_size, n);
+
+    if (!ptep) {
+        return 0;
+    }
+
+    vmm_set_ptes_contig(ptep, pte, lvl_size, n);
+
+    ptr_t va = page_addr(ptep_pfn(ptep));
+
+    tlb_flush_kernel_ranged(va, n);
+    
+    return va;
+}
+
+void
+vunmap(ptr_t ptr, struct leaflet* leaflet)
+{    
+    pte_t* ptep;
+    unsigned int npages;
+    assert(start <= ptr && ptr <= VMAP_END);
+    
+    npages = leaflet_nfold(leaflet);
+    ptep = mkptep_va(VMS_SELF, ptr);
+
+    vmm_unset_ptes(ptep, npages);
+
+    tlb_flush_kernel_ranged(ptr, npages);
 }
\ No newline at end of file