Code-base clean-up and refactoring (#47)
[lunaix-os.git] / lunaix-os / kernel / mm / procvm.c
index 119efde25b389eae2750218665bd2a9d3428bb1c..31d9f3f5503ead2155867c4c9c9f01c1294a852f 100644 (file)
@@ -5,7 +5,7 @@
 #include <lunaix/mm/mmap.h>
 #include <lunaix/process.h>
 
 #include <lunaix/mm/mmap.h>
 #include <lunaix/process.h>
 
-#include <sys/mm/mm_defs.h>
+#include <asm/mm_defs.h>
 
 #include <klibc/string.h>
 
 
 #include <klibc/string.h>
 
@@ -29,158 +29,125 @@ __ptep_advancement(struct leaflet* leaflet, int level)
     return (1 << (leaflet_order(leaflet) % shifts)) - 1;
 }
 
     return (1 << (leaflet_order(leaflet) % shifts)) - 1;
 }
 
-static ptr_t
-vmscpy(ptr_t dest_mnt, ptr_t src_mnt, bool only_kernel)
+static inline int
+__descend(ptr_t dest_mnt, ptr_t src_mnt, ptr_t va, bool alloc)
 {
 {
-    pte_t* ptep_dest    = mkl0tep(mkptep_va(dest_mnt, 0));
-    pte_t* ptep         = mkl0tep(mkptep_va(src_mnt, 0));
-    pte_t* ptepd_kernel = mkl0tep(mkptep_va(dest_mnt, KERNEL_RESIDENT));
-    pte_t* ptep_kernel  = mkl0tep(mkptep_va(src_mnt, KERNEL_RESIDENT));
+    pte_t *dest, *src, pte;
 
 
-    // Build the self-reference on dest vms
+    int i = 0;
+    while (!pt_last_level(i))
+    {
+        dest = mklntep_va(i, dest_mnt, va);
+        src  = mklntep_va(i, src_mnt, va);
+        pte  = pte_at(src);
 
 
-    /* 
-     *        -- What the heck are ptep_ssm and ptep_sms ? --
-     *      
-     *      ptep_dest point to the pagetable itself that is mounted
-     *          at dest_mnt (or simply mnt): 
-     *              mnt -> self -> self -> self -> L0TE@offset
-     * 
-     *      ptep_sms shallowed the recursion chain:
-     *              self -> mnt -> self -> self -> L0TE@self
-     * 
-     *      ptep_ssm shallowed the recursion chain:
-     *              self -> self -> mnt -> self -> L0TE@self
-     *      
-     *      Now, here is the problem, back to x86_32, the translation is 
-     *      a depth-3 recursion:
-     *              L0T -> LFT -> Page
-     *      
-     *      So ptep_ssm will terminate at mnt and give us a leaf
-     *      slot for allocate a fresh page table for mnt:
-     *              self -> self -> L0TE@mnt
-     * 
-     *      but in x86_64 translation has extra two more step:
-     *              L0T -> L1T -> L2T -> LFT -> Page
-     *      
-     *      So we must continue push down.... 
-     *      ptep_sssms shallowed the recursion chain:
-     *              self -> self -> self -> mnt  -> L0TE@self
-     * 
-     *      ptep_ssssm shallowed the recursion chain:
-     *              self -> self -> self -> self -> L0TE@mnt
-     * 
-     *      Note: PML4: 2 extra steps
-     *            PML5: 3 extra steps
-    */
-    pte_t* ptep_ssm     = mkl0tep_va(VMS_SELF, dest_mnt);
-    pte_t* ptep_sms     = mkl1tep_va(VMS_SELF, dest_mnt) + VMS_SELF_L0TI;
-    pte_t  pte_sms      = mkpte_prot(KERNEL_PGTAB);
+        if (!pte_isloaded(pte) || pte_huge(pte)) {
+            break;
+        }
 
 
-    pte_sms = alloc_kpage_at(ptep_ssm, pte_sms, 0);
-    set_pte(ptep_sms, pte_sms);    
+        if (alloc && pte_isnull(pte_at(dest))) {
+            alloc_kpage_at(dest, pte, 0);
+        }
+
+        i++;
+    }
+
+    return i;
+}
+
+static inline void
+copy_leaf(pte_t* dest, pte_t* src, pte_t pte, int level)
+{
+    struct leaflet* leaflet;
+
+    set_pte(dest, pte);
+
+    if (!pte_isloaded(pte)) {
+        return;
+    }
+
+    leaflet = pte_leaflet(pte);
+    assert(leaflet_refcount(leaflet));
     
     
-    tlb_flush_kernel((ptr_t)dest_mnt);
-    tlb_flush_kernel((ptr_t)ptep_sms);
-
-    if (only_kernel) {
-        ptep = ptep_kernel;
-        ptep_dest += ptep_vfn(ptep_kernel);
-    } else {
-        ptep++;
-        ptep_dest++;
+    if (leaflet_ppfn(leaflet) == pte_ppfn(pte)) {
+        leaflet_borrow(leaflet);
     }
     }
+}
 
 
-    int level = 0;
+static inline void
+copy_root(pte_t* dest, pte_t* src, pte_t pte, int level)
+{
+    alloc_kpage_at(dest, pte, 0);
+}
+
+static void
+vmrcpy(ptr_t dest_mnt, ptr_t src_mnt, struct mm_region* region)
+{
+    pte_t *src, *dest;
+    ptr_t loc;
+    int level;
     struct leaflet* leaflet;
 
     struct leaflet* leaflet;
 
-    while (ptep < ptep_kernel)
+    loc  = region->start;
+    src  = mkptep_va(src_mnt, loc);
+    dest = mkptep_va(dest_mnt, loc);
+
+    level = __descend(dest_mnt, src_mnt, loc, true);
+
+    while (loc < region->end)
     {
     {
-        pte_t pte = *ptep;
+        pte_t pte = *src;
 
         if (pte_isnull(pte)) {
             goto cont;
         } 
         
         if (pt_last_level(level) || pte_huge(pte)) {
 
         if (pte_isnull(pte)) {
             goto cont;
         } 
         
         if (pt_last_level(level) || pte_huge(pte)) {
-            set_pte(ptep_dest, pte);
-
-            if (pte_isloaded(pte)) {
-                leaflet = pte_leaflet(pte);
-                assert(leaflet_refcount(leaflet));
-                
-                if (leaflet_ppfn(leaflet) == pte_ppfn(pte)) {
-                    leaflet_borrow(leaflet);
-                }
-            }
+            copy_leaf(dest, src, pte, level);
+            goto cont;
         }
         }
-        else if (!pt_last_level(level)) {
-            alloc_kpage_at(ptep_dest, pte, 0);
+        
+        if (!pt_last_level(level)) {
+            copy_root(dest, src, pte, level);
 
 
-            ptep = ptep_step_into(ptep);
-            ptep_dest = ptep_step_into(ptep_dest);
+            src = ptep_step_into(src);
+            dest = ptep_step_into(dest);
             level++;
 
             continue;
         }
         
     cont:
             level++;
 
             continue;
         }
         
     cont:
-        while (ptep_vfn(ptep) == MAX_PTEN - 1) {
+        loc += lnt_page_size(level);
+        while (ptep_vfn(src) == MAX_PTEN - 1) {
             assert(level > 0);
             assert(level > 0);
-            ptep = ptep_step_out(ptep);
-            ptep_dest = ptep_step_out(ptep_dest);
+            src = ptep_step_out(src);
+            dest = ptep_step_out(dest);
             level--;
         }
 
             level--;
         }
 
-        ptep++;
-        ptep_dest++;
-    }
-
-    // Ensure we step back to L0T
-    assert(!level);
-    assert(ptep_dest == ptepd_kernel);
-    
-    // Carry over the kernel (exclude last two entry)
-    unsigned int i = ptep_vfn(ptep);
-    while (i++ < MAX_PTEN) {
-        pte_t pte = *ptep;
-
-        if (l0tep_implie_vmnts(ptep)) {
-            goto _cont;
-        }
-
-        assert(!pte_isnull(pte));
-
-        // Ensure it is a next level pagetable,
-        //  we MAY relax this later allow kernel
-        //  to have huge leaflet mapped at L0T
-        leaflet = pte_leaflet_aligned(pte);
-        assert(leaflet_order(leaflet) == 0);
-
-        set_pte(ptep_dest, pte);
-        leaflet_borrow(leaflet);
-    
-    _cont:
-        ptep++;
-        ptep_dest++;
+        src++;
+        dest++;
     }
     }
-
-    return pte_paddr(pte_sms);
 }
 
 static void
 }
 
 static void
