1.1 ARM MMU
1.1.1 虚拟地址位宽配置
64 位虚拟地址中,并不是所有位都用上,除了高 16 位用于区分内核空间和用户空间的虚拟地址外,虚拟地址的有效位的配置可以是:36, 39, 42, 47。在代码中,可以看到寄存器 TCR_EL1, Translation Control Register (EL1)
有关 T0SZ
, T1SZ
的设置, 这个域就是用来配置这个项目的, 虚拟地址的有效位数为 64-TxSZ
(或者, 也可以说 TxSZ
是用来设置高位无效位数的):
- 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
:
- 以
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 (2 30 bytes) ;
- L2 table 的 entry 指向 L3 的 table 或 2M block (2 21 bytes) ;
- L3 table 的 entry 指向 4KB block, 2 12 bytes 的基地址。
- bit[11:0] 用于定位具体的地址。
以 16KB
grandule size为例,每个页表 2 11 项= 2048项 ,需要 VA
的 11
位提供索引。
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 的虚拟地址空间了。Level0 表仅包含两项,对应 128TB范围如下
1.2 Block descriptor and Page descriptor
AArch64 描述符格式被用在所有级别的表中,从Level 0 到 Level 3。
Level 0 描述符仅能输出 Level 1表的地址 。
Level 3 描述符不能指向其它表 ,仅能输出最终内存页的地址。因而 Level 3 格式稍有不同。
页表项的 [1:0]
位用于表示页表项的类型 :
bit[0]
为 0 表示该页表项无效,1
才表示该页表项有效;bit[0]
为 1 表示该页表项有效:bit[1]
为 0 表示该页表项是个 Block descriptor , 也就是该页表项中的 Output address 填写的是物理地址,也即下图中[49:n]
域填写的是物理地址,该物理地址加上[n-1:0]
偏移即可获取实际物理地址。
关于 MMU 块描述符和页描述符更详细的内容见 : 【ARM Cache 系列文章 7.3 – ARMv8/v9 MMU 块描述符与页表描述符】
1.2.1 内存属性配置
虚拟地址空间和物理地址空间之间的映射是在一组转换表中定义的,有时也称为页表。对于虚拟地址的每个块或页,转换表提供相应的物理地址和用于访问该页的属性。转换表的每一项称为块描述符或者页描述符,在大多数情况下,属性都来自于该描述符。
下图展示了块描述符及属性字段的示例。
在块描述表和页描述表中属性域被分为两部分:Upper attributes 和 Lower attributes:
1.2.1.1 Lower Attributes
-
UXN or XN Excute-never, 决定了descriptor指向的 region 是否 excuteable;
-
PXN privileged excute-never, 特权模式下不能执行(在EL3或者当HCR_EL2.E2H==0时EL2下,称为XN);
-
Contiguous 该表项是否为连续表项中的一项。即转换表在该表项前后是连续的,没有空洞。这样,这些连续的表项便有可能一次性加载到 Cache中(比如由一个TLB entry缓存);
-
DBM dirty bit modifier, Armv8.1‑A 新增了处理器管理块或者页脏状态的功能。脏状态记录块或页是否已被写入,这很有用,因为如果块或页被调出,脏状态会告诉管理软件是否需要将 RAM 的内容写出到存储中。
例如,让我们考虑一个文本文件。文件最初从磁盘(闪存或硬盘驱动器)加载到 RAM 中。当稍后从内存中删除它时,操作系统需要知道 RAM 中的内容是否比磁盘上的内容新。如果 RAM 中的内容较新,则需要更新磁盘上的副本。如果不是,则可以删除 RAM 中的副本。
当启用脏状态管理时,软件最初会创建转换表条目,并将访问权限设置为只读,并设置 DBM(Dirty Bit Modifier)位。如果写入该页,硬件会自动将访问权限更新为读写。
将 DBM 位设置为 1 会更改访问权限位(
AP[2]
和S2AP[1]
)的功能,以便它们记录脏状态,而不是记录写权限。这意味着当 DBM 位设置为 1 时,访问权限位不会导致权限错误。
1.2.1.2 Lower Attributes
- bit[11] 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 有权限访问。
- bit[10] AF access flag, 当该标志为0,标明对应的内存区域(一个block或者一个page)是第一次访问;
- AF=0:区域未被访问过
- AF=1:区域已被访问过
AF对于操作系统十分有用,因为你可以使用这个位来标记页面是否被使用过,并且用于页面回收(从RAM中移除)。
当使用AF位时,最初创建转换表时AF位会被清零。当访问页面时,AF置位。软件可以解析这些表来检查 AF 位是否已设置或清除。 AF==0
的页面表示还没有被访问,并且可能适合被回收。
有两种方法可以在访问时设置AF位:
-
软件更新:当第一次访问页面时会触发同步异常( Access Flag Fault )。在异常处理程序中,软件可以将相关转换表中的AF置位,然后返回。
-
硬件更新:访问页面会导致硬件自动设置AF 位,而无需生成异常。这需要启用 Armv8.1‑A 中的转换控制寄存器 ( TCR_ELx.HA ) 的硬件访问更新位。
-
bit[9:8] SH shareable attribute: 指当前内存页表项的数据是否可以同步到其它CPU上,多核CPU调用带有该属性页表项的数据,一旦某个CPU修改了数据,那么系统将自动更新到其它CPU的数据拷贝,实现内存数据一致性。对于Normal类型的内存,有 3 种情况:
- Inner Shareable, 该内存位置可以被InnerShareability domain 中的所有处理器访问,并且硬件保证该位置在这些处理器间的数据一致性,InnerShareability domain中的处理器一般被同一个 虚拟机 监视器或操作系统控制;
- Outer Shareable, 该内存位置可以被OuterShareability domain中的所有处理器访问,并且硬件保证该位置在这些处理器间的数据一致性,InnerShareability domain 是OuterShareability domain的一个子集;
- Non-shareable, 该内存位置一般只能被唯一处理器访问,如果还有其他处理器能访问该位置,可能需要软件用缓存一致性指令来保证缓存一致性。
-
bit[6:7] AP access permission, 设置数据访问的权限,可以设置为 4 种:
-
bit[5] NS security bit, 对于从安全状态访问内存,指定输出地址是在安全地址映射中还是在非安全地址映射中:
NS == 0
访问安全PA空间;NS == 1
访问非安全PA空间 。
对于从非安全状态进行的存储器访问,该位为RES 0,被PE忽略。
-
bit[4:2] AttrIndx 指向内存区域的类型以及可缓存性,一共3bit,可以组成8种内存属性,在地址翻译的时候硬件会根据AttiIndex的值到
MAIR_ELx
找到对应的配置,详情见文章: 【ARM Cache 与 MMU 系列文章 7.6 – ARMv8 MMU 相关寄存器介绍】bit[1]
为 1 表示该页表指向下一级 table。