MPU(メモリ保護ユニット)続き
stm32で、Cortex-MのMPUを使って、スタックオーバーフローを
検出する方法について。
armの提供するドキュメントを参照すると、Cortex-Mコアに存在する
(チップベンダ依存だけど)MPUを使うと、最小32バイト単位のエリアを
アクセス禁止エリアに設定できるとある。
これを使って、スタティックエリアの最後か、想定するスタックの上限に
アクセス禁止エリアを作った上で、
MPUのメモリ管理ハンドラへの割り込みを許可する。
これで、アクセス禁止エリアへのアクセスを、ソフトウエアで処理できる。
ペリフェラルの初期設定は、
SCB->SHCSR = (1 << 16); //メモリフォルト許可
(許可しないとハードフォルトとして処理される)
MPU->RBAR = 0x20002010; //保護エリア先頭アドレス+イネーブルビット
MPU->RASR = //保護エリアアトリビュート指定(サイズなど)
(0 << 24) |
(4 << 1) |
(1 << 0) |
0;
MPU->CTRL = //メモリ管理イベント許可
(1 << 2) |
(1 << 1) |
(1 << 0) |
0;
で、アドレス0x20002000から、32バイトが
アクセス禁止エリアとして指定される。
このエリアを読み書きすると、メモリ保護違反イベントが発生して
ベクタテーブルのオフセット0x10にある
アドレスに分岐するので、こちらもハンドラを記述する。
void MemManage_Handler(void){
__ASM volatile ("bl main");
}
CFSRの当該ビットをクリアできれば、元の処理に戻れそうな
気がするんだけど、なぜかクリアできない...
ので、仕方なく、無条件ジャンプで、main()へ戻っている。
このコードでは、普通の変数初期化が実行されないので、
通常リセットとの区別は簡単に付けられる。
(適当なスタティック変数をメモリ保護エラーフラグにしておいて、
起動直後に参照する。
色々なサンプルコードを当たると、ハードフォルトや
今回のようなメモリ保護違反での例外処理時は、
元の処理に復帰せず、ブレークポイントを設定して、
whike(1)の無限ループで停止する例ばかり出てくる。
まあ、スタックオーバーフローしているような状況で
処理を戻して如何にする?のも確かだ。
これで、まあなんとか、ソフトウエアのオーバーヘッド
無しで、スタックオーバーフローを検出できるようには
なったようだ。
------
MPUでなくて、DWTを使えば、もっとうまく実装できそうなんだけど、
こっちはなんだかうまく行かない。
色々ドキュメントを当たっているんだけど、
コア部分なので、チップベンダの資料にはほとんど記述が無い。
そもそもarmのドキュメントは、なかなか不親切だ(日本文も英文も)
まあ、実装するかどうはチップベンダ依存なので、
armのドキュメントがそっけないのも分かるけど、
もうちょっと何とかならないかなあ。
検索しても、あんまりいい情報にめくり合わない。
質問は色々ヒットするんだけど、ロクな回答がない。
------
まあ、チップベンダはコアのペリフェラルを手厚くサポートしても
得るもの少ないだろうし、需要はマルチプラットフォームの
デバッガなんかを開発しているベンダーくらいかなあ。
あんまり深追いしても、アレな気がしてきては居るんだけど、
DWTなんかは面白そうな機能が用意されているようだし、
stm32のCortex-M4は、コアのペリフェラルも
結構実装されているようなので、使いこなしたい気もしている。
(チップベンダ依存だけど)MPUを使うと、最小32バイト単位のエリアを
アクセス禁止エリアに設定できるとある。
これを使って、スタティックエリアの最後か、想定するスタックの上限に
アクセス禁止エリアを作った上で、
MPUのメモリ管理ハンドラへの割り込みを許可する。
これで、アクセス禁止エリアへのアクセスを、ソフトウエアで処理できる。
ペリフェラルの初期設定は、
SCB->SHCSR = (1 << 16); //メモリフォルト許可
(許可しないとハードフォルトとして処理される)
MPU->RBAR = 0x20002010; //保護エリア先頭アドレス+イネーブルビット
MPU->RASR = //保護エリアアトリビュート指定(サイズなど)
(0 << 24) |
(4 << 1) |
(1 << 0) |
0;
MPU->CTRL = //メモリ管理イベント許可
(1 << 2) |
(1 << 1) |
(1 << 0) |
0;
で、アドレス0x20002000から、32バイトが
アクセス禁止エリアとして指定される。
このエリアを読み書きすると、メモリ保護違反イベントが発生して
ベクタテーブルのオフセット0x10にある
アドレスに分岐するので、こちらもハンドラを記述する。
void MemManage_Handler(void){
__ASM volatile ("bl main");
}
CFSRの当該ビットをクリアできれば、元の処理に戻れそうな
気がするんだけど、なぜかクリアできない...
ので、仕方なく、無条件ジャンプで、main()へ戻っている。
このコードでは、普通の変数初期化が実行されないので、
通常リセットとの区別は簡単に付けられる。
(適当なスタティック変数をメモリ保護エラーフラグにしておいて、
起動直後に参照する。
色々なサンプルコードを当たると、ハードフォルトや
今回のようなメモリ保護違反での例外処理時は、
元の処理に復帰せず、ブレークポイントを設定して、
whike(1)の無限ループで停止する例ばかり出てくる。
まあ、スタックオーバーフローしているような状況で
処理を戻して如何にする?のも確かだ。
これで、まあなんとか、ソフトウエアのオーバーヘッド
無しで、スタックオーバーフローを検出できるようには
なったようだ。
------
MPUでなくて、DWTを使えば、もっとうまく実装できそうなんだけど、
こっちはなんだかうまく行かない。
色々ドキュメントを当たっているんだけど、
コア部分なので、チップベンダの資料にはほとんど記述が無い。
そもそもarmのドキュメントは、なかなか不親切だ(日本文も英文も)
まあ、実装するかどうはチップベンダ依存なので、
armのドキュメントがそっけないのも分かるけど、
もうちょっと何とかならないかなあ。
検索しても、あんまりいい情報にめくり合わない。
質問は色々ヒットするんだけど、ロクな回答がない。
------
まあ、チップベンダはコアのペリフェラルを手厚くサポートしても
得るもの少ないだろうし、需要はマルチプラットフォームの
デバッガなんかを開発しているベンダーくらいかなあ。
あんまり深追いしても、アレな気がしてきては居るんだけど、
DWTなんかは面白そうな機能が用意されているようだし、
stm32のCortex-M4は、コアのペリフェラルも
結構実装されているようなので、使いこなしたい気もしている。
| 固定リンク | 0
コメント