OS-Lab2总结
虚拟地址到物理地址的映射
软件访问的虚拟地址会先被 MMU 映射到物理地址,然后通过物理地址来访问内存或其他外设。我们在编程过程中使用到的地址均为虚拟地址。
- 若虚拟地址位于 kseg0 段,则将虚拟地址的最高位置零得到物理地址,通过 cache 访存。
- 若虚拟地址位于 kseg1 段,则将虚拟地址的高三位置零得到物理地址,不通过 cache 访存。
- 若虚拟地址位于 kuseg 段,则需要通过 TLB 获取物理地址,通过 cache 访存。
在 MMU 中通过硬件 TLB 来完成地址映射。但是我们需要通过软件来完成 TLB 重填。
物理内存管理
我们使用链表管理空闲页表。C 语言中没有泛型,因此我们需要巧妙地使用宏来实现链表。链表宏的代码位于 include/queue.h
中。实现非常巧妙,建议仔细阅读理解。(其中对链表进行遍历的宏 LIST_FOREACH, TAILQ_FOREACH
在课下不会用到,但是在上机时很有可能会用到,建议理解含义)
pmap.h
这个头文件中定义了许多我们可能会用到的函数。是必读的头文件。这些用于转换的函数都应该记住。阅读这些头文件也会有助于我们理解程序进行地址转换的过程。
1 | extern Pde *cur_pgdir; // 当前的页目录基地址 |
pmap.c
本文件中的函数涉及的都是很底层的部分。
- void *alloc:分配一定的物理内存。仅在建立虚拟内存系统时会被使用。
- void mips_vm_init:只干了一件事:为二级页表结构分配空间。
- void page_init:初始化页表管理结构,将空闲页表都插入到
page_free_list
中。 - int page_alloc:从空闲页表中取出一页并分配。
- int page_free:释放一页,
- int pgdir_walk:通过给出的页目录基地址,找到虚拟地址 va 对应的页表项并将其地址赋给 ppte。若不存在页表项且 create 为 1 则为其分配一个页表。
- int page_insert:将虚拟地址 va 映射到 pp 对应的物理页面。
- struct Page *page_lookup:寻找虚拟地址 va 映射到的页面。将二级页表项地址赋值给 ppte。返回对应的页控制块。
- void page_decref:减少页面的引用。若减少后引用数为 0,则释放这一页。
- void page_remove:取消 va 映射的页面。
- void tlb_invalidate:使 TLB 中带有 asid 的 va 地址的表项无效。
这些函数还是要自己都读一遍才能理解好。
TLB无效化与重填
在本次实验中可能用到的相关指令:
- tlbr:以 Index 寄存器中的值为索引,读出 TLB 中对应的表项到 EntryHi 与 EntryLo。
- tlbwi:以 Index 寄存器中的值为索引,将此时 EntryHi 与 EntryLo 的值写到索引指定的 TLB 表项中。
- tlbwr:将 EntryHi 与 EntryLo 的数据随机写到一个 TLB 表项中。
- tlbp:根据 EntryHi 中的 Key(包含 VPN 与 ASID),查找 TLB 中与之对应的表项,并将表项的索引存入 Index 寄存器(若未找到匹配项,则 Index 最高位被置 1)。
TLB 的无效化是通过 kern/tlb_asm.S
中的 tlb_out 实现的。首先通过 tlbq 指令拿出索引,然后将 CP0_ENTRYHI 和 CP0_ENTRYLO0 赋值为零,再通过 tlbwi 写回到指定的 TLB 表项中。
这个函数在 kern/pmap.c
中的 void tlb_invalidate()
被调用。
TLB 的无效化由 kern/tlb_asm.S
中的 do_tlb_refill 完成。这个函数首先取出引发错误的虚拟地址,然后取出进程对应的 asid,然后调用 _do_tlb_refill 函数(该函数位于 kern/tlbex.c
中)。最后将物理地址存入 EntryLo, 并执行 tlbwr 将此时的 EntryHi 与 EntryLo 写入到 TLB 中。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Bluebean's Blog!
评论