&amazon() {作りながら学ぶOSカーネル―保護モードプログラミングの基本と実践
}
を、暫く前からだらだらと読み進めていて、ようやく4章の割り込みの所に到達した。
で、PIC(Programmable Interrupt Controller)の初期化と割り込みハンドラのソースコードの部分で基礎的な知識が無かった故に「??」となってしまった部分があるのでメモしておく。
103pからの「ソース4-6 kernel2.asm」で、デフォルトの割り込みハンドラ"isr_ignore"とTimer用割り込みハンドラ"isr_32_timer"で、
MOV AL, 0x20
OUT 0x20, AL
というのが出てくるが、これの解説がどうも載っていない。コメントも無い。
また100pから始まる「ソース4-5 boot2.asm」にもPICの初期化処理で"OUT"命令が出てくるが、そのIOポートが次の4種類出てくる。
OUT 0x20, AL
OUT 0x21, AL
OUT 0xA0, AL
OUT 0xA1, AL
この違いについて調べてみた。本の解説にもあるとおり、割り込みはIntelの8259Aというコントローラ(とその互換chip)が担当しているとの事で、PIC 8259Aを中心に色々Googleに訊いてまわる事になった。
* 8259Aへのコマンド・データ指示とIOポート番号について
8259Aの物理的な構造としてD0-D7pin, A0pinが今回の件に関連している。PICの初期化や内部レジスタの操作にはA0pin, D0-D7pinで行う。データバスを介して行われるPICの処理命令(Command Words)とA0pinの関係についてまずまとめる。初期化処理系(ICWx)は一度のみ、操作処理系(OCWx)は初期化完了後は何度でも呼べる。
- 初期化処理系(ICW : Initialization Command Words)
-- ICW1(A0=0) : PICの初期化実行
-- ICW2(A0=1) : 割り込み番号のベクタアドレス(上乗せ値)の指定
-- ICW3(A0=1) : マスター・スレーブの連結方法の指定
-- ICW4(A0=1) : 追加命令
- 操作処理系(OCW : Operation Command Words)
-- OCW1(A0=1) : IRQ番号のmask設定
-- OCW2(A0=0) : EOI(End of Interruption)指示
-- OCW3(A0=0) : "スペシャルマスク"設定
前述のboot2.asm, kernel2.asmで使われているのはICW1-4, OCW1-2である。それぞれをOUTで指定する時のIOポートアドレスをA0pinの状態と比べてみる。
| ICW1 | A0=0 | OUT 0x20/0xA0 |
| ICW2 | A0=1 | OUT 0x21/0xA1 |
| ICW3 | A0=1 | OUT 0x21/0xA1 |
| ICW4 | A0=1 | OUT 0x21/0xA1 |
| OCW1 | A0=1 | OUT 0x21/0xA1 |
| OCW2 | A0=0 | OUT 0x20/0xA0 |
このように、0x20/0xA0ならA0=0, 0x21/0xA1ならA0=1というように対応している。
結論から言うと、このA0pin/D0-D7pinとIOポート番号の対応はBIOSのPOST処理により設定される。
命令の種類として、A0pin = 0 のものは主に初期化処理や内部レジスタの状態を変更する命令、 A0pin = 1 のものは内部レジスタの値を直接操作したり、アドレスoffsetを操作する透過的なデータ操作命令として、以下のような分類にしているようだ。A0pinのON/OFF切り替えはCPU内部で行われているものと思われる((さすがにここまでは追跡できなかった))。
| 0x20/0xA0 | 初期化命令, EOI指示(ICW1, OCW2, OCW3) |
| 0x21/0xA1 | マスク/値の設定(ICW2, ICW3, ICW4, OCW1) |
ICW4は追加命令なので0x20/0xA0の方がふさわしいように思えるが、それ以外はおおむね分類として合っているように思われる。
ここで、boot2.asm, kernel2.asm のソースに戻って見直してみる。
まずboot2.asmでは、ICW1-4の設定を行うところは順に 0x20/0xA0(ICW1), 0x21/0xA1(ICW2-4) へOUTしている。
また
mov al, 0xFF ; スレーブPICの全ての割り込みを
out 0xA1, al ; 防いでおく。
dw 0x00eb, 0x00eb
mov al, 0xFB ; マスターPICのIRQ2番を除いた、
out 0x21, al ; 全ての割り込みを防いでおく。
ここの部分は OCW1、mask設定になる為これも 0x21/0xA1へのOUTとなっている。
kernel2.asmの無限ループへ入る直前、
mov al, 0xFE ; 防いでおいた割り込み中、
out 0x21, al ; タイマーだけを有効にする。
こちらもOCW1, mask設定で 0x21へのOUTとなっている。
今回の調査に駆り立てたきっかけである、isr_ignore, isr_32_timerの次の箇所を読み解いてみる。
mov al, 0x20
out 0x20, al
まず0x20へのOUTで、0x20というコマンド値は OCW2, EOI指定である。8259Aの仕様では0x20は「非指定EOI」である。
* OCW2, EOI(End of Interruption)指示について
ここでEOIの意味について簡単にまとめておく。
8259Aの内部レジスタには以下の3つがある。
- Interrupt Request Register (IRR) : 割り込み信号は受け取ったが、まだCPUに送られていないIRQ番号のbitが1になっている。
- In-Sevice Register (ISR) : CPUに送られ、INTA待ちのIRQ番号のbitが1になっている。
- Interrupt Mask Register (IMR) : 割り込みを受信するIRQ番号のbitmask
PICはEOIを受け付けると、該当するISRビットを"0"にする。これにより、次の割り込みが受け付けられるようになる。EOIには次の3種類がある。
- 自動EOI(Automatic EOI)
-- 自動EOIはICW4のAEOIビットが"1"になっている場合のみ有効。CPUが割り込みを受け付け、INTAが出た時点で自動的にISRがリセットされる。
- 非指定EOI(Non-Specific EOI)
-- ISRの中でもっとも優先度の高いものをPICが自動判定し、クリアする。通常はIRQ番号が低いほど優先度が高いと見なされる。
- 指定EOI(Specific EOI)
-- 割り込み番号を特定したい場合に使う。bit0-2で割り込み番号を指定する。
boot2.asmのICW4ではAEOIビットがズバリ、"0"になっている。このため割り込みハンドラの中でOCW2, EOIコマンドを発行する必要があった。非指定EOIを使っているのは、割り込み番号を特に指定する必要のない小規模な実験コードだからだろう。
* 参考資料
- "パソコンのレガシィI/O活用大全"
-- http://www.cqpub.co.jp/column/books/2001a/34331PC_Legacy/default.htm
-- 絶版。Amazonでもコレクター商品として19,980円とかついてる。
- "Operating Systems Development - 8259A PIC Microcontroller", by Mike "Crypter" 2007
-- http://www.brokenthorn.com/Resources/OSDevPic.html
--- 英語だが、かなり詳しい。A0pinとIOポート番号のmappingがBIOSで制御されてるのはこのリソースで知った。
- "Input/Output Base Address - Wikipedia, the free encyclopedia"
-- http://en.wikipedia.org/wiki/Input/Output_Base_Address
- "Programmable Interrupt Controller - Wikipedia, the free encyclopedia"
-- http://en.wikipedia.org/wiki/Programmable_Interrupt_Controller
--- 電子計算機系の技術を調べる時は、やはり英語版のWikipediaの方が充実している。
- "I/O Ports and Controllers on IBM Compatibles and PS/2"
-- http://www.os2site.com/sw/info/memory/ports.txt
--- IOポート番号一覧。どうやって調べたのか知りたい・・・。
- "8259A PROGRAMMABLE INTERRUPT CONTROLLER (8259A 8259A-2)"
-- http://bochs.sourceforge.net/techspec/intel-8259a-pic.pdf.gz
--- bochsのサイトに何故かあった8259Aのデータシート。ちゃんと文章がテキストとして検索できるようになっていたので、こちらを参考にした。
----
IOポート番号や8259Aの仕様など、非常にハード寄りの部分の調査になった為、それなりに大変だった。ここまで調べたが、かといって8259Aの仕様を完全に理解したのかと言われると否。今回はA0pinとIOポート番号のmappingがどこで行われているのかを最優先にして資料を流し読みしたため、ICWやOCWの各命令詳細やPICの内部ダイアグラムまで追っかけたわけではない。
486アーキテクチャなどのハード系はインターネットが一般に広まる1995年以前に完成していた為、Google先生に訊いてもなかなか日本語で分かりやすい資料が見つからず、結局英語資料の方が役に立った。
しかし近年のアーキテクチャではAPICとしてCPUのコアに統合されているらしく、これを使うと数十の割り込みコントローラを連結させたりする事も出来るらしい。非常に奥が深い世界なのだと思い知らされた。