前書き:XINU (Real Time OS)で学んだARMに関する情報

本記事では、ARM CPU(Cortex-A8、32bit)に対する調査内容を備忘録としてまとめています。

ARMに関する調査は、XINUのソースコードを読むために実施しました。XINU (Xinu Is Not Unix )とは、パデュー大学のダグラス・カマーが教育目的で開発した Real Time OS であり、ARM Cortex-A8が搭載されたBeagleBone Black(シングルボードコンピュータ)上で動作します。

XINUは、Kernel空間とUser空間が分離していないシンプルな作りであり、OSを勉強したい人にはオススメです。

OSの勉強用にXINUソースコードを読むメリット

  • 小規模( 約 1 万 LOC)
  • 産業用途での使用実績がある事(= 実運用に耐えられる設計である事)
  • C 言語の文法が古くない事(= 古い UNIX は小規模であるが、文法が古くて読みづらい)
  • 副読書が存在する事(Xinu オペレーティングシステムデザイン 改訂 2 版

以上を踏まえて、本記事では以下の内容を紹介します。

  • XINUがKernelとして動作する時(例:デバイス操作時やシステムコール実行時)に操作するレジスタ情報
  • ARM 32Bit命令
  • インライアセンブラの書き方

ARM Coretex-A8/BeagleBone Blackリファレンス

本記事に書かれた内容は誤りが含まれる可能性があるため、より正確な情報を得るには、以下のテクニカルリファレンスや外部サイトをご参照ください。

ARM 32bit レジスタ一覧

ARM 32bitレジスタの中で、頻繁に使用するものを下表に示します。

引数の受け渡しにスタックのみを使うi386アーキテクチャと異なり、ARMでは汎用レジスタr0〜r3を使用して関数の引数を渡します(汎用レジスタが不足する場合はスタックを使用します)。返り値も汎用レジスタで返します。

レジスタ別名役割
r0a1汎用レジスタ(引数の受け渡し、関数の返り値に使用)
r1a2汎用レジスタ(引数の受け渡し、関数の返り値に使用)
r2a3汎用レジスタ(引数の受け渡し、関数の返り値に使用)
r3a4汎用レジスタ(引数の受け渡し、関数の返り値に使用)
r4v1汎用レジスタ
r5v2汎用レジスタ
r6v3汎用レジスタ
r7v4汎用レジスタ
r8v5汎用レジスタ
r9sb汎用レジスタ(静的データセグメントのベースアドレス)
r10sl汎用レジスタ (スタックリミット)
r11fp汎用レジスタ(フレームポインタ)
r12ipプロシージャ内呼び出しスクラッチレジスタ
r13spスタックポインタ
r14lrリンクレジスタ(リターンアドレス)
r15pcプログラムカウンタ
cpsr-カレントプログラムステータスレジスタ

cpsr(カレントプログラムステータスレジスタ)

cpsr は、プロセッサの演算結果や動作モード・割り込み設定状態を保持するレジスタです。

Bit名称役割
31N演算結果が負の場合に設定される
30Z演算結果が 0 の場合に設定される
29C演算結果がキャリーアウトの場合に設定される
28V演算結果がオーバフローの場合に設定される
27Q飽和が発生した事を示す(自動クリアされない)
26〜25ITThumb IT (If-Then)命令用のステータスを示す
24Jプロセッサが Jazelle(※1) 状態かどうかを示す
23〜20予約予約された Bit。
19〜16GE[3:0]演算結果が〇〇以上の場合に設定される(SIMD 命令で使用される)
15〜10IT[7:2]Thumb IT (If-Then)命令の状態を示す
9Eロード/ストア命令のエンディアン形式を設定する (0:リトルエンディアン、1:ビックエンディアン)
8A非同期アボートマスクする場合に設定される
7IIRQ をマスクする場合に設定される
6FFIQ をマスクする場合に設定される
5TThumb 命令の状態を示す
4〜0Mモード領域

※1 Java 仮想マシンによるバイトコード実行時にハードウェアアクセラレーションのアーキテクチャサポートを提供する。Jazelle-DBX と Jazelle-RCT がある。

コプロセッサ一覧

プロセッサキャッシュや MMU の操作などでは、コプロセッサとコプロセッサ用レジスタを使用します。コプロセッサは 16 個存在します。

CP0〜9、CP12、CP13 は、システム独自の外部コプロセッサとして使用できます。その他のコプロセッサは、下表に示す通り、予め役割を定められています。

コプロセッサ役割
CP10VFP(Vector Floating Point、単精度の浮動小数点)制御
CP11VFP(Vector Floating Point、倍精度の浮動小数点)制御
CP14デバッグおよび ETM(Embedded Trace Macrocell、実行命令履歴)制御
CP15システム制御

ARM 32bit 命令

命令役割
and論理積を取る
orr論理和を取る。
bicビットをクリアする。
pushレジスタ値をメモリに保存する
popレジスタ値をメモリから復元する
mrsステータスレジスタから汎用レジスタに値を移す
msr汎用レジスタからステータスレジスタに値を移す
mrcコプロセッサから汎用レジスタに値を移す
mcr汎用レジスタからコプロセッサに値を移す
movレジスタからレジスタに値を移動する
strレジスタからメモリに値を移動する
ldrレジスタからレジスタに値を読み込む
bPC 値にオフセットを加えたメモリアドレス(ラベル先)に分岐する。
blラベル先へ分岐し、次の命令アドレスを r14(lr)にコピーする(※2)
cpsieI:IRQ 割り込みを許可、F:FIQ 割り込みを許可
cpsidI:IRQ 割り込みを禁止、F:FIQ 割り込みを禁止

※2 指定の番地へ分岐する前に戻りアドレスを R14=LR に保存するため、lrの内容を pc に書き込むと(MOV PC,LR)、元に戻る。

IRQ/FIQ 割り込み

FIQは高い優先度の高速割り込みであり、IRQ は通常優先度の割り込みです。

FIQは、プロセッサが状態を保存しなくて良いハードウェアのために存在し、 割り込み要求の処理中に「IRQ」および「その他の FIQ ハンドラ」を無効にする事によって優先順位を付けています。FIQ ハンドラ処理中に、他の割り込みは発生しません。

  • cpsr の I ビットが 0 および IRQ 端子が有効になった場合、IRQ 割り込み例外が発生。
  • cpsr の F ビットが 0 および FIQ 端子が有効になった場合、FIQ 割り込み例外が発生。

ARMインラインアセンブラ(GCC)の書き方

インラインアセンブラとは、C 言語ソースコード中でアセンブラ命令を埋め込む機能です。インラインアセンブラの使用時に用いる命令は、下表の通りです。

命令役割
__asm__インラインアセンブラの使用開始を意味する
__volatile__コードの最適化を抑制する。

構文は、__asm__(アセンブラコード :出力オペランド :入力オペランド :上書きされるレジスタリスト)という形式で、
“:“以降の指定は全てオプションです。記載例は、以下の通りです。

int func(int *a)
{
    int result = 0;
    __asm__ __volatile__ (
        "mov r1, #99;"
        "str r1, [%1];"
        "mov %0, #88;"
        : "=r"(result) /* 出力オペランド。"=r"の後に(C言語の変数名)を記載する(オプション) */
        : "r"(a)       /* 入力オペランド・"=r"の後に(C言語の変数名)を記載する(オプション) */
        :              /* 上書きされるレジスタ。オプションなので無記載でも良い。記載する場合は"r2"、"r3"...と記載する。*/
    );                 /* 補足:アセンブラ命令の%n部分(nは正の数値)が入出力オペランド。数値は定義順に昇順で割り当てる。*/
    return ret;
}

上書きされるレジスタには"memory"も指定でき、指定した場合は「インラインアセンブラの中で変数(レジスタ)が書き換わっている事」を明示しています。

つまり、“memory"はコンパイラに向けた宣言であり、「インラインアセンブラで変数が書き換わるので、それを踏まえて最適化してください」と伝えています

ただし、“memory"によってコンパイラレベルでの最適化はコントロールできますが、ハードウェアによる実行時並べ替え(Out of Order 実行)までは制御できません。