Scarlet Serenade

Computer Architecture | RISC V | Virtual Memory

All harts in a system must employ the same PTE-update scheme as each other

--

supervisor mode 提供了虚拟内存,启用分页的时候大多数地址(包括 load/store 和 pc 中的地址)都是虚拟地址。要访问物理内存,它们必须通过页表被转换为真正的物理地址。

一个页表总是一页大小并且总是按页对齐的。根页表的 physical page number 被存储 在 satp 寄存器中。


RISC V 的分页方案以 SvX 命名,其中 X 为虚拟地址的长度。

  • 例如 RV32 采用 Sv32 方案,采用了两级页表,每页 4KB
  • 例如 RV64 采用 Sv39 方案(通常),采用了三级页表,每页 4KB

以 Sv39 为例,

VirtualAddr:
+----------+---------+---------+---------+-------------+
| Not Used | VPN[2]  | VPN[1]  | VPN[0]  | page offset |
+----------+---------+---------+---------+-------------+
| 63 - 39  | 38 - 30 | 29 - 21 | 20 - 12 | 11 - 0      |
+----------+---------+---------+---------+-------------+

PhysicalAddr:
+----------+---------+---------+---------+-------------+
| Not Used | PPN[2]  | PPN[1]  | PPN[0]  | Page Offset |
+----------+---------+---------+---------+-------------+
| 63 - 56  | 55 - 30 | 29 - 21 | 20 - 12 | 11 - 0      |
+----------+---------+---------+---------+-------------+
Entry: 
+----------+---------+---------+---------+-------+---+---+---+---+---+---+---+---+
| Not Used | PPN[2]  | PPN[1]  | PPN[0]  | RSW   | D | A | G | U | X | W | R | V |
+----------+---------+---------+---------+-------+---+---+---+---+---+---+---+---+
| 63 - 54  | 53 - 28 | 27 - 19 | 18 - 10 | 9 - 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+----------+---------+---------+---------+-------+---+---+---+---+---+---+---+---+

The U bit indicates whether the page is accessible to user mode。通常情况下 supervisor mode operates with the SUM bit clear,supervisor mode 不能访问用户页,但是如果 SUM bit is set, supervisor mode 也能访问用户页。

The G bit 指定全局映射,意味着该映射存在于所有地址空间中(如果是一个非页 PTE 被设置为 global 则其 subsequent levels of the page table are global.

Each leaf PTE contains an accessed (A) and dirty (D) bit.

  • The A bit indicates the virtual page has been read, written, or fetched from since the last time the A bit was cleared.
  • The D bit indicates the virtual page has been written since the last time the D bit was cleared.

Virtual Address Translation Process:

pub fn virt_to_phys(root: *const Table, vaddr: VirtualAddr) -> Option<PhysicalAddr> {
    let mut table = root;
    for lvl in (1..=2).rev() {
        let entry = unsafe { &(*table).entries[vaddr.extract_vpn(lvl)] };
        if !entry.is_valid() {
            return None;
        }
        let ppn = entry.extract_ppn_all();
        table = PhysicalAddr::from(ppn, 0).as_mut_ptr::<Table>();
    }

    let entry = unsafe { &(*table).entries[vaddr.extract_vpn(0)] };
    let ppn = entry.extract_ppn_all();
    Some(PhysicalAddr::from(ppn, vaddr.extract_offset()))
}