Interrupts in Real Mode x86 Systems
Table of Content
Interrupts
This is to understand interrupts and related concepts including interrupt, interrupt request number, interrupt number, interrupt service routine, interrupt vector table, and interrupt vector.
To make it simple, we design these example programs as boot sector code and these program runs in x86 real mode.
Experiment and Programming Environment
Refer to the bootstrap tutorial for the experiment and programming environment, and for how to compile and run the programs here.
Example 0 Keyboard Interrupt
This example consists of three .asm files, int0.asm, print_byte.asm and print_space.asm. To compile this program, you only need to compile int0.asm since we “include” the other two files in int0.asm. These two .asm files, print_byte.asm and print_space.asm defines two subroutines to print a byte in hexadecimal and to print a space.
;
; int0.asm
;
[org 0x7c00]
; Keybaord interrupt is maskable. To Intel 8259 Programmable Interrupt
; Controller, the IRQ number of the keyboard interrupt is 1, which
; means if we were to mask the interrupt, we set the 1st bit of the
; mask (a byte) as 1, i.e, 0x02 (0000 0010 in binary).
;
; For interrupt request number assignment on PC, see
; https://en.wikibooks.org/wiki/X86_Assembly/Programmable_Interrupt_Controller
;
; Uncomment the following two statements, and run the code. Does
; the keyboard interrupt work now?
;
; mov al, 0x02
; out 21h, al
jmp START
KBD_ISR:
push ax
push es
push bx
; VGA
; https://en.wikipedia.org/wiki/VGA-compatible_text_mode
; https://en.wikipedia.org/wiki/Video_Graphics_Array#Color_palette
mov ax, 0xb800
mov es, ax
mov bx, [POS]
mov byte [es:bx], 'C'
inc bx
mov byte [es:bx], 0x01
inc bx
mov byte [es:bx], 'I'
inc bx
mov byte [es:bx], 0x02
inc bx
mov byte [es:bx], 'S'
inc bx
mov byte [es:bx], 0x03
inc bx
mov byte [es:bx], 'C'
inc bx
mov byte [es:bx], 0x04
inc bx
mov [POS], bx
pop bx
pop es
pop ax
iret
START:
; Set interrupt number 0x16 (or 21 in decimal)'s interrupt
; service routine as ours. For interrupt 0x16, see
; https://en.wikipedia.org/wiki/INT_16H
cli
cld
mov ax, 0
mov es, ax
mov ax, KBD_ISR
mov [es:21*4], ax
; mov ax, 0
; mov [es:21*4+2], ax
mov [es:21*4+2], cs
sti
; print interrupt vector
mov ax, cs
mov cl, ah
call print_byte
call print_space
mov cl, al
call print_byte
call print_space
mov ax, KBD_ISR
mov cl, ah
call print_byte
call print_space
mov cl, al
call print_byte
call print_space
jmp $
%include "print_byte.asm"
%include "print_space.asm"
POS:
db 0, 0, 0, 0
times 510-($-$$) db 0
dw 0xaa55
Required Subroutines
;
; print_byte.asm
;
; print a byte in register cl to hex assuming ASCII encoding
; void * print_byte(char c)
print_byte:
pusha ; Push AX, CX, DX, BX, original SP, BP, SI, and DI.
mov ch, cl
shr ch, 4
and ch, 0x0f
push cx
mov cl, ch
call print_low_4bits
pop cx
mov ch, cl
and ch, 0x0f
push cx
mov cl, ch
call print_low_4bits
pop cx
popa
ret
; print lower 4 bits in register cl to hex assuming ASCII encoding
; void * print_byte(char c)
print_low_4bits:
pusha
mov ah, 0x0e
mov ch, cl
and ch, 0x0f
cmp ch, 0x09
jg A_TO_F
add ch, '0'
jmp PRINT_CHAR
A_TO_F:
sub ch, 0x0a
add ch, 'A'
jmp PRINT_CHAR
PRINT_CHAR:
mov al, ch
int 0x10
popa
ret
;
; print_space.asm
;
print_space:
pusha
mov ah, 0x0e
mov al, ' '
int 0x10
popa
ret