OS Lab2 实验报告
实现功能
首先重新实现 sys_gettimeofday
和 sys_task_info
,用户传的指针是用户页表中的虚拟地址,内核使用 copyout
接口向用户给定虚拟地址写入数据。
然后在 syscall.c
中增加了 sys_mmap
和 sys_munmap
两个系统调用,sys_mmap
的核心是调用 kalloc
申请匿名物理内存并使用 mappages
映射到由 start
开始的某一段虚存,sys_munmap
中核心则是调用 uvmunmap
取消虚存映射。
问答题
第 1 题:SV39 页表项
SV39 页表项组成如下所示:
1 | 63 54 53 10 9 8 7 6 5 4 3 2 1 0 |
最高 10 位为保留位,中间 44 位为物理页号 PPN(非叶子节点即指向下一级页表起始位置的物理页号),最低 10 位为标志位。标志位有以下作用:
- V:有效位,表示页表项是否有效。
- R, W, X:对叶节点页表项,这些位分别表示页面是否可读、可写和可执行;对非叶节点页表项,三个位均为 0(且 V 位为 1)表示是合法页目录表项,指向页面表的下一级。
- U:用户位,表示对应虚拟页面是否可在用户态下访问。
- G:全局位,表示对应的页面是否是全局的,若是全局的在进程切换时不必刷新该页的 TLB 缓存。对于非叶结点页表项,全局设置意味着页表后续级别中的所有映射都是全局的。
- A:访问位,表示对应的页面是否被访问过,为页面置换算法提供信息。
- D:脏位,表示对应的页面是否被修改过,若修改过换出内存页时需要写回磁盘。
- RSW:为内核程序预留,硬件不会对此做任何其他操作。
第 2 题:缺页
- 请问哪些异常可能是缺页导致的?
常见因缺页引起异常的场景包括:- 地址空间映射关系未建立:用户进程访问未经物理内存映射(未向操作系统申请)的虚拟地址;或申请的虚拟地址尚未分配实际的物理页面(lazy策略),在首次访问时会触发缺页异常;
- 地址空间映射关系已建立,但访问的页面被交换(swap)到磁盘,不在内存中;
- 访问的地址空间不合法(如用户态访问内核地址空间),或访问页面的执行权限不够(如修改只读页面)。
- 发生缺页时,描述相关的重要寄存器的值。
sscratch
中是发生缺页进程的 trapframe 地址,satp
中是发生缺页进程的页表根地址,sepc
中是发生缺页异常的指令地址,mcause
中 Interrupt 位是 0(表示异常),Exception Code 是 12、13 或 15。 - Lazy 策略有哪些好处?
有助于节省物理空间,减少不必要的页表操作。 - 请问处理 10G 连续的内存页面,需要操作的页表实际大致占用多少内存(给出数量级即可)?
一个叶子节点页表项可映射 4KB 物理内存,一个物理页面包含 512 个页表项,可映射 2MB 内存,则处理 10G 连续页面需要三级页表 10G / 2M = 5K 个;这 5K 个连续三级页表对应二级页表个数大约为 5K / 512 = 10 << 5K,故在数量级上可忽略一级二级页表占用的内存。由此估计,所需的页表大致内存为 5K * 4KB = 20MB。 - 请简单思考如何才能在现有框架基础上实现 Lazy 策略,缺页时又如何处理?描述合理即可,不需要考虑实现。
为每个用户进程分配一张表,记录其申请的虚拟内存地址,在申请时仅在表上记录,暂时不映射到真实物理内存;当发生缺页时,首先查找该表判断是否访问的地址是否已经申请过,若已经申请过则将该地址从表上移出,并分配一段与访问空间大小相应的物理内存,修改页表建立映射,然后返回缺页异常的指令继续执行。 - 内存页面可能被换到磁盘上了,导致对应页面失效。此时页面失效如何表现在页表项(PTE)上?
对应叶子节点 PTE 的 V 位(有效位)为 0,但 R/W/X 位不全为 0。
第 3 题:单页表和双页表
- 单页表情况下,如何更换页表?
同样通过csrw
修改satp
寄存器,并使用sfence.vma zero, zero
刷新 TLB 实现更换。 - 单页表情况下,如何控制用户态无法访问内核页面?
将内核页面对应的页表项 U 位置 0。 - 单页表有何优势?
只需在进程切换时更换页表、刷新 TLB,在同一进程的用户态和内核态之间切换时(如异常处理、系统调用)不用更换页表和刷新 TLB,减少时间开销,提升程序效率。 - 双页表实现下,何时需要更换页表?假设你写一个单页表操作系统,你会选择何时更换页表?
进程切换和用户态、内核态之间的切换都要更换页表。可以选择在进程调度时更换页表。