Создание обработчика мыши в сборке x86 - PullRequest
0 голосов
/ 20 января 2019

Я пишу операционную систему в сборке NASM, и у меня проблема с созданием обработчика мыши (обработчик POINTING DEVICE BIOS INTERFACE). Я пытался сделать это в течение недели, но мне пока не удалось

Я пытался найти в интернете, как это сделать, но это мне не очень помогло.

Вот мой код настройки в начале кода:

call checkPS2 ;PS2 routines
jc NOMOUSE
call enablePS2
jc NOMOUSE

А вот и функции PS2

;PS2 mouse routines
NOMOUSE:
    ;Prompt error
ret

checkPS2:
    int 11h         ; get equipment list
    test al, 3
    jz  noPS2       ; jump if PS/2-Mouse not indicated
    mov  bh,3
    mov  ax, 0C205h
    int 15h             ; initialize mouse, bh=datasize
    jc noPS2
    mov bh,3
    mov ax, 0C203h
    int 15h             ; set mouse resolution bh
    jc noPS2
    mov ax, cs
    mov es, ax
    mov bx, PS2dummy
    mov ax, 0C207h
    int 15h             ; mouse, es:bx=ptr to handler
    jc noPS2
    xor bx, bx
    mov es, bx      ; mouse, es:bx=ptr to handler
    mov ax, 0C207h
    int 15h
ret

noPS2:
    stc
ret

PS2dummy:
retf

enablePS2:
    call disablePS2
    mov ax, cs
    mov es, ax
    mov bx, IRQhandler
    mov ax, 0C207h  ; es:bx=ptr to handler
    int 15h
    mov bh,1        ; set mouse on
    mov ax, 0C200h
    int 15h
ret

disablePS2:
    xor bx, bx      ; set mouse off
    mov ax, 0C200h
    int 15h
    xor bx, bx
    mov es, bx
    mov ax, 0C207h  ; es:bx=ptr to handler
    int 15h
ret

IRQhandler:
    ;assume  ds:nothing,es:nothing
    cld
    push ds
    push es
    pusha
    mov ax, cs
    mov ds, ax
    mov bp,sp
    mov al,[bp+24+6]    ; buttons
    mov bl,al
    shl al,3        ; CF=Y sign bit
    sbb ch,ch       ; signed extension 9->16 bit
    cbw         ; extend X sign bit
    mov al,[bp+24+4]    ; AX=X movement
    mov cl,[bp+24+2]    ; CX=Y movement
    xchg bx,ax
    neg cx              ; reverse Y movement
    popa
    pop es
    pop ds
retf

Мой цикл, который вызывает эти функции

mov ax, 0xc209 ;Reads from the mouse
int 15h        ;-||- 
mov dl, bl ;first byte(bl)
mov bl, 02h ;Color Green
call printhex ;prints dl in hex


mov ax, 0xc209 ;Reads from the mouse
int 15h        ;-||- 
mov dl, cl ;second byte(bl)
mov bl, 02h ;Color Green
call printhex ;prints dl in hex

mov ax, 0xc209 ;Reads from the mouse
int 15h        ;-||-
mov bl, 02h ;Color Green
call printhex ;prints dl(3rd byte read)

Первое, что я заметил, было то, что на экране было много белых точек, которые просто появлялись случайным образом и никогда не случались раньше.

Код, который я сделал, должен просто указать мне местоположение мыши, в то время как курсор мыши должен оставаться скрытым. Я уже проверил свою функцию printhex, и я знаю, что она работала, и числа, которые я видел, были:

0x02
0x00
0x00

Когда я переместил мышь, ни одно из значений не изменилось.
У меня были VirtualBox с мышью PS / 2.

1 Ответ

0 голосов
/ 25 января 2019

Вы не предоставили полный пример, однако у меня наконец-то было время взглянуть на это. Одна из основных проблем заключается в том, что Int 15h / AX = 0C209h является дополнительной функцией. В РБИЛ есть записка с надписью

Примечание: IBM классифицирует эту функцию как необязательную