-vmsfree(ptr_t vm_mnt)
+vmrfree(ptr_t vm_mnt, struct mm_region* region)
 {
 {
+    pte_t *src, *end;
+    ptr_t loc;
+    int level;
     struct leaflet* leaflet;
     struct leaflet* leaflet;
-    pte_t* ptep_head    = mkl0tep(mkptep_va(vm_mnt, 0));
-    pte_t* ptep_self    = mkl0tep(mkptep_va(vm_mnt, VMS_SELF));
-    pte_t* ptep_kernel  = mkl0tep(mkptep_va(vm_mnt, KERNEL_RESIDENT));
 
 
-    int level = 0;
-    pte_t* ptep = ptep_head;
-    while (ptep < ptep_kernel)
+    loc  = region->start;
+    src  = mkptep_va(vm_mnt, region->start);
+    end  = mkptep_va(vm_mnt, region->end);
+
+    level = __descend(0, vm_mnt, loc, false);
+
+    while (src < end)
     {
     {
-        pte_t pte = *ptep;
+        pte_t pte = *src;
         ptr_t pa  = pte_paddr(pte);
 
         if (pte_isnull(pte)) {
         ptr_t pa  = pte_paddr(pte);
 
         if (pte_isnull(pte)) {
@@ -188,7 +155,7 @@ vmsfree(ptr_t vm_mnt)
         } 
 
         if (!pt_last_level(level) && !pte_huge(pte)) {
         } 
 
         if (!pt_last_level(level) && !pte_huge(pte)) {
-            ptep = ptep_step_into(ptep);
+            src = ptep_step_into(src);
             level++;
 
             continue;
             level++;
 
             continue;
@@ -198,13 +165,13 @@ vmsfree(ptr_t vm_mnt)
             leaflet = pte_leaflet_aligned(pte);
             leaflet_return(leaflet);
 
             leaflet = pte_leaflet_aligned(pte);
             leaflet_return(leaflet);
 
-            ptep += __ptep_advancement(leaflet, level);
+            src += __ptep_advancement(leaflet, level);
         }
 
     cont:
         }
 
     cont:
-        while (ptep_vfn(ptep) == MAX_PTEN - 1) {
-            ptep = ptep_step_out(ptep);
-            leaflet = pte_leaflet_aligned(pte_at(ptep));
+        while (ptep_vfn(src) == MAX_PTEN - 1) {
+            src = ptep_step_out(src);
+            leaflet = pte_leaflet_aligned(pte_at(src));
             
             assert(leaflet_order(leaflet) == 0);
             leaflet_return(leaflet);
             
             assert(leaflet_order(leaflet) == 0);
             leaflet_return(leaflet);
@@ -212,9 +179,100 @@ vmsfree(ptr_t vm_mnt)
             level--;
         }
 
             level--;
         }
 
-        ptep++;
+        src++;
+    }
+}
+
+static void
+vmscpy(struct proc_mm* dest_mm, struct proc_mm* src_mm)
+{
+    // Build the self-reference on dest vms
+
+    /* 
+     *        -- What the heck are ptep_ssm and ptep_sms ? --
+     *      
+     *      ptep_dest point to the pagetable itself that is mounted
+     *          at dest_mnt (or simply mnt): 
+     *              mnt -> self -> self -> self -> L0TE@offset
+     * 
+     *      ptep_sms shallowed the recursion chain:
+     *              self -> mnt -> self -> self -> L0TE@self
+     * 
+     *      ptep_ssm shallowed the recursion chain:
+     *              self -> self -> mnt -> self -> L0TE@self
+     *      
+     *      Now, here is the problem, back to x86_32, the translation is 
+     *      a depth-3 recursion:
+     *              L0T -> LFT -> Page
+     *      
+     *      So ptep_ssm will terminate at mnt and give us a leaf
+     *      slot for allocate a fresh page table for mnt:
+     *              self -> self -> L0TE@mnt
+     * 
+     *      but in x86_64 translation has extra two more step:
+     *              L0T -> L1T -> L2T -> LFT -> Page
+     *      
+     *      So we must continue push down.... 
+     *      ptep_sssms shallowed the recursion chain:
+     *              self -> self -> self -> mnt  -> L0TE@self
+     * 
+     *      ptep_ssssm shallowed the recursion chain:
+     *              self -> self -> self -> self -> L0TE@mnt
+     * 
+     *      Note: PML4: 2 extra steps
+     *            PML5: 3 extra steps
+    */
+
+    ptr_t  dest_mnt, src_mnt;
+    
+    dest_mnt = dest_mm->vm_mnt;
+    assert(dest_mnt);
+
+    pte_t* ptep_ssm     = mkl0tep_va(VMS_SELF, dest_mnt);
+    pte_t* ptep_smx     = mkl1tep_va(VMS_SELF, dest_mnt);
+    pte_t  pte_sms      = mkpte_prot(KERNEL_PGTAB);
+
+    pte_sms = alloc_kpage_at(ptep_ssm, pte_sms, 0);
+    set_pte(&ptep_smx[VMS_SELF_L0TI], pte_sms);
+    
+    tlb_flush_kernel((ptr_t)dest_mnt);
+
+    if (!src_mm) {
+        goto done;
+    }
+
+    src_mnt = src_mm->vm_mnt;
+
+    struct mm_region *pos, *n;
+    llist_for_each(pos, n, &src_mm->regions, head)
+    {
+        vmrcpy(dest_mnt, src_mnt, pos);
     }
 
     }
 
+done:;
+    procvm_link_kernel(dest_mnt);
+    
+    dest_mm->vmroot = pte_paddr(pte_sms);
+}
+
+static void
+vmsfree(struct proc_mm* mm)
+{
+    struct leaflet* leaflet;
+    ptr_t vm_mnt;
+    pte_t* ptep_self;
+    
+    vm_mnt    = mm->vm_mnt;
+    ptep_self = mkl0tep(mkptep_va(vm_mnt, VMS_SELF));
+
+    struct mm_region *pos, *n;
+    llist_for_each(pos, n, &mm->regions, head)
+    {
+        vmrfree(vm_mnt, pos);
+    }
+
+    procvm_unlink_kernel();
+
     leaflet = pte_leaflet_aligned(pte_at(ptep_self));
     leaflet_return(leaflet);
 }
     leaflet = pte_leaflet_aligned(pte_at(ptep_self));
     leaflet_return(leaflet);
 }
