为什么我的 ARM LDREX/STREX C 函数不起作用?

Why doesn't my ARM LDREX/STREX C function work?

根据“Barrier Litmus Tests and Cookbook”文档,我用 C 编写了一个 claim_lock 函数。我检查了生成的代码,一切看起来都不错,但是没有用。

// This code conforms to the section 7.2 of PRD03-GENC-007826:
// "Acquiring and Releasing a Lock"
static inline void claim_lock( uint32_t volatile *lock )
{
  uint32_t failed = 1;
  uint32_t value;

  while (failed) {
    asm volatile ( "ldrex %[value], [%[lock]]"
                   : [value] "=&r" (value)
                   : [lock] "r" (lock) );
    if (value == 0) {
      // The failed and lock registers are not allowed to be the same, so
      // pretend to gcc that the lock pointer may be written as well as read.

      asm volatile ( "strex %[failed], %[value], [%[lock]]"
                     : [failed] "=&r" (failed)
                     , [lock] "+r" (lock)
                     : [value] "r" (1) );
    }
    else {
      asm ( "clrex" );
    }
  }
  asm ( "dmb sy" );
}

生成的代码 (gcc):

1000:       e3a03001        mov     r3, #1
1004:       e1902f9f        ldrex   r2, [r0]
1008:       e3520000        cmp     r2, #0
100c:       1a000004        bne     1024 <claim_lock+0x24>
1010:       e1802f93        strex   r2, r3, [r0]
1014:       e3520000        cmp     r2, #0
1018:       1afffff9        bne     1004 <claim_lock+0x4>
101c:       f57ff05f        dmb     sy
1020:       e12fff1e        bx      lr
1024:       f57ff01f        clrex
1028:       eafffff5        b       1004 <claim_lock+0x4>

对应的释放函数:

static inline void release_lock( uint32_t volatile *lock )
{
  // Ensure that any changes made while holding the lock are
  // visible before the lock is seen to have been released
  asm ( "dmb sy" );
  *lock = 0;
}

它在 QEMU 中工作,但要么挂起,要么允许所有内核在真实硬件(Raspberry Pi 3 Cortex-A53)上“声明”所谓的“锁定”。

如果:

LDREX指令会挂掉核心(除非我的测试没有报异常)
  • 未启用 MMU
  • 包含锁的虚拟内存区域没有被缓存

如果出现以下情况,核心似乎会忽略彼此的主张:

  • 尚未启用对称多处理

SMP 启用机制似乎因设备而异;检查特定内核的 TRM,它在 ARM ARM 的范围之外。

对于 Cortex-A53,要设置的位是 SMPEN,CPU 扩展控制寄存器的第 6 位,CPUECTLR。

较早的设备具有辅助控制寄存器的第 5 位,例如 (ARM11 MPcore),其中还需要考虑 SCU。我没有这样的设备,但正是我第一次注意到 SMP/nAMP 位的文档。

这是我在 ARMv7-M 架构的上下文切换部分找到的 参考手册

Blockquote

需要保证本地监视器在上下文切换后处于Open Access状态。在 ARMv7-M,本地监视器作为异常进入或退出的一部分自动更改为 Open Access 顺序。本地监视器也可以通过 CLREX 指令强制进入开放访问状态。 笔记 上下文切换不是应用程序级别的操作。但是,此信息包含在此处以 完成独占操作的描述。 上下文切换可能会导致后续 Store-Exclusive 失败,需要加载...存储序列 重播。为尽量减少发生这种情况的可能性,ARM 建议 Store-Exclusive 指令尽可能靠近关联的 Load-Exclusive 指令,参见 Load-Exclusive 和 Store-Exclusive 使用限制。

Blockquote