文章目录

    • 1.1 MMU
      • 1.1.1 虚拟地址位宽配置
      • 1.1.2 页面大小(grandule size)配置
      • 1.1.3 AArch64 页表项描述符格式
      • 1.1.4 内存属性配置

1.1 MMU

1.1.1 虚拟地址位宽配置

64 位虚拟地址中,并不是所有位都用上,除了高 16 位用于区分内核空间和用户空间的虚拟地址外,虚拟地址的有效位的配置可以是:36, 39, 42, 47。在代码中,可以看到寄存器 TCR_EL1, Translation Control Register (EL1) 有关 T0SZ, T1SZ 的设置, 这个域就是用来配置这个项目的, 虚拟地址的有效位数为 64-TxSZ (或者, 也可以说 TxSZ 是用来设置高位无效位数的):

图 1-1 TCR_EL1

  • T1SZ, bits [21:16] 通过TTBR1寻址的内存区域的大小偏移量;
  • T0SZ, bits [5:0] 通过TTBR0 寻址的内存区域的大小偏移量;

比如, 我们如果希望使用 48 位的虚拟地址, 就会将TxSZ设置为 64-48=16, 也即 TRC_ELx.TxSZ 设置为 16。如果需要使用 39bit 的虚拟地址那么就设置为 25。

比如我使用的内核中有效位配置为 CONFIG_ARM64_VA_BITS=39:
用户空间地址范围:0x00000000_00000000 ~ 0x0000007f_ffffffff,大小为 512G;
内核空间地址范围:0xffffff80_00000000 ~ 0xffffffff_ffffffff,大小为 512G。

1.1.2 页面大小(grandule size)配置

支持 3 种页面大小:4KB, 16KB, 64KB,见 TRC_ELx.TGx

三种不同的粒度及虚拟地址位宽会影响所需 translation table level 的 数量配置大小配置

  • 4KB grandule size且 虚拟地址为 48bit 为例, 硬件可以使用四级查表。每一级的地址转换有 9 bit ,所以每个页表 2^9=512 项 (即 512个 entry),需要 VA 的 9位做索引。
    9位,9位,9位,9位,12位,如下图:

    图 1-2 VA=48 Grandule=4K

    • VA的[47:39] 索引到 L0 表的 512项。每个表项对应512GB(2^39)范围,并指向 L1 表;
    • L1 table 中也有 512个 entry, 每一个entry指向 L1 table 或 1GB block;
    • L2 table 的 entry 指向 L3 的 table 或 2M block;
    • L3 table 的 entry 指向 4KB block 的基地址。
  • 16KB grandule size为例,每个页表 2^11 项=2048项,需要 VA11 位提供索引。
    1位,11位,11位,11位,14位:
    Level0 表仅包含两项,对应 128TB范围如下

    图 1-3 VA=48 Grandule=16K

  • 64KB grandule size为例,每个页表2^13项=8192项,需要 VA 的13 位提供索引。
    13位,13位,13位,16位:

图 1-4 VA=48 Grandule=64K

  • 4KB grandule size且 虚拟地址39bit 为例,如果要使用 leve0 table的话,那么只能使用 BIT[38:38]表示,我们从上文可以知道 BIT[38:30] 已经给 level1用了,所以这种情况下不需要使用 level0,直接从 level1开始就可以完全表示整个39bit 的虚拟地址空间了。

图 1-5 VA=39 Grandule=64K

而如果虚拟地址空间只有 30 位,那么只需要从 level2 开始就可以完整表示整个地址空间了。也即, 虚拟地址空间越小,那么所需的level也就越小

1.1.3 AArch64 页表项描述符格式

AArch64 描述符格式被用在所有级别的表中,从Level 0 到 Level 3。
Level 0 描述符仅能输出 Level 1表的地址
Level 3 描述符不能指向其它表,仅能输出最终内存页的地址。因而 Level 3 格式稍有不同。

页表项的 [1:0] 位用于表示页表项的类型

  • bit[0] 为 0 表示表示该页表项无效, bit[1] 才表示该页表项有效;
  • bit[0] 为 1,bit[1] 为 0 表示该页表项是个 Block descriptor, 也就是该页表项中的 Output address 填写的是物理地址,也即下图中[49:n]域填写的是物理地址,该物理地址加上 [n-1:0] 偏移即可获取实际物理地址
  • bit[0] 为 1,bit[1] 为 1 表示该页表指向下一级 table。

1.1.4 内存属性配置

  • UXN or XN Excute-never, 决定了descriptor指向的region是否excuteable

  • PXN privileged excute-never, 决定了descriptor指向的region在EL1是否excuteable

  • Contiguous 该表项是否为连续表项中的一项。即转换表在该表项前后是连续的,没有空洞。这样,这些连续的表项便有可能一次性加载到cache中(比如由一个TLB entry缓存)

  • DBM dirty bit modifier, dirty bit指示内存页有没有被修改

  • nG not global, 指明当前的 entry 是 global(nG=0,所有process都可以访问) 还是non-global(nG=1,only本process允许访问)。

    • 如果是global类型,则 TLB 中不会 tag ASID;
    • 如果是non-global类型,则 TLB 会 tag上 ASID,且 MMU 在 TLB 中查询时需要判断这个 ASID 和当前进程的 ASID 是否一致,只有一致才证明这条 entry 当前 process 有权限访问。
  • AF access flag,当该标志为0,标明对应的内存区域(一个block或者一个page)是第一次访问;

  • SH[1:0] shareable attribute: 指当前内存页表项的数据是否可以同步到其它CPU上,多核CPU调用带有该属性页表项的数据,一旦某个CPU修改了数据,那么系统将自动更新到其它CPU的数据拷贝,实现内存数据一致性。对于Normal类型的内存,有 3 种情况:

    • Inner Shareable, 该内存位置可以被InnerShareability domain 中的所有处理器访问,并且硬件保证该位置在这些处理器间的数据一致性,InnerShareability domain中的处理器一般被同一个虚拟机监视器或操作系统控制;

    • Outer Shareable, 该内存位置可以被OuterShareability domain中的所有处理器访问,并且硬件保证该位置在这些处理器间的数据一致性,InnerShareability domain 是OuterShareability domain的一个子集;

    • Non-shareable, 该内存位置一般只能被唯一处理器访问,如果还有其他处理器能访问该位置,可能需要软件用缓存一致性指令来保证缓存一致性。

  • AP[2:1] access permission, 设置数据访问的权限,可以设置为 4 种:

  • NS security bit, 对于从安全状态访问内存,指定输出地址是在安全地址映射中还是在非安全地址映射中:

    • NS == 0 访问安全PA空间;
    • NS == 1 访问非安全PA空间 。
      对于从非安全状态进行的存储器访问,该位为RES 0,被PE忽略。
  • AttrIndx index into the MAIR_ELn, 指向内存区域的类型以及可缓存性(见下文)

推荐阅读
https://developer.arm.com/documentation/102416/0100/Single-level-table-at-EL3?lang=en