OS自作入門 -Advent26-
Step7 割り込み処理を実装する 後半戦
step7の中盤戦の最後の方でソフトウェア割込みベクタの話があり、RAM領域の先頭の方にsoftvec
領域を用意し、ここに対して割込みハンドラのポインタを配置できるようになればよい。続きの実装をしていこう。
ブートローダに割込みハンドラを実装する
割込みハンドラの入口と出口
intr.h, intr.Sの実装
intr.hには「ソフトウェア・エラー」SOFTVEC_TYPE_SOFTERR
、「システム・コール」SOFTVEC_TYPE_SYSCALL
、「シリアル割込み」SOFTVEC_TYPE_SERINTR
を定義した。
intr.Sにはそれぞれに対応する割込みハンドラとしてintr_softerr
、intr_syscall
、intr_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.h、interrupt.cにそれぞれ置いておく。
interrupt.hにはソフトウェア・割込みベクタの種別を表す型としてsoftvec_type_t
を定義。ソフトウェア・割込みベクタに設定するハンドラの型としてsoftvec_handler_t
という型を定義。このハンドラの型はvoid handler(softvec_type_t type, unsiigned long sp);
として定義されているように、第一引数に割込みの種別、第二引数にスタックポインタの値を取るようになっている。また、リンカ・スクリプトの修正で行なったsoftvec
というシンボルを定義していて、そのシンボルを利用してソフトウェア・割込みベクタを参照する記述をしている。INTR_ENABLE
とINTR_DISABLE
はそれぞれ割込みの有効化/無効化のためのマクロを定義している。asm volatile()
を利用して インライン・アセンブラ を使ってc言語の中にアセンブラを直接書いている。
interrupt.cはそれぞれ実装である。関数は3つ定義されていてそれぞれ次のような感じ。softvec_init
はソフトウェア・割込みベクタの初期化をしている。各ソフトウェア・割込みベクタのベクタ・アドレスにNULL
を指定している。softvec_setintr
はソフトウェア・割込みベクタの設定用の関数である。引数にソフトウェア・割込みベクタの番号とハンドラのアドレスを受け取って、ベクタにセットしている。interrupt
がメインで、intr.S
から呼ばれていた関数になる。引数に割込み種別とスタックポインタを受け取り、ソフトウェア・割込みベクタの配列を参照し、設定されたハンドラを割込み種別に応じて呼び出す。
アドベントカレンダーが終わったがまだまだ続くOS自作!理解しながらやっていると遅い部分がきっと理解が少ないところなのだろう。個人的にはメモリ周りのやりとりと知らないc言語の書き方とアセンブラ、特にレジスタ操作の辺りの理解が一番怪しそう。
- 前の記事
OS自作入門 -Advent25- 2017.12.25
- 次の記事
祝!アドベントカレンダー完走 2017.12.29