Parcourir la source

new: vma反向映射

fslongjin il y a 2 ans
Parent
commit
1dd9195d69

+ 4 - 1
.vscode/settings.json

@@ -122,7 +122,10 @@
         "atomic.h": "c",
         "uart.h": "c",
         "fat_ent.h": "c",
-        "semaphore.h": "c"
+        "semaphore.h": "c",
+        "mm-types.h": "c",
+        "vfs.h": "c",
+        "current.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 1 - 1
Makefile

@@ -7,7 +7,7 @@ export ARCH=__x86_64__
 export ROOT_PATH=$(shell pwd)
 
 export DEBUG=DEBUG
-export GLOBAL_CFLAGS := -mcmodel=large -fno-builtin -m64  -fno-stack-protector -D $(ARCH) -O1
+export GLOBAL_CFLAGS := -mcmodel=large -fno-builtin -m64  -fno-stack-protector -D $(ARCH) -O0
 
 ifeq ($(DEBUG), DEBUG)
 GLOBAL_CFLAGS += -g 

+ 20 - 0
kernel/arch/x86_64/current.h

@@ -0,0 +1,20 @@
+#pragma once
+#include <common/glib.h>
+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+struct process_control_block;
+// 获取当前的pcb
+static __always_inline struct process_control_block *get_current_pcb()
+{
+	struct process_control_block *current = NULL;
+	// 利用了当前pcb和栈空间总大小为32k大小对齐,将rsp低15位清空,即可获得pcb的起始地址
+	barrier();
+	__asm__ __volatile__("andq %%rsp, %0   \n\t"
+						 : "=r"(current)
+						 : "0"(~32767UL));
+	barrier();
+	return current;
+};
+#define current_pcb get_current_pcb()
+#pragma GCC pop_options

+ 4 - 1
kernel/common/Makefile

@@ -10,7 +10,7 @@ $(kernel_common_subdirs): ECHO
 
 	$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
 
-all: glib.o printk.o cpu.o bitree.o kfifo.o wait_queue.o mutex.o wait.o unistd.o string.o $(kernel_common_subdirs)
+all: glib.o printk.o cpu.o bitree.o kfifo.o wait_queue.o mutex.o wait.o unistd.o string.o semaphore.o $(kernel_common_subdirs)
 
 
 glib.o: glib.c
@@ -42,3 +42,6 @@ unistd.o: unistd.c
 
 string.o: string.c
 	gcc $(CFLAGS) -c string.c -o string.o
+
+semaphore.o: semaphore.c
+	gcc $(CFLAGS) -c semaphore.c -o semaphore.o

+ 43 - 0
kernel/common/semaphore.c

@@ -0,0 +1,43 @@
+#include "semaphore.h"
+#include <sched/sched.h>
+#include <process/process.h>
+
+
+void semaphore_down(semaphore_t *sema)
+{
+    if (atomic_read(&sema->counter) > 0) // 信号量大于0,资源充足
+        atomic_dec(&sema->counter);
+    else // 资源不足,进程休眠
+    {
+        // 将当前进程加入信号量的等待队列
+        wait_queue_node_t wait;
+        wait_queue_init(&wait, current_pcb);
+
+        current_pcb->state = PROC_UNINTERRUPTIBLE;
+
+        list_append(&sema->wait_queue.wait_list, &wait.wait_list);
+
+        // 执行调度
+        sched_cfs();
+    }
+}
+
+void semaphore_up(semaphore_t *sema)
+{
+    if (list_empty(&sema->wait_queue.wait_list)) // 没有进程在等待资源
+    {
+        atomic_inc(&sema->counter);
+    }
+    else    // 有进程在等待资源,唤醒进程
+    {
+
+        wait_queue_node_t *wq = container_of(list_next(&sema->wait_queue.wait_list), wait_queue_node_t, wait_list);
+        list_del(&wq->wait_list);
+
+        wq->pcb->state = PROC_RUNNING;
+        sched_cfs_enqueue(wq->pcb);
+
+        // 当前进程缺少需要的资源,立即标为需要被调度
+        current_pcb->flags |= PF_NEED_SCHED;
+    }
+};

+ 7 - 41
kernel/common/semaphore.h

@@ -12,10 +12,7 @@
 #pragma once
 #include <common/atomic.h>
 
-#include <process/process.h>
-#include <sched/sched.h>
-#include "wait_queue.h"
-
+#include <common/wait_queue.h>
 
 /**
  * @brief 信号量的结构体
@@ -27,13 +24,16 @@ typedef struct
     wait_queue_node_t wait_queue;
 } semaphore_t;
 
+void __semaphore_invoke_sched();
+void __semaphore_sched_enqueue(struct process_control_block *pcb);
+
 /**
  * @brief 初始化信号量
  *
  * @param sema 信号量对象
  * @param count 信号量的初始值
  */
