OS自作入門 -Advent26-

NO IMAGE

Step7 割り込み処理を実装する 後半戦

step7の中盤戦の最後の方でソフトウェア割込みベクタの話があり、RAM領域の先頭の方にsoftvec領域を用意し、ここに対して割込みハンドラのポインタを配置できるようになればよい。続きの実装をしていこう。

ブートローダに割込みハンドラを実装する

割込みハンドラの入口と出口

intr.h, intr.Sの実装

intr.hintr.Sにそれぞれ置いておく。

intr.hには「ソフトウェア・エラー」SOFTVEC_TYPE_SOFTERR、「システム・コール」SOFTVEC_TYPE_SYSCALL、「シリアル割込み」SOFTVEC_TYPE_SERINTRを定義した。

intr.Sにはそれぞれに対応する割込みハンドラとしてintr_softerrintr_syscallintr_serintrという関数を定義している。ほぼ共通処理なので流れはほぼ一緒。最初に汎用レジスタを保存し(mov.l er6,@-er7とか)、ER1にER7の値をコピーし(mov.l er7,er1)、R0に「SOFTVEC_TYPE_SOFTERR」を代入。このためinterrupt()側では渡された第一引数を見れば割込みの種類が分かり(R0)、第二引数を見れば保存されている汎用レジスタの値を見ることができるようになっている。その後にinterrupt関数を呼び(jsr @_interrupt)、最後は反対に汎用レジスタの値を復旧する(mov.l @er7+,er0とか)、最後にrteを呼びプログラム・カウンタとCCRの値を復旧する。

interrupt.h, interrupt.cの実装

interrupt.hinterrupt.cにそれぞれ置いておく。

interrupt.hにはソフトウェア・割込みベクタの種別を表す型としてsoftvec_type_tを定義。ソフトウェア・割込みベクタに設定するハンドラの型としてsoftvec_handler_tという型を定義。このハンドラの型はvoid handler(softvec_type_t type, unsiigned long sp);として定義されているように、第一引数に割込みの種別、第二引数にスタックポインタの値を取るようになっている。また、リンカ・スクリプトの修正で行なったsoftvecというシンボルを定義していて、そのシンボルを利用してソフトウェア・割込みベクタを参照する記述をしている。INTR_ENABLEINTR_DISABLEはそれぞれ割込みの有効化/無効化のためのマクロを定義している。asm volatile()を利用して インライン・アセンブラ を使ってc言語の中にアセンブラを直接書いている。

interrupt.cはそれぞれ実装である。関数は3つ定義されていてそれぞれ次のような感じ。softvec_initはソフトウェア・割込みベクタの初期化をしている。各ソフトウェア・割込みベクタのベクタ・アドレスにNULLを指定している。softvec_setintrはソフトウェア・割込みベクタの設定用の関数である。引数にソフトウェア・割込みベクタの番号とハンドラのアドレスを受け取って、ベクタにセットしている。interruptがメインで、intr.Sから呼ばれていた関数になる。引数に割込み種別とスタックポインタを受け取り、ソフトウェア・割込みベクタの配列を参照し、設定されたハンドラを割込み種別に応じて呼び出す。


アドベントカレンダーが終わったがまだまだ続くOS自作!理解しながらやっていると遅い部分がきっと理解が少ないところなのだろう。個人的にはメモリ周りのやりとりと知らないc言語の書き方とアセンブラ、特にレジスタ操作の辺りの理解が一番怪しそう。