Browse Source

new: 初步完成了mmio地址空间自动分配(未测试)

bugfix: mmio虚拟地址分配的bug
fslongjin 2 years ago
parent
commit
0223232f3f

+ 2 - 1
.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": ""

+ 1 - 1
docs/kernel/core_api/mm-api.md

@@ -222,7 +222,7 @@ DragonOS支持对物理页的直接操作
 
   要取消映射的地址空间的长度
 
-### `mm_unmap(virt_addr, length)`
+### `mm_unmap_addr(virt_addr, length)`
 
 #### 描述
 

+ 1 - 1
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));

+ 10 - 2
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);
+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);

+ 18 - 0
kernel/mm/mm.c

@@ -1,5 +1,6 @@
 #include "mm.h"
 #include "mm-types.h"
+#include "mmio.h"
 #include "slab.h"
 #include <common/printk.h>
 #include <common/kprint.h>
@@ -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;
+}

+ 24 - 2
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页(物理内存页)

+ 113 - 8
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;
-}
+}
+
+/**
+ * @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;
+}

+ 7 - 17
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);
 }

+ 29 - 1
kernel/mm/mmio-buddy.h

@@ -3,6 +3,7 @@
 #include <common/glib.h>
 #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();
+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);

+ 89 - 5
kernel/mm/mmio.c

@@ -1,5 +1,6 @@
 #include "mmio.h"
 #include "mmio-buddy.h"
+#include <common/math.h>
 
 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);
+
+    // 将这些区域加入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;
+}

+ 3 - 4
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);
+int mmio_release(uint64_t vaddr, uint64_t size);

+ 11 - 7
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);
 }

+ 8 - 6
kernel/process/process.c

@@ -22,6 +22,8 @@
 
 #include <ktest/ktest.h>
 
+#include <mm/mmio.h>
+
 // #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);
     }
 
     // 释放顶层页表

+ 1 - 1
kernel/process/process.h

@@ -18,7 +18,7 @@
 #include <common/wait_queue.h>
 #include <mm/mm-types.h>
 
-#if ARCH(X86_64)
+#if ARCH(I386) || ARCH(X86_64)
 #include <arch/x86_64/current.h>
 #else
 #error Unsupported architecture!