Parcourir la source

new: 引入vmarea

fslongjin il y a 2 ans
Parent
commit
642fa1def8
5 fichiers modifiés avec 234 ajouts et 129 suppressions
  1. 1 2
      kernel/mm/mm.c
  2. 39 4
      kernel/mm/mm.h
  3. 27 23
      kernel/mm/mmap.c
  4. 80 1
      kernel/mm/vma.c
  5. 87 99
      kernel/process/process.c

+ 1 - 2
kernel/mm/mm.c

@@ -586,8 +586,7 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset)
     {
         for (uint64_t i = old_brk_end_addr; i < end_addr; i += PAGE_2M_SIZE)
         {
-            // kdebug("map [%#018lx]", i);
-            mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, i, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
+            mm_map_vma(current_pcb->mm,i, PAGE_2M_SIZE, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, VM_USER|VM_ACCESS_FLAGS, NULL);
         }
         current_pcb->mm->brk_end = end_addr;
     }

+ 39 - 4
kernel/mm/mm.h

@@ -382,6 +382,7 @@ ul set_page_attr(struct Page *page, ul flags);
 #define VM_SOFTDIRTY (1 << 5)
 #define VM_MAYSHARE (1 << 6) // 该vma可被共享
 #define VM_USER (1 << 7)     // 该vma可被用户态访问
+#define VM_DONTCOPY (1 << 8) // 当fork的时候不拷贝该虚拟内存区域
 
 /* VMA basic access permission flags */
 #define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
@@ -396,6 +397,7 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
 {
     memset(vma, 0, sizeof(struct vm_area_struct));
     vma->vm_mm = mm;
+    vma->vm_prev = vma->vm_next = NULL;
     vma->vm_ops = NULL;
 }
 
@@ -435,6 +437,31 @@ struct vm_area_struct *vm_area_alloc(struct mm_struct *mm);
  */
 void vm_area_free(struct vm_area_struct *vma);
 
+/**
+ * @brief 从链表中删除指定的vma结构体
+ *
+ * @param vma
+ */
+void vm_area_del(struct vm_area_struct *vma);
+
+/**
+ * @brief 查找第一个符合“addr < vm_end”条件的vma
+ * 
+ * @param mm 内存空间分布结构体
+ * @param addr 虚拟地址
+ * @return struct vm_area_struct* 符合条件的vma
+ */
+struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr);
+
+/**
+ * @brief 插入vma
+ *
+ * @param mm
+ * @param vma
+ * @return int
+ */
+int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma);
+
 /**
  * @brief 重新初始化页表的函数
  * 将所有物理页映射到线性地址空间
@@ -509,9 +536,7 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
  * @param paddr 返回的被取消映射的起始物理地址
  * @return int 返回码
  */
-int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct * vma, uint64_t *paddr);
-
-
+int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr);
 
 /**
  * @brief 检测是否为有效的2M页(物理内存页)
@@ -546,4 +571,14 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset);
  *
  * @return struct mm_stat_t 内存信息结构体
  */
-struct mm_stat_t mm_stat();
+struct mm_stat_t mm_stat();
+
+/**
+ * @brief 检测指定地址是否已经被映射
+ *
+ * @param page_table_phys_addr 页表的物理地址
+ * @param virt_addr 要检测的地址
+ * @return true 已经被映射
+ * @return false
+ */
+bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr);

+ 27 - 23
kernel/mm/mmap.c

@@ -78,7 +78,7 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
     uint64_t length_mapped = 0;
 
     // 对user标志位进行校正
-    if (flags & PAGE_U_S)
+    if ((flags & PAGE_U_S) != 0)
         user = true;
     else
         user = false;
@@ -108,14 +108,12 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
 
         uint64_t pdpte_id = (((virt_addr_start + length_mapped) >> PAGE_1G_SHIFT) & 0x1ff);
         uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
