MMU-AArch64


限于篇幅大小,将AArch64架构上的介绍从MMU-AArch32拆分出来独立成篇。

本文着重记录AArch64平台架构上MMU相关的一些常备知识点


MMU的作用

功能

  • 地址转换
  • 权限检测
  • 异常中止(PageFault)
  • 刷新TLB,锁定TLB中某些页表项

地址转换
AArch64平台上使用三级页表/四级页表+4KB Page,或者二级页表/三级页表+64KB Page的模式

无论如何选择映射方式、页大小、内存模型、以及CPU位数,MMU均根据OS选择的页表实现来完成“虚拟地址”=>“物理地址”的转换
页表实现见下一节<PageTable的作用>

根据页表具体实现,MMU寄存器设置:
TODO...

权限控制
TODO...

异常中止
TODO...

TLB控制
TODO...

MMU初始化

TODO...


PageTable的作用

页表结构

在AArch64架构下,地址线宽度最大值是48bit,根据MMU支持能力、内存大小、SOC上存储实际挂接和映射的物理地址、内核实现修改方便等因素,Linux虚拟内存模型选择有所不同。因此64bit系统上PageTable是比较复杂的。

在ARMv8 SPEC中给出的虚拟地址空间布局

在Linux操作系统中:

  • 高端地址区域部分TTBR1_EL1 Region分配给Kernelspace使用
  • 低端地址区域部分TTBR0_EL1 Region分配给Userspace使用

在内核文档kernel/Documentation/arm64/memory.txt建议的Linux虚拟内存空间模型
① AArch64 Linux memory layout with 4KB pages + 3 levels:

Start End Size Use
0000000000000000 0000007fffffffff 512GB (39-bit) user
ffffff8000000000 ffffffffffffffff 512GB (39-bit) kernel

② AArch64 Linux memory layout with 4KB pages + 4 levels:

Start End Size Use
0000000000000000 0000ffffffffffff 256TB (48-bit) user
ffff000000000000 ffffffffffffffff 256TB (48-bit) kernel

③ AArch64 Linux memory layout with 64KB pages + 2 levels:

Start End Size Use
0000000000000000 000003ffffffffff 4TB (42-bit) user
fffffc0000000000 ffffffffffffffff 4TB (42-bit) kernel

④ AArch64 Linux memory layout with 64KB pages + 3 levels:

Start End Size Use
0000000000000000 0000ffffffffffff 256TB (48-bit) user
ffff000000000000 ffffffffffffffff 256TB (48-bit) kernel

64bit虚拟地址结构
① 64KB页 地址结构

页表级别 Offset占据比特位 寻址空间 表项数量 表项寻址空间 页目录项是否支持Block
L1 bit[47:42] 256T = 2^48 64 = 2^6 4T N
L2 bit[41:29] 4T = 2^42 8192 = 2^13 512M Y
L3 bit[28:16] 512M = 2^29 8192 = 2^13 64K N

② 16K页 地址结构

页表级别 Offset占据比特位 寻址空间 表项数量 表项寻址空间 页目录项是否支持Block
L0 bit[47] 256T = 2^48 2 128T N
L1 bit[46:36] 128T = 2^47 2048 = 2^11 64G N
L2 bit[35:25] 64G = 2^36 2048 = 2^11 32M Y
L3 bit[24:14] 32M = 2^25 2048 = 2^11 16K N

③ 4KB页 地址结构

页表级别 Offset占据比特位 寻址空间 表项数量 表项寻址空间 页目录项是否支持Block
L0 bit[47:39] 256T = 2^48 512 = 2^9 512G N
L1 bit[38:30] 512G = 2^39 512 = 2^9 1G Y
L2 bit[29:21] 1G = 2^30 512 = 2^9 2M Y
L3 bit[20:12] 2M = 2^21 512 = 2^9 4K N

Tips:
① ARM VMSv8支持的16KB页的页表结构,这个在ARMv8 SPEC中有说明,但是在Linux Kernel文档中是没有给出的,不知是否因为Kernel不支持
② 实际表项寻址空间与下级页表寻址空间是一样大的
③ 最高位bit[63]标记是内核页表还是用户页表,1是内核页表占据高地址区域,0是用户页表占据低地址区域

基址寄存器
CP15的C2寄存器(TTBR)保存PGD基址的bit位起止范围根据所选择页大小不同(4KB/16KB/64KB)而不同,如下图所示

Tips:
① 当选择小于48bit的物理地址时,那么相应的TTBR[m:n]需要缩小范围,规则是高于物理地址bit位数的bit位全补0。比如:选择40bit物理地址,那么TTBR[63:39]=0,即40bit以上全为0
② ASID用于标记不同的线程,一共16bit,当使用小于16bit的ASID实现时,高位补0
③ TTBR0用于保存“用户空间”页表基址,寻址位于虚拟地址空间“底部”的userspace;
④ TTBR1用于保存“内核空间”页表基址,寻址位于虚拟地址空间“顶部”的kernelspace;

MMU支持多种地址转换模式组合
在64位架构上,最多支持4级页表结构,各级页表名称有所变化,1~4级分别被称为L0级、L1级、L2级、L3级。页表的段页式管理比较复杂,它会以页式映射为主(区分64KB页、16KB页、4KB页三种),但在页式映射的L1/L2级页表项中会包含Block块(区分1G块、512M块、32M块、2M块)的直接映射,这样去管理一个特殊用途的大个内存区域。分类组合如下:

  • 64KB页/512MB块 + 二级页表(L2+L3)/三级页表(L1+L2+L3)
  • 16KB页/32MB块 + 三级页表(L1+L2+L3)/四级页表(L0+L1+L2+L3)
  • 4KB页/1GB块/2MB块 + 三级页表(L1+L2+L3)/四级页表(L0+L1+L2+L3)

