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

问题描述

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

import os
from PyQt5.QtWidgets import  QCheckBox,QLineEdit,QWidget,QApplication,QVBoxLayout
from PyQt5.QtCore import QEvent,Qt

class CtrlaDel(QWidget):
    def __init__(self):
        super().__init__()
        self.setwindowTitle("Key Press Event")
        self.le = QLineEdit()
        self.cb = QCheckBox()
        self.cb.setChecked(True)
        self.vBox = QVBoxLayout(self)
        self.vBox.addWidget(self.le)
        self.vBox.addWidget(self.cb)


        self.le.installEventFilter(self)

    def eventFilter(self,source,event):
        if event.type() == QEvent.KeyPress and source is self.le:
            print("ddddsdsdsdsdsdsds")
            if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete and source is self.le:
                print("ddd")
                if len(self.le.text()) <= 1:
                    self.cb.setChecked(False)


            if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_A:
                print("I am inside of Ctrl+A")
                if event.key() == Qt.Key_Delete:
                    print("I am Inside of Delete")
                    self.cb.setChecked(False)
                    self.checkstatus = 0
                    return True
        return super(CtrlaDel,self).eventFilter(source,event)
if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    mainwindow = CtrlaDel()
    mainwindow.show()
    sys.exit(app.exec_())

生成代码(gcc):

// 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" );
}

对应的发布函数

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>

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

解决方法

如果出现以下情况,LDREX 指令将挂起内核(除非我的测试未报告异常):

  • 未启用 MMU
  • 没有缓存包含锁的虚拟内存区域

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

  • 尚未启用对称多处理

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

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

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