As Figure 3.2 shows, a RISC-V CPU translates a virtual address into a physical in three steps. A page table is stored in physical memory as a three-level tree. The root of the tree is a 4096-byte page-table page that contains 512 PTEs, which contain the physical addresses for page-table pages in the next level of the tree. Each of those pages contains 512 PTEs for the final level in the tree. The paging hardware uses the top 9 bits of the 27 bits to select a PTE in the root page-table page, the middle 9 bits to select a PTE in a page-table page in the next level of the tree, and the bottom 9 bits to select the final PTE. (In Sv48 RISC-V a page table has four levels, and bits 39 through 47 of a virtual address index into the top-level.)
diff --git a/kernel/riscv.h b/kernel/riscv.h index 20a01db..100895e 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -343,6 +343,7 @@ typedef uint64 *pagetable_t; // 512 PTEs #define PTE_W (1L << 2) #define PTE_X (1L << 3) #define PTE_U (1L << 4) // user can access +#define PTE_A (1L << 6) // shift a physical address to the right place for a PTE. #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 88644b2..296935f 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -71,11 +71,36 @@ sys_sleep(void) #ifdef LAB_PGTBL -int -sys_pgaccess(void) -{ - // lab pgtbl: your code here. - return 0; +int sys_pgaccess(void) { + + uint64 baseaddr; + int upper; + uint64 outaddr; + + uint64 va; + pte_t *pte; + uint64 abits = 0; + + argaddr(0, &baseaddr); + argint(1, &upper); + argaddr(2, &outaddr); + + struct proc *p = myproc(); + + for (int i = 0; i < upper; i++) { + va = baseaddr + i * PGSIZE; + pte = walk(p->pagetable, va, 0); + + if (*pte & PTE_A) { + abits = abits | (1 << i); // set bit + *pte = (*pte) & (~PTE_A); // reset PTE_A + } + } + + if (copyout(p->pagetable, outaddr, (char *)&abits, sizeof(abits)) < 0) + return -1; + + return 0; } #endif
测试结果
最后,make grade 查看结果,
== Test pgtbltest == $ make qemu-gdb (3.8s) == Test pgtbltest: ugetpid == pgtbltest: ugetpid: OK == Test pgtbltest: pgaccess == pgtbltest: pgaccess: OK == Test pte printout == $ make qemu-gdb pte printout: OK (0.7s) == Test answers-pgtbl.txt == answers-pgtbl.txt: OK == Test usertests == $ make qemu-gdb (141.1s) == Test usertests: all tests == usertests: all tests: OK == Test time == time: OK Score: 46/46