L0级页目录项格式

  • 64KB页是没有L0级页表的,因此L0级页表只包含16KB页、4KB页索引!
  • 对于stage1=>stage2页表转换阶段是否存在,需要去查看ARM SPEC规定,处理器处于不同的运行级别使用的有所不同

① 无效路径:(Demo)

比特位 取值 描述
bit[0] 0b0 页表项无效,输入地址是unmapped
bit[63:1] - IGN,硬件忽略位,软件可以考虑根据情况使用

② 16KB页路径:(Demo)

比特位 取值 描述
bit[0] 0b1 页表项有效,输入地址已经map过了
bit[1] 0b1 标识这是一个页表描述符
bit[13:2] 0b0 SBZ,未使用应该为0
bit[47:14] 据实际 L1页表基址
bit[51:48] 0b0 SBZ,未使用应该为0
bit[58:52] - IGN,硬件忽略位,软件可以考虑根据情况使用
bit[59] 据实际 PXN,在EL1内核态是否可执行
bit[60] 据实际 XN,在EL0用户态是否可执行
bit[62:61] 据实际 AP,数据访问权限控制
bit[63] 据实际 NS,用于安全模式

③ 4KB页路径:同上L0页目录项的16KB路径,区别bit[47:12]和bit[11:2];

L1级页目录项格式

  • 4KB页L1级支持block块直接映射,被映射的块大小是1G

① 无效路径:同上L0页目录项的无效路径;
② 64KB页路径:同上L0页目录项的16KB路径,区别bit[47:16]和bit[15:2];
③ 16KB页路径:同上L0页目录项的16KB路径;
④ 4KB页路径:同上L0页目录项的4KB路径;
⑤ 4KB页Block路径:(Demo)

比特位 取值 描述
bit[0] 0b1 页表项有效,输入地址已经map过了
bit[1] 0b0 标识这是一个block描述符
bit[11:2] 据实际 Lower Block Attributes
bit[29:12] 0b0 SBZ,未使用应该为0
bit[47:30] 据实际 Block基址
bit[51:48] 0b0 SBZ,未使用应该为0
bit[63:52] 据实际 Upper Block Attributes

L2级页目录项格式

  • 64KB页L2级支持block块直接映射,被映射的块大小是512M
  • 16KB页L2级支持block块直接映射,被映射的块大小是32M
  • 4KB页L2级支持block块直接映射,被映射的块大小是2M

① 无效路径:同上L0~1页目录项的无效路径;
② 64KB页路径:同上L0~1页目录项的64KB路径;
③ 16KB页路径:同上L0~1页目录项的16KB路径;
④ 4KB页路径:同上L0~1页目录项的4KB路径;
⑤ 64KB页Block路径:同上L1 4KB页的BLock路径,区别bit[47:29]和bit[28:12];
⑥ 16KB页Block路径:同上L1 4KB页的BLock路径,区别bit[47:25]和bit[24:12];
⑦ 4KB页Block路径:同上L1 4KB页的BLock路径,区别bit[47:21]和bit[20:12];

Tips:
以上可见,对于64KB页、16KB页、4KB页L0、L1、L2页表项结构大体是类似的,只是“下一级页表基址”包含bit位数略有不同

L3级页目录项格式

  • L3页表的页表项被称为page descriptor,指向对应page页

① 无效页:同上面L0~2页目录项
② 保留:bit[1:0]=0b01
③ 64KB大页:(Demo)

比特位 取值 描述
bit[0] 0b1 页表项有效,输入地址已经map过了
bit[1] 0b1 标识这是一个page描述符
bit[11:2] 据实际 Lower Block Attributes
bit[15:12] 0b0 SBZ,未使用应该为0
bit[47:16] 据实际 Page基址
bit[51:48] 0b0 SBZ,未使用应该为0
bit[63:52] 据实际 Upper Block Attributes

④ 16KB页:同上L3 64KB大页,区别bit[47:14]和bit[13:12];
⑤ 4KB小页:同上L3 64KB大页,区别bit[47:12];

转换过程示例
当Linux 64bit内核选择“页式映射 + 三级页表 + 4KB小页”转换模式,页表转换过程

以kernel空间为例使用基址寄存器TTBR1(user空间只是基址寄存器用TTBR0):

具体采用几级页表在MMU控制寄存器(TCR.TnSZ)和PageTable间对应关系如下图:

以上是以4KB的页为例,其它页见ARMv8 SPEC详细解释

初始化

1
TODO...

存储

Linux内核页表
TODO...

Linux用户态页表
TODO...


TLB的作用

结构

TODO...

更新

TODO...


CPU内存寻址过程

这里就描述一个64bit的用户态进程,从通过malloc分配堆内存到真正拿到物理内存的全过程,如下图表述:
TODO...


参考文档

Kernel ARM64 Memory Layout
s3c2410 MMU详解
MMU与CACHE详解
MMU详解
ARMv8内存管理架构
ARMv8-A_Architecture_Reference_Manual_(Issue_A.a)
浅谈Cache和MMU
MMU与CACHE详解
页表机制
ARMv8(aarch64)页表建立过程详细分析
Linux内存管理--内核页表的建立
32位arm linux,为什么内核在fork进程的时候要复制(memcpy)内核PGD init页表(swapper_pg_dir)

Comments
Write a Comment