历史上的今天
返回首页

历史上的今天

今天是:2024年10月26日(星期六)

2021年10月26日 | ARMv7-A 处理器窥探(5) —— MMU/TLB

2021-10-26 来源:eefocus

0、回顾

前面知道,MMU 用作虚拟地址和物理地址的相互转换,是为了能够给 OS 提供统一视角的虚拟地址空间;


TLB 的作用是作为 MMU 的 Cache,以提高 MMU 的性能,他们之间的关系如下:

1、ARM 处理器发出地址访问(虚拟地址),首先过 MMU 地址翻译单元的 TLB,如果 TLB 命中,那么直接返回真实的物理地址;


2、如果 TLB Miss,那么就要靠 Table Walk 单元去主存中查找表,以获取物理地址,然后通过 Cache,去访问;


3、Cache 如果命中,那么直接返回实际物理地址的数据,否则,也就是最糟糕的情况,会去访问主存的数据;


上面的过程呢,软件要做的,只有配置并放好这个 Transliation Tables,其他的过程,全部是硬件行为;下面马上仔细的过这部分的细节;


使能 MMU 的参考代码(因为是 CP15 的系统控制寄存器,所以使用 MRC/MCR 指令):


MRC p15, 0, R1, c1, C0, 0 ;Read control register

ORR R1, #0x1 ;Set M bit

MCR p15, 0,R1,C1, C0,0 ;Write control register and enable MMU

这里要注意的一点是,可能要用到内存屏障指令,因为这里就开启了 MMU,即将进入虚拟内存的世界,要确保在这之前,流水线干净,所以执行已经完毕;


1、TLB

TLB 的全称是:Translation Lookaside Buffer;从第一节的那个图可以看出来,MMU 做 Table Walk 的这个 Transliation Tables 是放到主存中,主存访问速度很慢(加 Cache 的根本原因),所以,这里每次都去再主存中做 Table Walk,显然效率非常低,所以,这里就为这个 Table Walk 定制了一个属于他的 “Cache”,称之为 TLB;


但是与 真是的 Cache 不一样(详见《ARMv7-A 处理器窥探(4) —— Cache》),这个 TLB 是专门缓存 Transliation Tables 的,典型的情况,他的组成如下:

由 VA、ASID、PA、Attributes 组成,即:


VA:虚拟地址;


PA:物理地址;


ASID:Address Space ID;


Attributes:属性;


1.1、TLB coherency

TLB 既然扮演的 Transliation Tables Cache 的角色,那么也会有一致性问题,最典型的就是再 OS 中,上下文切换的时候,上一个进程的虚拟地址对应的物理地址表,肯定是和另一个不一样,导致 TLB 一致性问题;此刻,OS 必须处理这种情况,使得上一个进程的 TLB 对下一个失效,也可以直接通过 CP15 控制寄存器,来 flush 掉 TLB(代价太大);


2、MMU

这里,抛开大物理地址扩展和 section 和 supersection 的分析,暂时就看最最常用的两段查找;两段页表查找,我们称第一级页表为 L1,第二级为 L2;


2.1、TTBR0、TTBR1、TTBCR

前面知道,软件需要负责构建这个虚拟地址到物理地址的转换表:Transliation Tables,当软件构件完毕这个表后,只需要告诉硬件,这个 Transliation Tables 放到了那个首地址即可,这个配置通过写 ARM 的 TTBR 寄存器实现(Translation Table Base Address );这里其实有两个 TTRB 寄存器,分别叫 TTBR0 和 TTBR1,为啥两个,后面解释;


2.1.1、TTBCR

和这个 TTBR0、TTBR1 勾肩搭背的,还有一个 TTBCR 寄存器,他们直接什么关系呢,看寄存器说明:


TTBCR:

PD0 和 PD1 是和 Security Extensions 相关的,不管他;


EAE 是和 Large Physical Address Extension  相关的,不管他;


主要关注这里的 N[2:0],指示TTBR0页表基址寄存器基址位宽,同时指示使用 TTBR0 还是 TTBR1 作为页表基址寄存器,以及 TTBR0 页表尺寸:


如果 N = 0 的话,则在做 Table Walk 的时候使用 TTBR0 指定的基地址作为 Transliation Tables 入口的地址;


如果 N > 0 的话:指示TTBR0页表基址寄存器基址位宽,同时指示使用 TTBR0 还是 TTBR1 作为页表基址寄存器,以及 TTBR0 页表尺寸;

