在16位x86程序集中注册中断

时间:2018-08-05 10:00:29

标签: assembly x86 nasm interrupt x86-16

我正在16位x86汇编语言中编写自己的OS,并且尝试注册自己的中断,例如MS-DOS中的INT 21H。 我在网上找不到任何东西。 我正在使用NASM作为汇编器。

1 个答案:

答案 0 :(得分:7)

您可以关闭中断,然后直接修改中断向量表(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运行时,它将显示为:

enter image description here

有关此特定键盘ISR的工作方式的更多信息,请参阅我以前的Stackoverflow answer


如果您打算创建自己的Int 21h处理程序,则需要像上面的示例一样更新IVT,但是IVT中的偏移量将为0x21 * 4 = 0x0000:0x0084。