Learn The Architecture Memory Management 译文

Learn The Architecture Memory Management 译文,转载
MMU

1、概述

本文档介绍了ARMv8-A架构内存管理的关键——内存地址转换,包括虚拟地址(VA)到物理地址(PA)的转换、页表(或称地址转换表)格式以及TLBs(Translation Lookaside Buffers)管理。

对于任何进行底层bootloader或者驱动代码开发的人员来说,这部分内容都是非常实用的,尤其是对进行MMU(Memory Management Unit)编码的人员。

本文档可以帮助你解到VA如何转换成PA的、如何识别不同的地址空间、地址转换时地址空间是如何映射的以及TLB相关的操作。

2、什么是内存管理?

内存管理描述了如何访问系统内存。每次操作系统或者应用程序尝试访问内存时,都是硬件负责进行内存管理的,对于应用程序而言,内存管理是一种动态分配内存区域的方式。

2.1、为什么需要内存管理?

因为操作系统和应用程序需要大量的内存来运行,同时,应用程序往往运行在虚拟地址空间,需要实际映射到物理地址空间。

3、虚拟地址和物理地址

使用虚拟地址的一个好处是,操作系统可以控制应用程序的内存布局,操作系统决定虚拟地址是否可见、是否允许访问。这种机制允许操作系统采取沙箱机制管理(即应用程序之间的隔离)应用程序,同时实现了对硬件的抽象。
  还有一个好处是,物理内存上不连续的内存区域,在虚拟内存地址空间中可以是连续的。
  对于应用程序开发人员而言,他们不需要关心具体的物理内存地址是否可以访问。
  实际上,每一个应用程序都维护一个独立的虚拟内存地址空间,它们被映射到不同的物理内存区域。操作系统在进行应用程序切换时负责重构虚拟内存地址空间,这就意味着当前应用程序的虚拟地址总是映射到正确的物理地址。
  虚拟地址通过映射的方式转换为物理地址。虚拟地址和物理地址的映射关系保存在页表(page tables,或称translation tables地址转换表)中,如下图所示:
  在这里插入图片描述
页表保存在内存中,由操作系统或者hypervisor(虚拟化技术)管理。页表不是静态的,而是根据应用程序对内存的需求及时更新的,页表更新的同时,也改变了虚拟地址和物理地址的映射关系。

4、MMU

MMU负责地址转换,包括:

1)table walk unit,负责从内存中读取页表;

2)TLBs,负责缓存最近使用的页表项;

需要强调的是,应用程序发起的任何内存地址访问都是虚拟地址。虚拟地址被发送给MMU,MMU首先在TLBs中查找是否有对应的页表项,如果没有找到对应的页表项,那么table walk unit会从内存中读取合适的页表项(table entry)。在这里插入图片描述
  访问物理内存之前,必须完成虚拟地址到物理地址的转换。对于访问缓存数据而言,同样需要提前完成VA-2-PA的转换,因为ARMv6以后的处理器都将缓存数据通过物理地址的方式(physically tagged)缓存,因此,必须在cache lookup之前完成VA-2-PA转换。ARM CPU包含数据缓存和指令缓存,可以理解为片内物理内存,各自拥有独立的物理地址段。

4.1、Table Entry 页表项

虚拟地址空间被划分为以页(32位系统下页大小通常为4KB)为单位的内存页,每一个内存页在页表中占据一个页表项,即Table Entry。页表项和内存页是一一对应的,Entry 0对应block 0(0号内存页),Entry 1对应block 1,依此类推。每一个页表项包含对应的物理地址以及访问属性
  在这里插入图片描述

4…2、Table lookup 页表查找

地址转换必然要涉及到页表查找,当发生地址转换时,虚拟地址被分为两部分:
  在这里插入图片描述
上图是一个一级页表(ARMv8硬件上支持4级页表,Linux内核默认使用3级页表)查找过程图。

虚拟地址的上半部分——Which entry,用来指定页表项,该页表项中保存了虚拟地址对应的物理地址。

虚拟地址的下半部分——Offset in block,表示页内偏移地址,在转换过程中保持不变

4.3、Mutilevel translation 多级页表转换

在这里插入图片描述

多级页表实际上是将虚拟内存地址空间划分为多个相同大小的页存大页,再将每个内存大页划分为多个相同大小的内存小页。

ARMv8最大支持4级页表,编号0~3。