N==0,使用 TTBR0。

N>0,如果虚拟地址[31:32-N]为0,则使用 TTBR0;其他情况使用TTRB1。这种情况下,N 指示了TTBR1的页表地址,也指示了 TTBR0 的页表大小。


TTRB0的页表大小由TTBCR.N控制,TTRB1的页表大小为16KB。


我换句话来说,当 N>0 的时候,比如 N=1,那么按照这种说法,VA [31:31] 也就是 VA 的 bit[31] 为 0 的时候,使用 TTBR0 否则使用 TTRB1,按照地址空间来划分,即,32bits 地址,当最高位为 0,即虚拟地址为 0x0000_0000 ~ 0x7FFF_FFFF  这个区间的时候,使用 TTBR0 作为 Transliation Tables 入口的地址,从 0x8000_000 ~ 0xFFFF_FFFF 的虚拟地址空间,使用 TTBR1;


ARM 官方举了个例子,当 TTBCR.N=3‘b111 的时候,VA [31:25] 全部为 0 的时候,使用 TTBR0,按照地址空间来划分就是,虚拟地址为:0x0000_0000 ~ 0x01FF_FFFF 这段区间使用 TTBR0 作为 Transliation Tables 入口的地址;


0x0200_0000 ~ 0xFFFF_FFFF 的虚拟地址空间,使用 TTBR1;

OK,现在可以理解为,配置 TTBCR.N 这个值,可以实现将虚拟地址切割成为两部分,一部分使用 TTBR0 指定的 Transliation Tables 进行 Table Walk,另一部分使用 TTBR1 指定的 Transliation Tables 进行 Table Walk,这个有什么好处呢?比如,内核的页表,是不会改变的,而进程上下文的页表是会改变的,有了这个的话,就可以考虑用一个 TTBR 来专门为内核服务,另一个 TTBR 为进程服务,这样避免进程和内核使用同一个页表,每次都要进行内核页表的拷贝;


由于 TTBCR 是 CP15 的寄存器,访问 TTBCR 的指令为:


MRC p15, 0, , c2, c0, 2 ; Read TTBCR into Rt

MCR p15, 0, , c2, c0, 2 ; Write RT to TTBCR

 

2.1.2、TTBR0、TTBR1

上面说了 TTBCR,下面来看 TTRB0、TTRB1 寄存器描述:


TTBR0

在带有多核处理器扩展的情况下 TTBR0 由一个可变的长度构成 Transliation Tables Base Address,这个 x 就是上面的 (14 - (TTBCR.N));


Bits[31:x]:x=(14-(TTBCR.N))。一级页表地址;


Bits[x-1:7]:Reserved;


NOS:Not Outer Shareable bit,指示了做 Table walk 的那个内存的属性,是 Outer Shareable 还是 Inner Shareable.


0  Outer Shareable.

1  Inner Shareable.

TTBR0.S == 0 时,该bit无效;


S:Shareable bit. 指示内存共享属性与页表转换的关系;


0  Non-shareable.

1  Shareable.

RNG:Region bits,指示 Outer Cache 属性与页表转换的关系;


0b00 Normal memory, Outer Non-cacheable.

0b01 Normal memory, Outer Write-Back Write-Allocate Cacheable.

0b10 Normal memory, Outer Write-Through Cacheable.

0b11 Normal memory, Outer Write-Back no Write-Allocate Cacheable.

IRGN[6,0]:Inner region bits,指示 Inner Cache 属性与页表转换的关系;


0b00 Normal memory, Inner Non-cacheable.

0b01 Normal memory, Inner Write-Back Write-Allocate Cacheable.

0b10 Normal memory, Inner Write-Through Cacheable.

0b11 Normal memory, Inner Write-Back no Write-Allocate Cacheable.

访问 TTBR0 的指令为:


MRC p15, 0, , c2, c0, 0 ; Read 32-bit TTBR0 into Rt

MCR p15, 0, , c2, c0, 0 ; Write Rt to 32-bit TTBR0

 

TTBR1

它的位域和 TTBR0 几乎一样,唯一不一样的地方在于,配置的地址区间在于 bit[31:14],这意味着,配置进 TTBR1 的 Transliation Tables Base Address 的物理地址,必须 16KB 对齐;


访问 TTBR1 的指令为:


