diff --git a/kernel/proc.c b/kernel/proc.c index 130d9ce..5abb747 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -123,14 +123,20 @@ allocproc(void) found: p->pid = allocpid(); - p->state = USED; // Allocate a trapframe page. if((p->trapframe = (struct trapframe *)kalloc()) == 0){ + release(&p->lock); + return 0; + } + + // Allocate a usyscall page. + if((p->usyscall = (struct usyscall *)kalloc()) == 0){ freeproc(p); release(&p->lock); return 0; } + p->usyscall->pid = p->pid ; // An empty user page table. p->pagetable = proc_pagetable(p); @@ -155,6 +161,9 @@ found: static void freeproc(struct proc *p) { + if (p->usyscall) { + kfree((void*)p->usyscall); + } if(p->trapframe) kfree((void*)p->trapframe); p->trapframe = 0; @@ -202,6 +211,16 @@ proc_pagetable(struct proc *p) return 0; } + // map the usyscall just below TRAMPOFRAME, for trampoline.S. + // 这个页需要设置PTE_U为,使得用户态可以访问 + if(mappages(pagetable, USYSCALL, PGSIZE, + (uint64)(p->usyscall), PTE_R | PTE_U) < 0){ + uvmunmap(pagetable, TRAPFRAME, 1, 0); + uvmunmap(pagetable, TRAMPOLINE, 1, 0); + uvmfree(pagetable, 0); + return 0; + } + return pagetable; } @@ -210,6 +229,7 @@ proc_pagetable(struct proc *p) void proc_freepagetable(pagetable_t pagetable, uint64 sz) { + uvmunmap(pagetable, USYSCALL, 1, 0); uvmunmap(pagetable, TRAMPOLINE, 1, 0); uvmunmap(pagetable, TRAPFRAME, 1, 0); uvmfree(pagetable, sz); diff --git a/kernel/proc.h b/kernel/proc.h index d021857..0af737d 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -94,11 +94,12 @@ struct proc { // wait_lock must be held when using this: struct proc *parent; // Parent process - - // these are private to the process, so p->lock need not be held. + // these are private to the process, so p->lock need not be held. uint64 kstack; // Virtual address of kernel stack uint64 sz; // Size of process memory (bytes) pagetable_t pagetable; // User page table + // 进程的结构体中需要加上usyscall字段 + struct usyscall *usyscall; // data page for usyscall struct trapframe *trapframe; // data page for trampoline.S struct context context; // swtch() here to run process struct file *ofile[NOFILE]; // Open files diff --git a/kernel/riscv.h b/kernel/riscv.h index 6cfff1e..8bf202c 100644 --- a/kernel/riscv.h +++ b/kernel/riscv.h @@ -375,7 +375,9 @@ 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) // Accessed bit +#define PTE_D (1L << 7) // Dirty bit +#define PTE_PS (1L << 7) // Page Size bit in PTE (for 2MB superpages) #if defined(LAB_MMAP) || defined(LAB_PGTBL) diff --git a/kernel/syscall.c b/kernel/syscall.c index 4aea542..968fbc7 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -111,6 +111,7 @@ extern uint64 sys_recv(void); #ifdef LAB_PGTBL extern uint64 sys_pgpte(void); extern uint64 sys_kpgtbl(void); +extern uint64 sys_pgaccess(void); #endif // An array mapping syscall numbers from syscall.h @@ -146,6 +147,7 @@ static uint64 (*syscalls[])(void) = { #ifdef LAB_PGTBL [SYS_pgpte] sys_pgpte, [SYS_kpgtbl] sys_kpgtbl, +[SYS_pgaccess] sys_pgaccess, #endif }; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index d9b7f9c..2e3b7be 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -123,3 +123,41 @@ sys_uptime(void) release(&tickslock); return xticks; } + +uint64 +sys_pgaccess(void) +{ + uint64 va; + int n; + uint64 user_mask_addr; + argaddr(0, &va); + argint(1, &n); + argaddr(2, &user_mask_addr); + if (va < 0 || n < 0 || user_mask_addr < 0) + return -1; + + if (n < 0 || n > 32) + return -1; + + struct proc *p = myproc(); + uint64 mask = 0; + + for (int i = 0; i < n; i++) { + uint64 v = va + i * PGSIZE; + pte_t *pte = walk(p->pagetable, v, 0); + + if (!pte || (*pte & PTE_PS)) + continue; + + if ((*pte & PTE_V) && (*pte & PTE_A)) { + mask |= (1 << i); // Set bit i in mask + *pte &= ~PTE_A; // Clear the Accessed bit + } + } + + if (copyout(p->pagetable, user_mask_addr, (char*)&mask, sizeof(mask)) < 0) + return -1; + + return 0; +} + diff --git a/kernel/vm.c b/kernel/vm.c index 7f388fe..1e9a6d8 100644 --- a/kernel/vm.c +++ b/kernel/vm.c @@ -101,6 +101,9 @@ walk(pagetable_t pagetable, uint64 va, int alloc) for(int level = 2; level > 0; level--) { pte_t *pte = &pagetable[PX(level, va)]; if(*pte & PTE_V) { + if (*pte & PTE_PS) { // 如果是 Superpage + return pte; + } pagetable = (pagetable_t)PTE2PA(*pte); #ifdef LAB_PGTBL if(PTE_LEAF(*pte)) {