2 Barriers
ARM架构包含能够强制访问序和在特定点完成的barrier指令。在一些架构中,类似的命令称为fence。
如果你写代码的地方顺序非常重要,看Appendix J7 Litmus Tests。
ARM架构参考手册定义了某些重要术语,特别的,术语observe和must be observed。在典型的系统中,它定义了master的总线接口(比如,core或者GPU和内联)必须处理总线事务。仅master可以看到传输。所有的总线事务都是由master发起的。master发起事务的顺序没有必要与事务在slave设备上完成的顺序一样,因为事务可能被内联重排,若没有特别的强制。
一个简单的方法来描述可见性:当我能读取你写的内容时我可以看到你写的内容,当我不再修改你读取的内容时,我看到你所读取的内容。这里提到的”我”和“你”为core和系统中的其他master。
这里有架构提供的三种barrier指令:
ISB:这用于保证任何后续的指令都被取出,这样当前MMU配置检查了特权和访问。用于保证任何之前已执行的修改上下文的操作,如写系统控制寄存器,在ISB完成时候也完成。对于硬件来说,这意味着指令流水线被冲刷。典型的在内存管理中使用这个,cache管理,上下文切换代码,或在内存中代码被移除。
DMB: 这可以防止数据访问指令的重排会跨barrier指令。所有的数据访问,loads或stores,不能为指令取出,处理器在DMB之前发出的,在特定的shareability域对其他master都可见,这也在DMB之后的任何数据访问之前可见。
比如:
LDR x0, [x1] // 在STR之前需要被内存系统看见
DMB ISHLD
ADD x2, #1 // 可能在内存系统看到前后执行
LDR.
STR x3, [x4] // 在LDR后必须被内存系统可见
它也保证了任何之前的数据或统一的cache维护操作在后续数据访问执行之前完成。
DC CSW, x5 // 通过组/路清除数据
LDR x0, [x1] // 数据cache清楚操作可能没有被本指令看到
DMB ISH
LDR x2, [x3] // 数据cache清除操作被本指令看到
Instruction
DSB: 这使用与DMB相同的顺序,只是会阻塞其他的指令,不仅是loads或stores,或两者,知道同步操作完成。这可以用于阻止SEV指令的执行,比如,这将向其他core发送信号表示有事件发生。它会等待直到所有cache,TLB和分支预测维护操作对特定的shareability domain已完成。
比如:
DC ISW, x5 //操作必须在DSB完成之前完成
STR x0, [x1] //访问必须在DSB完成之前完成
DSB ISH
ADD x2, x2, #3 //只有在DSB完成后才执行
从上述例子可以看出,DMB和DSB指令有一个参数指定barrier操作的访问类型,以及应用的shareability domain。
下表列出了有用的选项。
选项 | 访问顺序 | Shareability domain |
OSHLD | Load-load, Load-store | Outer shareability |
OSHST | Store-store | |
OSH | Any-any | |
NSHLD | Load-load, Load-store | Non-shareable |
NSHST | Store-store | |
NSOSH | Any-any | |
ISHLD | Load-load, Load-store | Inner shareable |
ISHST | Store-store | |
ISOSH | Any-any | |
LD | Load-load, Load-store | Full system |
ST | Store-store | |
SY | Any-any |
访问顺序域指明了barrier应用于哪些访问。有三种选择。
Load-Load/Store: 这意味着barrier要求所有的loads在barrier之前完成但不要求store完成。barrier之后的Loads和stores以程序顺序必须等待barrier完成在执行。
Store-store: 这意味着barrier仅影响store访问而loads仍可以在barrier自由重排。
Any-any: 这意味着loads和stores必须在barrier之前完成。Barrier之后的loads和stores必须等待barrier完成再执行。
barrier用于防止不安全的优化产生且强制一个特定的内存顺序。使用不必要的barrier指令可以减少软件性能。需要慎重考虑在特定情况下barrier是否有必要,若有必要,barrier使用正确。
一个更不易察觉的影响为指令接口,数据接口和core的MMU表walk被认为是分开的观察者。这意味着你需要使用DSB指令来保证对一个接口的访问可以在不同的接口中被看到。
如果你执行了一个数据cache清除和无效化操作,比如DCCVAU X0,你必须后面插入一个DSB指令,来保证后续页表walk,转换表项的修改,指令的获取,或内存中指令的更新,可以看到这个新的值。
比如,考虑转换表的更新:
STR X0,[X1] //更新转换表
DSB ISHST //保证写已完成
TLBI VAE1IS, X2 //无效化TLB中修改的页表项
DSB ISH //保证TLB无效化完成
ISB //在该处理器上同步上下文
DSB用于保证维护操作已完成且ISB保证这些操作的效果可以被接下来的指令看到。
处理器可以在任何时候预测性的访问标记为normal的地址。因此当考虑是否需要barrier时,不要仅考虑load或store指令产生的明确访问。
2.1 one-way barriers
AArch64增加了新的load和store指令携带了隐藏的barrier语义。这要求所有的load和store在隐藏barrier之前或之后以程序顺序访问被看见。
Load-Acquire(LDAR):在LDAR之后的所有loads和stores以程序顺序,与目标地址的shareability domain匹配,在LDAR之后被看见。
Store-Release(STLR):在STLR之前的所有loads和stores,与目标地址的shareability domain匹配陪,在STLR之前被看见。
还有一些互斥的版本,LDAXR和STLXR。
不像数据屏障指令,它需要一个qualifier来控制那些共享域看到屏障,LDAR和STLR指令使用访问地址的属性。
LDAR指令保证在LDAR之后的任何内存访问仅在load-acquire之后被可见。Store-release保证了所有更早的内存访问在store-release可见之前被看见,同时store对能够同时存储cache中数据的系统的所有部分可见。
上图显示了访问是如何在一个方向上跨过one-way barrier而不是在其他方向上。