第一个任务就是加速系统调用,具体点讲就是,用户空间和内核共享一块只读数据,这样,用户在一些特定的系统调用上就不需要进内核态,从而减少了开销。
然后这个任务是的流程如下:
首先是在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<