MRC p15, 0, , c2, c0, 1 ; Read 32-bit TTBR1 into Rt

MCR p15, 0, , c2, c0, 1 ; Write Rt to 32-bit TTBR1

 

2.2、Translation Table

现在我们知道了合理的配置 TTBCR/TTBR0/TTBR1 可以分配并指定 Transliation Tables,而这个 Transliation Tables 位于内存中,用作 MMU 来做 Table Walk;那么接下来我们需要知道页表的结构,这样我们才能够在内存中创建页表,并将页表配置给 TTBR 寄存器,完成 MMU 的配置;


不考虑大地址扩展和 SuperSection 以及 Section 的情况下,针对 Transliation Tables,ARMv7-A 的手册给出了如下的图解

图中,我们暂时只考虑 Page Table 的情况,即红色部分(其余的可以照着推);


蓝色的部分,可以理解为之前寄存器里面配置的那个 N 值;这里为了说明情况,我们暂时将 N 定为 0;


2.2.1、L1 Address Translation

我们先暂时不管使用 TTBR0 还是 TTBR1,其实过程是一样的;此刻当 N = 0 的时候,一级页表以虚拟地址(后面简称 VA,即 Virtual Address)VA[31:20] 作为 L1 Index,一共 12bits,最大能够表征 4K 的 Index:

每个入口是 4 Bytes 也就是一个 Word,32bits 的入口,L1 Index 从 0~4095,一共 4K,在内存上,每个入口 4Bytes,那么 L1 页表占用内存 4K x 4 Bytes = 16KB;


每一个入口是什么样子的呢,我们放大来看:

可以看到,这个入口,根据不同的配置,内容有所区别,一共有 4 种类型,这 4 种类型,通过 32bits 的尾部 2 bits 来区分,即,绿色部分(Section 和 SuperSection 的区分,还靠 bit[18]);


这里我们暂时不关心 Section 和 SuperSection,关注于红色部分和那个 Fault;


Level 2 Descriptor Base Address:指向的是 L2 页表的物理地址的基地址;可以看到他是 bit[31:10],是 1KB 边界对齐的;


这个 Domain 指的是 ARM 支持将内存标记为最多 16 个 domain,并以 Domain ID 作为区分,每个 Domain 可以支持配置成为不同的访问权限(通过配置 CP15 的 C3 的 Domain Access Control Register (DACR) 寄存器):

配置指令为:


MRC p15, 0, , c3, c0, 0 ; Read DACR into Rt

MCR p15, 0, , c3, c0, 0 ; Write Rt to DACR

针对这个 DACR 寄存器,ARM 官方建议配置成为 Client;


The use of domains is deprecated in the ARMv7 architecture, and will eventually be removed,

but in order for access permissions to be enforced, it is still necessary to assign a domain number

to a section and to ensure that the permission bits for that domain are set to client. Typically, you

would set all domain ID fields to 0 and set all fields in the DACR to ‘Client’.


2.2.2、L2 Address Translation

介绍完 L1 Address Translation 后,下面是二级页表!与 L1 页表不一样,二级页表不和 N 值挂钩,它直接采用 VA[19:12]  作为 L2 Index 索引,一共 8 bits,最大能够表征 256 的 L2 Index;


加入 L2 页表后结合 L1,通过一个给定的 VA 进行索引的第二步为(图中表示的 N 值为 0):

这样,一个 VA 通过高地址部分[31:20] 索引到了 L1,再从 L1 指向的 L2 加上 VA[19:12] 作为 L2 Index,索引到 L2 表的固定位置;


L2 也是每条由 4 Bytes 构成,即一个 32bits 的数,那么一个 L2 表大小为 256 x 4 Bytes = 1024 Bytes = 1KB;一共有 4096 个这样的 L2,那么 L2 表总的大小为:4096 x 1KB = 4MB;


我们放大每一条 L2 的入口:

我们只关心红色部分!可以看到,这个 Small Page Base Address 有 bit[31:12] 也就是 4KB 边界对齐!接下来我们看剩余几个位的含义:


AP/APX:Access Permission 即访问权限,每个内存区域 都有自己的权限,不符合访问权限的 内存访问都会引发 异常。如果是 数据访问 则引发 数据异常。如果是 指令访问,且该指令在执行前没有被 flush,将引发 预取指异常。引发的 异常原因将会被设置在 CP15 的 the fault address and fault status registers;

