[英]Registering Interrupt in 16 bit x86 Assembly
我在16位x86匯編中編寫自己的操作系統,我正在嘗試注冊自己的中斷,如MS-DOS中的INT 21H。 我在網上找不到任何東西。 我正在使用NASM作為匯編程序。
您可以關閉中斷,然后直接修改中斷向量表(IVT)。 實模式IVT可以在0x0000:0x0000到0x0000:0x03FF找到。 表中的每個條目都是4個字節。 前2個字節是中斷服務程序(ISR)的偏移量,后2個字節是段。
作為示例,鍵盤中斷(IRQ1)是中斷向量9.它將位於偏移9 * 4 = 36 = 0x0024,因此IVT條目將位於0x0000:0x0024。 下面是一個掛鈎鍵盤中斷的簡單引導程序示例:
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
從BOCHS運行時,它看起來像:
有關此特定鍵盤ISR如何工作的更多信息,您可以看到我以前的Stackoverflow答案
如果您打算創建自己的Int 21h處理程序,則需要像上面的示例一樣更新IVT,但IVT中的偏移量將為0x21 * 4 = 0x0000:0x0084。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.