X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/34f6af4f61e0eec9c96113e07f140b609b4113c8..669e8fc63dd1aa7fe4c830b1d40371a1ab47fc4f:/lunaix-os/kernel/mm/procvm.c?ds=inline diff --git a/lunaix-os/kernel/mm/procvm.c b/lunaix-os/kernel/mm/procvm.c index 31d9f3f..8081971 100644 --- a/lunaix-os/kernel/mm/procvm.c +++ b/lunaix-os/kernel/mm/procvm.c @@ -4,11 +4,25 @@ #include #include #include +#include #include #include +#define alloc_pagetable_trace(ptep, pte, ord, level) \ + ({ \ + alloc_kpage_at(ptep, pte, ord); \ + }) + +#define free_pagetable_trace(ptep, pte, level) \ + ({ \ + struct leaflet* leaflet = pte_leaflet_aligned(pte); \ + assert(leaflet_order(leaflet) == 0); \ + leaflet_return(leaflet); \ + set_pte(ptep, null_pte); \ + }) + struct proc_mm* procvm_create(struct proc_info* proc) { struct proc_mm* mm = vzalloc(sizeof(struct proc_mm)); @@ -46,7 +60,7 @@ __descend(ptr_t dest_mnt, ptr_t src_mnt, ptr_t va, bool alloc) } if (alloc && pte_isnull(pte_at(dest))) { - alloc_kpage_at(dest, pte, 0); + alloc_pagetable_trace(dest, pte, 0, i); } i++; @@ -77,7 +91,7 @@ copy_leaf(pte_t* dest, pte_t* src, pte_t pte, int level) static inline void copy_root(pte_t* dest, pte_t* src, pte_t pte, int level) { - alloc_kpage_at(dest, pte, 0); + alloc_pagetable_trace(dest, pte, 0, level); } static void @@ -143,7 +157,7 @@ vmrfree(ptr_t vm_mnt, struct mm_region* region) src = mkptep_va(vm_mnt, region->start); end = mkptep_va(vm_mnt, region->end); - level = __descend(0, vm_mnt, loc, false); + level = __descend(vm_mnt, vm_mnt, loc, false); while (src < end) { @@ -161,6 +175,8 @@ vmrfree(ptr_t vm_mnt, struct mm_region* region) continue; } + set_pte(src, null_pte); + if (pte_isloaded(pte)) { leaflet = pte_leaflet_aligned(pte); leaflet_return(leaflet); @@ -171,10 +187,7 @@ vmrfree(ptr_t vm_mnt, struct mm_region* region) cont: 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); + free_pagetable_trace(src, pte_at(src), level); level--; } @@ -232,7 +245,7 @@ vmscpy(struct proc_mm* dest_mm, struct proc_mm* src_mm) 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); + pte_sms = alloc_pagetable_trace(ptep_ssm, pte_sms, 0, 0); set_pte(&ptep_smx[VMS_SELF_L0TI], pte_sms); tlb_flush_kernel((ptr_t)dest_mnt); @@ -255,26 +268,60 @@ done:; dest_mm->vmroot = pte_paddr(pte_sms); } +static void +__purge_vms_residual(struct proc_mm* mm, int level, ptr_t va) +{ + pte_t *ptep, pte; + ptr_t _va; + + if (level >= MAX_LEVEL) { + return; + } + + ptep = mklntep_va(level, mm->vm_mnt, va); + + for (unsigned i = 0; i < LEVEL_SIZE; i++, ptep++) + { + pte = pte_at(ptep); + if (pte_isnull(pte) || !pte_isloaded(pte)) { + continue; + } + + if (lntep_implie_vmnts(ptep, lnt_page_size(level))) { + continue; + } + + _va = va + (i * lnt_page_size(level)); + __purge_vms_residual(mm, level + 1, _va); + + set_pte(ptep, null_pte); + leaflet_return(pte_leaflet_aligned(pte)); + } +} + static void vmsfree(struct proc_mm* mm) { struct leaflet* leaflet; + struct mm_region *pos, *n; ptr_t vm_mnt; pte_t* ptep_self; vm_mnt = mm->vm_mnt; - ptep_self = mkl0tep(mkptep_va(vm_mnt, VMS_SELF)); + ptep_self = mkl0tep_va(vm_mnt, VMS_SELF); - struct mm_region *pos, *n; + // first pass: free region mappings llist_for_each(pos, n, &mm->regions, head) { vmrfree(vm_mnt, pos); } - procvm_unlink_kernel(); + procvm_unlink_kernel(vm_mnt); + + // free up all allocated tables on intermediate levels + __purge_vms_residual(mm, 0, 0); - leaflet = pte_leaflet_aligned(pte_at(ptep_self)); - leaflet_return(leaflet); + free_pagetable_trace(ptep_self, pte_at(ptep_self), 0); } static inline void @@ -297,6 +344,11 @@ __detach_from_current_vms(struct proc_mm* guest_mm) } } +void +procvm_prune_vmr(ptr_t vm_mnt, struct mm_region* region) +{ + vmrfree(vm_mnt, region); +} void procvm_dupvms_mount(struct proc_mm* mm) { @@ -366,13 +418,19 @@ void procvm_unmount_release(struct proc_mm* mm) { ptr_t vm_mnt = mm->vm_mnt; struct mm_region *pos, *n; + llist_for_each(pos, n, &mm->regions, head) { mem_sync_pages(vm_mnt, pos, pos->start, pos->end - pos->start, 0); - region_release(pos); } vmsfree(mm); + + llist_for_each(pos, n, &mm->regions, head) + { + region_release(pos); + } + vms_unmount(vm_mnt); vfree(mm);