0%

ARM64内存屏障

基本逻辑

理解内存屏障需要从理解内存序出发,所谓内存屏障只是用内存屏障指令强制约束内存序而已。
对于现在弱内存序处理器而言,CPU上指令执行的顺序已经和程序员想象的顺序不一样,CPU
手册上会定义各种指令间执行顺序的具体行为,这些定义一般会约束指令之间不能乱序的行为,
除此之外指令之间都是可以乱序的。

CPU手册上还会定义一些内存屏障指令,这些指令强制约束了特定指令之间的执行顺序,这些
内存屏障指令是CPU基本内存序的补充。

一个关于内存屏障最经典的例子如下,在多个core上:

1
2
3
4
core 1           core 2

store data check flag
set flag get stored date

core1的逻辑是先准备数据,数据准备完后设立一个标记位。core2不断的在检测标记位,当
检测到标记位的时候,core2就可以使用准备好的数据了。

但是,core1的store date和set flag两个操作可能是乱序执行的,可能在core2看来flags
已经置位了,但是其实core1的数据还没有准备好, 这时,如果core2去使用数据,就有可能
出错。正确的做法是在store data和set flag执行加上内存屏障,确保store data在set flag
之前完成。注意,这里和cache一致性没有关系, 如果,我们单独看data或者单独看flag,
两者各自都是硬件保证cache一致性的。

ARM64基本内存序定义

简介里提到的”ARM Cortex-A Series Programmer’s Guide for ARMv8-A”并没有详细介绍CPU
的内存序。ARM构架手册的B2.2/2.3详细定义了ARM64的内存模型。

ARM构架手册的B2.2/B2.3的一个学习笔记可以参考这里

ARM64内存屏障指令

这几天又重新看了下宋老师写的关于ARM barrier的文章,这里把其中的关键信息抽取下。
关于barrier我们要明确的是在加barrier的场景中:1. 我们要隔离什么样的操作;2. 我们
隔离操作期望的可见范围是什么;3. 对于需要隔离的访存操作可以进一步区分类型或方向。

我们先具体看下DMB/DSB/ISB这三个barrier指令。DMB隔离的是访存的指令,它只对访存指令
的前后关系有约束,DSB在DMB的基础上可以约束其它指令的前后关系,ISB是最强的barrier
指令,它不单可以保证前后指令的顺序,而且会清空流水线。

这些指令可以带参数表示不同的作用域以及作用对象。ISH/OSH/SY表示的是inner shareble,
outer shareble以及全系统作用域,LD/ST表示只对barrier指令之前的load或者store指令
起作用。

画一个图说明下所谓的作用域是怎么回事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+-----------------------------------------------------+ system
| +-------------------------------------------+ outer |
| | +---------------------------------+ inner | |
| | | +-----+ +-----+ +-----+ | | |
| | | | CPU | | CPU | ... | CPU | | | |
| | | +--+--+ +--+--+ +--+--+ | | |
| | | | | | | | |
| | +----+---------+-------------+----+ | |
| | | | | | |
| | -----+------+--+-------------+-+----- | |
| | | system bus | | |
| | | +-----------+----------+ |
| | +----+-+-+-+ | | |
| | | |DMA| | | +--+-+ |
| | | +---+ | | | M3 | |
| | | device | | +----+ |
| | +----------+ | |
| +--------------------+ |
+-----------------------------------------------------+

如上所示,各个CPU在一个inner域里,DMA和CPU在一个outer域里,对于系统里的其它计算
单元(比如这里的M3),它和系统的其它部件在最大的system域里。

现在还没有想通的是DMA的情况,比如,先准备数据,然后写一个MMIO的doorbell发起DMA,
要保证准备好数据,然后触发DMA,只要保证准备数据和doorbell写之间的顺序就可以了,
也就是要保证store DDR和store MMIO之间的顺序,那么这个时候只要加DMB ISHST就可以了吧?

还有一个问题,怎么理解CPU改SMMU页表和SMMU page walk隐式页表访问的序? 因为一般的,
我们是这样理解保序的,一个MASTER发出两个操作,另一个CPU看到是保存的,这里CPU和
SMMU是两个MASTER,无法理解这里。