Boot framework rework (#45)
[lunaix-os.git] / lunaix-os / kernel / mm / procvm.c
index 7b07560efec366512b52e98bae663ef9df1e2073..119efde25b389eae2750218665bd2a9d3428bb1c 100644 (file)
@@ -38,14 +38,50 @@ vmscpy(ptr_t dest_mnt, ptr_t src_mnt, bool only_kernel)
     pte_t* ptep_kernel  = mkl0tep(mkptep_va(src_mnt, KERNEL_RESIDENT));
 
     // Build the self-reference on dest vms
-    pte_t* ptep_sms     = mkptep_va(VMS_SELF, (ptr_t)ptep_dest);
-    pte_t* ptep_ssm     = mkptep_va(VMS_SELF, (ptr_t)ptep_sms);
-    pte_t  pte_sms      = mkpte_prot(KERNEL_DATA);
+
+    /* 
+     *        -- 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);
 
     pte_sms = alloc_kpage_at(ptep_ssm, pte_sms, 0);
     set_pte(ptep_sms, pte_sms);    
     
     tlb_flush_kernel((ptr_t)dest_mnt);
+    tlb_flush_kernel((ptr_t)ptep_sms);
 
     if (only_kernel) {
         ptep = ptep_kernel;
@@ -89,7 +125,7 @@ vmscpy(ptr_t dest_mnt, ptr_t src_mnt, bool only_kernel)
         }
         
     cont:
-        if (ptep_vfn(ptep) == MAX_PTEN - 1) {
+        while (ptep_vfn(ptep) == MAX_PTEN - 1) {
             assert(level > 0);
             ptep = ptep_step_out(ptep);
             ptep_dest = ptep_step_out(ptep_dest);
@@ -105,8 +141,14 @@ vmscpy(ptr_t dest_mnt, ptr_t src_mnt, bool only_kernel)
     assert(ptep_dest == ptepd_kernel);
     
     // Carry over the kernel (exclude last two entry)
-    while (ptep_vfn(ptep) < MAX_PTEN - 2) {
+    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,
@@ -117,12 +159,13 @@ vmscpy(ptr_t dest_mnt, ptr_t src_mnt, bool only_kernel)
 
         set_pte(ptep_dest, pte);
         leaflet_borrow(leaflet);
-        
+    
+    _cont:
         ptep++;
         ptep_dest++;
     }
 
-    return pte_paddr(*(ptep_dest + 1));
+    return pte_paddr(pte_sms);
 }
 
 static void
@@ -130,6 +173,7 @@ vmsfree(ptr_t vm_mnt)
 {
     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;
@@ -158,7 +202,7 @@ vmsfree(ptr_t vm_mnt)
         }
 
     cont:
-        if (ptep_vfn(ptep) == MAX_PTEN - 1) {
+        while (ptep_vfn(ptep) == MAX_PTEN - 1) {
             ptep = ptep_step_out(ptep);
             leaflet = pte_leaflet_aligned(pte_at(ptep));
             
@@ -171,7 +215,7 @@ vmsfree(ptr_t vm_mnt)
         ptep++;
     }
 
-    leaflet = pte_leaflet_aligned(ptep_head[MAX_PTEN - 1]);
+    leaflet = pte_leaflet_aligned(pte_at(ptep_self));
     leaflet_return(leaflet);
 }
 
@@ -215,6 +259,12 @@ procvm_dupvms_mount(struct proc_mm* mm) {
 void
 procvm_mount(struct proc_mm* mm)
 {
+    // if current mm is already active
+    if (active_vms(mm->vm_mnt)) {
+        return;
+    }
+    
+    // we are double mounting
     assert(!mm->vm_mnt);
     assert(mm->vmroot);
 
@@ -228,9 +278,13 @@ procvm_mount(struct proc_mm* mm)
 void
 procvm_unmount(struct proc_mm* mm)
 {
+    if (active_vms(mm->vm_mnt)) {
+        return;
+    }
+    
     assert(mm->vm_mnt);
-
     vms_unmount(VMS_MOUNT_1);
+    
     struct proc_mm* mm_current = vmspace(__current);
     if (mm_current) {
         mm_current->guest_mm = NULL;
@@ -271,7 +325,6 @@ void
 procvm_mount_self(struct proc_mm* mm) 
 {
     assert(!mm->vm_mnt);
-    assert(!mm->guest_mm);
 
     mm->vm_mnt = VMS_SELF;
 }
@@ -279,7 +332,7 @@ procvm_mount_self(struct proc_mm* mm)
 void
 procvm_unmount_self(struct proc_mm* mm)
 {
-    assert(mm->vm_mnt == VMS_SELF);
+    assert(active_vms(mm->vm_mnt));
 
     mm->vm_mnt = 0;
 }
@@ -291,7 +344,7 @@ procvm_enter_remote(struct remote_vmctx* rvmctx, struct proc_mm* mm,
     ptr_t vm_mnt = mm->vm_mnt;
     assert(vm_mnt);
     
-    pfn_t size_pn = pfn(size + MEM_PAGE);
+    pfn_t size_pn = pfn(size + PAGE_SIZE);
     assert(size_pn < REMOTEVM_MAX_PAGES);
 
     struct mm_region* region = region_get(&mm->regions, remote_base);
@@ -306,11 +359,13 @@ procvm_enter_remote(struct remote_vmctx* rvmctx, struct proc_mm* mm,
 
     pte_t* rptep = mkptep_va(vm_mnt, remote_base);
     pte_t* lptep = mkptep_va(VMS_SELF, rvmctx->local_mnt);
-    unsigned int pattr = region_pteprot(region);
+
+    pte_t pte, rpte = null_pte;
+    rpte = region_tweakpte(region, rpte);
 
     for (size_t i = 0; i < size_pn; i++)
     {
-        pte_t pte = vmm_tryptep(rptep, PAGE_SIZE);
+        pte = vmm_tryptep(rptep, PAGE_SIZE);
         if (pte_isloaded(pte)) {
             set_pte(lptep, pte);
             continue;
@@ -318,7 +373,7 @@ procvm_enter_remote(struct remote_vmctx* rvmctx, struct proc_mm* mm,
 
         ptr_t pa = ppage_addr(pmm_alloc_normal(0));
         set_pte(lptep, mkpte(pa, KERNEL_DATA));
-        set_pte(rptep, mkpte(pa, pattr));
+        set_pte(rptep, pte_setpaddr(rpte, pa));
     }
 
     return vm_mnt;