“页表抽象可由多级页表实现。正文中的权限字段是OS 16的字段,不等于任一真实ISA的PTE位布局。”
形式陈述
多级页表把虚页到页框的映射理路页表地址转换与访问权限Page table address translation · VPN PFN offset · 虚实地址转换由虚页号、页内偏移与PTE计算物理地址,分别检查驻留、访问类型和用户权限,并建立可检查的隔离不变量。存成定高索引树。上层条目指向下一层页表页,最末层叶条目给数据PFN与权限;不存在的上层分支可不分配整个子表。这里的树是翻译索引,数据页不必按虚地址连续分配。
OS-16使用两级页表:16位虚地址拆为[4位根索引 i1 | 4位叶索引 i0 | 8位offset]。每张表16项,每项16B,恰好占一页。根与中间表页来自内核保留页框,普通用户无法读写;上层项只记录“存在、下层PFN”,权限全部在叶项检查,不含大页和上层权限。
设根物理基址为r,第一步读r+16i1;存在时取得下层页框t,第二步读256t+16i0。叶项有效且权限允许,才以其PFN加offset形成数据物理地址。表页访问使用物理地址,不能递归要求先通过正在遍历的用户页表翻译,否则没有明确的起点。
直觉
平表为每个可能虚页预留一个槽。两级表把16个相邻虚页归为一组:只有该组至少需要一个驻留映射时才分配叶表。地址空间越稀疏、映射越聚集,省下的空叶表越多;若每组只映一个页,省空间效果会明显减弱。
查表不是把整个地址拿去“查树”。每层消费固定的几位,位宽决定分支数,PTE宽度决定条目字节地址。页框号、表页基址和条目地址是三个不同的量。
例子与边界
两个根完整走一遍
P根在PFN0x01,即r=0x0100;根索引1指向叶表PFN0x02。Q根在PFN0x03,索引1指向PFN0x04。两张叶表的索引2分别映射到数据PFN0x30和0x50。
v=0x12AB给出i1=1,i0=2,o=0xAB。P先读根项物理地址0x0100+1×16=0x0110,得到0x02;再读0x0200+2×16=0x0220,得到0x30;最后访问0x30AB。Q相应读0x0310、0x0420,最后访问0x50AB。首次访问没有TLB命中、没有缓存表页时,两次PTE读取再加一次数据读取,共三次内存访问。
若P访问0x2701而根索引2不存在,遍历在第一层停止,不能继续把零当下一层地址读内核页。若根存在而叶项不驻留,则停在第二层。软件随后查合法区域;两种停止位置都没有直接告诉它“应该杀死进程”还是“应该分配页”。
空间不一定总比平表省
P仅映射VPN0x10、0x12、0x13时,共需根和一张叶表,512B。加入VPN0xF0后需第二张叶表,共768B。平表始终需256×16=4096B。若16个根分支都需要叶表,则两级结构占17页、4352B,比平表多一页;稀疏优化不意味着任何输入都更小。
按页分配表页时,新增某组第一个映射的成本包括清零整张叶表;新增同组的另一个映射只需改叶项。最后一个叶映射撤销后,只有确认没有并行遍历或缓存引用需要该表页,才可回收叶表。
推论与应用
对固定层数L,未缓存遍历最多读取L个PTE,成功数据访问再加一次。对一般每层f项、m个已映射虚页的树,空间取决于它们共享多少索引前缀,不能简单写成mL个新节点并称精确值。最坏按路径计上界可以,聚集映射通常共享很多上层页。
多级结构只解决表空间和查找组织,访问速度还需TLB理路TLB与地址翻译失效Translation lookaside buffer · TLB miss · TLB invalidation将翻译缓存键、权限和映射生命周期一起核对,区别TLB未命中与缺页,构造改PTE后仍越权的最短反例。。OS-16两级不是xv6的Sv39:rev5教材使用三个9位索引与12位偏移、8B PTE。把OS-16的地址直接套到Sv39会得到错误表项地址;同一分解方法可以迁移,参数必须重新取自ISA。
参考资料
- Remzi与Andrea Arpaci-Dusseau,OSTEP: Paging—Smaller Tables,第20章,多级表与稀疏空间;本文16×16布局及数字独立构造。
- Cox、Kaashoek、Morris,xv6教材 rev5,§3.1,Sv39参数对照。