mit6.s081 lecture4-5
Lecture5中是TA讲的关于栈帧等比较琐碎的东西 这里搞在一起了
Lecture4-5
页表 & 虚拟内存相关
接上Lecture3中的描述 我们已经知道了强隔离性对于操作系统中进程的独立运行是必须的
如何实现这个强隔离性呢?
使用pagetable是一种非常主流灵活的方法
what
按照页表的模式,整个操作系统需要分页硬件机制所支持
在xv6中 对于操作系统的单个CPU(核) 内核会自己维护一个页表 存储核心数据 可见kernel/main.c
中的uvminit()
与uvmiinithart()
前者进行了初始化配置,分配内存空间 而后者将配置后的程序与空闲空间进行了映射
整个的工作流中可以大致分为几个部分:

CPU VA MMU SATP MEM PA
系统得到携带参数进来执行调用需求
-> 用户空间将页表基址存储在SATP寄存器
-> 用户空间将其分配在虚拟地址VA
-> 内核通过MMU进行虚拟地址VA到物理地址PA间的转换
-> 内核空间根据PA在MEM中执行对应操作
可能会有点不严谨
当然了 因为页表是以进程为颗粒度的 每个进程独享一个虚拟空间的页表 每个页表对应的基址地址不同
所以在上下文切换的时候 就会顺带把SATP中的值更换
当然 也会有一定的优化操作 防止每一次查询都需要MMU到SATP中获取然后查页表 即MMU中的查询缓存TLB…
这个TLB的更新策略之类的也有很多名堂就是了
地址空间etc
此处以RISC-V为标准
由于RISC-V是64位的机器 可以观察到此处预留了25位作为兼容之类的 27位作为虚拟地址的索引 剩下的12位则用作偏移量
为什么Offset是12?
因为2^12刚好是4096
而在大部分分页操作系统当中 单页的大小基本都是4096 也就是说 操作系统的物理内存和虚拟内存本质上都是以4096(单页大小)作为单位的
同时为了节约虚拟地址内存和支持大规模的地址空间 发明了 多级页表 还有其他优点 但是暂时跟这里没多大关系
为什么说它可以节约呢?
在进程使用的时候 单级页表的模式下 无论进程是否使用 在启动的时候就已经为他赋予了对应虚拟地址空间的物理内存
但是实际上 由于局部性定理等 实际使用的内存空间往往是稀疏的 即实际分配的内存的总体使用率会比较低
而在多级页表的模式下 只有在当实际使用到的时候 才会实际分配内存
同时 由于两级的映射 毋庸置疑让他可以指向的虚拟地址空间相比单级页表来说更大
xv6中使用的就是两级页表
其中27位的索引可以定位到对应的PPN(页)中 是页目录索引和页表索引的集合
即通过页目录索引定位到是哪一个二级目录 通过页表索引定位到是具体的哪一页
这个索引的过程 体现在xv6的代码中kernel/vm.c
中的walkaddr() walk()
方法了
其中是对于Level2的va进行循环 直至Level0的时候 得到的便是真实的物理地址
但是偏移量不需要做这些处理 在传递va的时候 其中的12位offset不需要做其他处理 在计算出真实的物理地址之后定位即可
对于上方的说明 可以在使用一个实例来进行说明:
RISC-V中将27位索引位分为三层
在索引的时候 首先会根据SATP寻找到对应的页表基址
27位索引位可以分为高中低三个索引位
然后通过高索引位寻找到第一个page directory即页目录 定位到的目标叫做PTE(page table entry)
通过这个entry 结合中索引位 寻找第二个页目录 同理也会定位到一个PTE
同理通过低三位寻找第三个页目录 定位到最底层的PTE(Level0)
此时将定位到的PTE加上12位offset 就是真实的物理地址
这是整个查表的过程 接下来则是单级页表和多级页表之间索引效率的对比
对于单个进程 假如说只是用了1个page
单级索引:该模式下,虚拟地址和物理地址之间是一一映射的 所以也会申请到2^27
次方的空间 造成了很大的空间浪费 也就是上面所说的空间稀疏的问题
多级索引:多级索引会对这个page依次申请空间 即高,中,低三级页表分别都会申请一个directory的空间 3 *512
为什么一个pagedirectory是512?
在64位环境下 每一个条目的所占空间是8kb 所以一共有512个条目去组织它
PTE相关结构
对于每一个PTE(64位)
63-53:前10位是保留字段 这个保留字段的意思是 向后兼容的
53-10:对于虚拟地址处映射的44位物理实际地址
10-0:标志位 Vaild等 标志它是pagedirectory还是具体页表项 还有类似Readable Writeable等 表明是否能读写该标志位
物理内存结构
xv6中 可以看到物理内存空间的起始代码是0x80000000
该地址往上的高地址 是可分配可操作的空间代码
往下的低地址 则是实现IO等设备时的特定地址
在xv6中 对于0x80000000
往下的地址
虚拟地址和物理地址是对应的 无需映射
实际的操作系统中会有更加复杂的设计
这里牵扯到一个问题 在操作系统中 我们常说栈帧分配地址的时候 是从高地址分配到低地址的
这里所说的对象是逻辑地址 这一设计只是为了保证可维护性之类的
映射到实际的物理内存中仍是随机写