chapter4练习 ============================================ 编程作业 --------------------------------------------- 重写 sys_get_time 和 sys_task_info ++++++++++++++++++++++++++++++++++++++++++++ 引入虚存机制后,原来内核的 sys_get_time 和 sys_task_info 函数实现就无效了。请你重写这个函数,恢复其正常功能。 mmap 和 munmap 匿名映射 ++++++++++++++++++++++++++++++++++++++++++++ `mmap `_ 在 Linux 中主要用于在内存中映射文件, 本次实验简化它的功能,仅用于申请内存。 请实现 mmap 和 munmap 系统调用,mmap 定义如下: .. code-block:: rust fn sys_mmap(start: usize, len: usize, port: usize) -> isize - syscall ID:222 - 申请长度为 len 字节的物理内存(不要求实际物理内存位置,可以随便找一块),将其映射到 start 开始的虚存,内存页属性为 port - 参数: - start 需要映射的虚存起始地址,要求按页对齐 - len 映射字节长度,可以为 0 - port:第 0 位表示是否可读,第 1 位表示是否可写,第 2 位表示是否可执行。其他位无效且必须为 0 - 返回值:执行成功则返回 0,错误返回 -1 - 说明: - 为了简单,目标虚存区间要求按页对齐,len 可直接按页向上取整,不考虑分配失败时的页回收。 - 可能的错误: - start 没有按页大小对齐 - port & !0x7 != 0 (port 其余位必须为0) - port & 0x7 = 0 (这样的内存无意义) - [start, start + len) 中存在已经被映射的页 - 物理内存不足 munmap 定义如下: .. code-block:: rust fn sys_munmap(start: usize, len: usize) -> isize - syscall ID:215 - 取消到 [start, start + len) 虚存的映射 - 参数和返回值请参考 mmap - 说明: - 为了简单,参数错误时不考虑内存的恢复和回收。 - 可能的错误: - [start, start + len) 中存在未被映射的虚存。 tips: - 一定要注意 mmap 是的页表项,注意 riscv 页表项的格式与 port 的区别。 - 你增加 PTE_U 了吗? 实验要求 ++++++++++++++++++++++++++++++++++++++++++ - 实现分支:ch4。 - 实现 mmap 和 munmap 两个系统调用,通过所有测例。 - 实验目录请参考 ch3,报告命名 lab2.md/pdf TIPS:注意 port 参数的语义,它与内核定义的 MapPermission 有明显不同! 问答作业 ------------------------------------------------- 1. 请列举 SV39 页表页表项的组成,描述其中的标志位有何作用? 2. 缺页 缺页指的是进程访问页面时页面不在页表中或在页表中无效的现象,此时 MMU 将会返回一个中断, 告知 os 进程内存访问出了问题。os 选择填补页表并重新执行异常指令或者杀死进程。 - 请问哪些异常可能是缺页导致的? - 发生缺页时,描述相关重要寄存器的值,上次实验描述过的可以简略。 缺页有两个常见的原因,其一是 Lazy 策略,也就是直到内存页面被访问才实际进行页表操作。 比如,一个程序被执行时,进程的代码段理论上需要从磁盘加载到内存。但是 os 并不会马上这样做, 而是会保存 .text 段在磁盘的位置信息,在这些代码第一次被执行时才完成从磁盘的加载操作。 - 这样做有哪些好处? 其实,我们的 mmap 也可以采取 Lazy 策略,比如:一个用户进程先后申请了 10G 的内存空间, 然后用了其中 1M 就直接退出了。按照现在的做法,我们显然亏大了,进行了很多没有意义的页表操作。 - 处理 10G 连续的内存页面,对应的 SV39 页表大致占用多少内存 (估算数量级即可)? - 请简单思考如何才能实现 Lazy 策略,缺页时又如何处理?描述合理即可,不需要考虑实现。 缺页的另一个常见原因是 swap 策略,也就是内存页面可能被换到磁盘上了,导致对应页面失效。 - 此时页面失效如何表现在页表项(PTE)上? 3. 双页表与单页表 为了防范侧信道攻击,我们的 os 使用了双页表。但是传统的设计一直是单页表的,也就是说, 用户线程和对应的内核线程共用同一张页表,只不过内核对应的地址只允许在内核态访问。 (备注:这里的单/双的说法仅为自创的通俗说法,并无这个名词概念,详情见 `KPTI `_ ) - 在单页表情况下,如何更换页表? - 单页表情况下,如何控制用户态无法访问内核页面?(tips:看看上一题最后一问) - 单页表有何优势?(回答合理即可) - 双页表实现下,何时需要更换页表?假设你写一个单页表操作系统,你会选择何时更换页表(回答合理即可)? 报告要求 -------------------------------------------------------- - 简单总结你实现的功能(200字以内,不要贴代码)。 - 完成问答题。 - 加入 :doc:`/honorcode` 的内容。否则,你的提交将视作无效,本次实验的成绩将按“0”分计。 - 推荐markdown文档格式。 - (optional) 你对本次实验设计及难度/工作量的看法,以及有哪些需要改进的地方,欢迎畅所欲言。 选做题目 -------------------------------------------------------- 选作题目列表 - (4分)惰性页面分配(Lazy page allocation) - (4分)局部页面置换算法:改进的Clock页面置换算法 - (5分)全局页面置换算法:工作集置换策略 - (5分)全局页面置换算法:缺页率置换策略 提交要求 - (占分比:40%)实现代码(包括基本的注释) - (占分比:50%)设计与功能/性能测试分析文档,测试用例。 - (占分比:10%)鼓励形成可脱离OS独立存在的库,可以裸机测试或在用户态测试(比如easyfs那样)