SOLID未分類 SOLIDのMMU使いこなしー3(連載6)
(2023/7/5)
[連載6] SOLIDのMMU使いこなしー3
第一回から第三回まで、MMUを使いこなすことによる便利機能をご紹介ました。
NULLポインタやスタックオーバーフロー等、メモリのアクセス違反発生時に、ブレークして教えてくれました。
そのまま「メモリアクセスチェック」つながりで、第四回、第五回と、メモリアクセス先のアドレス妥当性を違反した際に教えてくれる、アドレスサニタイザ機能についてご紹介しました。
で、ここにきて、MMUでご紹介しておかなければならないもう一つの便利機能についてのご紹介を忘れていたことに気が付きました。
メモリアクセスチェックつながりで、だーっと行ってしまいましたが、またMMUに戻ります。
SOLID-IDEを使う場合、mmsファイルを編集することで仮想アドレスと物理アドレスの対応を自分のシステムにあうように変更・設定する。
もちろん、この設定、ずっと固定で良い場合もあるでしょう。
ですが、システムによっては違います。
例えば、ローダーというものについて考えてみましょう。
メモリの、とある部分がローダーになっていて、別の部分が実行ファイル格納場所になっているようなケースがあったとします。
・エリア1:ローダーが入っているエリア
・エリア2:ローダーによって書き換えられるファームウェアのエリア
ローダー動作時:
エリア2は、エリア1のローダーによって書き換えられますので、ライト可属性である必要があります。
ローダー終了しエリア2にジャンプ:
ローダーはエリア2にライト不可属性と実行可属性を付加し、エリア2にジャンプします。
もちろん、この通りではありません。
エリア2はずっと、ライト不可属性も実行可属性も両方つけていれば良いという考えもあります。
ですが、実行しないのがわかっているエリアに実行可属性を付けるのを躊躇したり、ファームウェア実行エリアがライト可になっていると壊されてしまった場合わからない、等の理由のため、このように設定する場合も多い事でしょう。
このように、MMUは、時としてプログラムから設定変更したいな、、、という場合があります。
こんな時のために、SOLID-OSでは、Cortex Aシリーズ用MMUの設定をアレコレするためのAPIを装備しています。
Cortex Aのマニュアルとにらめっこしながら、簡単ではないMMUの設定を、しかもアセンブラコードを使いながら書く必要はありません。
以下URLにまとまっています。
http://solid.kmckk.com/doc/skit/current/os/cs/memory.html#id1
一部ご紹介します。
(1)仮想/物理アドレスマップ
int SOLID_MEM_Map(SOLID_ADDRESS VA, size_t size, SOLID_PHYADDRESS PA)
⇒指定された仮想アドレスに、指定された物理アドレスを、指定されたサイズ分マップするAPIです。
(2) メモリ属性付きでマップ
以下のAPIは、メモリ属性付きでマップします。
int SOLID_MEM_MapWithAttribute(SOLID_ADDRESS VA, size_t size, SOLID_PHYADDRESS PA, int attr)
メモリ属性には、書き込み不可、実行可能、キャッシュ可能、等あります。
詳細はこちら。
http://solid.kmckk.com/doc/skit/current/os/cs/memory.html#solid-mem-attr
(3)キャッシュ操作:コードキャッシュ破棄
void SOLID_MEM_CACHE_InvalidateCode(SOLID_ADDRESS VA, size_t size)
例えばこのAPIは、指定された領域のコードキャッシュを破棄します。
コードキャッシュを破棄する場合の例をご紹介します。
例えば、ローダー等により、コード領域を意図的に書き換えようとする場合です。
その書き換え処理はデータ書き込みにより実行されます。
なので、キャッシュONのまま書き換えたとしても、それはデータキャッシュに載るだけで、コードキャッシュには、以前の命令コードが入りっぱなしです。
なので、一度コードキャッシュは破棄しておかないと、以前の命令が実行されてしまいます。
(4)キャッシュ操作:データキャッシュ書き戻し
void SOLID_MEM_CACHE_Clean(SOLID_ADDRESS VA, size_t size)
データキャッシュに載っているデータをメモリに書き戻すAPIです。
プログラムで、とある領域にデータを書きこみ、その領域をCPUを使わずに(DMA等で)ハードウェア的に転送する、といった際によく使います。
プログラムでデータ書き込みする、という事は、キャッシュにのみ書き込まれるワケで、DMA等のハードウェアが見ることができる物理的なメモリには反映されないからです。
もちろん、その対象領域をはじめからキャッシュ不可領域にすれば問題ありません。
プログラムから書き込む際にキャッシュONで書き込み、転送直前に物理メモリに書き戻すのか、そもそも最初からキャッシュ不可領域にしておくのか、それはシステム設計次第となります。
では、実際に使ってみましょう。
まず、今回使う仮想アドレスをマッピングしてみましょう。
どこの場所にしましょうか。
メモリマップデザイナーで、何も割り当てられていない仮想アドレスを調べてみましょう。
0x42000000から、しばらく空いていますね。
確認してみましょう。
以下のコードを書いてみました。
実行してみます。
リードアクセスで、Data Abort Exceptionが発生しました。アクセスできないですね。
メモリウインドウで見ても、アクセスができないことがわかります。
では、ここにマッピングしてみましょう。
SOLID_MEM_Alloc()関数を使用し、以下のコードを書いてみます。
実行してみます。
SOLID_MEM_Alloc()関数の戻り値は0なので、マッピング成功です。
0x42000000番地へのリードもライトも、例外発生していません。
また、メモリウインドウから見ると何かしら値が読めることから、マッピングOKですね。
ところで、この仮想アドレスは、どの物理アドレスにマッピングされたのでしょうか。
SOLID_MEM_VA2PA()関数を用いて調べてみます。
物理アドレス 0x4A000000であることがわかります。
先程のメモリマップデザイナをみると、この物理アドレスは”RAM”としてSOLIDが割り当て用に確保している領域であることがわかります。
次に、既に設定されている領域のアクセス属性を変更してみましょう。
まず、先ほど設定した仮想アドレス0x42000000のアクセス属性を調べてみましょう。
SOLID_MEM_GetAttr()関数を使います。
実行してみましょう。
0x0Cになっています。
属性について説明がされているURLを見てみましょう。
http://solid.kmckk.com/doc/skit/current/os/cs/memory.html#solid-mem-attr
0x0Cなので、
・キャッシュ可
・バッファ可
ですね。
そして最下位ビットが0なので、SOLID_MEM_ATTR_READONLYは0。
すなわち、リードライトOK、ですね。
では、リードオンリー(書き込み不可)にしてみましょう。
SOLID_MEM_SetAttr()関数を使います。
書き込みで例外が発生するはず、です。
実行してみます。
思惑通り、リードはできますが書き込みできませんでした。
例外発生しました。
最後に、メモリマッピングを削除しておきましょう。
SOLID_MEM_Free()関数を使います。
マッピング削除後、メモリリードができなくなっていることを確認します。
実行してみます。
メモリアクセスできなくなりました。
メモリウインドウからも、読めなくなりました。
マッピングが削除されたことがわかります。
今回は、MMUを操作するためのAPIについてご紹介しました。
具体的にはご紹介しませんでしたが、DMAによるデータ転送を行う際もこれらのAPIは重要です。
意図する仮想アドレスに対する物理アドレスがどこに配置されているのかを知らなければなりません
そのような時はSOLID_MEM_VA2PA()関数を使って知ることができます。
それに、そもそもキャッシュと関係ない所で物理アドレスで動作するDMAによるデータ転送と、仮想アドレスでキャッシュが有効であるところで動作するCPUが同じメモリを使うのですから、当然キャッシュの管理も必要になります。
例えば、必要な時にSOLID_MEM_CACHE_Clean()関数等で、キャッシュとメモリを一旦同期させたりします。
このように、本記事でご紹介したAPIは、さまざまなシーンで便利に活躍してくれています。
それと、もう一点書かせてください。
実はこの3章の実験をするにあたり、一度もCortex Aのデバイスマニュアルを見る必要がありませんでした。
MMUが持つ便利な機能を使おうとしても、設定を間違うと動作できなくなるし、なかなか簡単に使おうとすべきものじゃない、と思っていました。
しかしOSのAPIとして持っていてこんなに簡単に使えるのなら、メモリ保護等、使ってみたい用途は出てきますね。
大袈裟かもしれませんが、眠っていたMMUの可能性の扉を一つ開けたような感覚になりました。
次回は、SOLIDで使えるリアルタイムOSについてご紹介する予定です。