はじめに
まずは例外ハンドラの実装から。例外ハンドラが処理する事象は三つある。
システムコールは例外の一種として扱われる。SH-4Aのマニュアルでは、第5章に例外処理の解説がある。詳細はマニュアルを参照されたい。
システムコール
システムコールとはユーザプログラムからのカーネルの機能の呼び出しのことである。L4マイクロカーネルは自身を特権モードで動かし、ユーザプログラムを非特権モードで動かす。一般に非特権モードで動いているプログラムは特権モードで動いているプログラムよりも出来ることが少ないので、非特権モードのプログラムが特別な処理を使用とする場合には、特権モードで動くプログラムにお願いする必要がある。このお願いする方法が多くのカーネルではシステムコールとして提供されている。
SH-4AではTRAPAという命令でシステムコールを発行する。ユーザープログラムがTRAPAという命令を発行するとCPUのモードは非特権モードから特権モードに自動的に切り替わる。その上で、プログラムカウンタの値をあらかじめ設定された番地に変更する。この番地に特権モードで動くプログラム、すなわちシステムコールを処理するプログラムを置いておけば、自動的に実行される。特権モードで動くプログラムはRTEという命令を発行し、非特権モードのプログラムに戻る。RTEは自動的にCPUのモードを特権モードから非特権モードに切り替える。
例外
例外はユーザプログラムやカーネルが誤った操作をしたときに発生する。たとえば、書き込みが禁止されている領域にデータを書き込もうとした場合や、0で割り算をしようとした場合などである。この場合にも、システムコールと同じように、CPUはプログラムカウンタを特定の番地に変更する。この場所に例外を処理するプログラムを置いておくことで、例外の後片付けをすることが出来る。
TLBミス
TLBミスは特殊な例外だ。TLBはアドレス変換のデータを格納するキャッシュである。あるCPUではTLBへのデータの格納はハードウェアが自動的に行ってしまう。SH-4Aにはソフトウェアで設定できるTLBが搭載されている。したがって、TLBへデータを格納するには適切なプログラムを呼び出してやる必要がある。このプログラムを呼び出すためにTLBミスという例外がある。TLBミスは変換したいアドレスがTLBに見つけられないと発生する。
割り込み
割り込みとは周辺デバイスを処理するための仕組みである。たとえばキーボードのキーを押すと割り込みが発生する。L4は割り込み処理のほとんどをユーザープログラムで処理するような構造になっている。カーネルは割り込みを受け取り、それを適切な形でユーザープログラムに転送する。
設計
SH-4Aの例外処理
SH-4Aの例外の多くは、VBR(ベクタベースアドレス)に配置されたプログラムで処理されるようになっている。VBRはソフトウェアで自由に設定できる。VBRに設定できる例外処理プログラム(例外ハンドラ)はそのアドレスから三つに分類される。
一般例外(オフセット0×100):多くの例外がここで処理される。システムコールを発行するTRAPAもここで処理される。処理の内容としては大きく三つに分けることが出来る。
- システムコール:システムコールを実行
- ページフォルト:ページャに転送
- エラー:カーネルで処理、もしくはページャに転送
一般例外のハンドラでは、この場合分けを行う。詳細な処理はそれぞれ専用の関数をハンドラのコンテキストで呼び出し、処理を任せる。
命令実行前ユーザーブレーク・命令実行後ユーザーブレーク
デバッガに転送
命令TLB保護違反例外(故障検知)
アクセスがITLBの保護情報に反する場合に発生する。つまり、ユーザモードで特権領域のコードにアクセスすると発生する。 特権領域にあるのはカーネルコードだけなはずだから、これはデバッガに落ちるか、プロセスの強制終了になる。
一般不当命令例外・スロット不当命令例外
命令アドレスエラー・データアドレスエラー(故障検知)
データ境界以外からの命令フェッチもしくはアクセス、またはユーザーモードでの特権領域へのアクセスで発生する。
データTLB保護違反例外(故障検知、もしくはページフォルトに変換)
アクセスがUTLBの保護情報に反する場合に発生する。これは二つの場合が考えられる。一つ目は、ユーザプロセスが特権領域のアドレスにアクセスした場合、もう一つは、ユーザプロセスが非特権領域のアドレスで許可されていないアクセスをした場合、もしくはカーネルプロセスが特権領域のアドレスで許可されていないアクセスをした場合である。後者は例えば、書き込みの許可されていないアドレスに書き込みアクセスをした場合である。 特権領域へのアクセスは、システム全体で禁止されているので、そのプロセスは強制終了させられる。非特権領域でのこの例外はページフォルトとしてページャに転送される。
FPU例外
例外としてユーザプロセスに転送する。
初期ページ書き込み例外(ページフォルトに変換)
ストアアクセスでTLBにヒットしたが、ダーティビットはゼロの時に発生する。つまり、アドレスはTLBに格納されているのだが、そのアドレスにまだ書き込みがされていない状態で発生する。何らかの理由によってTLBエントリだけを設定していたり、アドレスに対して読み込みだけしていたりする場合にこの状態になる。 L4上ではこの例外は上がってきてはいけない。万が一この例外が補足された場合には書き込み要求のページフォルトに変換する。
無条件トラップ
システムコール
TLBミス(オフセット0×400):TLBミスを処理する。多くの場合は、ページフォルトとしてページャに転送されるものと予想する。
割り込み(オフセット0×600):割り込みを処理する。ユーザーレベルのプログラムに転送する。
例外処理中の例外
例外の処理はソフトウェアで行われるため、例外処理中に他の例外事象が発生する可能性がある。これに対し、例外処理中に他の例外処理をする仕組みと、例外処理中に他の例外処理を禁止する仕組みを考える必要がある。
CPUは例外によって特権モードに移行する。SH-4Aは二種類のレジスタセット(レジスタバンク)を提供しており、モードによって自動的に切り替 わる。バンク0のレジスタR0からR7はユーザーモードのレジスタR0からR7に割り当てられる。バンク1のレジスタR0からR7は特権モードのレジスタ R0からR7に割り当てられる。バンク0のレジスタは特権モードでもアクセスしたり、R0からR7に割り当てることが可能だが、バンク1のレジスタは特権 モードでしか操作できない。例外ハンドラ起動時にはレジスタR0からR7はバンク1のR0からR7に割り当てられている。R8からR15はモードによる切 り替えはない。
例外処理中に他の例外を処理するためにはバンクを1から0に切り替えておく必要がある。
例外の優先順位
例外には優先順位がつけられており、これを実装にどのように反映すべきか考える必要がある。
実装
バンクの切り替え
バンクの切り替えはSRレジスタのMDビットの操作で行う。SRレジスタの操作には少なくとも一つの汎用レジスタ(R0からR15のいずれか)の使用を伴うので、場合によっては汎用レジスタの内容を退避する必要がある。
コンテキストの退避と復旧
例外処理以前の状態に復帰するためにコンテキストを退避しておきたい場合がある。多くのカーネルの実装と同じく、ここでもレジスタの値をスタックに保存する。
ハンドラの配置
一般例外、TLBミス、割り込みの各ハンドラを適切なアドレスに配置する必要がある。これにはbalign命令を使う。
一般例外
無条件トラップ:システムコールハンドラへ分岐。システムコールを実行する。
TLB保護違反例外と初期ページ書き込み例外:TLBハンドラへ分岐。条件によってはページフォルトに変換する。
ユーザーブレーク:カーネルデバッガへ分岐。
その他:一般例外ハンドラへ分岐。プロセスの強制終了などを判断する。