Department of Electrical and Computer Engineering
Dalhousie University

80x86 Interrupts

Dr. Larry Hughes


Introduction

When a device interrupts the processor, a number of things occur. First, the task currently being run by the processor is suspended while the processor handles the interrupt. Second, a procedure, known as an interrupt handler (or interrupt service routine), must be activated. The interrupt handler is responsible for servicing the interrupt (that is, determining why the interrupt has occurred and what to do about it). Third, the suspended task must be resumed once the interrupt handler is finished.

In the case of the 80x86 processors, when an interrupt occurs, the task currently executing is suspended by pushing the instruction counter and the status flag on the stack, thereby permitting control to be returned to the task once the interrupt has been serviced. To ensure that no further interrupts will occur during the handling of the first interrupt, the 80x86 processor disables interrupts (i.e., if other interrupts occur, they are blocked until the processor either explicitly enables interrupts or resumes execution of the interrupted task).

Interrupt Requests

Each device on the PC is associated with a interrupt request number or IRQ:

IRQDevice
0 Clock
1 Keyboard
2 From slave 8259
3 Serial Port 2
4 Serial Port 1
5 Hard Disk
6 Floppy Disk
7 Printer

The lower the IRQ value, the higher the priority. For example, the clock (IRQ0) has higher priority than does the hard disk (IRQ5).

Interrupt Numbers

When an interrupt occurs, the interrupting device's IRQ is added to a constant that is the device's interrupt number. The interrupt number refers to the device's interrupt vector stored in segment zero. The constant can be any multiple of 8 (0, 8, 16, 24, and so forth); since the first few vectors are used for CPU exceptions, IBM and Microsoft chose the value of the constant to be 8.

The following table shows the assignment of interrupt numbers by IBM and Microsoft, interrupt vector locations, and the eight 'standard' devices (note that there is no obvious relationship between the ports associated with a device and the device's interrupt number):

Interrupt
Number
Interrupt
Vector Location
Device
0x08 0x20 - 0x23 Clock
0x09 0x24 - 0x27 Keyboard
0x0A 0x28 - 0x2B From slave 8259
0x0B 0x2C - 0x2F Serial Port 2
0x0C 0x30 - 0x33 Serial Port 1
0x0D 0x34 - 0x37 Hard Disk
0x0E 0x38 - 0x3B Floppy Disk
0x0F 0x3C - 0x3F Printer

When a device causes an interrupt, the instruction counter is assigned the value of the device's interrupt vector. Control is then passed to the interrupt handler. Once the interrupt has been serviced, the stack is popped, restoring the original task's instruction counter and status flag. Interrupts are reenabled because the interrupt enable bit is set in the status flag.

8259 Programmable Interrupt Controller

Although the 8086 processor is designed to handle up to eight external devices, there is only a single interrupt line connecting the processor to the outside world, meaning that without some form of additional hardware, at most one external device can be connected to the processor. Fortunately, hardware such as the Intel 8259 Interrupt Controller has been designed to share the single interrupt line between eight different devices. The following figure shows the relationship between the devices, the 8259, and the 80x86 processor.

This means that instead of interrupting the processor directly, a device first signals the 8259, which then interrupts the 8086 processor using the single interrupt line. The processor determines which device is interrupting by obtaining the device's number from the 8259. The 8086 processor uses the device number to access the list of interrupt vectors that indicates which interrupt handler should be activated.

Interrupt Mask

The 8259 permits the programmer to select those devices which are to interrupt the 8086 processor by writing a one-byte interrupt mask to the 8259. Each bit in the mask corresponds to one of the eight devices. Device priority is indicated from right to left, with the clock having the highest priority and the printer, the lowest:

Priority8259 BitDevice
Highest0 Clock

1 Keyboard

2 From slave 8259

3 Serial Port 2

4 Serial Port 1

5 Hard Disk

6 Floppy Disk
Lowest7 Printer

A bit value of one in the interrupt mask indicates that any interrupts coming from the device are to be ignored, while a bit value of zero means that the device is allowed to interrupt the 8086. For example, to permit clock, keyboard, and printer interrupts, the interrupt mask would be set to 0x7C.

The 8259 interrupt mask is accessed through port 0x21, the interrupt mask register. The above example could be implemented as follows:

#define INT_MASK   0x21
#define CLKENA     0xFE   /* Clock enable:    11111110 */
#define KEYENA     0xFD   /* Keyboard enable: 11111101 */
#define PRTENA     0x7F   /* Printer enable:  01111111 */
...
outportb(INT_MASK, CLKENA & KEYENA & PRTENA);

For each device that is selected, there must be a corresponding interrupt handler and the interrupt vector associated with the device must contain the entry point of the interrupt handler. Results will be unpredictable if either the interrupt handler is missing or the interrupt vector contains an invalid entry point, since control will be passed to a location that does not service the interrupt.

Acknowledging the 8259 After An Interrupt

If several devices interrupt simultaneously, the 8259 signals the processor with the highest priority interrupt. All other devices (with lower priority interrupts) are kept waiting. The keyboard interrupt has the highest priority of all the other devices (except the clock) to ensure that special sequences such as Ctrl-Alt-Del are not blocked. The interrupt handler should be kept as short as possible since all interrupts are blocked while the interrupt handler is active unless the interrupt handler explicitly enables interrupts. An unduly long interrupt handler can result in interrupts being lost. Once the interrupt has been serviced, the 8259 must be informed so that any pending (or any subsequent) interrupts can be signalled. This is done by writing EOI (end-of-interrupt, a value of 0x20) to the 8259 Operation Command Word register (port number 0x20):

#define EOI    0x20
#define OCW    0x20
 
void interrupt isr()
{
 
...
 
/* Acknowledge interrupt */
outportb(OCW, EOI);
}

It does not matter where interrupts are acknowledged, since CPU interrupts are blocked at this time. When control leaves the ISR, the next pending interrupt (if there is one), will occur. Conversely, if the 8259 is not acknowledged, no further interrupts will be made available.


© 2006 - Whale Lake Press