-void semaphore_init(semaphore_t *sema, ul count)
+static __always_inline void semaphore_init(semaphore_t *sema, ul count)
 {
     atomic_set(&sema->counter, count);
     wait_queue_init(&sema->wait_queue, NULL);
@@ -44,40 +44,6 @@ void semaphore_init(semaphore_t *sema, ul count)
  *
  * @param sema
  */
-void semaphore_down(semaphore_t *sema)
-{
-    if (atomic_read(&sema->counter) > 0) // 信号量大于0,资源充足
-        atomic_dec(&sema->counter);
-    else // 资源不足,进程休眠
-    {
-        // 将当前进程加入信号量的等待队列
-        wait_queue_node_t wait;
-        wait_queue_init(&wait, current_pcb);
-
-        current_pcb->state = PROC_UNINTERRUPTIBLE;
-
-        list_append(&sema->wait_queue.wait_list, &wait.wait_list);
-
-        // 执行调度
-        sched_cfs();
-    }
-}
-
-void semaphore_up(semaphore_t *sema)
-{
-    if (list_empty(&sema->wait_queue.wait_list)) // 没有进程在等待资源
-    {
-        atomic_inc(&sema->counter);
-    }
-    else    // 有进程在等待资源,唤醒进程
-    {
-
-        wait_queue_node_t *wq = container_of(list_next(&sema->wait_queue.wait_list), wait_queue_node_t, wait_list);
-        list_del(&wq->wait_list);
+void semaphore_down(semaphore_t *sema);
 
-        wq->pcb->state = PROC_RUNNING;
-        sched_cfs_enqueue(wq->pcb);
-        // 当前进程缺少需要的资源,立即标为需要被调度
-        current_pcb->flags |= PF_NEED_SCHED;
-    }
-}
+void semaphore_up(semaphore_t *sema);

+ 23 - 22
kernel/common/spinlock.h

@@ -18,18 +18,9 @@
  */
 typedef struct
 {
-    __volatile__ char lock; // 1:unlocked 0:locked
+    int8_t lock; // 1:unlocked 0:locked
 } spinlock_t;
 
-/**
- * @brief 初始化自旋锁
- *
- * @param lock
- */
-void spin_init(spinlock_t *lock)
-{
-    lock->lock = 1;
-}
 
 /**
  * @brief 自旋锁加锁
@@ -53,8 +44,8 @@ void spin_lock(spinlock_t *lock)
 
 /**
  * @brief 自旋锁解锁
- * 
- * @param lock 
+ *
+ * @param lock
  */
 void spin_unlock(spinlock_t *lock)
 {
@@ -63,14 +54,26 @@ void spin_unlock(spinlock_t *lock)
                          : "=m"(lock->lock)::"memory");
 }
 