@@ -251,8 +309,8 @@ procvm_dupvms_mount(struct proc_mm* mm) {
    
     mm->heap = mm_current->heap;
     mm->vm_mnt = VMS_MOUNT_1;
    
     mm->heap = mm_current->heap;
     mm->vm_mnt = VMS_MOUNT_1;
-    mm->vmroot = vmscpy(VMS_MOUNT_1, VMS_SELF, false);
     
     
+    vmscpy(mm, mm_current);  
     region_copy_mm(mm_current, mm);
 }
 
     region_copy_mm(mm_current, mm);
 }
 
@@ -301,7 +359,7 @@ procvm_initvms_mount(struct proc_mm* mm)
     __attach_to_current_vms(mm);
 
     mm->vm_mnt = VMS_MOUNT_1;
     __attach_to_current_vms(mm);
 
     mm->vm_mnt = VMS_MOUNT_1;
-    mm->vmroot = vmscpy(VMS_MOUNT_1, VMS_SELF, true);
+    vmscpy(mm, NULL);
 }
 
 void
 }
 
 void
@@ -314,9 +372,9 @@ procvm_unmount_release(struct proc_mm* mm) {
         region_release(pos);
     }
 
         region_release(pos);
     }
 
-    vfree(mm);
-    vmsfree(vm_mnt);
+    vmsfree(mm);
     vms_unmount(vm_mnt);
     vms_unmount(vm_mnt);
+    vfree(mm);
 
     __detach_from_current_vms(mm);
 }
 
     __detach_from_current_vms(mm);
 }