-        // kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
 
         // 循环填写二级页表
         for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
         {
             --pgt_num.num_PDPTE;
             uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
-            // kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
 
             // 创建新的三级页表
             if (*pdpte_ptr == 0)
@@ -123,12 +121,10 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
                 ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
                 memset(virt_addr, 0, PAGE_4K_SIZE);
                 set_pdpt(pdpte_ptr, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
-                // kdebug("created new pdt, *pdpte_ptr=%#018lx, virt_addr=%#018lx", *pdpte_ptr, virt_addr);
             }
 
             uint64_t pde_id = (((virt_addr_start + length_mapped) >> PAGE_2M_SHIFT) & 0x1ff);
             uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
-            // kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
 
             // 循环填写三级页表,初始化2M物理页
             for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
@@ -136,7 +132,6 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
                 --pgt_num.num_PDE;
                 // 计算当前2M物理页对应的pdt的页表项的物理地址
                 ul *pde_ptr = pd_ptr + pde_id;
-
                 // ====== 使用4k页 =======
                 if (unlikely(use4k))
                 {
@@ -144,7 +139,6 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
                     if (*pde_ptr == 0)
                     {
                         // 创建四级页表
-                        // kdebug("create PT");
                         uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
                         memset(vaddr, 0, PAGE_4K_SIZE);
                         set_pdt(pde_ptr, mk_pdt(virt_2_phys(vaddr), (user ? PAGE_USER_PDE : PAGE_KERNEL_PDE)));
@@ -156,27 +150,25 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
                     }
 
                     uint64_t pte_id = (((virt_addr_start + length_mapped) >> PAGE_4K_SHIFT) & 0x1ff);
-                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
+                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
 
                     // 循环填写4级页表,初始化4K页
-                    for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
+                    for (; (pgt_num.num_PTE > 0) && pte_id < 512; ++pte_id)
                     {
                         --pgt_num.num_PTE;
                         uint64_t *pte_ptr = pt_ptr + pte_id;
 
                         if (unlikely(*pte_ptr != 0))
-                        {
                             kwarn("pte already exists.");
-                            length_mapped += PAGE_4K_SIZE;
-                        }
-
-                        set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
+                        else
+                            set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
+                        length_mapped += PAGE_4K_SIZE;
                     }
                 }
                 // ======= 使用2M页 ========
                 else
                 {
-                    if (unlikely(*pde_ptr != 0 && user))
+                    if (unlikely((*pde_ptr != 0) && user == true))
                     {
                         // 如果是用户态可访问的页,则释放当前新获取的物理页
                         if (likely((((ul)phys_addr_start + length_mapped) >> PAGE_2M_SHIFT) < mm_total_2M_pages)) // 校验是否为内存中的物理页
@@ -213,7 +205,6 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
     // 计算线性地址对应的pml4页表项的地址
     mm_pgt_entry_num_t pgt_num;
     mm_calculate_entry_num(length, &pgt_num);
-    // kdebug("ent1=%d ent2=%d ent3=%d, ent4=%d", pgt_num.num_PML4E, pgt_num.num_PDPTE, pgt_num.num_PDE, pgt_num.num_PTE);
     // 已取消映射的内存大小
     uint64_t length_unmapped = 0;
 
@@ -272,21 +263,22 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
                 {
                     // 存在4K页
                     uint64_t pte_id = (((virt_addr_start + length_unmapped) >> PAGE_4K_SHIFT) & 0x1ff);
-                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0x1fffUL));
-                    uint64_t *pte_ptr = pt_ptr + pte_id;
-
+                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
                     // 循环处理4K页表
-                    for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id, ++pte_ptr)
+                    for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
                     {
+                        uint64_t *pte_ptr = pt_ptr + pte_id;
                         --pgt_num.num_PTE;
-                        // todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
                         *pte_ptr = 0;
                         length_unmapped += PAGE_4K_SIZE;
                     }
 
                     // 4级页表已经空了,释放页表
                     if (unlikely(mm_check_page_table(pt_ptr)) == 0)
+                    {
+                        *pde_ptr = 0;
                         kfree(pt_ptr);
+                    }
                 }
                 else
                 {
@@ -298,11 +290,17 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
 
             // 3级页表已经空了,释放页表
             if (unlikely(mm_check_page_table(pd_ptr)) == 0)
+            {
+                *pdpte_ptr = 0;
                 kfree(pd_ptr);
+            }
         }
         // 2级页表已经空了,释放页表
         if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
