From: acevest Date: Fri, 19 May 2023 16:36:37 +0000 (+0800) Subject: 重写了fork拷贝页目录逻辑和页写保护逻辑 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch07.html?a=commitdiff_plain;h=fb359b05ea7758dc16afaaa1107676f7d2ebbdc5;p=kernel.git 重写了fork拷贝页目录逻辑和页写保护逻辑 --- diff --git a/include/page.h b/include/page.h index afa35e1..e13173a 100644 --- a/include/page.h +++ b/include/page.h @@ -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 diff --git a/kernel/fork.c b/kernel/fork.c index e7e4590..057fcc9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -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(); diff --git a/mm/page.c b/mm/page.c index 6ac0e51..925580b 100644 --- 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;