【MIT6.S081】Lab3 page tables(下)
本关的任务为“Detect which pages have been accessed”,需要实现一个新的系统调用pgaccess
,它指出访问了哪些页面被访问了(读、写等)。系统调用需要三个参数:
- 第一个用户页面的起始虚拟地址
- 需要检查页数
- 一个存储每一页是否被访问的掩码
该lab的所有代码:Github
测试该系统调用的函数位于user/pgtbltest.c:pgaccess_test()
中:
1 | void |
分析下源码可以知道,测试程序分配了32个页,并且使用(or 访问)了这分配的32个页的第1、2、30页,之后程序调用pgaccess
来检测abits的第1、2、30位是否为1,即判断该系统调用是否实现了“检测已经访问的页”这个功能。
向内核添加系统调用的方法在lab2中已经了解过了,不过这里xv6已经帮我们添加好了,我们只需要实现系统调用kernel/sysproc.c:sys_pgaccess()
即可。
在xv6 book中可以知道一个PTE的每位构成如上图,其中0 - 9
位是一些标志位,第6位为Accessed
,也就是访问位,需要在内核中添加这个标志:
1 | // kernel/riscv.h |
而risc-v处理器会利用硬件将已访问的页的PTE_A
正确设置。
实现sys_pgaccess
的步骤大致可分为:
- 接受用户态传递的三个参数:
- 第一个用户页面的起始虚拟地址(指针)
- 需要检查页数(int)
- 一个存储每一页是否被访问的掩码(指针)
- 遍历“需要检查页数”,并每次检查遍历的页是否已访问。获取每个页对应的PTE将使用
walk
函数来获取,而检查将使用PTE_A
来判断;如果当前页的PTE_A
为1,则说明该页被访问过,利用位运算(是的,位运算在该lab里立大功)来存储信息,即第几页被访问了,并且不要忘记了实验指导中的提示,“Be sure to clear PTE_A after checking if it is set. Otherwise, it won’t be possible to determine if the page was accessed since the last time pgaccess() was called”,检测完后应该将PTE_A
标记位清除。 - 将存储的信息利用
copyout
函数从内核态传递给用户态,届时用户态可通过第三个参数获取。
具体实现如下:
1 | int |