+/**
+ * @brief 初始化自旋锁
+ *
+ * @param lock
+ */
+void spin_init(spinlock_t *lock)
+{
+    barrier();
+    lock->lock = 1;
+    barrier();
+}
+
 /**
  * @brief 自旋锁加锁(不改变自旋锁持有计数)
- * 
+ *
  * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
  */
 void spin_lock_no_preempt(spinlock_t *lock)
 {
-     __asm__ __volatile__("1:    \n\t"
+    __asm__ __volatile__("1:    \n\t"
                          "lock decq %0   \n\t" // 尝试-1
                          "jns 3f    \n\t"      // 加锁成功,跳转到步骤3
                          "2:    \n\t"          // 加锁失败,稍后再试
@@ -83,17 +86,15 @@ void spin_lock_no_preempt(spinlock_t *lock)
 }
 /**
  * @brief 自旋锁解锁(不改变自旋锁持有计数)
- * 
+ *
  * @warning 慎用此函数,除非你有十足的把握不会产生自旋锁计数错误
  */
-void spin_unlock_no_preempt(spinlock_t * lock)
+void spin_unlock_no_preempt(spinlock_t *lock)
 {
     __asm__ __volatile__("movq $1, %0   \n\t"
                          : "=m"(lock->lock)::"memory");
 }
 
-
-
 /**
  * @brief 尝试加锁
  *
@@ -125,7 +126,7 @@ long spin_trylock(spinlock_t *lock)
 
 /**
  * @brief 保存中断状态,关闭中断,并自旋锁加锁
- * 
+ *
  */
 #define spin_lock_irqsave(lock, flags) \
     do                                 \
@@ -136,7 +137,7 @@ long spin_trylock(spinlock_t *lock)
 
 /**
  * @brief 恢复rflags以及中断状态并解锁自旋锁
- * 
+ *
  */
 #define spin_unlock_irqrestore(lock, flags) \
     do                                      \
@@ -147,7 +148,7 @@ long spin_trylock(spinlock_t *lock)
 
 /**
  * @brief 关闭中断并加锁
- * 
+ *
  */
 #define spin_lock_irq(lock)  \
     do                       \
@@ -158,7 +159,7 @@ long spin_trylock(spinlock_t *lock)
 
 /**
  * @brief 解锁并开启中断
- * 
+ *
  */
 #define spin_unlock_irq(lock) \
     do                        \

+ 1 - 0
kernel/driver/disk/ahci/ahci.c

@@ -3,6 +3,7 @@
 #include <mm/slab.h>
 #include <syscall/syscall.h>
 #include <syscall/syscall_num.h>
+#include <sched/sched.h>
 
 struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES];
 

+ 2 - 0
kernel/lib/libUI/textui-render.c

@@ -1,5 +1,7 @@
 #include "textui.h"
 #include <driver/uart/uart.h>
+#include <common/errno.h>
+#include "screen_manager.h"
 
 #define WHITE 0x00ffffff  //白
 #define BLACK 0x00000000  //黑

+ 1 - 0
kernel/lib/libUI/textui.c

@@ -5,6 +5,7 @@
 #include <common/string.h>
 #include <common/printk.h>
 #include <common/atomic.h>
+#include <common/errno.h>
 
 struct scm_ui_framework_t textui_framework;
 static spinlock_t __window_id_lock = {1};

+ 41 - 6
kernel/mm/internal.h

@@ -4,26 +4,61 @@
 
 /**
  * @brief 将vma结构体插入mm_struct的链表之中
- * 
+ *
  * @param mm 内存空间分布结构体
  * @param vma 待插入的VMA结构体
  * @param prev 链表的前一个结点
  */
-void __vma_link_list(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev);
+void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev);
 
 /**
  * @brief 将vma给定结构体从vma链表的结点之中删除
- * 
+ *
  * @param mm 内存空间分布结构体
  * @param vma 待插入的VMA结构体
  */
-void __vma_unlink_list(struct mm_struct * mm, struct vm_area_struct * vma);
+void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma);
 
 /**
  * @brief 获取指定虚拟地址处映射的物理地址
- * 
+ *
  * @param mm 内存空间分布结构体
  * @param vaddr 虚拟地址
  * @return uint64_t 已映射的物理地址
  */
-uint64_t __mm_get_paddr(struct mm_struct * mm, uint64_t vaddr);
+uint64_t __mm_get_paddr(struct mm_struct *mm, uint64_t vaddr);
+
+/**
+ * @brief 创建anon_vma,并将其与页面结构体进行绑定
+ * 若提供的页面结构体指针为NULL,则只创建,不绑定
+ *
+ * @param page 页面结构体的指针
+ * @param lock_page 是否将页面结构体加锁
+ * @return struct anon_vma_t* 创建好的anon_vma
+ */
+struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page);
+
+/**
+ * @brief 释放anon vma结构体
+ *
+ * @param anon_vma 待释放的anon_vma结构体
+ * @return int 返回码
+ */
+int __anon_vma_free(struct anon_vma_t *anon_vma);
+
+/**
+ * @brief 将指定的vma加入到anon_vma的管理范围之中
+ *
+ * @param anon_vma 页面的anon_vma
+ * @param vma 待加入的vma
+ * @return int 返回码
+ */
+int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma);
+
+/**
+ * @brief 从anon_vma的管理范围中删除指定的vma
+ * (在进入这个函数之前,应该要加锁)
+ * @param vma 将要取消对应的anon_vma管理的vma结构体
+ * @return int 返回码
+ */
+int __anon_vma_del(struct vm_area_struct *vma);

+ 9 - 0
kernel/mm/mm-types.h

@@ -1,6 +1,7 @@
 #pragma once
 #include <common/glib.h>
 #include <common/semaphore.h>
+#include <common/spinlock.h>
 #include <common/atomic.h>
 
 struct mm_struct;
@@ -163,10 +164,18 @@ struct mm_struct
  */
 struct anon_vma_t
 {
+    // anon vma的操作信号量
     semaphore_t sem;
+    
+    /**
+     * 记录当前有多少个vma与该anon_vma关联,当vma被释放时,
+     * 应当检查这个值。当该值为0时,应当释放anon_vma结构体
+     */
     atomic_t ref_count;
 
     // todo: 把下面的循环链表更换成红黑树
     // 与当前anon_vma相关的vma的列表
     struct List vma_list;
+    // 当前anon vma对应的page
+    struct Page* page;
 };

+ 5 - 2
kernel/mm/mm.c

@@ -213,6 +213,7 @@ void mm_init()
         barrier();
         tmp_page = memory_management_struct.pages_struct + j;
         page_init(tmp_page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT);