使用多级页表的好处是,内存大页可以加速地址转换的效率,比如提高TLBs缓存的有效性;同时,内存小页有给应用程序提供了对虚拟内存地址空间的细粒化管理。但是与此同时,TLBs缓存内存小页的有效性就比较差。

为了降低这种开销,操作系统需要在内存大页的效率和内存小页的映射之间进行权衡,决定最合适的页表层级。

5、ARMv8-A虚拟地址空间

ARMv8-A架构有几个独立的虚拟地址空间,如下图所示:
  在这里插入图片描述
 上图显示了三种虚拟地址空间:

1)NS.EL0 and NS.EL1 (Non-secure EL0/EL1)

2)NS.EL2 (Non-secure EL2)

3)EL3

每一种虚拟地址空间都是独立的,而且拥有各自的页表设置(页表层级和页表),我们通常称这种页表设置为——translation regimes。同样的,Secure EL0/EL1/EL2也有各自的虚拟地址空间,只不过上图没有展示出来。

**注意:**Armv8.4-A中增加了对安全EL2的支持。

由于存在多个虚拟地址空间,因此指定地址位于哪个地址空间非常重要。例如:NS。“EL2:0x8000”表示非安全EL2虚拟地址空间中的地址“0x8000”。
该图还显示了来自非安全EL0和非安全EL1的虚拟地址经过两组表。
这些表支持虚拟化,并允许管理程序虚拟化虚拟机(VM)所看到的物理内存视图。

在虚拟化中,我们把由操作系统控制的转换集合称为阶段1。阶段1表将虚拟地址转换为中间物理地址(IPAs)。在阶段1中,操作系统认为ipa是物理地址空间。然而,管理程序控制第二组转换,我们称之为阶段2。第二组转换将ipa转换为物理地址。下图显示了两组翻译的工作原理:
在这里插入图片描述

虽然表的格式有一些细微的差别,但第一阶段和第二阶段的翻译过程通常是相同的。

5.1、地址大小

ARMv8-A架构是64位架构,但是并不意味着其地址位宽为64位。

5.1.1 虚拟地址位宽

虚拟地址以64位的格式保存,LDR和STR指令通常将地址保存在X寄存器中,但是这并不意味着X寄存器中所有的地址都是有效的。

下图演示了AArch64架构虚拟地址空间布局:
  在这里插入图片描述
EL0/EL1虚拟地址空间有两个区域:内核空间和应用程序空间。这两个区域显示在图的左侧,内核空间位于顶部,应用程序空间(被标记为“用户空间”)位于地址空间的底部。内核空间和用户空间各自维护相互独立的页表,这也意味着它们的地址映射也是相互独立的。

在地址空间的底部有一个区域,用于所有其他Exception级别。该区域显示在图表的右侧,是一个没有文本的框。

注意:如果您设置HCR_EL2。E2H to 1允许主机操作系统运行在EL2,主机操作系统的应用程序运行在EL0。在这种场景下,EL2也有上、下两个区域。
地址空间的每个区域的大小最多为252字节。然而,每个区域都可以独立地缩小到更小的尺寸。

TCR_ELx寄存器中的TnSZ字段控制虚拟地址空间的大小。例如,下图显示TCR_EL1控制EL0/EL1虚拟地址空间:
在这里插入图片描述

ARMv8架构目前最大支持48位虚拟地址。
**注意:**所有Armv8-A实现都支持48位虚拟地址。对52位虚拟地址的支持是可选的,由ID_AA64MMFR2_EL1报告。在撰写本文时,没有任何Arm Cortex-A处理器支持52位虚拟地址。

5.1.2、物理地址位宽

物理地址位宽由芯片决定,最大支持52位。ID_AA64MMFR0_EL1寄存器记录了芯片支持的物理地址位宽。对于ARM Cortex-A系列处理器而言,通常为40位或者44位。

ARMv8.0-A架构最大支持48位物理地址,ARM8.2-A架构最大支持52位物理地址。

5.1.3、合适的物理地址位宽 IPA

如果你在页表项(页表项中记录的是物理地址)中指定一个超过芯片最大物理地址的地址,那么MMU会产生一个物理地址大小异常。

IPA地址空间大小可以像虚拟地址空间一样构建。VTCR_EL2.TOSZ寄存器控制地址大小,理论上最大可以配置到和芯片支持的物理地址空间一样的大小。

5.2、地址空间标识 ASID

许多现代的操作系统让所有的应用运行在同样的地址区域,这就是我们提到的用户地址空间。实际上,不同的应用需要不同的地址映射。比如,VA 0x8000实际转换的物理地址取决于当前正在运行的应用,即每个应用程序自己维护一个页表。

