プロセッサモードの概要
Cortex-Aプロセッサを初めとする、Armプロセッサ(Cortex-Mシリーズを除く)は7つのプロセッサモードを持っています。例外が発生することで、プロセッサモードが変わり、自動的に一部のレジスタが切り替わります。
FIQモードは、r8からr14が専用レジスタになり、他のモードはr13とr14が専用レジスタとなり、cpsr(第4回参照)の内容は、各モードのspsr(保存プログラムステータスレジスタ)に保存されます。
あわせて読みたい
プロセッサモードが変化することでスタックポインタr13が自動的に切り替わりますので、プログラムにて使用するモードのスタックポインタを、割り込み禁止状態での初期化が必要です。
プロセッサモード | 内容 | 動作モード |
---|---|---|
SVC(スーパーバイザコール) | リセット例外とSVCを処理するモード | 特権モード |
FIQ | FIQ割り込みを処理するモード | |
IRQ | IRQ割り込みを処理するモード | |
アボート | メモリアクセス違反を処理するモード | |
未定義 | 未定義命令を処理するモード | |
システム | ユーザモードと同じレジスタを使用する特権モード | |
ユーザ | アプリケーションを実行するモード | 非特権モード |
プロセッサモードの変更方法
cpsrのMODE[4:0](0ビットから4ビット)を設定することで、プロセッサモードが変更可能です。
cpsrの特定フィールドにライトするフィールド設定が用意されています。
動作モード | プロセッサモード設定値 | 備考 |
---|---|---|
SVC | 10011(0x13) | — |
FIQ | 10001(0x11) | — |
IRQ | 10010(0x12) | — |
アボート | 10111(0x17) | — |
未定義 | 11011(0x1b) | — |
システム | 11111(0x1f) | ユーザモードと同一レジスタを使用する特権モード |
ユーザ | 10000(0x10) | — |
スタックポインタの初期化方法
プロセッサモードが変化することで、スタックポインタr13が自動的に切り替わるので、スタックポインタのアドレスは8バイト境界に確保し、SVC(スーパーバイザ)モード、割り込み禁止状態での初期化が必要です。
スタックを初期化する場合、次の手順で行います。
- MSR命令にて、cpsr_cフィールドを指定し、cpsr(カレントプログラムステータスレジスタ)のMODE[4:0]を書き換えます。
- LDR疑似命令にて、スタックポインタを初期化します。
MSR CPSR_c,<IRQ/FIQ割り込み禁止+プロセッサモード設定値> LDR SP,=<スタックアドレス>
【サンプルプログラム】
Mode_USR EQU 0x10 ; CPSR.mode[4:0]ユーザモード設定値 Mode_FIQ EQU 0x11 ; CPSR.mode[4:0]FIQモード設定値 Mode_IRQ EQU 0x12 ; CPSR.mode[4:0]IRQモード設定値 Mode_SVC EQU 0x13 ; CPSR.mode[4:0]スーパーバイザモード設定値 Mode_ABT EQU 0x17 ; CPSR.mode[4:0]アボートモード設定値 Mode_UND EQU 0x1B ; CPSR.mode[4:0]未定義モード設定値 Mode_SYS EQU 0x1F ; CPSR.mode[4:0]システムモード設定値 I_Bit EQU 0x80 ; IRQビット定義 F_Bit EQU 0x40 ; FIQビット定義 MSR CPSR_c,#Mode_IRQ:OR:I_Bit:OR:F_Bit ; IRQモードへ変更 LDR SP,=<IRQ_STACK_TOP> ; IRQモードモードスタックを初期化 MSR CPSR_c,#Mode_FIQ:OR:I_Bit:OR:F_Bit ; FIQモードへ変更 LDR SP,= <IRQ_STACK_TOP> ; FIQモードスタックを初期化 MSR CPSR_c,#Mode_UND:OR:I_Bit:OR:F_Bit ; 未定義モードへ変更 LDR SP,= <UND_STACK_TOP> ; 未定義モードスタックを初期化 MSR CPSR_c,#Mode_ABT:OR:I_Bit:OR:F_Bit ; アボートモードへ変更 LDR SP,= <ABT_STACK_TOP> ; アボートモードスタックを初期化 MSR CPSR_c,#Mode_SVC:OR:I_Bit:OR:F_Bit ; スーパーバイザモードへ変更 LDR SP,= <SVC_STACK_TOP> ; スーパーバイザモードスタックを初期化 MSR CPSR_c,#Mode_SYS:OR:I_Bit:OR:F_Bit ; システムモードへ変更 LDR SP,= <SYS_STACK_TOP> ; システムモードスタックを初期化
スタックアドレスの定義方法
ターゲットのメモリ配置設定(ROM/RAMなどの設定)は、リンカの設定で行うことが一般的です。プログラムの中で、個別に設定することも可能ですが、メモリ配置を変更する場合、複数のファイルを修正することになり、修正漏れによる不具合が発生する場合があります。
Armコンパイラの場合は、スキャッタローディングと呼ばれる方法で、スキャッタローディングファイルで設定したアドレス設定値をアセンブリ言語またはC/C++言語で確認できます。
アセンブリ言語の場合は、以下(<Name>はスキャッタローディングファイルで設定された領域名称)で確認できます。
“||Image$$<Name>$$ZI$$Limit||”
詳しくは、「Armコンパイラ Armlinkユーザガイド」を参照ください。
スキャッタローディングファイル例
スキャッタローディングファイルで、0x80000000番地を先頭に、各種スタックは16Kバイト単位で領域を確保します。
USR_STACK 0x80000000 ALIGN 8 EMPTY 0x4000 ; ユーザ/システムモードスタックを確保。 { } IRQ_STACK +0 ALIGN 8 EMPTY 0x4000 ; IRQスタックを確保 { } FIQ_STACK +0 ALIGN 8 EMPTY 0x4000 ; FIQモードスタックを確保 { } UND_STACK +0 ALIGN 8 EMPTY 0x4000 ; 未定義モードスタックを確保 { } ABT_STACK +0 ALIGN 8 EMPTY 0x4000 ; アボートモードスタックを確保 { } SVC_STACK +0 ALIGN 8 EMPTY 0x4000 ; スーパーバイザモードスタックを確保 { }
アセンブルソースファイル例
スキャッタローディングファイルのアドレス設定値を参照します。
; ; スキャッタローディングファイルからスタックアドレスを参照します。 ; IMPORT ||Image$$USR_STACK$$ZI$$Limit|| ; ユーザモードスタックアドレス IMPORT ||Image$$IRQ_STACK$$ZI$$Limit|| ; IRQモードスタックアドレス IMPORT ||Image$$FIQ_STACK$$ZI$$Limit|| ; FIQモードスタックアドレス IMPORT ||Image$$UND_STACK$$ZI$$Limit|| ; 未定義モードスタックアドレス IMPORT ||Image$$ABT_STACK$$ZI$$Limit|| ; アボートモードスタックアドレス IMPORT ||Image$$SVC_STACK$$ZI$$Limit|| ; スーパーバイザモードスタックアドレス … … MSR CPSR_c,#Mode_IRQ:OR:I_Bit:OR:F_Bit ; IRQモードへ変更 LDR SP,= ||Image$$IRQ_STACK$$ZI$$Limit|| IRQモードのモードスタックを初期化
こちらも是非
“もっと見る” Cortex-A編
初期化処理
リセット例外からmain()関数を呼び出すまでの初期化は、ユーザが作成する部分とArmコンパイラが実行する部分に分けることができます。コードのコピーや初期化変数/未初期化変数の初期化は、リンカのメモリ配置設定を処理系ライブラリが実行します。
PMU(パフォーマンス監視ユニット)
PMUに関連するレジスタは、ユーザモードでのアクセスは禁止されていますので、PMUSERENR(ユーザイネーブルレジスタ)を特権モードでユーザモードアクセス許可を設定します。PMUSERENRについては、 後述の該当項目を参照ください。
TrustZone(セキュリティ拡張機能)
TrustZoneはCortex-Aシリーズの拡張機能で、大規模OSやアプリケーションが動作するノーマルワールドとセキュリティ関連が動作するセキュアワールドを導入しています。TrustZoneでは、ノーマルワールドメモリ空間とセキュアワールドメモリ空間の分離が可能です。