ARM Cortex-M4 Mutex锁。 DMB指令

时间:2017-03-09 14:45:40

标签: assembly arm mutex semaphore

我阅读了以下文档: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时尝试获取对锁的访问权限,会发生什么情况。内存地址不是唯一锁定到第一个处理器,但写入未完成。

任何人都可以解释,为什么这样做有效且安全。我有我的问题。

2 个答案:

答案 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命令。在多核/多处理器环境中,除了内置的汇编命令外,没有其他方法可以准确地实现此功能。