+        barrier();
         page_num = tmp_page->addr_phys >> PAGE_2M_SHIFT;
         *(memory_management_struct.bmp + (page_num >> 6)) |= (1UL << (page_num % 64));
         ++tmp_page->zone->count_pages_using;
@@ -248,7 +249,7 @@ unsigned long page_init(struct Page *page, ul flags)
         ++page->zone->total_pages_link;
     }
     page->anon_vma = NULL;
-    spin_init(&page->op_lock);
+    spin_init(&(page->op_lock));
     return 0;
 }
 
@@ -588,7 +589,9 @@ 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)
         {
-            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);
+            struct vm_area_struct * vma=NULL;
+            mm_create_vma(current_pcb->mm, i, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
+            mm_map_vma(vma, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys);
         }
         current_pcb->mm->brk_end = end_addr;
     }

+ 13 - 3
kernel/mm/mm.h

@@ -325,6 +325,7 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
     vma->vm_mm = mm;
     vma->vm_prev = vma->vm_next = NULL;
     vma->vm_ops = NULL;
+    list_init(&vma->anon_vma_list);
 }
 
 /**
@@ -442,17 +443,26 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
 })
 
 /**
- * @brief 创建VMA,并将物理地址映射到指定的虚拟地址处
+ * @brief 创建VMA
  *
  * @param mm 要绑定的内存空间分布结构体
  * @param vaddr 起始虚拟地址
  * @param length 长度(字节)
- * @param paddr 起始物理地址
  * @param vm_flags vma的标志
  * @param vm_ops vma的操作接口
+ * @param res_vma 返回的vma指针
+ * @return int 错误码
+ */
+int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flags_t vm_flags, struct vm_operations_t *vm_ops, struct vm_area_struct **res_vma);
+
+/**
+ * @brief 将指定的物理地址映射到指定的vma处
+ *
+ * @param vma 要进行映射的VMA结构体
+ * @param paddr 起始物理地址
  * @return int 错误码
  */
-int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr, vm_flags_t vm_flags, struct vm_operations_t *vm_ops);
+int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr);
 
 /**
  * @brief 在页表中取消指定的vma的映射

+ 43 - 14
kernel/mm/mmap.c

@@ -306,17 +306,17 @@ void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_sta
 }
 
 /**
- * @brief 创建VMA,并将物理地址映射到指定的虚拟地址处
+ * @brief 创建VMA
  *
  * @param mm 要绑定的内存空间分布结构体
  * @param vaddr 起始虚拟地址
  * @param length 长度(字节)
- * @param paddr 起始物理地址
  * @param vm_flags vma的标志
  * @param vm_ops vma的操作接口
+ * @param res_vma 返回的vma指针
  * @return int 错误码
  */
-int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr, vm_flags_t vm_flags, struct vm_operations_t *vm_ops)
+int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flags_t vm_flags, struct vm_operations_t *vm_ops, struct vm_area_struct **res_vma)
 {
     int retval = 0;
     struct vm_area_struct *vma = vm_area_alloc(mm);
@@ -327,19 +327,50 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
     vma->vm_start = vaddr;
     vma->vm_end = vaddr + length;
 
-    // 将vma与对应的anon_vma进行绑定
-    struct Page * pg = Phy_to_2M_Page(paddr);
-    // 将VMA加入链表
+    // 将VMA加入mm的链表
     retval = vma_insert(mm, vma);
     if (retval == -EEXIST) // 之前已经存在了相同的vma,直接返回
     {
+        *res_vma = vma_find(mm, vma->vm_start);
         kfree(vma);
         return -EEXIST;
     }
+    *res_vma = vma;
+    return 0;
+}
+
+/**
+ * @brief 将指定的物理地址映射到指定的vma处
+ *
+ * @param vma 要进行映射的VMA结构体
+ * @param paddr 起始物理地址
+ * @return int 错误码
+ */
+int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr)
+{
+    int retval = 0;
+    // 获取物理地址对应的页面
+    struct Page *pg = Phy_to_2M_Page(paddr);
+    if (unlikely(pg->anon_vma == NULL)) // 若页面不存在anon_vma,则为页面创建anon_vma
+    {
+        uint64_t rflags;
+        // todo: 查明为什么在mm_init中,spin init之后,pg会变为0
+        spin_init(&pg->op_lock);
+        spin_lock_irqsave(&pg->op_lock, rflags);
+        if (unlikely(pg->anon_vma == NULL))
+            __anon_vma_create_alloc(pg, false);
+        spin_unlock_irqrestore(&pg->op_lock, rflags);
+    }
+    barrier();
+    // 将anon vma与vma进行绑定
+    __anon_vma_add(pg->anon_vma, vma);
+    barrier();
+
+    uint64_t length = vma->vm_end - vma->vm_start;
+    // ==== 将地址映射到页表 ====
     uint64_t len_4k = length % PAGE_2M_SIZE;
     uint64_t len_2m = length - len_4k;
 
-    // ==== 将地址映射到页表
     /*
         todo: 限制页面的读写权限
     */
@@ -348,12 +379,12 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
     if (likely(len_2m > 0))
     {
         uint64_t page_flags = 0;
-        if (vm_flags & VM_USER)
+        if (vma->vm_flags & VM_USER)
             page_flags = PAGE_USER_PAGE;
         else
             page_flags = PAGE_KERNEL_PAGE;
         // 这里直接设置user标志位为false,因为该函数内部会对其进行自动校正
-        retval = mm_map_proc_page_table((uint64_t)mm->pgd, true, vaddr, paddr, len_2m, page_flags, false, false, false);
+        retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start, paddr, len_2m, page_flags, false, false, false);
         if (unlikely(retval != 0))
             goto failed;
     }
