CS-220, Sec. 90, Week 10-C R. Eckert INTERRUPTS An interrupt is a signal that can cause the processor to suspend execution of the current program and transfer control to another program called an "interrupt service routine" (ISR), also known as an "interrupt handler." Types of interrupts-- Hardware: the source of the interrupt is some device connected to the computer. These can be further subdivided into "maskable" and "non-maskable" interrupts. Maskable interrupts can be disabled, which means that they will not be responded to. Non-maskable interrupts cannot be disabled and are always responded to by the processor. These could be used to alert the processor of catastrophic events such as a power failure. Internally generated: These signals are generated internally by the processor in response to certain conditions. They are also called "traps." For example, 80x86 processors generate an internal interrupt whenever there is divide overflow (the result of a division is too large to fit in the quotient register). Software: Some processors have instructions in their instruction sets that will generate an interrupt whenever they are executed. For example, the 80x86 INT instruction does this. Intel 80x86 interrupts-- Interrupts on the 80x86 family of processors are "vectored." In this system, the start address of the interrupt service routine is obtained from a table of "interrupt vectors." This table is memory resident and begins at absolute address 0. Each entry in the table is four bytes long. The low order two bytes specify the offset part of the start address of the ISR, and the high order two bytes the base address (divided by 16) of the segment containing the ISR. An "interrupt type number" is provided by the interrupting device (in the case of hardware interrupts) or as the operand of the INT instruction (in the case of software interrupts). The type number is a single byte, which means that there can be up to 256 possible values. The address of the vector that points to the ISR that corresponds to a given type number is computed by the processor by multiplying the type number by 4. The 80x86 has two hardware interrupt input signals, called INTR and NMI. The former is maskable, while the latter is non-maskable. In the case of devices connected to INTR, it is the responsibility of the interface circuitry to provide the type number on the data bus after the interrupt is generated. In the case of NMI, a type number of 2 is always generated. 80x86 maskable interrupts are enabled by the instruction STI and they are disabled by the instruction CLI. These instructions set or clear, respectively, the processor's interrupt-enabled status flag. The following is the sequence of events that automatically occurs anytime a device activates the INTR signal on an 80x86 processor: 1. A device activates INTR 2. The processor completes execution of the current instruction 3. If the interrupt-enabled flag is set (inerrupts enabled): A. The processor's flags register is pushed onto the stack (This means that the current status or context is saved) B. An interrupt type number is read from the data bus (the device must supply this) C. Interrupts are disabled D. Address of the interrupt vector is computed (4 * type number) E. CS and IP are pushed onto the stack (This means that the address of the next instruction is saved) F. CS and IP are loaded with the interrupt vector from the table (address from step D) As a consequence of this sequence of events, the next instruction will be fetched from the address obtained from the table of interrupt vectors. This effectively transfers control to the first instruction of the appropriate ISR. (Note for this to work properly, the table of interrupt vectors must be set up before interrupts will be handled. Also, the actual code for the ISR must also be be preloaded at the correct address--the address specified by the interrupt vector.) Also, note that the address of the instruction after the one that was executing when the interrupt came along has been safely saved on the stack. What must an ISR do? 1. It must save any registers it will alter (crucial!) 2. If it is to be interruptable, it must enable interrupts (STI) 3. It should "do it's thing"--for HW interrupts, this will usually be to perform (control) the I/O from or to the device that generated the interrupt 4. It must restore any registers it saved in step 1 6. It must execute an IRET instruction The IRET instruction performs three pops of the stack--the first into IP, the second into CS, and the third into the flags register. This guarantees that the next instruction to be fetched will be the one following the instruction that was executing when the interrupt was generated. It also guarantees that all the status flags will be restored to the values they had when the original program was executing. Interrupts on PC and PC-compatible computers-- Many I/O devices contected to a PC are interrupt driven. Some of the devices and the type numbers (also called IRQs) that are generated for them by the interrupt circuitry inside the PC are: Device type # Some Details Timer/Oscillator 0 8 Generated every 54.9 msec, used by OS to update the time of day. Keyboard 9 Generated with any key press or key release. A keyboard "scan code" will be in Port 60h. Serial Port 12 Diskette Drive 14 Parallel Printer 15 Software Interrupts and Operating System Services on a PC-- As mentioned above, the INT instruction generates a software interrupt. The same basic sequence of events as given above occurs, with the exception of Step B. The interrupt type number, instead of coming from a device, is obtained from the operand in the instruction. For example, in the following instruction: INT 35 the type number is 35. In many ways the INT instruction is like a call to a far procedure. The main difference is that in the case of a CALL, the address of the procedure is given in the instruction, whereas, in the case of the INT, the address must come from the table of interrupt vectors. Therefore it is very easy to implement "relocatable" procedures as interrupt service routines. The only thing that is necessary to relocate the routine is to change 4 bytes in the table of interrupt vectors. This means that the INT instruction can be used as an alternative to calling a procedure--a fact that is used extensively by the operating system on a PC to provide operating system services, such as the control of many different I/O devices. So we can talk about several levels of control of devices. At the lowest level, we can access the various ports or memory addresses associated with the device directly. (For example, the program you wrote to output to the parallel printer.) At a slightly higher level, the Basic Input/Output System (BIOS) part of the Operating System provides a series of low-level routines burned into Read-Only Memory (ROM) that provide control services for many devices. These services can be invoked using the appropriate INT instruction. Finally, the Disk Operating System (DOS) part of the Operating System provides higher-level routines loaded into Read/Write Memory (RAM) when the computer is started. These services can be invoked by using the DOS interrupt (INT 21h). We've already seen the examples of single character input from the keyboard and single character output to the screen. The following table gives some of the BIOS-level interrupts and the types of I/O control services provided. (We'll look at some of these in more detail later.) int 10h Video control services (text/graphics output) int 14h Serial communication services int 16h Keyboard control services (input from keyboard) int 17h Printer services int 25h,26h Disk I/O services (reading/writing disk sectors) It should be emphasized that these are NOT hardware interrupts generated by the devices--instead the interrupt service routines associated with these software interrupts provide code that controls the I/O from these devices. Some of the DOS interrupt services provided by int 21h are given below. In many cases parameters are passed from our program to the DOS routine (and vice-versa) in general-purpose registers. AH=1 Single-character keyboard input with echo--char returned in AL AH=2 Single-character screen output--char must be in DL AH=5 Single character printer output--char must be in DL AH=7 Single-char keyboard input, no echo--char returned in AL AH=9 String output--DS:DX points to string; must terminate with '$' AH=0Ah Buffered keybd input--DS:DX points to buffer AH=2Ah Get date--AL=day, CX=year, DH=month, DL=day AH=2Bh Set date--same registers used AH=2Ch Get time--CH=hour, CL=minute, DH=second, DL=1/100 second AH=4Ch Terminate a process, remove pgm from memory--AL=return code (0) AH=31h Terminate & stay resident--AL=0, DX=# of paragraphs to stay resident AH=25h Set interrupt vector--AL=type #, DS:DX=must contain vector to ISR* AH=35h Get interrupt vector--AL=type #, ES:BX will contain vector to ISR* AH=3C-42h Disk read/write operations * vector to ISR = segment base : offset of ISR There are many, many more DOS services available through INT 21h. It should be pointed out that when a PC is first booted up, the table of interrupt vectors is loaded with the addresses of all these hardware, BIOS, and DOS system interrupt service routines. If we want to intercept any of these interrupts (for example, write our own keyboard handler), we need to load the code for our handler into memory, make it resident (DOS service 31h can do this for us), and update the appropriate entry in the table of interrupt vectors with the vector (base/offset) to the start of your code (DOS service 25h can do this for us). Furthermore, if we want to restore the original handler provided by the operating system, we would need to get the original vector prior to the update (DOS service 35h can do this for us). Some 80x86 Traps-- Divide overflow--the processor generates a type-0 interrupt whenever this occurs. The default ISR outputs an appropriate mesage to the screen. Single step--If the processor's trap flag is set, the processor will generate a type-1 interrupt after every instruction is executed. INTO--This instruction will cause a type-4 interrupt if the overflow flag is set.