===================================================================== ARMプロセッサ依存部 Last Modified: 2015 Mar 27 15:13:30 ===================================================================== ○概要 ARM にはアーキテクチャーバージョンが幾つか存在する.本カーネルでは, ARMv4 以上のアーキテクチャーをサポートすることとする.基本的には, ARMv4 を前提として記述している.しかしながら,上位のアーキテクチャでは 記述方法を変更することによって性能向上を図れる箇所が存在する.そのよう な箇所については,条件コンパイルによって対応することにする. (注) 本ソフトウェアはASPカーネル向けのARMプロセッサ依存部を元にSSPへポーティング したものである.動作確認が十分に行われていないコードやデッドコード等も 含まれると思われるため,扱いには注意のこと. ○開発環境 コンパイラは,GNU Tools for ARM Embedded Processors でリリースされている GNU C/C++のバイナリを使用することとする. https://launchpad.net/gcc-arm-embedded ○CPU例外の取り扱い ●例外とPCの関連 例外 モード アドレス 戻り先PC リセット Reset svc 0x00000000 未定義命令 Undefined und 0x00000004 pc(コプロはpc-4) SWI Software Int swi 0x00000008 pc(次の命令) プリフェッチアボート Prefetch Abort abt 0x0000000C pc-4(再実行) データアボード Data Abort abt 0x00000010 pc-4(再実行pc-8) IRQ IRQ irq 0x00000018 pc-4(次の命令) FIQ FIQ fiq 0x0000001C pc-4(次の命令) ARMは,例外毎に戻り番地が異なり,例外の要因になった命令を再実行するか どうかによっても戻り番地が異なる.そのため,カーネルの例外ハンドラでは, 戻り先のPCは操作せず.戻り先のPCを設定させる機能を提供する.ユーザは CPU例外ハンドラでこれらの機能を用いて戻り先のアドレスを設定する. uint32_t x_get_exc_raddr(void *p_excinf); void x_set_exc_raddr(void *p_excinf, uint32_t pc); ●CPU例外ハンドラ番号 例外毎に次のようにCPU例外ハンドラ番号を割り付ける.なお,0番,5番にはユ ーザーはCPU例外ハンドラを登録できない. リセット 0 未定義命令 1 SWI 2 プリフェッチアボート 3 データアボード 4 IRQ 5 FIQ 6 ●ベクターテーブル ARMのベクタ(vector_table)は,ARMのベクタアドレス0x00000000から配置す る.vector_ref_tblは,例外発生時のジャンプ先のテーブルで,vector_tble の命令から参照される. .section .vector,"a" .global vector_table vector_table: ldr pc, reset_vector /* リセット */ ldr pc, undef_vector /* 未定義命令 */ ldr pc, swi_vector /* ソフトウェア割込み */ ldr pc, prefech_vector /* プリフェッチアボード */ ldr pc, data_abort_vector /* データアボード */ ldr pc, reset_vector ldr pc, irq_vector /* IRQ */ ldr pc, fiq_vector /* FIQ */ .align 2 .global vector_ref_tbl vector_ref_tbl: reset_vector: .long start undef_vector: .long undef_handler swi_vector: .long swi_handler prefech_vector: .long prefetch_handler data_abort_vector: .long data_abort_handler irq_vector: .long IRQ_Handler fiq_vector: .long fiq_handler また,vector_ref_tblをRAM上に配置した場合には,カーネル管理外の例外と して,vector_ref_tblに直接ユーザーのハンドラを登録する関数を用意する. なお,vector_ref_tblをフラッシュメモリに配置した場合は,このシステムコ ールは正常に動作しないので,注意が必要である. void x_install_exc(EXCNO excno, FP exchdr) ディフォルトのvector_ref_tblの登録内容は上に示した通りである.startと IRQ_Handler以外は,core_support.Sに定義されており,それぞれ,スーパーバ イザーモードに移行して,スタック上にコンテキストを積んだ後,元のモード に戻り,r0に例外発生時のpc, r1に例外発生時のcsr, r2に例外番号を入れて, ターゲット依存部で定義する target_exc_handler へジャンプする. ●ベクタの保護 前述の通りARMのベクタ(vector_table)は,0x00000000 に配置する必要があ る.通常はこのアドレスにはROMやフラッシュメモリ等の不揮発性のメモリが 割り当てられるが,ターゲットによっては,RAMをリマップすることが可能で ある.RAMを0x00000000 を配置して,ベクタ(vector_table)を配置すると, ユーザープログラムでベクタを書き換えることが可能となるので注意が必要で ある.特にユーザープログラムによる,NULLポインタによるアクセスにより書 き換えられる可能性が高い.安全性を高めるためには,ターゲット依存で次の 対策を行うことを推奨する. ・リマップを行わず,不揮発性メモリにベクタを置く. ・MMUによりベクタの領域を書き込み禁止とする. ・High Vector機能を使用し,ベクタを0x00000000以外に配置する. ●例外フレーム(CPU例外ハンドラへの引数) SSPカーネルの仕様では,CPU例外ハンドラの引数には,CPU例外に関する情報 を記憶している領域(例外フレーム)の先頭番地が渡される.そのため,CPU 例外発生時のコンテキストを保存したスタックへのポインタを渡す. 例外フレームは,ARMアーキテクチャ毎に異なり,ARMv4/ARMv5では次のように なる.このうち,R0,R1,R2,R3,ipに関しては,ARMプロセッサ依存部で設定さ れる.その他の値は,ターゲット毎の target_exc_handler で作成する.例外 前の割込み優先度マスクは,PRI(int_t)型の外部表現である. 例外フレーム(ARMv4-5) offset ------------------------------ | 例外前のネストカウント | 0 <-- p_excinf ------------------------------ | 例外前の割込み優先度マスク | 1 ------------------------------ | 例外前のCPSR | 2 ------------------------------ | R0 | 3 ------------------------------ | R1 | 4 ------------------------------ | R2 | 5 ------------------------------ | R3 | 6 ------------------------------ | IP | 7 ------------------------------ | LR_svc | 8 ------------------------------ | 例外前のPC(戻り先) | 9 ------------------------------ ○割り込みの取り扱い ●カーネル管理内/外の割込み IRQをカーネル管理内,FIQをカーネル管理外の割込みとする. ●CPUロックフラグ CPUロックフラグとして,ステータスレジスタのIRQビットを用いる.すなわち ,CPUロック状態では,IRQビットをセットし,カーネル管理内の割込みを禁止 し,CPUロック解除状態では,IRQビットをクリアする. ●割込みロックフラグ 割込みロックフラグとしては,CPSRのFIQビットとIRQビットを用いる.割り込 みロック状態では,IRQビットとFIQビットをセットする. ===================================================================== カーネル開発者向けの情報 ===================================================================== ○コンテキストの判定 カーネルは,割り込み/例外の入り口で,カーネル内のカウント用の変数( excpt_nest_count)をカウントアップし,出口でカウントダウンする.そのた め,excpt_nest_count が0の場合はタスクコンテキスト,1以上の場合は非タ スクコンテキストと判断する. ○例外エントリ処理 本節の説明対象となるエントリ処理は具体的に以下の処理を指す. undef_handler swi_handler prefetch_handler data_abort_handler fiq_handler irq_handler はこの説明の対象ではない. 各例外のエントリ処理は要因毎にカーネルで個別に持つ. ルーチンを共有化すると,例外発生後,一時的にレジスタを退避させるために 一時領域を用いる必要があるため,個別に持つように変更した. 各例外のエントリ処理では以下の処理を行う. ・タスク動作時のモードに移行(スタックを切り替える) ・r0-r3,ip,lr,pcを保存(PCはダミー) ・元のモードに戻る ・r0にlr,r1にspsrを,r2にCPU例外番号を入れる ・target_exc_handlerへジャンプ target_exc_handler はターゲット毎に用意する.ターゲット毎に用意するの は,前述の例外フレームに例外前の割込み優先度マスクが含まれており,この 割込み優先度マスクの扱いがターゲット毎に異なるためである. target_exc_handler では,前述の例外フレームのフォーマットに従って例外 フレームを作成して,その先頭番地を引数にして,対応するCPU例外ハンドラ を呼び出す. FIQのエントリ処理(fiq_handler)については,ターゲット依存部側で用意す る場合には,それぞれ,以下のマクロを定義すれば,ARM依存部側のエントリ 処理が無効となる. TARGET_FIQ_HANDLER ○アイドル処理 実行するべきタスクがない場合は,ディスパッチャーで割込みを許可して,割 込みを待つ(dispatcher_2).ARM依存部のコードでは,次のようになってい る. 割込みを許可 nop 割り込み禁止 ターゲット依存で,上記の処理の代わりに,省電力モード等に移行する処理を 記述したい場合には,ターゲット依存部で,TOPPERS_CUSTOM_IDLEを定義し, 代わりに実行した処理を toppers_asm_custom_idle というアセンブラマクロ として記述する.なお,toppers_asm_custom_idle の記述にあたっては,次の レジスタは使用できない. r0, r1, r2, r3, sp アセンブラマクロはC言語記述中に展開するとエラーとなる.pr_support.S で は,TOPPERS_ASM_MACRO というマクロを定義しているため,ターゲット依存部 で toppers_asm_custom_idle アセンブラマクロを定義する際には, TOPPERS_ASM_MACRO を条件コンパイルの条件として用いること. ○CPSRに常にセットする値 CPSRの変更時,常にセットするパターンを CPSR_ALWAYS_SET として,ターゲ ット依存部で定義可能である. ○Makefileでの定義事項 ===================================================================== 変更履歴 ===================================================================== 2015/05/27 ・SSP1.3.0への対応 2014/03/18 ・SSP1.2.1用のARM依存部としてコピー 2011/05/09 ・ASP 1.7.0 への追従. ・オフセットファイルの生成方法をコンフィギュレータを用いる方法に変更. 2011/03/10 ・ASP 1.7.0 への追従. 2010/10/04 ・Thumb Mode 用のsrの設定・参照関数の追加. 2010/10/01 ・アセンブラファイル中の分岐命令のAAPCS推奨への変更忘れを修正. 2010/08/01 ・ASP 1.6.0 へ追従. 2010/07/26 ・VECTOR_KERNELの廃止. 2010/07/26 ・アセンブラファイル中の分岐命令を AAPCS推奨に変更. 2010/07/25 ・ASP 1.5.0 へ追従. 2009/07/14 ・例外フレーム入れる例外前の割込み優先度マスクの値をターゲット依存の 値から外部表現に変更. 2008/08/27 ・core_support.S ・call_exit_kernel で割込みを許可していた問題を修正 ・共通部 Release 1.3.2への追従. ・特に変更内容なし 2008/05/13 ・共通部 Release 1.3.1への追従. 2008/04/15 ・start.S ・dataセクションの初期化を省略する TOPPERS_OMIT_DATA_INIT を追加 2008/04/12 ・非依存部 1.3.0 追従 2008/03/20 ・非依存部 1.2 追従 2007/12/25 ・core_support.S ・OMIT_DEFAULT_IDLE を TOPPERS_CUSTOM_IDLE に変更 ・idle処理のマクロ名を toppers_asm_custom_idle に変更 ・start.S ・bssの初期化を省略する TOPPERS_OMIT_BSS_INIT を追加 以上.