练习
============================================

课后练习
-------------------------------

编程题
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. `**` 使用sbrk，mmap,munmap,mprotect内存相关系统调用的linux应用程序。
2. `***` 修改本章操作系统内核，实现任务和操作系统内核共用同一张页表的单页表机制。
3. `***` 扩展内核，支持基于缺页异常机制，具有Lazy 策略的按需分页机制。
4. `***` 扩展内核，支持基于缺页异常的COW机制。（初始时，两个任务共享一个只读物理页。当一个任务执行写操作后，两个任务拥有各自的可写物理页）
5. `***` 扩展内核，实现swap in/out机制，并实现Clock置换算法或二次机会置换算法。
6. `***` 扩展内核，实现自映射机制。

问答题
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. chyyuu   这次的实验没有涉及到缺页有点遗憾，主要是缺页难以测试，而且更多的是一种优化，不符合这次实验的核心理念，所以这里补两道小题。

1. `*` 在使用高级语言编写用户程序的时候，手动用嵌入汇编的方法随机访问一个不在当前程序逻辑地址范围内的地址，比如向该地址读/写数据。该用户程序执行的时候可能会生什么？
2. `*` 用户程序在运行的过程中，看到的地址是逻辑地址还是物理地址？从用户程序访问某一个地址，到实际内存中的对应单元被读/写，会经过什么样的过程，这个过程中操作系统有什么作用？（站在学过计算机组成原理的角度）
3. `*` 覆盖、交换和虚拟存储有何异同，虚拟存储的优势和挑战体现在什么地方？
4. `*` 什么是局部性原理？为何很多程序具有局部性？局部性原理总是正确的吗？为何局部性原理为虚拟存储提供了性能的理论保证？
5. `**` 一条load指令，最多导致多少次页访问异常？尝试考虑较多情况。
6. `**` 如果在页访问异常中断服务例程执行时，再次出现页访问异常，这时计算机系统（软件或硬件）会如何处理？这种情况可能出现吗？
7. `*` 全局和局部置换算法有何不同？分别有哪些算法？
8. `*` 简单描述OPT、FIFO、LRU、Clock、LFU的工作过程和特点 (不用写太多字，简明扼要即可)
9. `**` 综合考虑置换算法的收益和开销，综合评判在哪种程序执行环境下使用何种算法比较合适？
10. `**` Clock算法仅仅能够记录近期是否访问过这一信息，对于访问的频度几乎没有记录，如何改进这一点？
11. `***` 哪些算法有belady现象？思考belady现象的成因，尝试给出说明OPT和LRU等为何没有belady现象。
12. `*` 什么是工作集？什么是常驻集？简单描述工作集算法的工作过程。
13. `*` 请列举 SV39 页`*` 页表项的组成，结合课堂内容，描述其中的标志位有何作用／潜在作用？
14. `**` 请问一个任务处理 10G 连续的内存页面，需要操作的页表实际大致占用多少内存(给出数量级即可)？
15. `**`  缺页指的是进程访问页面时页面不在页表中或在页表中无效的现象，此时 MMU 将会返回一个中断，告知操作系统：该进程内存访问出了问题。然后操作系统可选择填补页表并重新执行异常指令或者杀死进程。操作系统基于缺页异常进行优化的两个常见策略中，其一是 Lazy 策略，也就是直到内存页面被访问才实际进行页表操作。比如，一个程序被执行时，进程的代码段理论上需要从磁盘加载到内存。但是 操作系统并不会马上这样做，而是会保存 .text 段在磁盘的位置信息，在这些代码第一次被执行时才完成从磁盘的加载操作。 另一个常见策略是 swap 页置换策略，也就是内存页面可能被换到磁盘上了，导致对应页面失效，操作系统在任务访问到该页产生异常时，再把数据从磁盘加载到内存。

    - 哪些异常可能是缺页导致的？发生缺页时，描述与缺页相关的CSR寄存器的值及其含义。
    - Lazy 策略有哪些好处？请描述大致如何实现Lazy策略？
    - swap 页置换策略有哪些好处？此时页面失效如何表现在页表项(PTE)上？请描述大致如何实现swap策略？
  
16. `**` 为了防范侧信道攻击，本章的操作系统使用了双页表。但是传统的操作系统设计一般采用单页表，也就是说，任务和操作系统内核共用同一张页表，只不过内核对应的地址只允许在内核态访问。(备注：这里的单/双的说法仅为自创的通俗说法，并无这个名词概念，详情见 `KPTI <https://en.wikipedia.org/wiki/Kernel_page-table_isolation>`_ )

    - 单页表情况下，如何控制用户态无法访问内核页面？
    - 相对于双页表，单页表有何优势？
    - 请描述：在单页表和双页表模式下，分别在哪个时机，如何切换页表？


实验练习
-------------------------------

实验练习包括实践作业和问答作业两部分。

实践作业
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

重写 sys_get_time
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

引入虚存机制后，原来内核的 sys_get_time 函数实现就无效了。请你重写这个函数，恢复其正常功能。

mmap 和 munmap 匿名映射
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

`mmap <https://man7.org/linux/man-pages/man2/mmap.2.html>`_ 在 Linux 中主要用于在内存中映射文件，本次实验简化它的功能，仅用于申请内存。

请实现 mmap 和 munmap 系统调用，mmap 定义如下：


.. code-block:: rust

    fn sys_mmap(start: usize, len: usize, prot: usize) -> isize

- syscall ID：222
- 申请长度为 len 字节的物理内存（不要求实际物理内存位置，可以随便找一块），将其映射到 start 开始的虚存，内存页属性为 prot
- 参数：
    - start 需要映射的虚存起始地址，要求按页对齐
    - len 映射字节长度，可以为 0
    - prot：第 0 位表示是否可读，第 1 位表示是否可写，第 2 位表示是否可执行。其他位无效且必须为 0
- 返回值：执行成功则返回 0，错误返回 -1
- 说明：
    - 为了简单，目标虚存区间要求按页对齐，len 可直接按页向上取整，不考虑分配失败时的页回收。
- 可能的错误：
    - start 没有按页大小对齐
    - prot & !0x7 != 0 (prot 其余位必须为0)
    - prot & 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：注意 prot 参数的语义，它与内核定义的 MapPermission 有明显不同！

实验要求
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- 实现分支：ch4-lab
- 实验目录要求不变
- 通过所有测例

  在 os 目录下 ``make run TEST=1`` 测试 sys_get_time， ``make run TEST=2`` 测试 map 和 unmap。

challenge: 支持多核。

问答作业
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

无

实验练习的提交报告要求
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* 简单总结本次实验与上个实验相比你增加的东西。（控制在5行以内，不要贴代码）
* 完成问答问题。
* (optional) 你对本次实验设计及难度的看法。
   