Skip to content
Lesson 18 of 24

Step 1 of 5 · Reading · ~4 min

Read

System Calls & I/O

Interrupts & I/O

A CPU that has to poll every device in a loop wastes nearly all its time. Hardware instead lets devices interrupt: the device raises a signal, the CPU finishes its current instruction, looks up a handler in the IDT, runs it, and resumes. Between the device and the CPU sits an interrupt controller that decides which request gets through, in what order, and under which conditions. In this lesson your program is the classic PC controller, a pair of cascaded 8259 PICs, and you will see why every OS reprograms it before enabling interrupts.

Vectors: where interrupts go

The IDT (lesson 4) has 256 entries. Intel reserved the first 32 for CPU exceptions: 0 divide error, 6 invalid opcode, 8 double fault, 13 general protection, 14 page fault, and so on. Some exceptions push an error code (8, 10 to 14, 17), most do not. The remaining vectors, 32 to 255, are free for devices and software interrupts.

The two chips

An IBM PC has two 8259s. The master serves IRQ 0 to 7 (0 timer, 1 keyboard, 2 cascade, 3 and 4 serial ports, 6 floppy, 7 printer); the slave serves IRQ 8 to 15 (8 real-time clock, 12 mouse, 14 and 15 IDE disks) and is wired into the master's IRQ 2 line. Each chip has three 8-bit registers:

RegisterMeaning
IRRrequests that have arrived
ISRrequests currently in service (delivered, not yet acknowledged)
IMRmask: a 1 bit blocks that line

When a request arrives, the chip picks the highest-priority line (0 highest, then 1, then the whole slave group in the place of IRQ 2, then 3 to 7) that is requested, unmasked, and not blocked by something in service. It moves the request from IRR to ISR and hands the CPU a vector = base + line number. The kernel's handler must finish with an EOI (end of interrupt) command that clears the highest-priority bit in that chip's ISR. Until then, nothing of equal or lower priority is delivered. For an interrupt from the slave the kernel sends EOI to the slave and to the master.

Why remap

At reset the master's base is vector 8, so IRQ 0 (the timer) arrives as vector 8, the double fault exception. Every OS therefore reprograms the PICs during boot, typically to bases 0x20 and 0x28, well clear of the exceptions. Until the kernel unmasks a line, its requests wait in IRR.

A worked trace

Bases 0x20 and 0x28, everything masked after boot.

CommandOutputWhy
UNMASK 0, UNMASK 1timer and keyboard enabled
RAISE 1IRQ1 vec=0x21 keyboarddelivered, ISR bit 1 set
RAISE 1a second keypress waits in IRR: line 1 is in service
RAISE 0IRQ0 vec=0x20 timerline 0 outranks line 1, so it preempts the keyboard handler
EOI Mclears the lowest set ISR bit: the timer's
EOI MIRQ1 vec=0x21 keyboardclears the keyboard; the waiting keypress is delivered

A request that waits in IRR is not lost, but it also is not queued twice: two presses while the line is in service become one pending bit.

Slave interrupts also need the cascade open: with UNMASK 12 but IRQ 2 still masked on the master, RAISE 12 stays pending forever. UNMASK 2 releases it, delivered as vector 0x2C.

Common mistakes

  • Forgetting EOI: the line stays in service and everything at its level and below is blocked.
  • Not unmasking the cascade line (IRQ 2) and wondering why disk or mouse interrupts never arrive.
  • Sending EOI only to the master for a slave interrupt.
  • Delivering a lower-priority request while a higher-priority one is in service.

Modern hardware

PCs now use the APIC: a local APIC per CPU and I/O APICs that route interrupts to cores, and PCIe devices use MSI, writing the vector number straight to memory. The ideas are the same: mask, priority, acknowledge.

Your exercise

The starter parses commands and prints. You write the controller's delivery rule and EOI.

Up nextThe Timer & PreemptionSystem Calls & I/O

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…