From 0223232f3fb54645d72fa28e93f4649c818f4a3a Mon Sep 17 00:00:00 2001 From: fslongjin Date: Sat, 20 Aug 2022 01:05:15 +0800 Subject: [PATCH] =?UTF-8?q?new:=20=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BA=86mmio=E5=9C=B0=E5=9D=80=E7=A9=BA=E9=97=B4=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=86=E9=85=8D=EF=BC=88=E6=9C=AA=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bugfix: mmio虚拟地址分配的bug --- .vscode/settings.json | 3 +- docs/kernel/core_api/mm-api.md | 2 +- kernel/driver/usb/xhci/xhci.c | 2 +- kernel/mm/internal.h | 12 +++- kernel/mm/mm.c | 18 +++++ kernel/mm/mm.h | 26 ++++++- kernel/mm/mmap.c | 121 ++++++++++++++++++++++++++++++--- kernel/mm/mmio-buddy.c | 24 ++----- kernel/mm/mmio-buddy.h | 30 +++++++- kernel/mm/mmio.c | 94 +++++++++++++++++++++++-- kernel/mm/mmio.h | 7 +- kernel/mm/vma.c | 18 +++-- kernel/process/process.c | 14 ++-- kernel/process/process.h | 2 +- 14 files changed, 317 insertions(+), 56 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index eb07d92f..f671c0ea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -127,7 +127,8 @@ "vfs.h": "c", "current.h": "c", "proc-types.h": "c", - "traceback.h": "c" + "traceback.h": "c", + "bitcount.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "" diff --git a/docs/kernel/core_api/mm-api.md b/docs/kernel/core_api/mm-api.md index 10328e90..49fb13be 100644 --- a/docs/kernel/core_api/mm-api.md +++ b/docs/kernel/core_api/mm-api.md @@ -222,7 +222,7 @@ DragonOS支持对物理页的直接操作   要取消映射的地址空间的长度 -### `mm_unmap(virt_addr, length)` +### `mm_unmap_addr(virt_addr, length)` #### 描述 diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index 0411ebc4..92346644 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -983,7 +983,7 @@ failed_free_dyn:; // 释放动态申请的内存 failed:; io_mfence(); // 取消地址映射 - mm_unmap(xhci_hc[cid].vbase, 65536); + mm_unmap_addr(xhci_hc[cid].vbase, 65536); io_mfence(); // 清空数组 memset((void *)&xhci_hc[cid], 0, sizeof(struct xhci_host_controller_t)); diff --git a/kernel/mm/internal.h b/kernel/mm/internal.h index 67b3f9e6..1b97e77a 100644 --- a/kernel/mm/internal.h +++ b/kernel/mm/internal.h @@ -57,8 +57,16 @@ int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma); /** * @brief 从anon_vma的管理范围中删除指定的vma - * (在进入这个函数之前,应该要加锁) + * (在进入这个函数之前,应该要对anon_vma加锁) * @param vma 将要取消对应的anon_vma管理的vma结构体 * @return int 返回码 */ -int __anon_vma_del(struct vm_area_struct *vma); \ No newline at end of file +int __anon_vma_del(struct vm_area_struct *vma); + +/** + * @brief 创建mmio对应的页结构体 + * + * @param paddr 物理地址 + * @return struct Page* 创建成功的page + */ +struct Page* __create_mmio_page_struct(uint64_t paddr); \ No newline at end of file diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 298cf8c1..2a2c6075 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -1,5 +1,6 @@ #include "mm.h" #include "mm-types.h" +#include "mmio.h" #include "slab.h" #include #include @@ -228,6 +229,7 @@ void mm_init() // 初始化slab内存池 slab_init(); page_table_init(); + mmio_init(); } /** @@ -620,3 +622,19 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset) } return end_addr; } + +/** + * @brief 创建mmio对应的页结构体 + * + * @param paddr 物理地址 + * @return struct Page* 创建成功的page + */ +struct Page *__create_mmio_page_struct(uint64_t paddr) +{ + struct Page *p = (struct Page *)kzalloc(sizeof(struct Page), 0); + if (p == NULL) + return NULL; + p->addr_phys = paddr; + page_init(p, PAGE_DEVICE); + return p; +} \ No newline at end of file diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index 9656fa5f..4c6ab3a9 100644 --- a/kernel/mm/mm.h +++ b/kernel/mm/mm.h @@ -441,7 +441,7 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta * @param virt_addr 虚拟地址 * @param length 地址长度 */ -#define mm_unmap(virt_addr, length) ({ \ +#define mm_unmap_addr(virt_addr, length) ({ \ mm_unmap_proc_table((uint64_t)get_CR3(), true, virt_addr, length); \ }) @@ -467,6 +467,17 @@ int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flag */ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr); +/** + * @brief 在页表中映射物理地址到指定的虚拟地址(需要页表中已存在对应的vma) + * + * @param mm 内存管理结构体 + * @param vaddr 虚拟地址 + * @param length 长度(字节) + * @param paddr 物理地址 + * @return int 返回码 + */ +int mm_map(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr); + /** * @brief 在页表中取消指定的vma的映射 * @@ -475,7 +486,18 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr); * @param paddr 返回的被取消映射的起始物理地址 * @return int 返回码 */ -int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr); +int mm_unmap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr); + +/** + * @brief 解除一段虚拟地址的映射(这些地址必须在vma中存在) + * + * @param mm 内存空间结构体 + * @param vaddr 起始地址 + * @param length 结束地址 + * @param destroy 是否释放vma结构体 + * @return int 错误码 + */ +int mm_unmap(struct mm_struct *mm, uint64_t vaddr, uint64_t length, bool destroy); /** * @brief 检测是否为有效的2M页(物理内存页) diff --git a/kernel/mm/mmap.c b/kernel/mm/mmap.c index 64fa0f30..cd4b897a 100644 --- a/kernel/mm/mmap.c +++ b/kernel/mm/mmap.c @@ -326,7 +326,6 @@ int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flag vma->vm_flags = vm_flags; vma->vm_start = vaddr; vma->vm_end = vaddr + length; - // 将VMA加入mm的链表 retval = vma_insert(mm, vma); if (retval == -EEXIST) // 之前已经存在了相同的vma,直接返回 @@ -335,7 +334,8 @@ int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flag kfree(vma); return -EEXIST; } - *res_vma = vma; + if (res_vma != NULL) + *res_vma = vma; return 0; } @@ -350,7 +350,12 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr) { int retval = 0; // 获取物理地址对应的页面 - struct Page *pg = Phy_to_2M_Page(paddr); + struct Page *pg; + if (vma->vm_flags & VM_IO) // 对于mmio的内存,创建新的page结构体 + pg = __create_mmio_page_struct(paddr); + else + pg = Phy_to_2M_Page(paddr); + if (unlikely(pg->anon_vma == NULL)) // 若页面不存在anon_vma,则为页面创建anon_vma { spin_lock(&pg->op_lock); @@ -400,8 +405,13 @@ int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr) if (unlikely(retval != 0)) goto failed; } - // 计算当前vma的起始地址在对应的物理页中的偏移量 - vma->page_offset = paddr - (paddr & PAGE_2M_MASK); + + if (vma->vm_flags & VM_IO) + vma->page_offset = 0; + else + { // 计算当前vma的起始地址在对应的物理页中的偏移量 + vma->page_offset = paddr - (paddr & PAGE_2M_MASK); + } flush_tlb(); return 0; failed:; @@ -409,6 +419,46 @@ failed:; return retval; } +/** + * @brief 在页表中映射物理地址到指定的虚拟地址(需要页表中已存在对应的vma) + * + * @param mm 内存管理结构体 + * @param vaddr 虚拟地址 + * @param length 长度(字节) + * @param paddr 物理地址 + * @return int 返回码 + */ +int mm_map(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr) +{ + int retval = 0; + for (uint64_t mapped = 0; mapped < length;) + { + + struct vm_area_struct *vma = vma_find(mm, vaddr + mapped); + if (unlikely(vma == NULL)) + { + kerror("Map addr failed: vma not found. At address: %#018lx, pid=%ld", vaddr + mapped, current_pcb->pid); + return -EINVAL; + } + + if (unlikely(vma->vm_start != (vaddr + mapped))) + { + kerror("Map addr failed: addr_start is not equal to current: %#018lx.", vaddr + mapped); + return -EINVAL; + } + + retval = mm_map_vma(vma, paddr + mapped); + if (unlikely(retval != 0)) + goto failed; + + mapped += vma->vm_end - vma->vm_start; + } + return 0; +failed:; + kerror("Map addr failed."); + return retval; +} + /** * @brief 在页表中取消指定的vma的映射 * @@ -417,15 +467,70 @@ failed:; * @param paddr 返回的被取消映射的起始物理地址 * @return int 返回码 */ -int mm_umap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr) +int mm_unmap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr) { // 确保vma对应的mm与指定的mm相一致 if (unlikely(vma->vm_mm != mm)) return -EINVAL; - + struct anon_vma_t *anon = vma->anon_vma; if (paddr != NULL) *paddr = __mm_get_paddr(mm, vma->vm_start); + if (anon == NULL) + kwarn("anon is NULL"); + semaphore_down(&anon->sem); mm_unmap_proc_table((uint64_t)mm->pgd, true, vma->vm_start, vma->vm_end - vma->vm_start); + __anon_vma_del(vma); + /** todo: 这里应该会存在bug,应修复。 + * 若anon_vma的等待队列上有其他的进程,由于anon_vma被释放 + * 这些在等待队列上的进程将无法被唤醒。 + */ + list_init(&vma->anon_vma_list); + + semaphore_up(&anon->sem); + return 0; -} \ No newline at end of file +} + +/** + * @brief 解除一段虚拟地址的映射(这些地址必须在vma中存在) + * + * @param mm 内存空间结构体 + * @param vaddr 起始地址 + * @param length 结束地址 + * @param destroy 是否释放vma结构体 + * @return int 错误码 + */ +int mm_unmap(struct mm_struct *mm, uint64_t vaddr, uint64_t length, bool destroy) +{ + int retval = 0; + for (uint64_t unmapped = 0; unmapped < length;) + { + struct vm_area_struct *vma = vma_find(mm, vaddr + unmapped); + if (unlikely(vma == NULL)) + { + kerror("Unmap addr failed: vma not found. At address: %#018lx, pid=%ld", vaddr + unmapped, current_pcb->pid); + return -EINVAL; + } + + if (unlikely(vma->vm_start != (vaddr + unmapped))) + { + kerror("Unmap addr failed: addr_start is not equal to current: %#018lx.", vaddr + unmapped); + return -EINVAL; + } + if (vma->anon_vma != NULL) + mm_unmap_vma(mm, vma, NULL); + + unmapped += vma->vm_end - vma->vm_start; + // 释放vma结构体 + if (destroy) + { + vm_area_del(vma); + vm_area_free(vma); + } + } + return 0; +failed:; + kerror("Unmap addr failed."); + return retval; +} diff --git a/kernel/mm/mmio-buddy.c b/kernel/mm/mmio-buddy.c index 7c8a08bf..cabc1aa7 100644 --- a/kernel/mm/mmio-buddy.c +++ b/kernel/mm/mmio-buddy.c @@ -45,16 +45,6 @@ static __always_inline struct __mmio_buddy_addr_region *__mmio_buddy_create_regi return region; } -/** - * @brief 释放address region结构体 - * - * @param region 待释放的结构体 - */ -static __always_inline void __release_addr_region(struct __mmio_buddy_addr_region *region) -{ - kfree(region); -} - /** * @brief 将给定大小为(2^exp)的地址空间一分为二,并插入下一级的链表中 * @@ -84,9 +74,10 @@ static __always_inline int __buddy_merge_blocks(struct __mmio_buddy_addr_region return -EINVAL; // === 是一对伙伴,将他们合并 - // __mmio_pool.free_regions[__exp2index(exp)].num_free -=2; + // 减少计数的工作应在该函数外完成 + // 释放y - __release_addr_region(y); + __mmio_buddy_release_addr_region(y); // 插入x __buddy_add_region_obj(__exp2index(exp + 1), x); @@ -101,7 +92,7 @@ static __always_inline int __buddy_merge_blocks(struct __mmio_buddy_addr_region */ static __always_inline struct __mmio_buddy_addr_region *__buddy_pop_region(int exp) { - if (unlikely(&__mmio_pool.free_regions[__exp2index(exp)].list_head)) + if (unlikely(list_empty(&__mmio_pool.free_regions[__exp2index(exp)].list_head))) return NULL; struct __mmio_buddy_addr_region *r = container_of(list_next(&__mmio_pool.free_regions[__exp2index(exp)].list_head), struct __mmio_buddy_addr_region, list); list_del(&r->list); @@ -176,7 +167,7 @@ static void __buddy_merge(int exp) * @param exp 内存区域的大小(2^exp) * @return struct __mmio_buddy_addr_region* 符合要求的内存区域。没有满足要求的时候,返回NULL */ -static struct __mmio_buddy_addr_region *__buddy_query_addr_region(int exp) +struct __mmio_buddy_addr_region *mmio_buddy_query_addr_region(int exp) { if (exp >= MMIO_BUDDY_MAX_EXP) return NULL; @@ -223,7 +214,7 @@ has_block:; // 有可用的内存块,分配 * @param exp 内存空间的大小(2^exp) * @return int 返回码 */ -static __always_inline int __buddy_give_back(uint64_t vaddr, int exp) +int __mmio_buddy_give_back(uint64_t vaddr, int exp) { // 确保内存对齐,低位都要为0 if (vaddr & ((1UL << exp) - 1)) @@ -255,6 +246,5 @@ void mmio_buddy_init() uint32_t cnt_1g_blocks = (MMIO_TOP - MMIO_BASE) / PAGE_1G_SIZE; uint64_t vaddr_base = MMIO_BASE; for (uint32_t i = 0; i < cnt_1g_blocks; ++i, vaddr_base += PAGE_1G_SIZE) - __buddy_give_back(vaddr_base, PAGE_1G_SHIFT); - + __mmio_buddy_give_back(vaddr_base, PAGE_1G_SHIFT); } \ No newline at end of file diff --git a/kernel/mm/mmio-buddy.h b/kernel/mm/mmio-buddy.h index af7d675e..2df0a8e9 100644 --- a/kernel/mm/mmio-buddy.h +++ b/kernel/mm/mmio-buddy.h @@ -3,6 +3,7 @@ #include #include "mm-types.h" #include "mm.h" +#include "slab.h" #define MMIO_BUDDY_MAX_EXP PAGE_1G_SHIFT #define MMIO_BUDDY_MIN_EXP PAGE_4K_SHIFT @@ -44,8 +45,35 @@ struct mmio_buddy_mem_pool struct __mmio_free_region_list free_regions[MMIO_BUDDY_REGION_COUNT]; }; +/** + * @brief 释放address region结构体 + * + * @param region 待释放的结构体 + */ +static __always_inline void __mmio_buddy_release_addr_region(struct __mmio_buddy_addr_region *region) +{ + kfree(region); +} + +/** + * @brief 归还一块内存空间到buddy + * + * @param vaddr 虚拟地址 + * @param exp 内存空间的大小(2^exp) + * @return int 返回码 + */ +int __mmio_buddy_give_back(uint64_t vaddr, int exp); + /** * @brief 初始化mmio的伙伴系统 * */ -void mmio_buddy_init(); \ No newline at end of file +void mmio_buddy_init(); + +/** + * @brief 从buddy中申请一块指定大小的内存区域 + * + * @param exp 内存区域的大小(2^exp) + * @return struct __mmio_buddy_addr_region* 符合要求的内存区域。没有满足要求的时候,返回NULL + */ +struct __mmio_buddy_addr_region *mmio_buddy_query_addr_region(int exp); \ No newline at end of file diff --git a/kernel/mm/mmio.c b/kernel/mm/mmio.c index a84a26c9..6a096b71 100644 --- a/kernel/mm/mmio.c +++ b/kernel/mm/mmio.c @@ -1,5 +1,6 @@ #include "mmio.h" #include "mmio-buddy.h" +#include void mmio_init() { @@ -10,25 +11,108 @@ void mmio_init() * @brief 创建一块mmio区域,并将vma绑定到initial_mm * * @param size mmio区域的大小(字节) - * @param length mmio区域长度 * @param vm_flags 要把vma设置成的标志 * @param res_vaddr 返回值-分配得到的虚拟地址 * @param res_length 返回值-分配的虚拟地址空间长度 * @return int 错误码 */ -int mmio_create(uint32_t size, uint64_t length, vm_flags_t vm_flags, uint64_t * res_vaddr, uint64_t *res_length) +int mmio_create(uint32_t size, vm_flags_t vm_flags, uint64_t *res_vaddr, uint64_t *res_size) { - + int retval = 0; + // 申请的内存超过允许的最大大小 + if (unlikely(size > PAGE_1G_SIZE || size == 0)) + return -EPERM; + + // 计算要从buddy中申请地址空间大小(按照2的n次幂来对齐) + int size_exp = 31 - __clz(size); + if (size_exp < PAGE_4K_SHIFT) + { + size_exp = PAGE_4K_SHIFT; + size = PAGE_4K_SIZE; + } + else if (size & (~(1 << size_exp))) + { + ++size_exp; + size = 1 << size_exp; + } + // 申请内存 + struct __mmio_buddy_addr_region *buddy_region = mmio_buddy_query_addr_region(size_exp); + if (buddy_region == NULL) // 没有空闲的mmio空间了 + return -ENOMEM; + + *res_vaddr = buddy_region->vaddr; + *res_size = size; + // 释放region + __mmio_buddy_release_addr_region(buddy_region); + + // ====创建vma=== + // 设置vma flags + vm_flags |= (VM_IO | VM_DONTCOPY); + uint64_t len_4k = size % PAGE_2M_SIZE; + uint64_t len_2m = size - len_4k; + // 先创建2M的vma,然后创建4k的 + for (uint32_t i = 0; i < len_2m; i += PAGE_2M_SIZE) + { + + retval = mm_create_vma(&initial_mm, buddy_region->vaddr + i, PAGE_2M_SIZE, vm_flags, NULL, NULL); + if (unlikely(retval != 0)) + goto failed; + } + + for (uint32_t i = len_2m; i < size; i += PAGE_4K_SIZE) + { + retval = mm_create_vma(&initial_mm, buddy_region->vaddr + i, PAGE_4K_SIZE, vm_flags, NULL, NULL); + if (unlikely(retval != 0)) + goto failed; + } + return 0; +failed:; + kerror("failed to create mmio vma. pid=%d", current_pcb->pid); + // todo: 当失败时,将已创建的vma删除 + return retval; } /** * @brief 取消mmio的映射并将地址空间归还到buddy中 - * + * * @param vaddr 起始的虚拟地址 * @param length 要归还的地址空间的长度 * @return int 错误码 */ int mmio_release(uint64_t vaddr, uint64_t length) { + int retval = 0; + // 先将这些区域都unmap了 + mm_unmap(&initial_mm, vaddr, length, false); -} \ No newline at end of file + // 将这些区域加入buddy + for (uint64_t i = 0; i < length;) + { + struct vm_area_struct *vma = vma_find(&initial_mm, vaddr + i); + if (unlikely(vma == NULL)) + { + kerror("mmio_release failed: vma not found. At address: %#018lx, pid=%ld", vaddr + i, current_pcb->pid); + return -EINVAL; + } + + if (unlikely(vma->vm_start != (vaddr + i))) + { + kerror("mmio_release failed: addr_start is not equal to current: %#018lx.", vaddr + i); + return -EINVAL; + } + // 往buddy中插入内存块 + retval = __mmio_buddy_give_back(vma->vm_start, 31 - __clz(vma->vm_end - vma->vm_start)); + i += vma->vm_end - vma->vm_start; + + // 释放vma结构体 + vm_area_del(vma); + vm_area_free(vma); + + if (unlikely(retval != 0)) + goto give_back_failed; + } + return 0; +give_back_failed:; + kerror("mmio_release give_back failed: "); + return retval; +} diff --git a/kernel/mm/mmio.h b/kernel/mm/mmio.h index bf9b159d..08d63140 100644 --- a/kernel/mm/mmio.h +++ b/kernel/mm/mmio.h @@ -7,19 +7,18 @@ void mmio_init(); * @brief 创建一块mmio区域,并将vma绑定到initial_mm * * @param size mmio区域的大小(字节) - * @param length mmio区域长度 * @param vm_flags 要把vma设置成的标志 * @param res_vaddr 返回值-分配得到的虚拟地址 * @param res_length 返回值-分配的虚拟地址空间长度 * @return int 错误码 */ -int mmio_create(uint32_t size, uint64_t length, vm_flags_t vm_flags, uint64_t * res_vaddr, uint64_t *res_length); +int mmio_create(uint32_t size, vm_flags_t vm_flags, uint64_t * res_vaddr, uint64_t *res_size); /** * @brief 取消mmio的映射并将地址空间归还到buddy中 * * @param vaddr 起始的虚拟地址 - * @param length 要归还的地址空间的长度 + * @param size 要归还的地址空间的长度 * @return int 错误码 */ -int mmio_release(uint64_t vaddr, uint64_t length); \ No newline at end of file +int mmio_release(uint64_t vaddr, uint64_t size); \ No newline at end of file diff --git a/kernel/mm/vma.c b/kernel/mm/vma.c index ee99d9cc..9e887582 100644 --- a/kernel/mm/vma.c +++ b/kernel/mm/vma.c @@ -229,7 +229,7 @@ int __anon_vma_free(struct anon_vma_t *anon_vma) /** * @brief 从anon_vma的管理范围中删除指定的vma - * (在进入这个函数之前,应该要加锁) + * (在进入这个函数之前,应该要对anon_vma加锁) * @param vma 将要取消对应的anon_vma管理的vma结构体 * @return int 返回码 */ @@ -240,16 +240,20 @@ int __anon_vma_del(struct vm_area_struct *vma) return -EINVAL; list_del(&vma->anon_vma_list); - semaphore_down(&vma->anon_vma->sem); atomic_dec(&vma->anon_vma->ref_count); + // 若当前anon_vma的引用计数归零,则意味着可以释放内存页 if (unlikely(atomic_read(&vma->anon_vma->ref_count) == 0)) // 应当释放该anon_vma { + // 若页面结构体是mmio创建的,则释放页面结构体 + if (vma->anon_vma->page->attr & PAGE_DEVICE) + kfree(vma->anon_vma->page); + else + free_pages(vma->anon_vma->page, 1); __anon_vma_free(vma->anon_vma); - // 释放了anon_vma之后,清理当前vma的关联数据 - vma->anon_vma = NULL; - list_init(&vma->anon_vma_list); } - else - semaphore_up(&vma->anon_vma->sem); + + // 清理当前vma的关联数据 + vma->anon_vma = NULL; + list_init(&vma->anon_vma_list); } diff --git a/kernel/process/process.c b/kernel/process/process.c index a216ca27..2d4f9b55 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -22,6 +22,8 @@ #include +#include + // #pragma GCC push_options // #pragma GCC optimize("O0") @@ -921,7 +923,7 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb struct vm_area_struct *vma = current_pcb->mm->vmas; while (vma != NULL) { - if (vma->vm_end > USER_MAX_LINEAR_ADDR) + if (vma->vm_end > USER_MAX_LINEAR_ADDR || vma->vm_flags & VM_DONTCOPY) { vma = vma->vm_next; continue; @@ -997,19 +999,19 @@ uint64_t process_exit_mm(struct process_control_block *pcb) struct vm_area_struct *vma = pcb->mm->vmas; while (vma != NULL) { + struct vm_area_struct *cur_vma = vma; vma = cur_vma->vm_next; uint64_t pa; - mm_umap_vma(pcb->mm, cur_vma, &pa); + // kdebug("vm start=%#018lx, sem=%d", cur_vma->vm_start, cur_vma->anon_vma->sem.counter); + mm_unmap_vma(pcb->mm, cur_vma, &pa); + uint64_t size = (cur_vma->vm_end - cur_vma->vm_start); // 释放内存 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; @@ -1017,7 +1019,7 @@ uint64_t process_exit_mm(struct process_control_block *pcb) break; } vm_area_del(cur_vma); - kfree(cur_vma); + vm_area_free(cur_vma); } // 释放顶层页表 diff --git a/kernel/process/process.h b/kernel/process/process.h index 6d6e8f90..c2a8fbea 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -18,7 +18,7 @@ #include #include -#if ARCH(X86_64) +#if ARCH(I386) || ARCH(X86_64) #include #else #error Unsupported architecture!