理想状态下,我们希望不同的应用的页表项共存于TLBs中,防止上下文切换时TLB中没有当前应用(准确地讲应该是指进程)的页表项。但是处理器怎么知道不同应用的VA 0x8000对应的物理地址呢?在ARMv8-A架构中,答案是Address Space Identifier (ASIDs)。

对于EL0/EL1虚拟地址空间,通过页表项属性字段的nG位标记页表为Global(G)或者Non-Global(nG)。比如,内核地址映射为全局页表,应用程序地址映射为非全局页表。不管当前执行的是哪个应用程序,全局页表都是生效的;非全局页表只有在特定应用执行时才生效。

非全局页表项在TLBs中使用ASID标记。在进行TLB查找时,将当前选择的ASID与TLB页表项中的ASID进行比较。如果不匹配,则表示当前TLB页表项无效。下图显示了全局页表和局部页表,以及ASID标记:
  在这里插入图片描述
上图展示了不同应用的TLB页表项可以在缓存中共存,由ASID决定哪一个页表项生效。

ASID保存在两个TTBRn_EL1寄存器之中,通常用户空间使用TTBR0_EL1寄存器。因此,TTBRn_EL1寄存器值的更新会同时更新ASID和当前生效的页表项。

需要注意的是,当HCR_EL2.E2H置位时,ASID标记在EL2模式同样生效。

5.3、虚拟机标识 VMID

通过VMID(Virtual Machine Identifier)允许不同的虚拟机页表共存于cache中,类似于ASID。

5.4、Common not Private (CnP)

试想,在一个多处理器系统中,一个处理器上的ASIDs和VMIDs是否可以同样应用在其他处理器上呢?

对于ARMv8.0-A架构而言,答案是完全没有必要。因为应用程序不需要ASID跨处理器生效。比如,ASID 5在A处理器上可能是计算机程序,在B处理器上是浏览器。这一点说明,一个处理器创建的TLB页表项不能用在其他处理器上,即每个处理器维护自己的页表。

但是ARMv8.2-A架构在TTBR(Translation Table Base Register)寄存器中引入了Common not Private(CnP)位,通过设置CnP位,软件可以使ASIDs和VMIDs跨处理器生效,即允许一个处理器创建的页表项在另外一个处理器上同样生效。

6、地址转换控制

6.1、页表格式

以下是集中页表项的格式:
在这里插入图片描述
 每一个页表项都是64位,最低两位表示页表层级。

顶层页表没有Table描述符,底层页表没有Page描述符。

7、页大小 Translation Granule

翻译颗粒是可以描述的最小内存块。没有更小的东西可以被描述,只有更大的块,它们是颗粒的倍数

页是虚拟地址空间分配的最小单位。ARMv8-A架构支持4KB/16KB/64KB几种大小的页。

ID_AA64MMFR0_EL1寄存器设置了芯片支持的页大小,所有ARM Cortex-A系列处理器都支持4KB和64KB页。
  在这里插入图片描述
4KB和16KB页最大支持48位虚拟地址,如果要支持52位虚拟地址,必须使用64KB页。

注意:TCR_EL1有两个独立的字段,分别控制内核空间和用户空间虚拟地址范围的粒度大小。这些字段被称为TG1(内核空间)和TG0(用户空间)。对于程序员来说,一个潜在的问题是这两个字段有不同的编码

7.2.虚拟地址的各级页表序号

粒子和虚拟地址空间的大小共同控制着地址转换的起始级别
上表总结了表的每个级别上每个颗粒的块大小(单个条目所覆盖的虚拟地址范围的大小)。从块大小中,您可以计算出虚拟地址的哪些位用于索引表的每个级别。

让我们以4KB颗粒为例。下图显示了用于索引一个4KB颗粒的不同级别表的位:
在这里插入图片描述
想象一下,对于一个配置,您设置了虚拟地址空间TCR_ELx的大小。T0SZ,到32。那么虚拟地址空间的大小(以地址位为单位)计算如下:
64 - T0SZ = 32位地址空间(地址位31:0)
如果我们再次查看之前的4KB颗粒图,级别0是由47:39位索引的。对于32位地址空间,您没有这些位。因此,配置的初始转换级别为级别1。
接下来,假设您将T0SZ设置为34:
64 - T0SZ = 30位地址空间(地址位29:0)
这一次,您没有用于索引0级表或1级表的任何其他位,因此配置的初始转换级别为2级。
正如前面的图表所示,当虚拟地址空间的大小减小时,您需要更少的表级别来描述它。
这些示例基于使用4KB颗粒。同样的原理也适用于使用16KB和64KB的颗粒,但是地址位发生了变化。