Я обнаружил, что на ряде эмуляторов (QEMU, BOCHs, VirtualBox) эта функция BIOS, похоже, не реализована. Вызов этого не даст данных, которые вы ищете. Вы можете использовать обработчик мыши для чтения байтов движения и состояния X и Y и обновления глобальных переменных, которые может опрашивать ваша основная программа. Ваш обработчик мыши IRQhandler на самом деле не обработчик IRQ, а функция FAR, которую вызовет обработчик прерываний мыши BIOS. У вас есть некоторый существующий код в этом обработчике, который извлекает движение X и Y, но ничего с ним не делает. Если вы поддерживаете несколько глобальных переменных для X и Y и добавляете к ним значения движения, вы можете поддерживать абсолютные координаты, которые могут запрашиваться вашим основным циклом. Вы также можете создать глобальную переменную для хранения прочитанного байта состояния.

Используя ваш код в качестве шаблона, я создал этот простой загрузчик, который тестирует этот код. Загрузчик содержит блок параметров BIOS на случай, если вы собираетесь загружаться с USB с использованием эмуляции дискеты на реальном оборудовании. Его можно удалить, если он не нужен. Я также предоставляю некоторые процедуры для отображения байтов и слов без знака в шестнадцатеричном формате. Режим видео можно настроить, но я по умолчанию использовал режим 13h (320x200x256):

bpb.inc

global bpb_disk_info

    jmp boot_start
    TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.

bpb_disk_info:
    ; Dos 4.0 EBPB 1.44MB floppy
    OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
    bytesPerSector:    dw    512
    sectPerCluster:    db    1
    reservedSectors:   dw    1
    numFAT:            db    2
    numRootDirEntries: dw    224
    numSectors:        dw    2880
    mediaType:         db    0xf0
    numFATsectors:     dw    9
    sectorsPerTrack:   dw    18
    numHeads:          dw    2
    numHiddenSectors:  dd    0
    numSectorsHuge:    dd    0
    driveNum:          db    0
    reserved:          db    0
    signature:         db    0x29
    volumeID:          dd    0x2d7e5a1a
    volumeLabel:       db    "NO NAME    "
    fileSysType:       db    "FAT12   "

boot.asm :

HW_EQUIP_PS2     equ 4          ; PS2 mouse installed?
MOUSE_PKT_BYTES  equ 3          ; Number of bytes in mouse packet
MOUSE_RESOLUTION equ 3          ; Mouse resolution 8 counts/mm

VIDEO_MODE       equ 0x13

bits 16
cpu 8086
ORG 0x7c00

; Include a BPB (1.44MB floppy with FAT12) to be more compatible with USB floppy media
%include "bpb.inc"

boot_start:
    xor ax, ax                  ; DS=SS=ES=0
    mov ds, ax
    mov ss, ax                  ; Stack at 0x0000:0x7c00
    mov sp, 0x7c00
    cld                         ; Set string instructions to use forward movement

    ; FAR JMP to ensure set CS to 0
    jmp 0x0000:.setcs
.setcs:

    mov ax, VIDEO_MODE
    int 0x10                    ; Set video mode

    call mouse_initialize
    jc .no_mouse                ; If CF set then error, inform user and end
    call mouse_enable           ; Enable the mouse

    sti
.main_loop:
    hlt                         ; Halt processor until next interrupt
    call poll_mouse             ; Poll mouse and update display with coordintes & status
    jmp .main_loop              ; Endless main loop

.no_mouse:
    mov si, noMouseMsg          ; Error enabling mouse
    call print_string           ; Display message and enter infinite loop

.err_loop:
    hlt
    jmp .err_loop

; Function: mouse_initialize
;           Initialize the mouse if present
;
; Inputs:   None
; Returns:  CF = 1 if error, CF=0 success
; Clobbers: AX