@@ -363,12 +394,12 @@ int mm_map_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t p
         len_4k = ALIGN(len_4k, PAGE_4K_SIZE);
 
         uint64_t page_flags = 0;
-        if (vm_flags & VM_USER)
+        if (vma->vm_flags & VM_USER)
             page_flags = PAGE_USER_4K_PAGE;
         else
             page_flags = PAGE_KERNEL_4K_PAGE;
         // 这里直接设置user标志位为false,因为该函数内部会对其进行自动校正
-        retval = mm_map_proc_page_table((uint64_t)mm->pgd, true, vaddr + len_2m, paddr + len_2m, len_4k, page_flags, false, false, true);
+        retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + len_2m, paddr + len_2m, len_4k, page_flags, false, false, true);
         if (unlikely(retval != 0))
             goto failed;
     }
@@ -376,9 +407,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);
+    kdebug("map VMA failed.");
     return retval;
 }
 

+ 103 - 4
kernel/mm/vma.c

@@ -139,10 +139,10 @@ int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
         prev = prev->vm_prev;
     if (prev == NULL) // 要将当前vma插入到链表的尾部
     {
-        struct vm_area_struct * ptr = mm->vmas;
-        while(ptr)
+        struct vm_area_struct *ptr = mm->vmas;
+        while (ptr)
         {
-            if(ptr->vm_next)
+            if (ptr->vm_next)
                 ptr = ptr->vm_next;
             else
             {
@@ -153,4 +153,103 @@ int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
     }
     __vma_link_list(mm, vma, prev);
     return 0;
-}
+}
+
+/**
+ * @brief 创建anon_vma,并将其与页面结构体进行绑定
+ * 若提供的页面结构体指针为NULL,则只创建,不绑定
+ *
+ * @param page 页面结构体的指针
+ * @param lock_page 是否将页面结构体加锁
+ * @return struct anon_vma_t* 创建好的anon_vma
+ */
+struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page)
+{
+    struct anon_vma_t *anon_vma = (struct anon_vma_t *)kmalloc(sizeof(struct anon_vma_t), 0);
+    if (unlikely(anon_vma == NULL))
+        return NULL;
+    memset(anon_vma, 0, sizeof(struct anon_vma_t));
+
+    list_init(&anon_vma->vma_list);
+    semaphore_init(&anon_vma->sem, 1);
+
+    // 需要和page进行绑定
+    if (page != NULL)
+    {
+        if (lock_page == true) // 需要加锁
+        {
+            uint64_t rflags;
+            spin_lock_irqsave(&page->op_lock, rflags);
+            page->anon_vma = anon_vma;
+            spin_unlock_irqrestore(&page->op_lock, rflags);
+        }
+        else
+            page->anon_vma = anon_vma;
+
+        anon_vma->page = page;
+    }
+    return anon_vma;
+}
+
+/**
+ * @brief 将指定的vma加入到anon_vma的管理范围之中
+ *
+ * @param anon_vma 页面的anon_vma
+ * @param vma 待加入的vma
+ * @return int 返回码
+ */
+int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma)
+{
+    semaphore_down(&anon_vma->sem);
+    list_add(&anon_vma->vma_list, &vma->anon_vma_list);
+    vma->anon_vma = anon_vma;
+    atomic_inc(&anon_vma->ref_count);
+    semaphore_up(&anon_vma->sem);
+    return 0;
+}
+
+/**
+ * @brief 释放anon vma结构体
+ *
+ * @param anon_vma 待释放的anon_vma结构体
+ * @return int 返回码
+ */
+int __anon_vma_free(struct anon_vma_t *anon_vma)
+{
+    if (anon_vma->page != NULL)
+    {
+        spin_lock(&anon_vma->page->op_lock);
+        anon_vma->page->anon_vma = NULL;
+        spin_unlock(&anon_vma->page->op_lock);
+    }
+    kfree(anon_vma);
+
+    return 0;
+}
+
+/**
+ * @brief 从anon_vma的管理范围中删除指定的vma
+ * (在进入这个函数之前,应该要加锁)
+ * @param vma 将要取消对应的anon_vma管理的vma结构体
+ * @return int 返回码
+ */
+int __anon_vma_del(struct vm_area_struct *vma)
+{
+    // 当前vma没有绑定anon_vma
+    if (vma->anon_vma == NULL)
+        return -EINVAL;
+
+    list_del(&vma->anon_vma_list);
+    semaphore_down(&vma->anon_vma->sem);
+    atomic_dec(&vma->anon_vma->ref_count);
+
+    if (unlikely(atomic_read(&vma->anon_vma->ref_count) == 0)) // 应当释放该anon_vma
+    {
+        __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);
+}