+        {
+            *pml4e_ptr = 0;
             kfree(pdpt_ptr);
+        }
     }
     flush_tlb();
 }
@@ -330,10 +328,15 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
     vma->vm_end = vaddr + length;
 
     // 将VMA加入链表
-    __vma_link_list(mm, vma, mm->vmas);
+    retval = vma_insert(mm, vma);
+    if (retval == -EEXIST) // 之前已经存在了相同的vma,直接返回
+    {
+        kfree(vma);
+        return -EEXIST;
+    }
     uint64_t len_4k = length % PAGE_2M_SIZE;
     uint64_t len_2m = length - len_4k;
-
+    // kdebug("len_2m=%ld", len_2m);
     // ==== 将地址映射到页表
     /*
         todo: 限制页面的读写权限
@@ -371,6 +374,7 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
     flush_tlb();
     return 0;
 failed:;
+    kdebug("failed.");
     __vma_unlink_list(mm, vma);
     vm_area_free(vma);
     return retval;

+ 80 - 1
kernel/mm/vma.c

@@ -16,6 +16,18 @@ struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
     return vma;
 }
 
+/**
+ * @brief 从链表中删除指定的vma结构体
+ *
+ * @param vma
+ */
+void vm_area_del(struct vm_area_struct *vma)
+{
+    if (vma->vm_mm == NULL)
+        return;
+    __vma_unlink_list(vma->vm_mm, vma);
+}
+
 /**
  * @brief 释放vma结构体
  *
@@ -71,7 +83,74 @@ void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma)
         prev->vm_next = next;
     else // 当前vma是链表中的第一个vma
         mm->vmas = next;
-    
+
     if (next)
         next->vm_prev = prev;
+}
+
+/**
+ * @brief 查找第一个符合“addr < vm_end”条件的vma
+ *
+ * @param mm 内存空间分布结构体
+ * @param addr 虚拟地址
+ * @return struct vm_area_struct* 符合条件的vma
+ */
+struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr)
+{
+    struct vm_area_struct *vma = mm->vmas;
+    struct vm_area_struct *result = NULL;
+    while (vma != NULL)
+    {
+        if (vma->vm_end > addr)
+        {
+            result = vma;
+            break;
+        }
+        vma = vma->vm_next;
+    }
+    return result;
+}
+
+/**
+ * @brief 插入vma
+ *
+ * @param mm
+ * @param vma
+ * @return int
+ */
+int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
+{
+
+    struct vm_area_struct *prev;
+    prev = vma_find(mm, vma->vm_start);
+    if (prev && prev->vm_start == vma->vm_start && prev->vm_end == vma->vm_end)
+    {
+        // 已经存在了相同的vma
+        return -EEXIST;
+    }
+    else if (prev && (prev->vm_start == vma->vm_start || prev->vm_end == vma->vm_end)) // 暂时不支持扩展vma
+    {
+        kwarn("Not support: expand vma");
+        return -ENOTSUP;
+    }
+
+    prev = vma_find(mm, vma->vm_end);
+    if (prev)
+        prev = prev->vm_prev;
+    if (prev == NULL) // 要将当前vma插入到链表的尾部
+    {
+        struct vm_area_struct * ptr = mm->vmas;
+        while(ptr)
+        {
+            if(ptr->vm_next)
+                ptr = ptr->vm_next;
+            else
+            {
+                prev = ptr;
+                break;
+            }
+        }
+    }
+    __vma_link_list(mm, vma, prev);
+    return 0;
 }