内存区域类型 可以通过 TEX字段、C字段 和 B字段 来进行设置:

XN:指的是 Execute Never,不允许执行,如果往这里取地址执行,那么会导致异常发生;通常,Device memory 类型的区域会配置成为 XN;


S:指的是是否具有 Shareable 属性;


nG:non-Global,这个标记告诉 MMU,这个页表是否是一个全局的,什么意思呢?看下面:


当 nG 为 0 的时候,说明此区域是全局可见的,换句话来说,就是任何时候都生效;


当 nG 为 1 的时候,说明此区域不是全局的,要联合这个 ASID 来确认;


每一个 nG=1 的区域,都会和 ASID 来关联,ASID (Address Space Identifier),这代表,TLB 可以存在多个不同进程的页表缓存,后面说 ASID 的时候会仔细说;


自此,L1/L2 分析完毕,那么整个 Table Walk 的流程为:

VA 的 4K 页内偏移,直接对应到 PA 的 4KB 页内偏移;


3、OS Usage Of Translation Tables

通常情况下,在使用 Cortex-A 系列处理器的时候,典型场景是跑多任务 OS;每一个任务(或者成为应用),都有它独立的虚拟地址空间,以及他的独立的 Translation Table;但是对于 OS 来说,Kernel 的 Translation Tables 其实是固定的,只是进程之间的 Translation Tables 不一样而已;


当一个进程启动的时候,OS 负责为他 code 和 data 段建立映射表(Translation Tables);当进程调用诸如 malloc 之类分配内存的行为,OS 负责修改 Translation Tables(Linux 中,实际访问分配的内存的时候,才去修改页表),进程生命周期消亡,OS 负责回收它的资源和页表,并可以为下一个新的进程提供资源;每一个进程都有自己的独立的页表,这便可以保证进程之间不会相互干扰;


3.1、Address Space ID(ASID)

在操作系统中,多进程是一种常态。那么多进程 的情况下,每次切换进程都需要进行 TLB 清理。这样会导致切换的效率变低。为了解决问题,TLB 引入了 ASID(Address Space ID) 。ASID 的范围是 0-255。ASID 由操作系统分配,当前进程的ASID值 被写在 ASID 寄存器 (使用CP15 c3访问)。TLB 在更新页表项时也会将 ASID 写入 TLB。


如果设置了如果 当前进程的ASID,那么 MMU 在查找 TLB 时, 只会查找 TLB 中具有 相同ASID值 的 TLB行。且在切换进程是,TLB 中被设置了 ASID 的 TLB行 不会被清理掉,当下次切换回来的时候还在。所以ASID 的出现使得切换进程时不需要清理 TLB 中的所有数据,可以大大减少切换开销。


有了这个 ASID + nG 的机制,那么 TLB 中就可以缓存不同进程的页表,不用每次都去 flush TLB,导致性能的损失:

3.2、TTBR0、TTBR1

前面我们说了 TTBR0、TTBR1 是根据 TTBCR.N 来进行划分的,典型场景下 OS 跑多任务,如果处理器只能够支持一个 TTBR 的话,也就意味着用户空间和内核空间使用同一个 TTBR,由于内核空间的 code 和 data 几乎是不变的,但是多任务的用户空间都是不一样的,这样就会存在两个问题:


1、多个任务的页表里面,都有同样一部分内核映射的拷贝副本;


2、要修改内核映射的时候,所有任务的页表都要修改;


加入两个 TTBR 的原因,是因为希望内核和用户空间使用两套 TTBR,这样就可以避免上面的尴尬;内核空间固定使用一组,用户空间不断的切换(比如,配合 TTBR0 + ASID 进行性能的提升)


参考文献:


https://www.jianshu.com/p/ef1e93e9d65b


https://www.cs.rutgers.edu/~pxk/416/notes/10-paging.html


https://blog.csdn.net/liyuewuwunaile/article/details/106773630?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

推荐阅读

史海拾趣

Elec & Eltek公司的发展小趣事

随着市场需求的不断变化,Elec公司意识到单一产品已无法满足客户的多样化需求。于是,Elec公司开始寻求与同行业公司的合作。在一次行业交流会上,Elec公司的代表与Eltek公司的代表相识,并发现双方的产品具有很强的互补性。经过多次深入交流,Elec公司与Eltek公司决定开展合作,共同研发具有更高性能、更广泛应用的电子产品。这一合作不仅增强了双方的竞争力,也为客户提供了更多样化的选择。

