Tag Archives: トラップハンドラ

割り込みコントローラ

SH7780では割り込みの受付時にINTEVTレジスタ(メモリ割り付けレジスタ)を読むことでどの要因で割り込みが発生したのか特定できるようになっている。割り込みコントローラ(ハードウェア)は、タイマーやDMACなどから割り込みの要求が入るとINTEVTにその要求に割り当てられた数字を書き込む。割り込みハンドラ(プログラム)はINTEVTレジスタを読み込み、スケジューリングやIRQの転送などの処理へ分岐していく。

割り込みの要因は四種類に大別できる。NMI、IRQ、IRL、内蔵モジュールである。NMIはNon Maskable Interruptで、マスクできない、つまり、プロセッサがどのような状態にあっても入ってくる割り込みである。IRQはInterrupt Requestで、一般に周辺機器を制御するための割り込みである。SH7780には8チャネルのIRQ端子があり、それぞれ独立して割り込みの状態を設定できる。IRLはIRQと同じように周辺機器を制御するための割り込みなのだが、割り込みをチャネルではなくレベル(あるいはチャネルの状態のパターン)で分類する。IRLを使うと効果的な場面はよくわからない。内蔵モジュールの割り込みは、タイマー、DMAC、シリアルインタフェースなどからの割り込みである。

割り込みには優先順位をつけることが出来る。レベル16が最高で、レベル1が最低となっている。レベル0では割り込みが受け付けられない。割り込みの優先順位は同時刻に発生した割り込みを開発者の思うとおりに制御するために必要である。たとえば、タイマー割り込みの優先度が高ければ、スケジューリングの遅延を避けることが出来、結果として、実時間性を向上させることが出来る。

割り込み要因の考慮

先述のように割り込みの要因は四つある。NMIはカーネルで処理する。したがって、ユーザー空間に転送しなければならない割り込みは、大別すると外部割り込み(IRQもしくはIRL)と内部割り込み(内蔵モジュール)の二種類になる。L4のAPIでは割り込みは一つの空間にまとめられている。IA32やARMでは割り込みの空間は一種類なので良かったが、二種類の割り込みの空間があるSH4Aではカーネルはどのように処理したらよいのだろうか。

カーネル内部ではIRQを管理する配列がある。IRQそれぞれに対し、一要素を割り当てる。SH4Aでは12ビットの例外コードによって、外部割り込み、内部割り込みに関わらず、要因を区別する。これらの割り込みは合計すると68種類にもなる。例外コードの内、下位5ビットは使われていない。つまり、ゼロだ。下位5ビットを算術シフト演算で取り除き、オフセット値を引けば、0からの通し番号に変換できる。しかし、例外コードをよく見てみると、所々番号が飛んでいるところがある。なんともいやらしいなぁ。

外部割り込みだけなら話は簡単だ。しかし、デバイスドライバの処理に必要なDMACやシリアルポートの割り込みは内部割り込みだ。

とりあえずの解法として、飛び石の番号を無視して配列を確保してしまうことにした。例外コードは0×200から始まり0xFE0までなので、0×20毎に例外コードがあるとすれば112要素必要になる。実際には例外コードは68種類しかないので54要素分は不要になる。各要素は12バイトのデータ構造なので、648バイトは無駄になる。

割り込みコントローラの設定

  • 端子モードはIRQを使用する(IRLモードは使用しない。効果的な使い方を知らないので。)
  • IRQ0からIRQ7はオフ(ユーザプロセスからの要求に従ってオン)
  • TMU0はオン

SH4Aは二種類のタイマーを提供する。TMUは独立したチャンネルが六つあり、割り込みも独立して入る。CMTにもチャンネルはあるが、割り込みは共通している。特に理由はなくTMU0をスレッドディスパッチ用タイマーとして選択する。

カーネル内の割り込みハンドラ

例外処理ルーチンの先頭アドレスは各割り込みで共通である。なので、割り込み要因を識別するためにINTEVTをオフセットとして分岐する。

  • IRQをIPCに変換する (IRQ0からIRQ7)
  • スケジューリングする (TMU)

カーネル割り込みハンドラの中でやらなければいけないこと

1.IRQを配送する

IRQはユーザプロセスで処理されるので、そのためにカーネルは受け取った割り込み要求をユーザプロセスに配送しなければならない。例:simplesoc_handle_irq_rescheduleを呼び出す。(rescheduleの意味は何?)

2.スケジューリングする

handle_timer_interruptを呼び出す。

カーネル割り込みハンドラの中でやらないこと

シリアルインタフェースの割り込み処理など、その他の割り込み。

割り込みAPI

割り込みハンドラの登録

割り込み処理

はじめに

まずは例外ハンドラの実装から。例外ハンドラが処理する事象は三つある。

  • システムコール
  • 例外
  • 割り込み

システムコールは例外の一種として扱われる。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もここで処理される。処理の内容としては大きく三つに分けることが出来る。

  1. システムコール:システムコールを実行
  2. ページフォルト:ページャに転送
  3. エラー:カーネルで処理、もしくはページャに転送

一般例外のハンドラでは、この場合分けを行う。詳細な処理はそれぞれ専用の関数をハンドラのコンテキストで呼び出し、処理を任せる。

命令実行前ユーザーブレーク・命令実行後ユーザーブレーク
デバッガに転送

命令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ハンドラへ分岐。条件によってはページフォルトに変換する。

ユーザーブレーク:カーネルデバッガへ分岐。

その他:一般例外ハンドラへ分岐。プロセスの強制終了などを判断する。