+ 87 - 99
kernel/process/process.c

@@ -252,18 +252,39 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
         pos = phdr->p_offset;
 
         uint64_t virt_base = phdr->p_vaddr;
-        // kdebug("virt_base = %#018lx, &memory_management_struct=%#018lx", virt_base, &memory_management_struct);
 
         while (remain_mem_size > 0)
         {
+            // kdebug("loading...");
+            int64_t map_size = 0;
 
-            // todo: 改用slab分配4K大小内存块并映射到4K页
-            if (!mm_check_mapped((uint64_t)current_pcb->mm->pgd, virt_base)) // 未映射,则新增物理页
+            if (remain_mem_size > PAGE_2M_SIZE / 2)
             {
-                mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, virt_base, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
 
+                uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
+                int ret = mm_map_vma(current_pcb->mm, virt_base, PAGE_2M_SIZE, pa, VM_USER | VM_ACCESS_FLAGS, NULL);
+                // 防止内存泄露
+                if (ret == -EEXIST)
+                    free_pages(Phy_to_2M_Page(pa), 1);
                 memset((void *)virt_base, 0, PAGE_2M_SIZE);
+                map_size = PAGE_2M_SIZE;
+            }
+            else
+            {
+                // todo: 使用4K、8K、32K大小内存块混合进行分配,提高空间利用率(减少了bmp的大小)
+                map_size = ALIGN(remain_mem_size, PAGE_4K_SIZE);
+                // 循环分配4K大小内存块
+                for (uint64_t off = 0; off < map_size; off += PAGE_4K_SIZE)
+                {
+                    uint64_t paddr = virt_2_phys((uint64_t)kmalloc(PAGE_4K_SIZE, 0));
+
+                    int val = mm_map_vma(current_pcb->mm, virt_base + off, PAGE_4K_SIZE, paddr, VM_USER | VM_ACCESS_FLAGS, NULL);
+                    if (val == -EEXIST)
+                        kfree(phys_2_virt(paddr));
+                    memset((void *)(virt_base + off), 0, PAGE_4K_SIZE);
+                }
             }
+
             pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
             int64_t val = 0;
             if (remain_file_size != 0)
@@ -275,9 +296,9 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
             if (val < 0)
                 goto load_elf_failed;
 
-            remain_mem_size -= PAGE_2M_SIZE;
+            remain_mem_size -= map_size;
             remain_file_size -= val;
-            virt_base += PAGE_2M_SIZE;
+            virt_base += map_size;
         }
     }
 
@@ -285,9 +306,12 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
     regs->rsp = current_pcb->mm->stack_start;
     regs->rbp = current_pcb->mm->stack_start;
 
-    uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
-
-    mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, current_pcb->mm->stack_start - PAGE_2M_SIZE, pa, PAGE_2M_SIZE, PAGE_USER_PAGE, true, true, false);
+    {
+        uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
+        int val = mm_map_vma(current_pcb->mm, current_pcb->mm->stack_start - PAGE_2M_SIZE, PAGE_2M_SIZE, pa, VM_USER | VM_ACCESS_FLAGS, NULL);
+        if (val == -EEXIST)
+            free_pages(Phy_to_2M_Page(pa), 1);
+    }
 
     // 清空栈空间
     memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE);
@@ -870,7 +894,7 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
     memset(new_mms, 0, sizeof(struct mm_struct));
 
     memcpy(new_mms, current_pcb->mm, sizeof(struct mm_struct));
-
+    new_mms->vmas = NULL;
     pcb->mm = new_mms;
 
     // 分配顶层页表, 并设置顶层页表的物理地址
@@ -884,55 +908,40 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
     uint64_t *current_pgd = (uint64_t *)phys_2_virt(current_pcb->mm->pgd);
 
     uint64_t *new_pml4t = (uint64_t *)phys_2_virt(new_mms->pgd);