+ 2 - 1
kernel/process/preempt.h

@@ -1,6 +1,7 @@
 #pragma once
 
-#include <process/process.h>
+#include <arch/x86_64/current.h>
+#include "proc-types.h"
 
 /**
  * @brief 增加自旋锁计数变量

+ 131 - 0
kernel/process/proc-types.h

@@ -0,0 +1,131 @@
+#pragma once
+
+#include <common/wait_queue.h>
+
+// 进程最大可拥有的文件描述符数量
+#define PROC_MAX_FD_NUM 16
+
+// 进程的内核栈大小 32K
+#define STACK_SIZE 32768
+
+// 进程的运行状态
+// 正在运行
+#define PROC_RUNNING (1 << 0)
+// 可被中断
+#define PROC_INTERRUPTIBLE (1 << 1)
+// 不可被中断
+#define PROC_UNINTERRUPTIBLE (1 << 2)
+// 挂起
+#define PROC_ZOMBIE (1 << 3)
+// 已停止
+#define PROC_STOPPED (1 << 4)
+
+// 内核代码段基地址
+#define KERNEL_CS (0x08)
+// 内核数据段基地址
+#define KERNEL_DS (0x10)
+// 用户代码段基地址
+#define USER_CS (0x28)
+// 用户数据段基地址
+#define USER_DS (0x30)
+
+// 进程初始化时的数据拷贝标志位
+#define CLONE_FS (1 << 0) // 在进程间共享打开的文件
+#define CLONE_SIGNAL (1 << 1)
+#define CLONE_VM (1 << 2) // 在进程间共享虚拟内存空间
+
+struct thread_struct
+{
+	// 内核层栈基指针
+	ul rbp; // in tss rsp0
+	// 内核层代码指针
+	ul rip;
+	// 内核层栈指针
+	ul rsp;
+
+	ul fs, gs;
+
+	ul cr2;
+	// 异常号
+	ul trap_num;
+	// 错误码
+	ul err_code;
+};
+
+// ========= pcb->flags =========
+// 进程标志位
+#define PF_KTHREAD (1UL << 0)	 // 内核线程
+#define PF_NEED_SCHED (1UL << 1) // 进程需要被调度
+#define PF_VFORK (1UL << 2)		 // 标志进程是否由于vfork而存在资源共享
+#define PF_KFORK (1UL << 3)		 // 标志在内核态下调用fork(临时标记,do_fork()结束后会将其复位)
+
+/**
+ * @brief 进程控制块
+ *
+ */
+struct process_control_block
+{
+	// 进程的状态
+	volatile long state;
+	// 进程标志:进程、线程、内核线程
+	unsigned long flags;
+	int64_t preempt_count; // 持有的自旋锁的数量
+	long signal;
+	long cpu_id; // 当前进程在哪个CPU核心上运行
+	// 内存空间分布结构体, 记录内存页表和程序段信息
+	struct mm_struct *mm;
+
+	// 进程切换时保存的状态信息
+	struct thread_struct *thread;
+
+	// 连接各个pcb的双向链表
+	struct List list;
+
+	// 地址空间范围
+	// 用户空间: 0x0000 0000 0000 0000 ~ 0x0000 7fff ffff ffff
+	// 内核空间: 0xffff 8000 0000 0000 ~ 0xffff ffff ffff ffff
+	uint64_t addr_limit;
+
+	long pid;
+	long priority;			 // 优先级
+	int64_t virtual_runtime; // 虚拟运行时间
+
+	// 进程拥有的文件描述符的指针数组
+	// todo: 改用动态指针数组
+	struct vfs_file_t *fds[PROC_MAX_FD_NUM];
+
+	// 链表中的下一个pcb
+	struct process_control_block *next_pcb;
+	// 父进程的pcb
+	struct process_control_block *parent_pcb;
+
+	int32_t exit_code;						// 进程退出时的返回码
+	wait_queue_node_t wait_child_proc_exit; // 子进程退出等待队列
+};
+
+// 将进程的pcb和内核栈融合到一起,8字节对齐
+union proc_union
+{
+	struct process_control_block pcb;
+	ul stack[STACK_SIZE / sizeof(ul)];
+} __attribute__((aligned(8)));
+
+struct tss_struct
+{
+	unsigned int reserved0;
+	ul rsp0;
+	ul rsp1;
+	ul rsp2;
+	ul reserved1;
+	ul ist1;
+	ul ist2;
+	ul ist3;
+	ul ist4;
+	ul ist5;
+	ul ist6;
+	ul ist7;
+	ul reserved2;
+	unsigned short reserved3;
+	// io位图基地址
+	unsigned short io_map_base_addr;
+} __attribute__((packed)); // 使用packed表明是紧凑结构,编译器不会对成员变量进行字节对齐。