mouse_initialize:
    push es
    push bx

    int 0x11                    ; Get equipment list
    test ax, HW_EQUIP_PS2       ; Is a PS2 mouse installed?
    jz .no_mouse                ;     if not print error and end

    mov ax, 0xC205              ; Initialize mouse
    mov bh, MOUSE_PKT_BYTES     ; 3 byte packets
    int 0x15                    ; Call BIOS to initialize
    jc .no_mouse                ;    If not successful assume no mouse

    mov ax, 0xC203              ; Set resolution
    mov bh, MOUSE_RESOLUTION    ; 8 counts / mm
    int 0x15                    ; Call BIOS to set resolution
    jc .no_mouse                ;    If not successful assume no mouse

    push cs
    pop es                      ; ES = segment where code and mouse handler reside

    mov bx, mouse_callback_dummy
    mov ax, 0xC207              ; Install a default null handler (ES:BX)
    int 0x15                    ; Call BIOS to set callback
    jc .no_mouse                ;    If not successful assume no mouse

    clc                         ; CF=0 is success
    jmp .finished
.no_mouse:
    stc                         ; CF=1 is error
.finished:
    pop bx
    pop es
    ret

; Function: mouse_enable
;           Enable the mouse
;
; Inputs:   None
; Returns:  None
; Clobbers: AX

mouse_enable:
    push es
    push bx

    call mouse_disable          ; Disable mouse before enabling

    push cs
    pop es
    mov bx, mouse_callback
    mov ax, 0xC207              ; Set mouse callback function (ES:BX)
    int 0x15                    ; Call BIOS to set callback

    mov ax, 0xC200              ; Enable/Disable mouse
    mov bh, 1                   ; BH = Enable = 1
    int 0x15                    ; Call BIOS to disable mouse

    pop bx
    pop es
    ret

; Function: mouse_disable
;           Disable the mouse
;
; Inputs:   None
; Returns:  None
; Clobbers: AX

mouse_disable:
    push es
    push bx

    mov ax, 0xC200              ; Enable/Disable mouse
    xor bx, bx                  ; BH = Disable = 0
    int 0x15                    ; Call BIOS to disable mouse

    mov es, bx
    mov ax, 0xC207              ; Clear callback function (ES:BX=0:0)
    int 0x15                    ; Call BIOS to set callback

    pop bx
    pop es
    ret

; Function: mouse_callback (FAR)
;           called by the interrupt handler to process a mouse data packet
;           All registers that are modified must be saved and restored
;           Since we are polling manually this handler does nothing
;
; Inputs:   SP+4  = Unused (0)
;           SP+6  = MovementY
;           SP+8  = MovementX
;           SP+10 = Mouse Status
;
; Returns:  None
; Clobbers: None

ARG_OFFSETS      equ 6          ; Offset of args from BP

mouse_callback:
    push bp                     ; Function prologue
    mov bp, sp
    push ds                     ; Save registers we modify
    push ax
    push bx
    push cx
    push dx

    push cs
    pop ds                      ; DS = CS, CS = where our variables are stored

    mov al,[bp+ARG_OFFSETS+6]
    mov bl, al                  ; BX = copy of status byte
    mov cl, 3                   ; Shift signY (bit 5) left 3 bits
    shl al, cl                  ; CF = signY
                                ; Sign bit of AL = SignX
    sbb dh, dh                  ; CH = SignY value set in all bits
    cbw                         ; AH = SignX value set in all bits
    mov dl, [bp+ARG_OFFSETS+2]  ; CX = movementY
    mov al, [bp+ARG_OFFSETS+4]  ; AX = movementX

    ; new mouse X_coord = X_Coord + movementX
    ; new mouse Y_coord = Y_Coord + (-movementY)
    neg dx
    mov cx, [mouseY]
    add dx, cx                  ; DX = new mouse Y_coord
    mov cx, [mouseX]
    add ax, cx                  ; AX = new mouse X_coord

    ; Status
    mov [curStatus], bl         ; Update the current status with the new bits
    mov [mouseX], ax            ; Update current virtual mouseX coord
    mov [mouseY], dx            ; Update current virtual mouseY coord

    pop dx                      ; Restore all modified registers
    pop cx
    pop bx
    pop ax
    pop ds
    pop bp                      ; Function epilogue

mouse_callback_dummy:
    retf                        ; This routine was reached via FAR CALL. Need a FAR RET

; Function: poll_mouse
;           Poll the mouse state and display the X and Y coordinates and the status byte
;
; Inputs:   None
; Returns:  None
; Clobbers: None

