]> Zhao Yanbai Git Server - kernel.git/commitdiff
重写了fork拷贝页目录逻辑和页写保护逻辑
authoracevest <zhaoyanbai@126.com>
Fri, 19 May 2023 16:36:37 +0000 (00:36 +0800)
committeracevest <zhaoyanbai@126.com>
Fri, 19 May 2023 16:36:37 +0000 (00:36 +0800)
include/page.h
kernel/fork.c
mm/page.c

index afa35e1b504f6282cd725d5f153b10fedbfe02ad..e13173a632382b15311571458abc11d0754e3c66 100644 (file)
@@ -36,7 +36,8 @@
 
 #define PAGE_SHIFT (12)
 #define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PAGE_MASK (~((1UL << PAGE_SHIFT) - 1))
+#define PAGE_FLAG_MASK ((1UL << PAGE_SHIFT) - 1)
+#define PAGE_MASK (~PAGE_FLAG_MASK)
 #define PAGE_OFFSET (0xC0000000)
 #define PAGE_PDE_CNT 1024
 #define PAGE_PTE_CNT 1024
index e7e4590f84953c201f91bc478cc8b612c5782ac8..057fcc94416986a1c7d838bb81f9ff86d4f73fd4 100644 (file)
@@ -51,6 +51,9 @@ int do_fork(pt_regs_t *regs, unsigned long flags) {
             continue;
         }
 
+#if 1
+        pde_dst[i] = pde_src[i] & (~PDE_RW);
+#else
         // 这里不用再为每个PDE拷贝一次PageTable,只需要拷贝PageDirectory并将其低于768的写权限去掉
         // 同时需要修改缺页异常doPageFault的逻辑
         if (PAGE_ALIGN(spde) != 0) {
@@ -77,6 +80,7 @@ int do_fork(pt_regs_t *regs, unsigned long flags) {
             page_t *page = pa2page(pte_src[j]);
             page->count++;
         }
+#endif
     }
 
     tsk->pid = get_next_pid();
index 6ac0e51b457c99d8d865d3c56ed044d95eddf27c..925580b94205c764b5367cfb05719517d45a8ce8 100644 (file)
--- a/mm/page.c
+++ b/mm/page.c
@@ -51,6 +51,58 @@ void do_wp_page(void *addr) {
     int npde = get_npde(addr);
     int npte = get_npte(addr);
 
+    pde_t *page_dir = (pde_t *)pa2va(current->cr3);
+    pde_t *pde = page_dir + npde;
+
+    // 如果是因为PDE被写保护
+    if (*pde & PDE_RW == 0) {
+        // 1. 分配一个页表
+        unsigned long newtbl = alloc_one_page(0);
+        assert(newtbl != 0);
+
+        // 2. 拷贝页表
+        pte_t *oldtbl = pa2va(PAGE_ALIGN(page_dir[npde]));
+        memcpy((void *)newtbl, (void *)oldtbl, PAGE_SIZE);
+
+        // 3. 对所有PTE加上写保护
+        pte_t *pte = (pte_t *)newtbl;
+        for (int i = 0; i < PTECNT_PER_PAGE; i++) {
+            *pte &= ~PTE_RW;
+            pte++;
+        }
+
+        // 4. 记下原PDE的权限
+        unsigned long flags = PAGE_FLAGS(*pde);
+
+        // 5. 设置新的PDE
+        *pde = va2pa(newtbl);
+        *pde |= flags;
+
+        // 6. 解除PDE的写保护
+        *pde |= PDE_RW;
+    }
+
+    pte_t *page_tbl = pa2va(PAGE_ALIGN(page_dir[npde]));
+    pte_t *pte = page_tbl + npte;
+
+    // 如果PTE的位置被写保护
+    if (*pte & PTE_RW == 0) {
+        // 1. 分配一个页表
+        unsigned long newaddr = alloc_one_page(0);
+        assert(newaddr != 0);
+
+        // 2. 拷贝页表
+        pte_t *oldaddr = pa2va(PAGE_ALIGN(page_dir[npde]));
+        memcpy((void *)newaddr, (void *)oldaddr, PAGE_SIZE);
+
+        // 3. 解除PTE的写保护
+        *pte |= PTE_RW;
+    }
+
+#if 0
+    int npde = get_npde(addr);
+    int npte = get_npte(addr);
+
     pde_t *page_dir = (pde_t *)pa2va(current->cr3);
     pte_t *page_tbl = pa2va(PAGE_ALIGN(page_dir[npde]));
 
@@ -70,6 +122,7 @@ void do_wp_page(void *addr) {
     }
 
     page_tbl[npte] |= PAGE_WR;
+#endif
 #if 0
     page_tbl[npte] |= PAGE_US;
     page_dir[npde] |= PAGE_WR;