实验三:虚实地址转换

优质
小牛编辑
125浏览
2023-12-01

实验三:虚实地址转换

实验之前

  • 阅读实验指导三,可以结合 lab-3 分支的代码来理解。
  • 本次的实验题将使用 lab-3+ 分支,它包含了后面章节的内容,而我们不需要管那些部分。

实验题

  1. 原理:在 os/src/entry.asm 中,boot_page_table 的意义是什么?当跳转执行 rust_main 时,不考虑缓存,硬件通过哪些地址找到了 rust_main 的第一条指令?

    Click to show
    1. boot_page_table 是一个用二进制表示的根页表,其中包含两个 1GB 大页,分别是将虚拟地址 0x8000_00000xc000_0000 映射到物理地址 0x8000_00000xc000_0000,以及将虚拟地址 0xffff_ffff_8000_00000xffff_ffff_c000_0000 映射到物理地址 0x8000_00000xc000_0000

      由于我们在 linker.ld 中指定了起始地址为 0xffff_ffff_8020_0000,操作系统执行文件会认为所有的符号都是在这个高地址上的。但是我们在硬件上只能将内核加载到 0x8020_0000 开始的内存空间上,此时的 pc 也会调转到这里。

      为了让程序能够正确跳转至高地址的 rust_main,我们需要在 entry.asm 中先应用内核重映射,即将高地址映射到低地址。但我们不可能在替换页表的同时修改 pc,此时 pc 仍然处于低地址。所以,页表中的另一项(低地址的恒等映射)则保证程序替换页表后的短暂时间内,pc 仍然可以顺着低地址去执行内存中的指令。

      注:如果 boot_page_table 中不包含低地址恒等映射,程序可能仍然可以正常运行。这可能和硬件的缓存设计有关。但保险起见,应当保留这两个映射。

    2. 执行 jal rust_main 时,硬件需要加载 rust_main 对应的地址,大概是 0xffff_ffff_802x_xxxx

      • 页表已经启用,硬件先从 satp 高位置读取内存映射模式,再从 satp 低位置读取根页表页号,即 boot_page_table 的物理页号
      • 对于 Sv39 模式,页号有三级共 27 位。对于 rust_main 而言,一级页号是其 [30:38] 位,即 510。硬件此时定位到根页表的第 510 项
      • 这一项的标志为 XWR,说明它指向一个大页而不是指向下一级页表;目标的页号为 0x8_0000,即物理地址 0x8000_0000 开始的区间;这一项的 V 位为 1,说明目标在内存中。因此,硬件寻址到页基址 + 页内偏移,即 0x8000_0000 + 0x2x_xxxx,找到 rust_main
  2. 分析:为什么 Mapping 中的 page_tablesmapped_pairs 都保存了一些 FrameTracker?二者有何不同?

    Click to show

    页表也是需要我们去分配页面来存储的。因此,page_tables 存放了所有页表所用到的页面,而 mapped_pairs 则存放了进程所用到的页面。

  3. 分析:假设某进程需要虚拟地址 A 到物理地址 B 的映射,这需要操作系统来完成。那么操作系统在建立映射时有没有访问 B?如果有,它是怎么在还没有映射的情况下访问 B 的呢?

    Click to show

    建立映射不需要访问 B,而只需要操作页表即可。不过,通常程序都会需要操作系统建立映射的同时向页面中加载一些数据。此时,尽管 A→B 的映射尚不存在,因为我们将整个可用物理内存都建立了内核映射,所以操作系统仍然可以通过线性偏移量来访问到 B。

  4. 实验:了解并实现时钟页面置换算法(或任何你感兴趣的算法),可以自行设计样例来比较性能

    • 置换算法只需要修改 os/src/memory/mapping/swapper.rs

    • main.rs 中调用 create_kernel_thread 来创建线程,你可以任意修改其中运行的函数,以达到测试效果