+ 29 - 6
kernel/process/process.c

@@ -262,10 +262,13 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
             {
 
                 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);
+                struct vm_area_struct *vma = NULL;
+                int ret = mm_create_vma(current_pcb->mm, virt_base, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
                 // 防止内存泄露
                 if (ret == -EEXIST)
                     free_pages(Phy_to_2M_Page(pa), 1);
+                else
+                    mm_map_vma(vma, pa);
                 memset((void *)virt_base, 0, PAGE_2M_SIZE);
                 map_size = PAGE_2M_SIZE;
             }
@@ -278,9 +281,12 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
                 {
                     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);
+                    struct vm_area_struct *vma = NULL;
+                    int val = mm_create_vma(current_pcb->mm, virt_base + off, PAGE_4K_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
                     if (val == -EEXIST)
                         kfree(phys_2_virt(paddr));
+                    else
+                        mm_map_vma(vma, paddr);
                     memset((void *)(virt_base + off), 0, PAGE_4K_SIZE);
                 }
             }
@@ -307,10 +313,13 @@ static int process_load_elf_file(struct pt_regs *regs, char *path)
     regs->rbp = current_pcb->mm->stack_start;
 
     {
+        struct vm_area_struct *vma = NULL;
         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);
+        int val = mm_create_vma(current_pcb->mm, current_pcb->mm->stack_start - PAGE_2M_SIZE, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
         if (val == -EEXIST)
             free_pages(Phy_to_2M_Page(pa), 1);
+        else
+            mm_map_vma(vma, pa);
     }
 
     // 清空栈空间
@@ -928,8 +937,14 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
             {
                 uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys;
 
-                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);
+                struct vm_area_struct *new_vma = NULL;
+                int ret = mm_create_vma(new_mms, vma->vm_start + i * PAGE_2M_SIZE, PAGE_2M_SIZE, vma->vm_flags, vma->vm_ops, &new_vma);
+                // 防止内存泄露
+                if (unlikely(ret == -EEXIST))
+                    free_pages(Phy_to_2M_Page(pa), 1);
+                else
+                    mm_map_vma(new_vma, pa);
+
                 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;
             }
@@ -938,7 +953,15 @@ uint64_t process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb
         {
             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);
+
+            struct vm_area_struct *new_vma = NULL;
+            int ret = mm_create_vma(new_mms, vma->vm_start, map_size, vma->vm_flags, vma->vm_ops, &new_vma);
+            // 防止内存泄露
+            if (unlikely(ret == -EEXIST))
+                kfree((void *)va);
+            else
+                mm_map_vma(new_vma, virt_2_phys(va));
+
             memcpy((void *)va, (void *)vma->vm_start, vma_size);
         }
         vma = vma->vm_next;

+ 4 - 143
kernel/process/process.h

@@ -17,114 +17,8 @@
 #include <filesystem/VFS/VFS.h>
 #include <common/wait_queue.h>
 #include <mm/mm-types.h>
