第一个任务就是加速系统调用,具体点讲就是,用户空间和内核共享一块只读数据,这样,用户在一些特定的系统调用上就不需要进内核态,从而减少了开销。
然后这个任务是的流程如下:
首先是在proc的数据结构里边多加一个usyscall结构体的指针:
- struct usyscall {
- int pid; // Process ID
- };
- struct proc {
- struct usyscall *usc;
- ...
- }
有了这个指针,我们就可以在proc.c的proc_pagetable()函数中申请一个新的页大小来存储这个结构体。这里有两个要注意的点:
标志位要带上用户可用和读两个标志。
如果分配页失败了,要用uvmunmap()把之前的页面映射给删了,这里没有释放物理页,后边freeproc删除了具体的物理页。然后用freewalk把页表给删了。
具体修改如下:
- // 分配一个页用于存储pid
- if(mappages(pagetable, USYSCALL, PGSIZE,
- (uint64)(p->usc), PTE_R | PTE_U) < 0){
- uvmunmap(pagetable, TRAMPOLINE, 1, 0);
- uvmunmap(pagetable, TRAPFRAME, 1, 0);
- uvmfree(pagetable, 0);
- return 0;
- }
在这一步之前的allocproc里边是分配了一页物理地址的:
- if((p->usc = (struct usyscall *)kalloc()) == 0){
- freeproc(p);
- release(&p->lock);
- return 0;
- }
最后在freeproc的时候还要记得把这个物理页给释放掉:
- if(p->usc)
- kfree((void*)p->usc);
- p->usc=0;
这个就是很简单的一个实现了,递归一下就好了,具体实现如下:
- void vmprintRecursive(pagetable_t pagetable, int level)
- {
- if (level > 3)
- {
- return;
- }
- for (int i = 0; i < 512; i++)
- {
- pte_t pte = pagetable[i];
- if (pte & PTE_V)
- {
- for (int k = 0; k < level; k++)
- {
- printf(" ..");
- }
- uint64 pa = PTE2PA(pte);
- printf("%d: pte %p pa %p\n", i, pte, pa);
- vmprintRecursive((pagetable_t)pa, level+1);
- }
- }
- }
-
- void vmprint(pagetable_t pagetable)
- {
- printf("page table %p\n", pagetable);
- vmprintRecursive(pagetable, 1);
- }
这个任务三是要实现一个统计页表是否被访问过的系统调用。
输入三个参数:
1.虚拟地址
2.统计页面数
3.用户地址
我们知道,在xv6里边有几个函数可以帮助我们取用户传进来的参数,这里我们用argint和argaddr就行,分别用来取int和uint64的地址。然后我们就可以自己实现一个函数来写mask标记这里边的页哪些是被访问过的,访问过的页要清空PTE_A,这样就确保了下次访问PTE_A的标志位一定是在最近用完这个系统调用之后的。
这个实现如下所示:
- int
- sys_pgaccess(void)
- {
- int va,sz;
- uint64 u_addr;
-
- if(argint(0, &va) < 0)
- return -1;
- if(argint(1, &sz) < 0)
- return -1;
- if(argaddr(2, &u_addr) < 0)
- return -1;
-
- struct proc *p=myproc();
- if (pgaccess(p->pagetable,va,sz,u_addr)<0)
- {
- return -1;
- }
-
- return 0;
- }
-
- // 检测虚拟地址va开始的size大小的页面的PTE_A是否为1 并且设置mask位
- // 清空为PTE_A为1的页表项 保证下次是1的是access的页面
- uint64 pgaccess(pagetable_t pagetable, uint64 va, uint64 pagenum, uint64 u_addr)
- {
- // 限定最长页数不超过64页
- if (pagenum > 64)
- {
- return -1;
- }
- // if (va%PGSIZE)
- // {
- // return -1;
- // }
-
- uint64 start,mask,v_va;
- mask=0;
- v_va=va;
- for (int i = 0; i < pagenum; i++)
- {
- start = PGROUNDDOWN(v_va);
- pte_t *p=walk(pagetable,start,0);
- if (p==0)
- {
- return -1;
- }
- if (PTE_A & *p)
- {
- mask |= 1<
- *p &= ~PTE_A;//清空对应access位置
- }
- v_va += PGSIZE;
- }
- copyout(pagetable,u_addr,(char *)&mask,sizeof(mask));
-
- return pagenum;
- }