Lab pgtbl
Speed up system calls
@@ -132,6 +132,13 @@ found:
return 0;
}
+ // Allocate a usyscall page.
+ if ((p->usyscall = (struct usyscall *)kalloc()) == 0) {
+ freeproc(p);
+ release(&p->lock);
+ return 0;
+ }
+
// An empty user page table.
p->pagetable = proc_pagetable(p);
if(p->pagetable == 0){
@@ -145,6 +152,7 @@ found:
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
+ p->usyscall->pid = p->pid;
return p;
}
@@ -155,6 +163,9 @@ found:
static void
freeproc(struct proc *p)
{
+ if (p->usyscall)
+ kfree((void*)p->usyscall);
+ p->usyscall = 0;
if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
@@ -202,6 +213,15 @@ proc_pagetable(struct proc *p)
return 0;
}
+ // map the usyscall page just below the trapframe page
+ 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 +230,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);
@@ -100,6 +100,7 @@ struct proc {
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
+ struct usyscall *usyscall; // data page for usyscall
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
Print a page table
@@ -173,6 +173,7 @@ uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t, char *, uint64, uint64);
+void vmprint(pagetable_t);
// plic.c
void plicinit(void);
@@ -128,6 +128,8 @@ exec(char *path, char **argv)
p->trapframe->sp = sp; // initial stack pointer
proc_freepagetable(oldpagetable, oldsz);
+ if (p->pid == 1)
+ vmprint(p->pagetable);
return argc; // this ends up in a0, the first argument to main(argc, argv)
bad:
@@ -437,3 +437,37 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
return -1;
}
}
+
+void
+printpte(pte_t pte, int index, int level)
+{
+ for (int i = level; i >= 0; i--)
+ printf(" ..");
+ printf("%d: pte %p pa %p\n", index, pte, PTE2PA(pte));
+}
+
+void
+_vmprint(pagetable_t pagetable, int level)
+{
+ for (int i = 0; i < 512; i++) {
+ pte_t pte = pagetable[i];
+ if(pte & PTE_V) {
+ printpte(pte, i, level);
+ if ((pte & (PTE_R|PTE_W|PTE_X)) == 0) {
+ // this PTE points to a lower-level page table.
+ uint64 child = PTE2PA(pte);
+ _vmprint((pagetable_t)child, level + 1);
+ }
+ }
+ }
+}
+
+void
+vmprint(pagetable_t pagetable)
+{
+ printf("page table 0x%16x\n", (uint64)pagetable);
+ _vmprint(pagetable, 0);
+}
Detect which pages have been accessed
@@ -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) // access bit
// shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
@@ -75,6 +75,34 @@ int
sys_pgaccess(void)
{
// lab pgtbl: your code here.
+ uint64 va, addr;
+ int size;
+
+ argaddr(0, &va);
+ argint(1, &size);
+ argaddr(2, &addr);
+
+ struct proc *proc = myproc();
+ pagetable_t pagetable = proc->pagetable;
+ uint64 a, last;
+ pte_t *pte;
+ unsigned int abits = 0;
+
+ if(size == 0)
+ panic("pgaccess: size");
+
+ a = PGROUNDDOWN(va);
+ last = PGROUNDDOWN(va + size * PGSIZE - 1);
+ last = last > MAXVA ? MAXVA : last;
+ for (unsigned i = 0; i < 32 && a <= last; i++, a += PGSIZE) {
+ if((pte = walk(pagetable, a, 0)) == 0)
+ continue;
+ if(*pte & PTE_A) {
+ abits |= (1 << i);
+ *pte &= ~PTE_A;
+ }
+ }
+
+ copyout(pagetable, addr, (char *)&abits, sizeof(abits));
return 0;
}
#endif