-    // 迭代地拷贝用户空间
-    for (int i = 0; i <= 255; ++i)
+
+    // 拷贝用户空间的vma
+    struct vm_area_struct *vma = current_pcb->mm->vmas;
+    while (vma != NULL)
     {
-        // 当前页表项为空
-        if ((*(uint64_t *)(current_pgd + i)) == 0)
+        if (vma->vm_end > USER_MAX_LINEAR_ADDR)
+        {
+            vma = vma->vm_next;
             continue;
+        }
 
-        // 分配新的二级页表
-        uint64_t *new_pdpt = (uint64_t *)kmalloc(PAGE_4K_SIZE, 0);
-        memset(new_pdpt, 0, PAGE_4K_SIZE);
-
-        // 在新的一级页表中设置新的二级页表表项
-        set_pml4t(new_pml4t + i, mk_pml4t(virt_2_phys(new_pdpt), (*(current_pgd + i)) & 0xfffUL));
-
-        uint64_t *current_pdpt = (uint64_t *)phys_2_virt((*(uint64_t *)(current_pgd + i)) & (~0xfffUL));
-        // kdebug("current_pdpt=%#018lx, current_pid=%d", current_pdpt, current_pcb->pid);
-        for (int j = 0; j < 512; ++j)
+        int64_t vma_size = vma->vm_end - vma->vm_start;
+        // kdebug("vma_size=%ld, vm_start=%#018lx", vma_size, vma->vm_start);
+        if (vma_size > PAGE_2M_SIZE / 2)
         {
-            if (*(current_pdpt + j) == 0)
-                continue;
-
-            // 分配新的三级页表
-            uint64_t *new_pdt = (uint64_t *)kmalloc(PAGE_4K_SIZE, 0);
-            memset(new_pdt, 0, PAGE_4K_SIZE);
-            // 在二级页表中填写新的三级页表
-            // 在新的二级页表中设置三级页表的表项
-            set_pdpt((uint64_t *)(new_pdpt + j), mk_pdpt(virt_2_phys(new_pdt), (*(current_pdpt + j)) & 0xfffUL));
-
-            uint64_t *current_pdt = (uint64_t *)phys_2_virt((*(current_pdpt + j)) & (~0xfffUL));
-            // kdebug("current_pdt=%#018lx", current_pdt);
-
-            // 循环拷贝三级页表
-            for (int k = 0; k < 512; ++k)
+            int page_to_alloc = (PAGE_2M_ALIGN(vma_size)) >> PAGE_2M_SHIFT;
+            for (int i = 0; i < page_to_alloc; ++i)
             {
-
-                if (*(current_pdt + k) == 0)
-                    continue;
-
-                // 获取新的物理页
                 uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
 
-                memset((void *)phys_2_virt(pa), 0, PAGE_2M_SIZE);
-
-                set_pdt((uint64_t *)(new_pdt + k), mk_pdt(pa, *(current_pdt + k) & 0x1ffUL));
-
-                // 拷贝数据
-                memcpy(phys_2_virt(pa), phys_2_virt((*(current_pdt + k)) & (~0x1ffUL)), PAGE_2M_SIZE);
+                mm_map_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, pa, vma->vm_flags, vma->vm_ops);
+                // kdebug("phys_2_virt(pa)=%#018lx, vaddr=%#018lx", phys_2_virt(pa), vma->vm_start + i * PAGE_2M_SIZE);
+                memcpy((void *)phys_2_virt(pa), (void *)(vma->vm_start + i * PAGE_2M_SIZE), (vma_size >= PAGE_2M_SIZE) ? PAGE_2M_SIZE : vma_size);
+                vma_size -= PAGE_2M_SIZE;
             }
         }
