diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index c86844f8..c4466a87 100644 --- a/kernel/mm/mm.c +++ b/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; } diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index ca64e19f..9291ea6b 100644 --- a/kernel/mm/mm.h +++ b/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(); \ No newline at end of file +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); \ No newline at end of file diff --git a/kernel/mm/mmap.c b/kernel/mm/mmap.c index b2f6649b..d8770c8b 100644 --- a/kernel/mm/mmap.c +++ b/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; diff --git a/kernel/mm/vma.c b/kernel/mm/vma.c index 0e264532..72578144 100644 --- a/kernel/mm/vma.c +++ b/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; } \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c index 2fbab92f..7e93fd71 100644 --- a/kernel/process/process.c +++ b/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) - 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) + if (vma->vm_end > USER_MAX_LINEAR_ADDR) { - if (*(current_pdpt + j) == 0) - continue; + vma = vma->vm_next; + 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) + 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) + { + 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) + uint64_t pa; + mm_umap_vma(pcb->mm, cur_vma, &pa); + uint64_t size = (cur_vma->vm_end - cur_vma->vm_start); + + // 释放内存 + switch (size) { - if ((current_pdpt + j)->pdpt == 0) - continue; - - // 三级页表的entry - pdt_t *current_pdt = (pdt_t *)phys_2_virt((current_pdpt + j)->pdpt & (~0xfffUL)); - - // 释放三级页表的内存页 - 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); + 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);