我阅读了以下文档:ARM的Barrier_Litmus_Tests_and_Cookbook。
第7.2节显示了获取互斥锁/信号量的代码。
Loop
LDREX R5, [R1] ; read lock
CMP R5, #0 ; check if 0
STREXEQ R5, R0, [R1] ; attempt to store new value
CMPEQ R5, #0 ; test if store suceeded
BNE Loop ; retry if not
DMB
LDREX指令请求对存储器地址进行独占访问。如果处理器具有独占访问权限,则仅使用STREX写入成功。 他们使用DMB指令确保独占写入与所有处理器同步。
我有一个小问题。假设处理器具有对内存地址的独占访问权并将其锁定。完成STREX指令后,将删除独占访问。从现在开始,其他处理器可以访问此内存。但是,写入仍然在处理器的缓存中,直到DMB完成。如果另一个处理器在第一个处理器已锁定但尚未同步到RAM时尝试获取对锁的访问权限,会发生什么情况。内存地址不是唯一锁定到第一个处理器,但写入未完成。
任何人都可以解释,为什么这样做有效且安全。我有我的问题。
答案 0 :(得分:3)
我认为你过度复杂了。看看amba / axi规范(以及你在哪里找到了多核心皮质-m4?)。 ldrex / strex用于在多处理器芯片中跨处理器共享资源。他们一段时间以来被错误地用于其他事情。不幸的是,ARM在正确记录所有这些方面做得非常糟糕。
ldr的独有部分是processorid和地址(范围)保存在表中。当strex发生时,检查该地址(范围)的processorid是否与EXOKAY匹配,如果不是OKAY则不进行存储。 Strex没有清除任何东西,他们有趣地拥有这个clrex指令,我假设将processorid设置为某个不会达到的值,或者取决于他们如何构建表,他们释放了一个表项。
我可以在写完之后尝试这个,但你可以轻松ldrex然后strex然后strex,相当肯定我已经在全尺寸手臂上做了int,将尝试在皮质-m4 ldrex,strex,strex,clrex,strex看看会发生什么。
在单处理器系统中,ldrex / strex预计可以在ARM的逻辑中工作,但芯片供应商不需要支持它,可能只是返回OKAY(而不是EXOKAY)。 L1当然也可能是L2是超出芯片供应商的臂逻辑。 (皮质有没有l2?)。通常情况下,您不必担心触及芯片供应商代码,如果不是无限期地运行很长时间而不知道任何此类代码,因为您将保留在其中一个缓存中。例如,禁用Linux中的两个缓存是皇家PITA,它们可能使它看起来像是编译时选项,但是深入挖掘并看到现实。如果只有一个处理器,您如何获得不同的处理器ID?
在多处理器芯片中,芯片供应商应该在缓存之外正确支持它,如果你甚至可以通过独占访问,如何正常使用ldrex / strex,你最有可能在你的L1缓存中并且永远不会暴露于芯片供应商所提供的内容,但如果您在两者之间中断并且您很可能被L2保存,则可能会发生这种情况。在这种情况下,芯片中有多个处理器ID是有意义的,因为有多个处理器。
很不错
Cortex-M4处理器实现了本地专用监视器。该 处理器内的本地监视器已经构建成它 不包含任何物理地址,而是将任何访问视为 匹配先前LDREX的地址。这意味着 实现独家预约granule是整个内存 地址范围。
m7 trm也说了同样的话。
没有多个核心怎么可能/会产生不同的ID? 文档使用术语processorid来指示正在使用哪个处理器。皮质中有多少个处理器?也许它在其他地方使用不同的字符串/名称进行了记录,但是此时我不知道如何生成cortex-m中的processorid并且单个处理器是多于一个?我无法访问核心以确定。
因此,即使逻辑不支持每地址独占访问,他们也没有说他们没有检查处理器ID,他们只是考虑所有标记为共享的内存的strex访问权限与最后一个ldrex的processorid进行检查独立于它的地址。
修改
PUT32(0x01000600,0x600);
PUT32(0x01000700,0x700);
PUT32(0x01000800,0x800);
CLREX();
hexstring(STREX(0x20000600,0x12345678));
hexstring(STREX(0x20000700,0x12345678));
hexstring(STREX(0x20000800,0x12345678));
hexstring(LDREX(0x20000600));
hexstring(STREX(0x20000600,0x6666));
hexstring(STREX(0x20000700,0x12345678));
hexstring(STREX(0x20000800,0x12345678));
hexstring(LDREX(0x20000600));
hexstring(STREX(0x20000700,0x7777));
hexstring(STREX(0x20000800,0x12345678));
hexstring(GET32(0x20000600));
hexstring(GET32(0x20000700));
hexstring(GET32(0x20000800));
CLREX();
hexstring(0xAABBCCDD);
hexstring(LDREX(0x20000600));
CLREX();
hexstring(STREX(0x20000600,0x2222));
hexstring(GET32(0x20000600));
制造
00000001
00000001
00000001
00000600 <-- ldrex
00000000 <-- strex pass
00000001 <-- strex fail
00000001
00006666
00000000
00000001
00006666
00007777
00000800
AABBCCDD
00006666
00000001
00006666
看起来他们在这里所做的是在ldrex独立于地址后传递的下一个strex。所以使用你的术语strex&#34;清除锁定&#34;。
请注意,在ldrex和strex之间放置一个clrex确实会使strex失败。
没有点击同一个地址并不重要一个ldrex到一个strex
hexstring(LDREX(0x20000900));
hexstring(STREX(0x20000900,0x2222));
hexstring(STREX(0x20000900,0x2222));
3EEDCC1B
00000000
00000001
打开数据缓存并没有改变结果。
测试功能:
.thumb_func
.globl LDREX
LDREX:
ldrex r0,[r0]
bx lr
.thumb_func
.globl CLREX
CLREX:
clrex
bx lr
.thumb_func
.globl STREX
STREX:
strex r0,r1,[r0]
bx lr
与大哥ARM不同:
CLREX();
hexstring(STREX(0x20000600,0x12345678));
hexstring(LDREX(0x20000600));
hexstring(STREX(0x20000600,0x6666));
hexstring(LDREX(0x20000600));
PUT32(0x20000600,0x11);
hexstring(STREX(0x20000600,0x6666));
00000001
00000600
00000000
00006666
00000000
strex在两者之间存在非独占访问权限,至少基于您发布的非专有商店的文档应该破坏之前的ldrex(在armv7-a上)。
注意以上是在cortex-m4上的r0p1 CPUID 0x410FC241
答案 1 :(得分:0)
这是安全的,因为芯片设计师使其安全。操作系统将使用Test_and_Set指令的全部内容来处理semaphone和mutex命令。在多核/多处理器环境中,除了内置的汇编命令外,没有其他方法可以准确地实现此功能。