I am writing my own OS in 16 bit x86 Assembly, and I'm trying to register my own interrupt, something like INT 21H in MS-DOS. I couldn't find anything on the web. I'm using NASM as the assembler.
-
3You need to add your interrupt handler to the *interrupt vector table* located right at the beginning of RAM at address `0000:0000` to `0000:03ff`. – fuz Aug 05 '18 at 10:13
-
There's some discussion [here](https://stackoverflow.com/q/19398704/2189500). – David Wohlferd Aug 05 '18 at 10:13
-
http://www.felixcloutier.com/x86/INTn:INTO:INT3:INT1.html – Ped7g Aug 05 '18 at 10:24
1 Answers
You can turn off interrupts and then modify the interrupt vector table (IVT) directly. The real mode IVT can be found at 0x0000:0x0000 through 0x0000:0x03FF. Each entry in the table is 4 bytes. The first 2 bytes are the offset of the interrupt service routine (ISR) and the second 2 bytes are the segment.
As an example the keyboard interrupt (IRQ1) is interrupt vector 9. It will be located at offset 9*4=36=0x0024, Thus the IVT entry will be at 0x0000:0x0024. Here is an example of a simple bootloader that hooks the keyboard interrupt:
KBD_BUFSIZE equ 32 ; Keyboard Buffer length. **Must** be a power of 2
; Maximum buffer size is 2^15 (32768)
KBD_IVT_OFFSET equ 9*4 ; Base address of keyboard interrupt (IRQ) in IVT
bits 16
org 0x7c00
start:
xor ax, ax ; AX=0
mov ds, ax ; DS=0 since we use an ORG of 0x7c00.
; 0x0000<<4+0x7C00=0x07C00
mov ss, ax
mov sp, 0x7c00 ; SS:SP stack pointer set below bootloader
; ****** Hooks the keyboard interrupt here ******
cli ; Don't want to be interrupted when updating IVT
mov word [KBD_IVT_OFFSET], kbd_isr
; DS set to 0x0000 above. These MOV are relative to DS
; 0x0000:0x0024 = IRQ1 offset in IVT
mov [KBD_IVT_OFFSET+2], ax ; 0x0000:0x0026 = IRQ1 segment in IVT
sti ; Enable interrupts
mov ax, 0xb800
mov es, ax ; Set ES to text mode segment (page 0)
xor di, di ; DI screen offset = 0 (upper left)
mov ah, 0x1F ; AH = White on Blue screen attribute
mov bx, keyboard_map ; BX = address of translate table used by XLAT
cld ; String instructions set to forward direction
.main_loop:
hlt ; Halt processor until next interrupt
mov si, [kbd_read_pos]
cmp si, [kbd_write_pos]
je .main_loop ; If (read_pos == write_pos) then buffer empty and
; we're finished
lea cx, [si+1] ; Index of next read (tmp = read_pos + 1)
and si, KBD_BUFSIZE-1 ; Normalize read_pos to be within 0 to KBD_BUFSIZE
mov al, [kbd_buffer+si] ; Get next scancode
mov [kbd_read_pos], cx ; read_pos++ (read_pos = tmp)
test al, 0x80 ; Is scancode a key up event?
jne .main_loop ; If so we are finished
xlat ; Translate scancode to ASCII character
test al, al
je .main_loop ; If character to print is NUL we are finished
stosw ; Display character on console in white on blue
jmp .main_loop
; Keyboard ISR (IRQ1)
kbd_isr:
push ax ; Save all registers we modify
push si
push cx
in al, 0x60 ; Get keystroke
mov cx, [cs:kbd_write_pos]
mov si, cx
sub cx, [cs:kbd_read_pos]
cmp cx, KBD_BUFSIZE ; If (write_pos-read_pos)==KBD_BUFSIZE then buffer full
je .end ; If buffer full throw char away, we're finished
lea cx, [si+1] ; Index of next write (tmp = write_pos + 1)
and si, KBD_BUFSIZE-1 ; Normalize write_pos to be within 0 to KBD_BUFSIZE
mov [cs:kbd_buffer+si], al ; Save character to buffer
mov [cs:kbd_write_pos], cx ; write_pos++ (write_pos = tmp)
.end:
mov al, 0x20
out 0x20, al ; Send EOI to Master PIC
pop cx ; Restore all modified registers
pop si
pop ax
iret
align 2
kbd_read_pos: dw 0
kbd_write_pos: dw 0
kbd_buffer: times KBD_BUFSIZE db 0
; Scancode to ASCII character translation table
keyboard_map:
db 0, 27, '1', '2', '3', '4', '5', '6', '7', '8' ; 9
db '9', '0', '-', '=', 0x08 ; Backspace
db 0x09 ; Tab
db 'q', 'w', 'e', 'r' ; 19
db 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x0a ; Enter key
db 0 ; 29 - Control
db 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';' ; 39
db "'", '`', 0 ; Left shift
db "\", 'z', 'x', 'c', 'v', 'b', 'n' ; 49
db 'm', ',', '.', '/', 0 ; Right shift
db '*'
db 0 ; Alt
db ' ' ; Space bar
db 0 ; Caps lock
db 0 ; 59 - F1 key ... >
db 0, 0, 0, 0, 0, 0, 0, 0
db 0 ; < ... F10
db 0 ; 69 - Num lock
db 0 ; Scroll Lock
db 0 ; Home key
db 0 ; Up Arrow
db 0 ; Page Up
db '-'
db 0 ; Left Arrow
db 0
db 0 ; Right Arrow
db '+'
db 0 ; 79 - End key
db 0 ; Down Arrow
db 0 ; Page Down
db 0 ; Insert Key
db 0 ; Delete Key
db 0, 0, 0
db 0 ; F11 Key
db 0 ; F12 Key
times 128 - ($-keyboard_map) db 0 ; All other keys are undefined
times 510 - ($-$$) db 0 ; Boot signature
dw 0xAA55
When run from BOCHS it would appear like:
For more information on how this particular keyboard ISR works you can see my previous Stackoverflow answer
If your intention is to create your own Int 21h handler, you will need to update the IVT like the example above but the offset in the IVT will be 0x21*4 = 0x0000:0x0084.
- 46,082
- 8
- 107
- 198
-
Would it be safe to update the IVT with one atomic 32-bit store, like `mov dword [KBD_IVT_OFFSET], kbd_isr`, without disabling interrupts? (I know that would require a 386-compatible CPU, and not saying it would be a better answer. I'm just curious.) – Peter Cordes Aug 05 '18 at 19:24
-
1@PeterCordes That doesn't exist on an 8086, and since this is in a bootloader unless you are targeting other processors THIS is the preferred way of doing it for 16-bit code. The OP also said he is writing a 16-bit OS. Unless I specify otherwise I don't even target 80186- I'll target the lowest common denominator the 8086 – Michael Petch Aug 05 '18 at 19:27
-
I know all that, see the 2nd half of my comment. It would be safe on a 386, though, right? – Peter Cordes Aug 05 '18 at 19:28
-
@PeterCordes : On a 386 (in real mode) sure, but then it would no longer be 16-bit. – Michael Petch Aug 05 '18 at 19:31
-
Thanks. And BTW, if you want to be really belt-and-suspenders, would you `cli` before setting `ss` and `sp`, in case of buggy 8086 CPUs that don't defer interrupts properly on `mov` to `ss`? – Peter Cordes Aug 05 '18 at 19:31
-
@PeterCordes You can see my previous answers that discuss that very fact. Something I discuss in my [General Bootloader Tips](https://stackoverflow.com/a/32705076/3857942) – Michael Petch Aug 05 '18 at 19:32
