3.1: 分页硬件(Paging hardware)
虚拟地址与物理地址的关系: RISC-V 指令(无论是用户模式还是内核模式)操作的是虚拟地址,而物理内存(RAM)则通过物理地址进行索引。RISC-V 的页表硬件连接了这两种地址,通过将每个虚拟地址映射到一个物理地址来实现。
Sv39 页表
页表的构成
Sv39 页表: xv6 操作系统运行在 Sv39 配置的 RISC-V 上,这意味着只有 64 位虚拟地址的最低 39 位被使用,而最高 25 位没有被使用。
在这种 Sv39 配置下,RISC-V 页表逻辑上是一个由 2^27(134,217,728)个页表条目(PTE)组成的数组。每个 PTE 包含一个 44 位的物理页号(PPN)和一些标志位。
分页硬件通过使用虚拟地址的前 27 位来索引页表,找到对应的 PTE,然后构建出一个 56 位的物理地址,其中前 44 位来自 PTE 中的 PPN,后 12 位直接来自原始虚拟地址的低 12 位。
PTE中,44位PPN,即物理页号为物理地址右移12位获得,最后10位为标记位,PTE中54-63位保留 物理地址的位数:64 位 RISC-V 处理器的物理地址空间可能并不需要使用完整的 64 位。很多实现可能只使用 44 位或 48 位的物理地址空间,这样可以有效降低硬件复杂性。 页表项和物理页号(PPN):在大多数实现中,物理页号可能只需要 44 位,因此即使是 64 位的系统,也可以通过右移 12 位来得到物理页号,然后通过左移 10 位空间来存储控制标记位,这些标记位包括:
// shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
#define PTE2PA(pte) (((pte) >> 10) << 12)
页表的层级结构
页表的层级结构: RISC-V 的页表是一棵三层的树,每层都包含 512 个 PTE,具体结构如图所示。

根页表页是一个 4096 字节的页面,包含 512 个 PTE(每个PTE8个字节64位),这些 PTE 指向下一级页表。
在分页过程中,硬件依次使用虚拟地址的前三个 9 位来选择页表中的 PTE。 假设虚拟地址分为三个部分:高 9 位选择根页表中的 PTE,中间 9 位选择次级页表中的 PTE,最后 9 位选择最终的 PTE。
如果在翻译过程中,任何一个 PTE 不存在,分页硬件会触发一个页错误(page fault)异常,由内核来处理这个异常。
页表标志位: 每个 PTE 包含标志位,标明该虚拟地址的访问权限:
PTE_V(有效位):标记该页是否存在。
PTE_R(可读位):控制是否允许读取页面。
PTE_W(可写位):控制是否允许写入页面。
PTE_X(可执行位):控制是否允许执行页面中的内容。
PTE_U(用户模式位):控制用户模式是否允许访问该页。
如何使用页表
要让 CPU 使用页表,内核需要将根页表的物理地址写入 satp 寄存器中。每个 CPU 有一个独立的 satp 寄存器,因此不同的 CPU 可以运行不同的进程,每个进程有自己独立的地址空间,由其自己的页表描述。
虚拟地址与物理地址的转换过程: RISC-V CPU 将虚拟地址转换为物理地址的过程分为三个步骤。通过页表的三级结构,CPU 依次访问页表,获取所需的 PTE,从而完成虚拟地址到物理地址的转换。这一过程由硬件自动完成。为了提高性能,CPU 会将常用的页表条目缓存在转译后备缓冲区(TLB)中,以避免频繁访问物理内存。
页表的内存节省: 三层结构比单层设计更加节省内存。例如,当某个应用程序只使用少量页面时,三层结构能够省去大量无效的页表页,从而减少内存消耗。
总结:
xv6 使用 RISC-V 的 Sv39 配置进行分页管理,通过三层页表结构实现虚拟地址到物理地址的转换。分页硬件不仅能高效地管理内存,还能通过一系列的标志位来控制内存的访问权限。每个进程的地址空间都通过页表与物理内存分离,确保了进程之间的隔离性和安全性。
问题:
由于xv6中内存分配以页为单位,页表机制也是一样的,因此用户空间一级页表所占空间就是一个内存页,但是由于在用户空间,其虚拟地址最高为为0,因此有效的pte条目最多为256项,是可以这么理解吗?
为什么sv39中最高位为0,是针对用户空间的虚拟地址的定义的吗?
内核的直接映射中低地址采用直接映射,低地址的虚拟地址的最高位会为0,是不是和内核态的虚拟地址高位为1相矛盾,如0x80000000地址的虚拟地址的(4个字节,32位),0100 0000 0000 0000 0000 0000 0000 0000,还有相面更多的和硬件寄存器相关联的地址映射