The k project

8259A controller

The programmable interrupt controller is a chip on the IBM PC which is responsible for multiplexing interrupts from peripherals into one interrupt line on the CPU.

Operation mode

When a device needs to inform the system (i.e.: when new data is available, or on completion of a task), it fires an Interrupt Request (hence the name IRQ). The PIC then decides what to do with this interrupt request by looking at his internal configuration registers. The PIC can then decide to deliver the interrupt to the CPU (if the interrupt line is not masked), and find out the number of the IDT entry to call.

Typical wiring of the PIC

Each PIC has eight input lines (connected to peripherals) and one output line (connected to the CPU). The IBM PC has typically 2 PICs : one master and one slave. The slave’s output pin is connected to the master’s second input pin.

Here are the devices typically conntected to the PICs on an IBM PC :

Configuring the PIC

The IBM PC’s PIC is configured by using regular port-mapped I/O. The four port numbers are:

Initialization

The PIC’s initialization is done with Initialization Command Words (ICW). The kernel has to send a series of ICW (ICW1 through ICW4) to both PICs to initialize them.

ICW1

The first ICW sets a few parameters controlling the PIC’s mode of operation. ICW1 has to be sent to port A of each PIC.

0 0 0 1 x 0 x x
        |   | |
        |   | +---- (1)
        |   +------ (2)
        +---------- (3)
  1. ICW4 present (set) or not (clear)
  2. single controller (set) or cascade mode (clear)
  3. level triggered mode (set) or edge triggered mode (clear)

As said earlier, we typically have two PICs on an IBM PC, so we work in cascade mode. We also know that interrupts are edge triggered and we will need to program the ICW4, so a typical initialization sequence would be:

mov $0x11, %al      ; We can only output %al to I/O ports, not immediate values
outb %al, $0x20     ; Send $0x11 to the master PIC
outb %al, $0xA0     ; Send $0x11 to the slave PIC

ICW2

The second ICW informs the PIC about the base offset in the interrupt descriptor table (IDT) to use when transmitting an IRQ from a device to the CPU. The base offset must be a multiple of 8 (hence the three last zeroes in the following scheme). ICW2 has to be sent to port B of each PIC.

x x x x x 0 0 0
| | | | | | | |
+------------------ (1)
  1. Interrupt vector base address

Both PICs handle different IRQs from devices, so a different base offset must be configured for each one of them.

For example, if we send the following command words:

mov $0x40, %al
outb %al, 0x21      ; Set the master PIC's base offset to 64
add $0x10, %al
outb %al, 0xA1      ; Set the slave PIC's base offset to 80

an IRQ coming from the keyboard would be handled by the IDT entry number 65 (0x40 + 1), and an IRQ coming from the hard disk controller 1 by the IDT entry number 86 (0x50 + 6).

ICW3

The third ICW is used to give information about how master and slave PICs are connected. The ICW3 is sent to port B of each PIC.

The ICW3’s format is not the same for the master and the slave PIC:

   Master PIC
x x x x x x x x
| | | | | | | |
+------------------ (1)

   Slave PIC
0 0 0 0 0 x x x
          | | |
          +-------- (2)
  1. For each bit, indicate whether a slave PIC is connected to this pin (set) or not (clear)
  2. Indicate to the slave his slave ID (which pin of the master it is connected to)

ICW4

The fourth ICW sets some additional operation modes for the PICs. It has to be sent to port B of each PIC.

0 0 0 x x x x 1
      | --- |
      |  |  +------ (1)
      |  +--------- (2)
      +------------ (3)
  1. Automatic (set) EOI or normal (clear) EOI
  2. Buffering mode
  3. Special mode fully nested (set) or not (clear)

When no special mode of operation is required, the programmer can just clear every configuration bit. For example:

mov $0x01, %al
outb %al, 0x21
outb %al, 0xA1

Normal operation

When the PIC is initialized, the kernel can send Operation Control Words (OCW) to the PIC to perform various tasks such as acknowledging an IRQ.

OCW1

OCW1 is used to mask/unmask IRQs on a PIC. It is just sent to port B of the PIC.

x x x x x x x x
| | | | | | | |
+------------------ (1)
  1. For each bit, indicate whether the corresponding IRQ is masked (set) or not (clear)

For example, if we want to mask the IRQ 3 of the master PIC, we could do something like:

mov $1, %bl
shl $3, %bl
inb $0x21, %al
or %bl, %al
outb %al, $0x21

OCW2

OCW2 is one of the most frequently used control words in normal operation mode. It allows the kernel, among other things, to acknowledge an IRQ. If an IRQ is not acknowledged, the PIC won’t send any other interrupt for a given peripheral. OCW2 is sent to each PIC’s port A.

x x x 0 0 x x x
| | |     -----
| | |       |
| | |       +------ (1)
| | +-------------- (2)
| +---------------- (3)
+------------------ (4)
  1. Interrupt level to be acted upon when sending a specific command
  2. Send an EOI (end of interrupt command) (set)
  3. Send a specific (set) or a non-specific (clear) command
  4. Rotate priorities (set) or not (clear)

When the kernel just wants to acknowledge the latest IRQ handled, it can just send a non-specific EOI command. Always remember that if the IRQ was fired by the slave PIC, both master and slave PICs have to be acknowledged:

mov $0x20, %al
outb %al, $0x20     ; Send ACK to master PIC
outb %al, $0xA0     ; Send ACK to slave PIC

Thanks to the nested interrupts system, the latest handled IRQ is always the one with the highest priority (i.e.: the one with the smallest number), so a specific EOI command is not required and the PIC can determine the acknowledged IRQ by itself.

Attached files