8259A 初期化
マクロから類推できる範囲で解析。ペンディングにしている APIC マワリな部分についても早めに見とく必要がありそうな気が。
init_8259A()#arch/i386/kernel/i8259.c の以下の部分について
outb(0xff, PIC_MASTER_IMR); outb(0xff, PIC_SLAVE_IMR); outb_p(0x11, PIC_MASTER_CMD); outb_p(0x20 + 0, PIC_MASTER_IMR); outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); if (auto_eoi) outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); else outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); outb_p(0x11, PIC_SLAVE_CMD); outb_p(0x20 + 8, PIC_SLAVE_IMR); outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); if (auto_eoi) i8259A_irq_type.ack = disable_8259A_irq; else i8259A_irq_type.ack = mask_and_ack_8259A; udelay(100); outb(cached_master_mask, PIC_MASTER_IMR); outb(cached_slave_mask, PIC_SLAVE_IMR);
ざっくりベースで上記処理は
- master、slave の割り込み停止 (マスク)
- master の初期化
- slave の初期化
- master、slave のマスク解除
では、順に。まずマスク処理。
outb(0xff, PIC_MASTER_IMR); outb(0xff, PIC_SLAVE_IMR);
マクロ PIC_MASTER_IMR、PIC_SLAVE_IMR は include/asm-i386/io_ports.h にて定義。
#define PIC_MASTER_IMR 0x21 #define PIC_SLAVE_IMR 0xa1
IMR はマニュアルによれば、Interrupt Mask Register との事。8259A には他にレジスタが二つある。In-Service Register (ISR)、Interrupt Request Register (IRR) とマニュアルには記述されている。
で、IMR ですが、フラグが立った IRQ は割込みを受け付けない状態になる、と。マニュアルにもamazon:Linux カーネル解析入門にも OCW1 (Operation Command Words 1) と記述されている。
次からは master に対する初期化手続き。初期化手続きは 4 つのフェイズ (ICW1 から ICW4) に分かれているとの事。ICW は Initialization Command Words の略、とマニュアルにあり。
amazon:Linux カーネル解析入門より引用
マニュアルによると、ICW1 において ICW3 および ICW4 が必要かどうかの指定をしているとの事。
outb_p(0x11, PIC_MASTER_CMD);
上記では ICW3 も ICW4 も必要、との意味になっている。又、PIC_MASTER_CMD マクロは include/asm-i386/io_ports.h によると以下のように定義されている。
#define PIC_MASTER_CMD 0x20
master の ICW1 はポート 0x20 に出力する必要があるらしい。
で、次は ICW2 でコメントにある通り、IRQ 0〜7 を 0x20〜0x27 にマップするよう指示している。根拠は不明。コメントが仕様、としか言いようが無いかも。(弱
outb_p(0x20 + 0, PIC_MASTER_IMR);
ICW2 は PIC_MASTER_IMR (0x21) に出力という事か。ちなみにマニュアルには A0 という input signal が 1 か 0 かという指定はある。ICW1 は 0 で、ICW2 は 1 となっていたが、これとポートの関係がどうなのかは微妙。
次。ICW1 でカスケードします、と言っているので ICW3 が必要。
outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
ちなみに PIC_CASCADE_IR マクロは include/asm-i386/io_ports.h にて定義。
#define PIC_CASCADE_IR 2
0x04 を PIC_MASTER_IMR (0x21) に出力。IRQ2 を slave に接続するという指示をしている模様。コメントにもそう書いてありますな。
で、最後の ICW4 ですが以下。
if (auto_eoi) outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); else outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
init_8259A() の引数 auto_eoi の値によって条件分岐している。呼出し元は init_ISA_irqs()#arch/i386/kernel/i8259.c で以下のように呼び出している。
init_8259A(0);
というコトで、ここでは else なブロックの処理が実行される。MASTER_ICW4_DEFAULT マクロは include/asm-i386/io_ports.h によると以下。
#define MASTER_ICW4_DEFAULT 0x01
amazon:Linux カーネル解析入門によれば、EOI は自分でヤリますよ、という指示を主に通知している模様。
これで一旦 master 向けの初期化は終了。slave の初期化処理はまとめて以下に。
outb_p(0x11, PIC_SLAVE_CMD); outb_p(0x20 + 8, PIC_SLAVE_IMR); outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
上記コードの関連マクロは include/asm-i386/io_ports.h にて定義。
#define PIC_SLAVE_CMD 0xa0 #define PIC_SLAVE_IMR 0xa1 #define PIC_CASCADE_IR 2 #define SLAVE_ICW4_DEFAULT 0x01
master と異なる点は以下。
- 出力ポート ICW1 が 0xa0 で ICW2〜4 が 0xa1 になっている。
- IRQ 0〜7 を 0x28〜0x2f にマップするよう指示している。
- slave の場合、ICW3 における出力はフラグ (ってかビットマップ) ではなく値になる模様。
もう少し後処理が残っていますが、とりあえずここで一旦ストップ。
TODO
根拠が微妙だととても気になるのは悪いクセかも。