+        else
+        {
+            uint64_t map_size = PAGE_4K_ALIGN(vma_size);
+            uint64_t va = (uint64_t)kmalloc(map_size, 0);
+            mm_map_vma(new_mms, vma->vm_start, map_size, virt_2_phys(va), vma->vm_flags, vma->vm_ops);
+            memcpy((void *)va, (void *)vma->vm_start, vma_size);
+        }
+        vma = vma->vm_next;
     }
 
     return retval;
@@ -958,64 +967,43 @@ uint64_t process_exit_mm(struct process_control_block *pcb)
         kdebug("pcb->mm->pgd==NULL");
         return 0;
     }
-    // 获取顶层页表
+
+    // // 获取顶层页表
     pml4t_t *current_pgd = (pml4t_t *)phys_2_virt(pcb->mm->pgd);
 
-    // 迭代地释放用户空间
-    for (int i = 0; i <= 255; ++i)
+    // 循环释放VMA中的内存
+    struct vm_area_struct *vma = pcb->mm->vmas;
+    while (vma != NULL)
     {
-        // 当前页表项为空
-        if ((current_pgd + i)->pml4t == 0)
-            continue;
+        struct vm_area_struct *cur_vma = vma;
+        vma = cur_vma->vm_next;
 
-        // 二级页表entry
-        pdpt_t *current_pdpt = (pdpt_t *)phys_2_virt((current_pgd + i)->pml4t & (~0xfffUL));
-        // 遍历二级页表
-        for (int j = 0; j < 512; ++j)
-        {
-            if ((current_pdpt + j)->pdpt == 0)
-                continue;
-
-            // 三级页表的entry
-            pdt_t *current_pdt = (pdt_t *)phys_2_virt((current_pdpt + j)->pdpt & (~0xfffUL));
+        uint64_t pa;
+        mm_umap_vma(pcb->mm, cur_vma, &pa);
+        uint64_t size = (cur_vma->vm_end - cur_vma->vm_start);
 
-            // 释放三级页表的内存页
-            for (int k = 0; k < 512; ++k)
-            {
-                if ((current_pdt + k)->pdt == 0)
-                    continue;
-                // 存在4级页表
-                if (unlikely(((current_pdt + k)->pdt & (1 << 7)) == 0))
-                {
-                    // 存在4K页
-                    uint64_t *pt_ptr = (uint64_t *)phys_2_virt((current_pdt + k)->pdt & (~0x1fffUL));
-                    uint64_t *pte_ptr = pt_ptr;
-
-                    // 循环处理4K页表, 直接清空
-                    // todo: 当支持使用slab分配4K内存作为进程的4K页之后,在这里需要释放这些4K对象
-                    for (int16_t g = 0; g < 512; ++g, ++pte_ptr)
-                        *pte_ptr = 0;
-
-                    // 4级页表已经空了,释放页表
-                    if (unlikely(mm_check_page_table(pt_ptr)) == 0)
-                        kfree(pt_ptr);
-                }
-                else
-                {
-                    // 释放内存页
-                    if (mm_is_2M_page((current_pdt + k)->pdt & (~0x1fffUL))) // 校验是否为内存中的物理页
-                        free_pages(Phy_to_2M_Page((current_pdt + k)->pdt & (~0x1fffUL)), 1);
-                }
-            }
-            // 释放三级页表
-            kfree(current_pdt);
+        // 释放内存
+        switch (size)
+        {
+        case PAGE_2M_SIZE:
+            free_pages(Phy_to_2M_Page(pa), 1);
+            break;
+        case PAGE_4K_SIZE:
+            kfree(phys_2_virt(pa));
+            break;
+        default:
+            break;
         }
-        // 释放二级页表
-        kfree(current_pdpt);
+        vm_area_del(cur_vma);
+        kfree(cur_vma);
     }
+
     // 释放顶层页表
     kfree(current_pgd);
-
+    if (unlikely(pcb->mm->vmas != NULL))
+    {
+        kwarn("pcb.mm.vmas!=NULL");
+    }
     // 释放内存空间分布结构体
     kfree(pcb->mm);