注意してください、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 はペアで実行され、共有メモリ システム ロジックは同じアドレスでペアを検索し、ハードウェアはこの 2 つの間にそのアドレスへの他のアクセスがなかったことを確認します。2人の間に誰が入るのを心配していますか? 1)割り込み/スワップを行い、非常に幸運な場合 2)そのメモリを使用している別のプロセッサ。私が覚えている限り、Linux が行うことは、タイトな無限ループに入ることです。
while(1)
{
ldrex
strex
if(rd==0) break;
}
現在、ユニプロセッサ システムでは、共有アクセスをサポートする必要がないという ARM ARM の提案は、より単純であるためです (なぜその複雑さを追加する必要があるのでしょうか?)。
あなたがプログラマーとして見ていないもの。ldrex と strex に対して ARLOCK または AWLOCK が設定されています。共有アクセスを実装している場合は、これらのビットに注意してください。共有アクセスを実装している場合、2 つの間にアクセスがなければ、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 はキャッシュ ライン フィルを実行し、キャッシュ可能な NOT LOCKED 読み取りを実行します。これにより、L2 がヒットまたはミスします。L2 がミスした場合、ベンダー固有のロジックに送信され、この場合は OKAY が返されますが、LOCKED ではなく通常のアクセスであったため問題ありません。l2 と l1 が満たされると、L1 は元の転送を実行し、EXOKAY を返します。
ここにキッカーがあります。まず、これをハードウェアに実装するのは無駄であり、リスクがあるため、ユニプロセッサ ARMv6 以降は EXOKAY を返さないと予想されます。ケースバイケースでテストする必要があります。2 つ目は、キャッシュをオフにして Linux を実行するのは PITA です。実際には少し手間がかかりました。そのため、通常、Linux でこれを目にすることはほとんどありません。しかし、問題はそこにあります。人々はそれを見てきました。これらの指示を自分で使用するときはいつでも、それらを適切に使用するように注意する必要があります. ベアメタル プログラミングを使用してシステムがハングするかどうかをテストするのは非常に簡単で、コードを記述するのに数秒または数分かかるはずです。システムをそのコードを試すことができる状態にする (ブートローダーを中断する、jtag を使用してジャンプするなど) には、より長い時間がかかる可能性があります。