前回の記事
タイトルにある「キャッシュ制御」はハード制御の際に思わぬ不具合の原因となる可能性がありますのでしっかりと概念を理解しておく必要があります。
逆に言えば概念さえ理解していればさほど難しくはないです。丸暗記も必要ありません。
前回記事に記載のハードレジスタ経由で直接入力データを受け取ってメインメモリ上へコピーする方式だと一度に入力できるデータは、ハードレジスタのデータ幅(例えば32bitとか64bitとか扱うCPUアーキテクチャに依存)に制限されます。
これでは大量のデータは扱えません。
そこで、コンピュータのデータの入出力を行う方法に DMA(Direct Memory Access) という方式を使用します。
これはその名のとおり CPUを介さず直接ハードデバイスがメモリにデータ読み・書きを行う方式 です。
プログラム的にみると、決められた手順通りにハードレジスタにデバイス制御(入出力)命令をセットして、あとはハードウェアが動いてメモリ上のデータ転送完了を待つだけとなります。
データの転送中はバス調停でメモリの使用権をCPU→ハードデバイスに渡してしまいますのでその間CPUは停止状態になることが多いです。
(いろいろな方式ありますが、とりあえずはこの理解でOK)。
簡単なポンチ絵ですが以下の感じです。
さほど難しい概念ではないですね。
さて、ここからが本題なのですが、最近のCPUではメインメモリ-CPU間にキャッシュメモリが入ることが多いです。
そうすると上記のDMA方式のデータ転送では不都合が起きます。
CPUから見えているメモリ上のデータ(=実はキャッシュ上にある)と、メインメモリ上のデータがDMA転送のデータの書き換えにより不整合が発生するわけです。
以下簡単なポンチ絵です。
(データ入力時の例ですが、もちろん出力時でも同様の問題が発生します)
ネットでは "キャッシュ" "コヒーレンシ" で検索するといろいろな事例がHITします。
この問題に対処する方法は簡単です。
-
データ入力開始する場合はCPUキャッシュ上にあるデータを破棄する
つまりCPUキャッシュを意図的にミスヒットさせてメモリ上から改めてデータ転送後のデータをCPUキャッシュ上へ汲み上げる。 -
データ出力開始する場合はCPUキャッシュからメインメモリへのデータの書き出しを行う。
以下がデータ入力時の概念図です。
続いてデータ出力時の概念図
結論: Linux上でDMA転送を行うデバイスドライバーを解析する際には、以下のキーワードを覚えておけばデバイス制御の基本的な構成が判ります。 ソースコード解析の際の大きな助けになることでしょう。
- cacheflush() :CPUキャッシュ上のデータをメモリ上に書き出す。
→DMAを使ったデバイスドライバー上ではデータの出力時に使用。 - Invalidate() :CPUキャッシュ上のデータを破棄する。
→DMAを使ったデバイスドライバー上ではデータの入力時に使用。
DMA転送を行う基本的な入出力ドライバープログラムは意外と単純なものです。
ソフト制御的には意味がないと思われるハードレジスタ制御処理、そしてデータ入出力のタイミングで実装されているキャッシュ制御処理を見極めれば比較的簡単に全体像を見渡すことが可能になります。
もし業務で扱うことがあれば記憶の片隅にでも入れておいてください。
きっと役立つ情報となるでしょう。