请注意,LDREX/STREX 并没有像许多人认为的那样做。它们适用于多处理器系统,单处理器系统应考虑使用交换。ARM 文档通常非常好,但在这种特殊情况下,它们之间存在巨大差距。Linux 一直在不正确地使用这些指令,并且具有单处理器 ARM 内核的公司已经注意到这一点(由于人们在没有适当研究的情况下添加代码,Linux 存在许多与 ARM 相关的错误,每个版本都必须修复)。如果您在单处理器系统上拥有 L1 缓存,则可以,因为缓存支持该访问类型,如果它到达 AXI 总线,AMBA/AXI 规范会告诉硬件工程师,对于单处理器系统,您不需要支持该事务类型。不幸的是,ARM ARM/TRM 告诉软件工程师你应该停止使用交换并开始使用 LDREX/STREX,
这不是您的问题的答案,只是有关这些说明的一般信息,以尝试教育人们正确使用和所涉及的风险。(是的,去过那里,完成了,使用这些指令被烧毁了,必须修补 linux(在其他 linux 修补程序之上))
编辑....更多细节
在 ARM ARM 中:
Historically, support for shared memory synchronization has been with the read-locked-write operations
that swap register contents with memory; the SWP and SWPB instructions described in...
...
ARMv6 provides a new mechanism to support more comprehensive non-blocking shared-memory synchronization primitives
that scale for multiple-processor system designs.
...
The swap and swap byte instructions are deprecated in ARMv6. It is recommended that all software
migrates to using the new synchronization primitives.
...
Uniprocessor systems are only required to support the non-shared memory model, allowing them to support
synchronization primitives with the minimum amount of hardware overhead.
...
Multi-processor systems are required to implement an address monitor for each processor.
STREX:
<Rd> Specifies the destination register for the returned status value. The value returned is:
0 if the operation updates memory
1 if the operation fails to update memory.
MemoryAccess(B-bit, E-bit)
if ConditionPassed(cond) then
processor_id = ExecutingProcessor()
physical_address = TLB(Rn)
if IsExclusiveLocal(physical_address, processor_id, 4) then
if Shared(Rn) == 1 then
if IsExclusiveGlobal(physical_address, processor_id, 4) then
Memory[Rn,4] = Rm
Rd = 0
ClearExclusiveByAddress(physical_address,processor_id,4)
else
Rd = 1
else
Memory[Rn,4] = Rm
Rd = 0
else
Rd = 1
ClearExclusiveLocal(processor_id)
AMBA/AXI 规格
The ARLOCK[1:0] or AWLOCK[1:0] signal selects exclusive access, and the RRESP[1:0]
or BRESP[1:0] signal (see Table 7-1 on page 7-2) indicates the success or failure
of the exclusive access.
...
If the master attempts an exclusive read from a slave that does not support exclusive
accesses, the slave returns the OKAY response instead of the EXOKAY response. The
master can treat this as an error condition indicating that the exclusive access is not
supported. It is recommended that the master not perform the write portion of this
exclusive operation.
...
b00 OKAY
b01 EXOKAY
...
ARLOCK/AWLOCK
b00 normal access
b01 exclusive access
所以在软件方面,ARM ARM 告诉我们使用 LDREX/STREX 而不是交换,部分原因是它可以扩展到多处理器、共享内存、系统。但他们也告诉我们,单处理器系统不需要支持共享内存同步。因此,即使从软件方面来看,您也应该三思而后行……
我们从 STREX 的描述中知道,如果它返回独占 rd = 0,那么它就起作用了。如果 rd = 1 那么它不是排他性的(或其他原因)。LDREX 和 STREX 是成对完成的,共享内存系统逻辑正在寻找相同地址的对,并且硬件验证两者之间没有其他对该地址的访问。你担心谁会夹在两者之间?1)如果您中断/交换并且非常幸运 2)使用该内存的另一个处理器。linux 所做的,据我所知,进入一个紧密的无限循环,
while(1)
{
ldrex
strex
if(rd==0) break;
}
现在在单处理器系统上,ARM ARM 都建议它们不需要支持共享访问,因为它更简单(为什么需要增加这种复杂性?)。
作为程序员你看不到的东西。为 ldrex 和 strex 设置了 ARLOCK 或 AWLOCK,如果您正在实现共享访问,那么您关心这些位。如果您正在实现共享访问,那么如果两者之间没有访问,则将 EXOKAY 返回给 strex。EXOKAY 是一个 b01,在 strex 伪代码中是独占的全局,rd = 0。如果硬件返回 OKAY,b00,它不是独占的,对于 strex,rd = 1。然后 AMBA/AXI 规范说,如果您不支持共享系统,可以返回 OKAY 进行独占访问。因此,在尚未实现独占访问的单处理器上,strex 可以和/或将始终返回 OKAY,而不是 EXOKAY。这意味着 strex 永远不会得到 rd = 0 并且 linux 在无限循环中挂起。
这里真正的 linux 错误是我们当时看到的代码说如果(ARMv6 或更高版本)则使用 LDREX/STREX,否则使用 SWP。如果(ARMv6 或更新版本和多处理器)修复错误,则使用 LDREX/STREX,否则使用 SWP。
这意味着其他任何人想要使用 LDREX/STREX 出于任何其他原因,这正是这张票中引起我注意的地方。
现在你问,缓存跟它有什么关系?L1 缓存在处理器内核内部,它不会在 AXI/AMBA 总线上输出。它为 strex 返回 EXOKAY,和/或它完全实现共享。因此,如果 L1 缓存打开,那么您将获得 EXOKAY(第一次或最终,我不确定)。
现在你问,如果有缓存未命中怎么办?如果 L1 缓存关闭,那么首先关闭,然后它会在没有可缓存位的情况下到达 L2 缓存边界。所以 L2 缓存会按原样传递它,并且它会作为独占的。当 L1 缓存打开时,它会像上面一样返回 EXOKAY(最终或总是,不知道)如果 L1 未命中,则 L1 执行缓存行填充,它执行可缓存的未锁定读取。这会导致 L2 命中或未命中,如果 L2 未命中,则它会转到供应商特定的逻辑,在这种情况下返回 OKAY 但这没关系,因为它没有被锁定,它是一个正常的访问。一旦 l2 和 l1 被填满,L1 就会执行原始传输并返回 EXOKAY。
现在这是关键,首先在硬件中实现它是一种浪费和风险,所以我希望单处理器 ARMv6 和更新版本不会返回 EXOKAY,你必须逐案测试。第二,它是让 linux 在缓存关闭的情况下运行的 PITA。事实上,这需要一些工作。所以你不太可能在linux中正常看到这个。但问题就在那里,人们已经看到了,任何时候你自己使用这些说明时,你都应该小心正确地使用它们。使用裸机编程来测试系统以查看它是否会挂起应该非常简单,应该需要几秒钟/几分钟来编写代码。将系统置于可以尝试该代码的状态可能需要更长的时间(中断引导加载程序,使用 jtag 跳转等)。