2021 XV6 3:页表

1.speed up system calls

第一个任务就是加速系统调用,具体点讲就是,用户空间和内核共享一块只读数据,这样,用户在一些特定的系统调用上就不需要进内核态,从而减少了开销。

然后这个任务是的流程如下:

首先是在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;

2.Print a page table

这个就是很简单的一个实现了,递归一下就好了,具体实现如下:

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);
}

3.Detecting which pages have been accessed

这个任务三是要实现一个统计页表是否被访问过的系统调用。

输入三个参数:

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<<i;
      *p &= ~PTE_A;//清空对应access位置
    }
    v_va += PGSIZE;
  }
  copyout(pagetable,u_addr,(char *)&mask,sizeof(mask));
  
  return pagenum;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值