### 背景信息 - **页面表结构**: - 页面大小(`PGSIZE`):通常为 4KB(4096 字节)。 - 最大虚拟地址(`MAXVA`):在 Sv39 模式下为 2^39(512GB)。 - 页面表条目(PTE):包含物理地址(PA)、权限位(读/写/执行等)以及有效位(Valid bit)。 - 三级页面表:PML4(顶级),L2(中间级),L1(最低级),每个页面表包含 512 条目(2^9)。 - 虚拟地址(VA):39 位,分为 VPN[2](9 位,顶级索引)、VPN[1](9 位,中间级索引)、VPN[0](9 位,最低级索引)和 12 位页面偏移。 - **`print_pgtbl` 函数**: - 打印前 10 个页面(VA 从 `0` 到 `9 * PGSIZE`)和最后 10 个页面(接近 `MAXVA`)的页面表条目。 - 调用 `print_pte`,输出虚拟地址对应的页面表条目信息。 ### 输出分析 以下是提供的输出: ``` xv6 kernel is booting hart 1 starting hart 2 starting page table 0x0000000087f4d000 0: pte 0x0000000021fd2401 pa 0x0000000087f49000 ..0: pte 0x0000000021fd2001 pa 0x0000000087f48000 .. ..0: pte 0x0000000021fd281b pa 0x0000000087f4a000 va 0x0000000000000000 flags RXU .. ..1: pte 0x0000000021fd1c17 pa 0x0000000087f47000 va 0x0000000000000001 flags RWU .. ..2: pte 0x0000000021fd1807 pa 0x0000000087f46000 va 0x0000000000000002 flags RW .. ..3: pte 0x0000000021fd1417 pa 0x0000000087f45000 va 0x0000000000000003 flags RWU 255: pte 0x0000000021fd3001 pa 0x0000000087f4c000 ..511: pte 0x0000000021fd2c01 pa 0x0000000087f4b000 .. ..509: pte 0x0000000021fd5413 pa 0x0000000087f55000 va 0x0000000003fffffd flags RU .. ..510: pte 0x0000000021fd5807 pa 0x0000000087f56000 va 0x0000000003fffffe flags RW .. ..511: pte 0x000000002000180b pa 0x0000000080006000 va 0x0000000003ffffff flags RX init: starting sh ``` #### 1. **输出结构与 `print_pgtbl` 的关联** - 输出由 `print_pgtbl` 函数生成,包含: - **顶级页面表地址**:`page table 0x0000000087f4d000`(根页面表所在的物理地址)。 - **前几个页面表条目**(对应 `for (uint64 i = 0; i < 10; i++)` 循环): - 打印顶级页面表索引 0 的条目,以及其下级页面表的条目。 - 具体为虚拟地址 `0x0` 到 `0x3000`(前 4 个页面)。 - **最后几个页面表条目**(对应 `for (uint64 i = top - 10; i < top; i++)` 循环): - 打印顶级页面表索引 255 的条目,以及其下级页面表的最后几个条目(509–511)。 - 对应虚拟地址接近 `MAXVA`(`0x3fffffd` 到 `0x3ffffff`)。 - 输出格式: - 每行表示一个页面表条目,格式为: ``` [索引]: pte [PTE值] pa [物理地址] [va 虚拟地址 flags 权限] ``` - 缩进(`..`)表示页面表层级:顶级(无缩进)、L2(`..`)、L1(`.. ..`)。 - 仅 L1 页面表条目包含虚拟地址(`va`)和权限标志(`flags`)。 #### 2. **页面表条目解析** 页面表条目(PTE)格式(RISC-V Sv39): - **PTE 结构**:64 位,包含: - 物理页面号(PPN):44 位(高 44 位,右移 10 位得到物理页面地址)。 - 权限位:V(Valid,有效)、R(Read,读)、W(Write,写)、X(Execute,执行)、U(User,用户态可访问)。 - 其他标志:G(Global)、A(Accessed)、D(Dirty)等。 - **物理地址(PA)**:从 PTE 的 PPN 字段计算,`PA = PPN << 12`。 - **权限标志(flags)**:输出中的 `RXU`、`RWU`、`RW` 等表示权限组合: - `R`:可读,`W`:可写,`X`:可执行,`U`:用户态可访问。 ##### **前 4 个页面(VA 0x0 到 0x3000)** - **顶级页面表(索引 0)**: - `0: pte 0x0000000021fd2401 pa 0x0000000087f49000` - PTE 值:`0x21fd2401`。 - 物理地址:`0x87f49000`(L2 页面表地址)。 - 标志:`0x401` 的低 10 位为 `0x001`,表示 Valid(V=1)。 - **L2 页面表(索引 0)**: - `..0: pte 0x0000000021fd2001 pa 0x0000000087f48000` - PTE 值:`0x21fd2001`。 - 物理地址:`0x87f48000`(L1 页面表地址)。 - 标志:Valid(V=1)。 - **L1 页面表(索引 0–3)**: - `.. ..0: pte 0x0000000021fd281b pa 0x0000000087f4a000 va 0x0000000000000000 flags RXU` - 虚拟地址:`0x0`。 - 物理地址:`0x87f4a000`。 - 标志:`RXU`(Read, Execute, User),`0x1b` = `0b11011`(V=1, R=1, X=1, U=1)。 - 用途:可能是内核代码段(可读、可执行、用户态可访问)。 - `.. ..1: pte 0x0000000021fd1c17 pa 0x0000000087f47000 va 0x0000000000000001 flags RWU` - 虚拟地址:`0x1000`(1 * PGSIZE)。 - 物理地址:`0x87f47000`。 - 标志:`RWU`(Read, Write, User),`0x17` = `0b10111`(V=1, R=1, W=1, U=1)。 - 用途:可能是数据段或堆栈(可读、可写、用户态可访问)。 - `.. ..2: pte 0x0000000021fd1807 pa 0x0000000087f46000 va 0x0000000000000002 flags RW` - 虚拟地址:`0x2000`(2 * PGSIZE)。 - 物理地址:`0x87f46000`。 - 标志:`RW`(Read, Write),`0x07` = `0b00111`(V=1, R=1, W=1)。 - 用途:可能是内核数据(可读、可写,仅内核态)。 - `.. ..3: pte 0x0000000021fd1417 pa 0x0000000087f45000 va 0x0000000000000003 flags RWU` - 虚拟地址:`0x3000`(3 * PGSIZE)。 - 物理地址:`0x87f45000`。 - 标志:`RWU`(Read, Write, User),`0x17` = `0b10111`(V=1, R=1, W=1, U=1)。 - 用途:可能是用户态数据或堆栈。 ##### **最后 3 个页面(VA 0x3fffffd 到 0x3ffffff)** - **顶级页面表(索引 255)**: - `255: pte 0x0000000021fd3001 pa 0x0000000087f4c000` - PTE 值:`0x21fd3001`。 - 物理地址:`0x87f4c000`(L2 页面表地址)。 - 标志:Valid(V=1)。 - **L2 页面表(索引 511)**: - `..511: pte 0x0000000021fd2c01 pa 0x0000000087f4b000` - PTE 值:`0x21fd2c01`。 - 物理地址:`0x87f4b000`(L1 页面表地址)。 - 标志:Valid(V=1)。 - **L1 页面表(索引 509–511)**: - `.. ..509: pte 0x0000000021fd5413 pa 0x0000000087f55000 va 0x0000000003fffffd flags RU` - 虚拟地址:`0x3fffffd000`(接近 MAXVA)。 - 物理地址:`0x87f55000`。 - 标志:`RU`(Read, User),`0x13` = `0b10011`(V=1, R=1, U=1)。 - 用途:可能是用户态只读数据。 - `.. ..510: pte 0x0000000021fd5807 pa 0x0000000087f56000 va 0x0000000003fffffe flags RW` - 虚拟地址:`0x3fffffe000`。 - 物理地址:`0x87f56000`。 - 标志:`RW`(Read, Write),`0x07` = `0b00111`(V=1, R=1, W=1)。 - 用途:可能是内核数据(仅内核态)。 - `.. ..511: pte 0x000000002000180b pa 0x0000000080006000 va 0x0000000003ffffff flags RX` - 虚拟地址:`0x3ffffff000`(MAXVA - PGSIZE)。 - 物理地址:`0x80006000`。 - 标志:`RX`(Read, Execute),`0x0b` = `0b01011`(V=1, R=1, X=1)。 - 用途:可能是内核代码或设备映射(可读、可执行,仅内核态)。 #### 3. **与 `print_pgtbl` 的关联** - **前 10 个页面**: - 输出只显示了虚拟地址 `0x0` 到 `0x3000`(4 个页面),而不是 10 个,可能是因为 `print_pgtbl` 的循环被修改或页面表中只有前 4 个页面有有效映射。 - 虚拟地址计算: - `i * PGSIZE`(`i` 从 0 到 3),与输出中的 `va 0x0`、`0x1000`、`0x2000`、`0x3000` 匹配。 - **最后 10 个页面**: - 输出显示索引 509–511(虚拟地址 `0x3fffffd000` 到 `0x3ffffff000`),对应 `i` 从 `top - 3` 到 `top - 1`。 - 计算 `top`: - `MAXVA = 2^39 = 512GB`,`PGSIZE = 4096`,`top = 512GB / 4096 = 2^27 = 134,217,728`。 - 虚拟地址 `0x3ffffff`(十进制 2^30 - 1)对应页面号 `2^30 / 4096 = 2^18 - 1 = 262,143`。 - 顶级索引:`262,143 >> 18 = 255`(匹配 `255:`)。 - L2 索引:`(262,143 >> 9) & 0x1FF = 511`(匹配 `..511:`)。 - L1 索引:`262,143 & 0x1FF = 511`(匹配 `.. ..511:`)。 - 输出只显示最后 3 个页面(509–511),可能是因为只有这些页面有有效映射。 - **缺失的 `print_pgtbl` 输出**: - 函数应打印 `"print_pgtbl starting\n"` 和 `"print_pgtbl: OK\n"`,但输出中缺失,可能是被其他日志覆盖或函数被修改。 #### 4. **页面表条目含义** - **前 4 个页面**: - 映射到物理地址 `0x87f4a000` 到 `0x87f45000`,连续的物理页面。 - 权限多样(`RXU`、`RWU`、`RW`),表明这些页面用于不同用途: - `RXU`:用户态代码(例如,初始用户程序)。 - `RWU`:用户态数据或堆栈。 - `RW`:内核数据(仅内核态)。 - **最后 3 个页面**: - 映射到物理地址 `0x87f55000` 到 `0x80006000`,不完全连续。 - 权限包括 `RU`(用户态只读)、`RW`(内核读写)、`RX`(内核代码)。 - 最后一个页面(`va 0x3ffffff000`, `pa 0x80006000`)可能是设备内存映射(常见于内核高地址空间)。 - **物理地址**: - 大部分物理地址在 `0x87fxxxxx` 范围内,表明内存分配集中在某一区域。 - 最后一个页面映射到 `0x80006000`,可能是设备寄存器或内核代码的固定映射。