poll_mouse:
    push ax
    push bx
    push dx

    mov bx, 0x0002              ; Set display page to 0 (BH) and color green (BL)

    cli
    mov ax, [mouseX]            ; Retrieve current mouse coordinates. Disable interrupts
    mov dx, [mouseY]            ; So that these two variables are read atomically
    sti

    call print_word_hex         ; Print the mouseX coordinate
    mov si, delimCommaSpc
    call print_string

    mov ax, dx
    call print_word_hex         ; Print the mouseY coordinate
    mov si, delimCommaSpc
    call print_string

    mov al, [curStatus]
    call print_byte_hex         ; Print the last read mouse state byte

    mov al, 0x0d
    call print_char             ; Print carriage return to return to beginning of line

    pop dx
    pop bx
    pop ax
    ret

; Function: print_string
;           Display a string to the console on the specified page and in a
;           specified color if running in a graphics mode
;
; Inputs:   SI = Offset of address to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Clobbers: SI

print_string:
    push ax
    mov ah, 0x0e                ; BIOS TTY Print
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    pop ax
    ret

; Function: print_char
;           Print character on specified page and in a specified color
;           if running in a graphics mode
;
; Inputs:   AL = Character to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Returns:  None
; Clobbers: AX

print_char:
    mov ah, 0x0e                ; TTY function to display character in AL
    int 0x10                    ; Make BIOS call
    ret

; Function: print_word_hex
;           Print a 16-bit unsigned integer in hexadecimal on specified
;           page and in a specified color if running in a graphics mode
;
; Inputs:   AX = Unsigned 16-bit integer to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Returns:  None
; Clobbers: Mone

print_word_hex:
    xchg al, ah                 ; Print the high byte first
    call print_byte_hex
    xchg al, ah                 ; Print the low byte second
    call print_byte_hex
    ret

; Function: print_byte_hex
;           Print a 8-bit unsigned integer in hexadecimal on specified
;           page and in a specified color if running in a graphics mode
;
; Inputs:   AL = Unsigned 8-bit integer to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Returns:  None
; Clobbers: Mone

print_byte_hex:
    push ax
    push cx
    push bx

    lea bx, [.table]            ; Get translation table address

    ; Translate each nibble to its ASCII equivalent
    mov ah, al                  ; Make copy of byte to print
    and al, 0x0f                ;     Isolate lower nibble in AL
    mov cl, 4
    shr ah, cl                  ; Isolate the upper nibble in AH
    xlat                        ; Translate lower nibble to ASCII
    xchg ah, al
    xlat                        ; Translate upper nibble to ASCII

    pop bx                      ; Restore attribute and page
    mov ch, ah                  ; Make copy of lower nibble
    mov ah, 0x0e
    int 0x10                    ; Print the high nibble
    mov al, ch
    int 0x10                    ; Print the low nibble

    pop cx
    pop ax
    ret
.table: db "0123456789ABCDEF", 0

; Uncomment these lines if not using a BPB (via bpb.inc)
; numHeads:        dw 2         ; 1.44MB Floppy has 2 heads & 18 sector per track
; sectorsPerTrack: dw 18

align 2
mouseX:       dw 0              ; Current mouse X coordinate
mouseY:       dw 0              ; Current mouse Y coordinate
curStatus:    db 0              ; Current mouse status
noMouseMsg:   db "Error setting up & initializing mouse", 0x0d, 0x0a, 0
delimCommaSpc:db ", ", 0

bootDevice:   db 0x00

; Pad boot sector to 510 bytes and add 2 byte boot signature for 512 total bytes
TIMES 510-($-$$) db  0
dw 0xaa55

Код может быть встроен в образ диска с помощью:

nasm -f bin boot.asm -o boot.bin

# Build 1.44MB disk image
dd if=/dev/zero of=disk.img bs=1024 count=1440
dd if=boot.bin of=disk.img conv=notrunc

Я предоставляю этот код, потому что не могу понять, почему ваш код иногда отображал нежелательные пиксели. Такая проблема может быть связана с кодом, который вы не предоставили. При запуске в VirtualBox это должно выглядеть примерно так: enter image description here

...