7.2、控制地址转换的寄存器

  • SCTLR_ELx
        M - 使能MMU
        C - 使能数据缓存和unified缓存(所有处理器共用的缓存)
        EE - 页表字节序

  • TTBR0_ELx和TTBR1_ELx
        BADDR - 起始页表项的物理地址
        ASID - 局部页表的地址空间标识

  • TCR_ELx
        PS/IPS - 最大物理地址位宽
        TnSZ - 页表覆盖的地址空间大小
        TGn - 页大小
        SH/IRGN/ORGN - MMU页表遍历是的缓存性和共享性
        TBIn - 禁止页表遍历到指定的页表项

  • MAIR_ELx
        Attr - 一级页表的类型和缓存性

7.3、关闭MMU

当MMU禁用时,所有的地址都flat-mapped,可以理解为没有虚拟地址。

8、TLB维护

TLB缓存最近使用的页表项,从而允许接下来的页表项查找复用缓存的页表项,而不需要重新加载页表。

当内存中的页表项发生改变时,必须丢弃TLB中缓存对应的页表项,从而保证页表项的一致性。

当发生如下错误时,TLBs不应该缓存页表项:

1)发生地址转换错误(unmapped address)

2)发生地址发小错误(超出地址范围)

3)访问权限错误

8.1、TLB操作方法

使用TLBI指令丢弃TLB中的页表项,其语法如下:

TLBI {IS|OS} {, }

type字段表示丢弃哪个页表项:

All - 所有页表项

VA - 匹配xt字段中的VA和ASID的页表项

VAA - 匹配xt中的VA的页表项,对所有ASID生效

ASID - 匹配xt字段中ASID的页表项

level字段表示虚拟地址空间类别

E1 - EL0/1虚拟地址空间

E2 - EL2虚拟地址空间

E3 - EL3虚拟地址空间

IS | OS字段设置内部共享或者外部共享

IS - 广播到Inner Shareable domain的其他核

OS - 广播到Outer Shareable domain的其他核

Xt字段设置VA和ASID

举例说明:

STR X1, [X5]    //写入页表入口
DSB ISH          //设置内存屏障
TBLI VAAE1IS, X0 //丢弃EL0/1中匹配VA地址的页表项
DSB ISH          //解除内存屏障
ISB                 //指令屏障,同步处理器上下文

9地址转换指令

使用地址转换指令(AT指令),可以查询指定VA对应的PA,结果写入PAR_EL1(Physical Address Register)寄存器。

高级别的运行模式可以使用AT指令查询低级别运行模式的地址转换。

需要注意的是,使用AT指令发生地址转换异常时,不会抛出任何异常,只会在PAR_EL1寄存器中记录下来。

"Learn Python the Hard Way" 是一本非常受欢迎的Python编程入门教材,由Zed Shaw编著。虽然很多人推荐这本书,但是可能有人会想要获取中文版的PDF。 实际上,"Learn Python the Hard Way" 的官方版本只有英文版,目前没有官方中文翻译。然而,你仍然可以通过互联网上的其他资源找到非官方的中文翻译版本。在很多技术论坛和编程社区上,都有Python爱好者提供自己的中文翻译版本,一些电子书资源网站上也有非官方的中文PDF版本。 要找到中文翻译版,你可以在搜索引擎中输入相关关键词,比如 "learn python the hard way 中文pdf" 或者 "learn python the hard way 中文翻译"。在搜索结果中,你可能会找到一些免费的资源供你下载或在线阅读。此外,还有一些网站提供付费的中文翻译版本,你可以根据自己的需求决定是否购买。 无论你选择哪种方式,记得要确认翻译版本的质量和真实性。可以通过查看评论、评级或者与其他Python学习者交流来了解其他人对于该版本的评价。另外,虽然中文翻译版本对于初学者会有一定帮助,但如果你有能力阅读英文,最好还是参考官方英文版来学习,以避免因为翻译的不准确而导致的误解或困惑。 总而言之,虽然"Learn Python the Hard Way"的官方版本只有英文版,但你可以通过互联网查找一些非官方的中文翻译版本。希望你能够找到一本合适的中文翻译版本,顺利学习Python编程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值