#include #include #include /* * 8259A master/slave. the slave sits on master IRQ2, so it must be masked * before the master's IRQ2 is dealt with, or a spurious cascade can arrive. */ #define PIC1_CMD 0x20 #define PIC1_DATA 0x21 #define PIC2_CMD 0xA0 #define PIC2_DATA 0xA1 #define PIC_EOI 0x20 /* non-specific end of interrupt, to the master */ #define ICW1_INIT 0x11 /* edge triggered, cascade, expect ICW4 */ #define ICW4_8086 0x01 /* 8086/88 mode */ /* * remap both PICs out of the way of the CPU exception vectors, then mask every * line. * * the remap matters as much as the mask: firmware may leave the PIC base at * the default 0x08, which collides with the #DF vector, so even a fully masked * stray line would be reported as a double fault. 0xF0 sits above our spurious * vector (0xFF) and is otherwise unassigned. */ #define PIC1_BASE 0xF0 #define PIC2_BASE 0xF8 static void pic_init_one(uint16_t cmd, uint16_t data, uint8_t base) { outb(cmd, ICW1_INIT); outb(data, base); outb(data, base + 8); outb(data, ICW4_8086); /* mask every line (bit set = masked) */ outb(data, 0xFF); } void pic_disarm(void) { /* mask the slave first, then the master, so no cascade slips through */ outb(PIC2_DATA, 0xFF); outb(PIC1_DATA, 0xFF); /* acknowledge anything already pending, then remap and mask for real */ outb(PIC2_CMD, PIC_EOI); outb(PIC1_CMD, PIC_EOI); pic_init_one(PIC1_CMD, PIC1_DATA, PIC1_BASE); pic_init_one(PIC2_CMD, PIC2_DATA, PIC2_BASE); /* * both PICs are masked now, but the master still needs to know the slave is * cascaded on IRQ2 or it raises spurious interrupts forever. */ outb(PIC1_DATA, 0xFF); }