• 2021 XV6 3:页表


    1.speed up system calls

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

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

    首先是在proc的数据结构里边多加一个usyscall结构体的指针:

    1. struct usyscall {
    2. int pid; // Process ID
    3. };
    1. struct proc {
    2. struct usyscall *usc;
    3. ...
    4. }

    有了这个指针,我们就可以在proc.c的proc_pagetable()函数中申请一个新的页大小来存储这个结构体。这里有两个要注意的点:

    标志位要带上用户可用和读两个标志。

    如果分配页失败了,要用uvmunmap()把之前的页面映射给删了,这里没有释放物理页,后边freeproc删除了具体的物理页。然后用freewalk把页表给删了。

    具体修改如下:

    1. // 分配一个页用于存储pid
    2. if(mappages(pagetable, USYSCALL, PGSIZE,
    3. (uint64)(p->usc), PTE_R | PTE_U) < 0){
    4. uvmunmap(pagetable, TRAMPOLINE, 1, 0);
    5. uvmunmap(pagetable, TRAPFRAME, 1, 0);
    6. uvmfree(pagetable, 0);
    7. return 0;
    8. }

    在这一步之前的allocproc里边是分配了一页物理地址的:

    1. if((p->usc = (struct usyscall *)kalloc()) == 0){
    2. freeproc(p);
    3. release(&p->lock);
    4. return 0;
    5. }

    最后在freeproc的时候还要记得把这个物理页给释放掉:

    1. if(p->usc)
    2. kfree((void*)p->usc);
    3. p->usc=0;

    2.Print a page table

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

    1. void vmprintRecursive(pagetable_t pagetable, int level)
    2. {
    3. if (level > 3)
    4. {
    5. return;
    6. }
    7. for (int i = 0; i < 512; i++)
    8. {
    9. pte_t pte = pagetable[i];
    10. if (pte & PTE_V)
    11. {
    12. for (int k = 0; k < level; k++)
    13. {
    14. printf(" ..");
    15. }
    16. uint64 pa = PTE2PA(pte);
    17. printf("%d: pte %p pa %p\n", i, pte, pa);
    18. vmprintRecursive((pagetable_t)pa, level+1);
    19. }
    20. }
    21. }
    22. void vmprint(pagetable_t pagetable)
    23. {
    24. printf("page table %p\n", pagetable);
    25. vmprintRecursive(pagetable, 1);
    26. }

    3.Detecting which pages have been accessed

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

    输入三个参数:

    1.虚拟地址

    2.统计页面数

    3.用户地址

    我们知道,在xv6里边有几个函数可以帮助我们取用户传进来的参数,这里我们用argint和argaddr就行,分别用来取int和uint64的地址。然后我们就可以自己实现一个函数来写mask标记这里边的页哪些是被访问过的,访问过的页要清空PTE_A,这样就确保了下次访问PTE_A的标志位一定是在最近用完这个系统调用之后的。

    这个实现如下所示:

    1. int
    2. sys_pgaccess(void)
    3. {
    4. int va,sz;
    5. uint64 u_addr;
    6. if(argint(0, &va) < 0)
    7. return -1;
    8. if(argint(1, &sz) < 0)
    9. return -1;
    10. if(argaddr(2, &u_addr) < 0)
    11. return -1;
    12. struct proc *p=myproc();
    13. if (pgaccess(p->pagetable,va,sz,u_addr)<0)
    14. {
    15. return -1;
    16. }
    17. return 0;
    18. }
    19. // 检测虚拟地址va开始的size大小的页面的PTE_A是否为1 并且设置mask位
    20. // 清空为PTE_A为1的页表项 保证下次是1的是access的页面
    21. uint64 pgaccess(pagetable_t pagetable, uint64 va, uint64 pagenum, uint64 u_addr)
    22. {
    23. // 限定最长页数不超过64页
    24. if (pagenum > 64)
    25. {
    26. return -1;
    27. }
    28. // if (va%PGSIZE)
    29. // {
    30. // return -1;
    31. // }
    32. uint64 start,mask,v_va;
    33. mask=0;
    34. v_va=va;
    35. for (int i = 0; i < pagenum; i++)
    36. {
    37. start = PGROUNDDOWN(v_va);
    38. pte_t *p=walk(pagetable,start,0);
    39. if (p==0)
    40. {
    41. return -1;
    42. }
    43. if (PTE_A & *p)
    44. {
    45. mask |= 1<
    46. *p &= ~PTE_A;//清空对应access位置
    47. }
    48. v_va += PGSIZE;
    49. }
    50. copyout(pagetable,u_addr,(char *)&mask,sizeof(mask));
    51. return pagenum;
    52. }

  • 相关阅读:
    Python开源项目周排行 2023年第35周
    腾讯云大数据ES Serverless
    竞赛选题 基于机器学习与大数据的糖尿病预测
    1043 输出PATest
    ts流中的时间概念: pcr,pts,dts 实例解说
    TI单芯片毫米波雷达代码走读(二十七)—— 角度维(3D)处理之通道间幅相一致性补偿
    java计算机毕业设计家政服务网站源程序+mysql+系统+lw文档+远程调试
    `sh -c`命令——解决命令权限问题、一条命令中执行多个指令
    切换OpenJDK引发的惨案
    Deno 下一代JavaScript运行时
  • 原文地址:https://blog.csdn.net/weixin_46266058/article/details/127777175