Dresden Elektronik公司的发展小趣事

Dresden Elektronik公司始终将产品质量放在首位。他们建立了严格的质量管理体系,从原材料采购到生产、检测、包装等各个环节都严格把关。这种对品质的执着追求使公司的产品在市场上赢得了良好的口碑,也为公司赢得了众多忠实的客户。

ZTE高新兴(Gosuncn)公司的发展小趣事

在技术和产品的双重驱动下,Dresden Elektronik公司开始积极拓展市场。他们不仅在国内市场上取得了显著的成绩,还积极开拓国际市场。通过参加国际展会、与跨国企业合作等方式,公司的知名度和影响力逐渐提升,市场份额也不断扩大。

Enovation Controls LLC公司的发展小趣事

在Dresden Elektronik公司创立之初,其创始人看中了电子行业中嵌入式系统技术的巨大潜力。他们凭借对技术的深刻理解和敏锐的市场洞察力,开发出了一系列高性能、低成本的嵌入式系统解决方案。这些创新产品迅速在市场上获得了认可,为公司赢得了第一桶金,也为后续的发展奠定了坚实的基础。

台湾第一电阻(Firstohm)公司的发展小趣事
电冰箱不制冷可能由多种原因引起,包括电源问题、温度设置不当、制冷系统故障等。首先,检查电源插头是否牢固插入插座,并确保插座有电。其次,检查温度设置是否正确,冷藏室温度一般应设置在2-4摄氏度,冷冻室温度应设置在-18摄氏度左右。如果以上均正常,可能是制冷系统出现故障,如压缩机故障、制冷剂泄漏等,需要请专业人员进行检查和维修。
Anaheim Automation公司的发展小趣事

2005年,AMOTECH被Deloitte评为“亚太技术500强”,这进一步提升了公司在国际上的知名度和影响力。同年,公司还获得了ISO14001认证,这体现了公司对环境保护的重视和承诺。随着业务的不断拓展,AMOTECH在2006年和2008年分别建立了青岛办公室和韩国第四工厂,进一步提升了公司的产能和效率。

问答坊 | AI 解惑

wince应用程序常见的错误与解决办法

这几天一直在改wince的应用程序bug,现把自己遇到的一些问题总结下来,在此抛砖引玉,希望大家也把自己遇到的一些提高应用程序稳定性的方法发出来一起分享。 1.指针的使用不能越界,否则很可能误修改其他变量的值,导致不可预测的结果,而且进行错 ...…

查看全部问答>

WINCE6自带RIL的GPRS上网问题!

本人这段时间正在弄WINCE6自带RIL的GPRS上网的问题,本人编译了WINCE6并且加入了RIL模块组件,现在通过RIL也可拨打电话,但在新建拨号连接时选择 Cellular Line 时,能够显示 Device Connected ,但打开IE浏览器时却还是不能连接上,而且上MSN是提示网络 ...…

查看全部问答>

恳求有关IRIG-B码硬件对时的解决方案

能否提供一些IRIG-B码对时方面的电路,谢谢!…

查看全部问答>

为什么 我的定时器不好使呢?

在点按钮后 启动定时器,但是OnTimer好像一直没有启动,对话框始终弹不出来,请教一下,这是什么原因? void CTestTimerDlg::OnButton1() {                 SetTimer(0,1000,NULL); } void CTestTime ...…

查看全部问答>

安防电子的IP化最大的冷水在于网络安全

想想intnet的病毒与黑客吧,用传统的专网,有利于网络安全,这就如中国军队在开发了程控之类的东东后,还保留了大量的人工传接台。专网的安全性想对高,而且成本与维护上都有利。…

查看全部问答>

高性能,低成本,针对Altera Cyclone IV: 3.3-V的TPS54318解决方案

The Altera® Stratix™ IV FPGA参考设计展示了TI TPS54318。…

查看全部问答>

清单里的各种传感器资料,需要的拿走先看着

本帖最后由 paulhyde 于 2014-9-15 09:10 编辑 看到2011国赛的清单后,估计大家的第一反应…

查看全部问答>

STM32串口通信收发不一致,急!

代码如下: while(1) {       while(!USART_GetFlagStatus(USART1,USART_FLAG_RXNE));       //接收           i = USART_ReceiveData(USART1);      ...…

查看全部问答>