-
-// 进程最大可拥有的文件描述符数量
-#define PROC_MAX_FD_NUM 16
-
-// 进程的内核栈大小 32K
-#define STACK_SIZE 32768
-
-// 进程的运行状态
-// 正在运行
-#define PROC_RUNNING (1 << 0)
-// 可被中断
-#define PROC_INTERRUPTIBLE (1 << 1)
-// 不可被中断
-#define PROC_UNINTERRUPTIBLE (1 << 2)
-// 挂起
-#define PROC_ZOMBIE (1 << 3)
-// 已停止
-#define PROC_STOPPED (1 << 4)
-
-// 内核代码段基地址
-#define KERNEL_CS (0x08)
-// 内核数据段基地址
-#define KERNEL_DS (0x10)
-// 用户代码段基地址
-#define USER_CS (0x28)
-// 用户数据段基地址
-#define USER_DS (0x30)
-
-// 进程初始化时的数据拷贝标志位
-#define CLONE_FS (1 << 0) // 在进程间共享打开的文件
-#define CLONE_SIGNAL (1 << 1)
-#define CLONE_VM (1 << 2) // 在进程间共享虚拟内存空间
-
-struct thread_struct
-{
-	// 内核层栈基指针
-	ul rbp; // in tss rsp0
-	// 内核层代码指针
-	ul rip;
-	// 内核层栈指针
-	ul rsp;
-
-	ul fs, gs;
-
-	ul cr2;
-	// 异常号
-	ul trap_num;
-	// 错误码
-	ul err_code;
-};
-
-// ========= pcb->flags =========
-// 进程标志位
-#define PF_KTHREAD (1UL << 0)	 // 内核线程
-#define PF_NEED_SCHED (1UL << 1) // 进程需要被调度
-#define PF_VFORK (1UL << 2)		 // 标志进程是否由于vfork而存在资源共享
-#define PF_KFORK (1UL << 3)		 // 标志在内核态下调用fork(临时标记,do_fork()结束后会将其复位)
-
-/**
- * @brief 进程控制块
- *
- */
-struct process_control_block
-{
-	// 进程的状态
-	volatile long state;
-	// 进程标志:进程、线程、内核线程
-	unsigned long flags;
-	int64_t preempt_count; // 持有的自旋锁的数量
-	long signal;
-	long cpu_id; // 当前进程在哪个CPU核心上运行
-	// 内存空间分布结构体, 记录内存页表和程序段信息
-	struct mm_struct *mm;
-
-	// 进程切换时保存的状态信息
-	struct thread_struct *thread;
-
-	// 连接各个pcb的双向链表
-	struct List list;
-
-	// 地址空间范围
-	// 用户空间: 0x0000 0000 0000 0000 ~ 0x0000 7fff ffff ffff
-	// 内核空间: 0xffff 8000 0000 0000 ~ 0xffff ffff ffff ffff
-	uint64_t addr_limit;
-
-	long pid;
-	long priority;			 // 优先级
-	int64_t virtual_runtime; // 虚拟运行时间
-
-	// 进程拥有的文件描述符的指针数组
-	// todo: 改用动态指针数组
-	struct vfs_file_t *fds[PROC_MAX_FD_NUM];
-
-	// 链表中的下一个pcb
-	struct process_control_block *next_pcb;
-	// 父进程的pcb
-	struct process_control_block *parent_pcb;
-
-	int32_t exit_code;						// 进程退出时的返回码
-	wait_queue_node_t wait_child_proc_exit; // 子进程退出等待队列
-};
-
-// 将进程的pcb和内核栈融合到一起,8字节对齐
-union proc_union
-{
-	struct process_control_block pcb;
-	ul stack[STACK_SIZE / sizeof(ul)];
-} __attribute__((aligned(8)));
+#include <arch/x86_64/current.h>
+#include "proc-types.h"
 
 // 设置初始进程的PCB
 #define INITIAL_PROC(proc)                \
@@ -151,25 +45,7 @@ union proc_union
  * @brief 任务状态段结构体
  *
  */
-struct tss_struct
-{
-	unsigned int reserved0;
-	ul rsp0;
-	ul rsp1;
-	ul rsp2;
-	ul reserved1;
-	ul ist1;
-	ul ist2;
-	ul ist3;
-	ul ist4;
-	ul ist5;
-	ul ist6;
-	ul ist7;
-	ul reserved2;
-	unsigned short reserved3;
-	// io位图基地址
-	unsigned short io_map_base_addr;
-} __attribute__((packed)); // 使用packed表明是紧凑结构,编译器不会对成员变量进行字节对齐。
+
 
 // 设置初始进程的tss
 #define INITIAL_TSS                                                       \
@@ -191,22 +67,7 @@ struct tss_struct
 		.io_map_base_addr = 0                                             \
 	}
 
-#pragma GCC push_options
-#pragma GCC optimize("O0")
-// 获取当前的pcb
-struct process_control_block *get_current_pcb()
-{
-	struct process_control_block *current = NULL;
-	// 利用了当前pcb和栈空间总大小为32k大小对齐,将rsp低15位清空,即可获得pcb的起始地址
-	barrier();
-	__asm__ __volatile__("andq %%rsp, %0   \n\t"
-						 : "=r"(current)
-						 : "0"(~32767UL));
-	barrier();
-	return current;
-};
-#pragma GCC pop_options
-#define current_pcb get_current_pcb()
+
 
 #define GET_CURRENT_PCB    \
 	"movq %rsp, %rbx \n\t" \