处理09h中断

时间:2014-05-02 11:20:28

标签: assembly dos tasm

我有09h中断的问题。我挂钩int vector并设置我的处理程序09h,它正常工作。但是,当我将基本处理程序返回到int vector并终止程序时,DOS打印完整的键盘缓冲区,然后任何按键操作都不起作用。

我的简单程序打印按下/未按下键的扫描码。

    model   tiny
    .code
    .386
    org     100h

main:
    xor     ax, ax
    push    ax
    pop     es
    jmp     start

handler:
    push    bx cx ax dx
    in      al, 60h
    cmp     al, 81h 
    je      hand_end
    call    tohex

    lea     dx, nl
    mov     ah, 09h
    int     21h

    in      al,61H             ;get value of keyboard control lines
    mov     ah,al              ; save it
    or      al,80h             ;set the "enable kbd" bit
    out     61H,al             ; and write it out the control port
    xchg    ah,al              ;fetch the original control port value
    out     61H,al             ; and write it back
    mov     al, 20h             ;send End-Of-Interrupt signal
    out     20h, al             ; to the 8259 Interrupt Controller

    pop     dx ax cx bx
    jmp     dword ptr cs:[vec]
hand_end:
    pop     dx ax cx bx
    jmp     exit

start:
    cli
    mov     ax, 3509h
    int     21h
    mov     word ptr [vec], bx
    mov     word ptr [vec + 2], es

    mov     ax, 2509h
    lea     dx, handler
    int     21h
    sti

lp:
    jmp     lp

exit:   
    ; returning iVector
    cli
    push    ds
    mov     ax, 2509h
    mov     ds, word ptr [vec + 2]
    mov     dx, word ptr [vec]
    int     21h
    pop     ds
    sti 

    mov     ax, 4c00h
    int     21h

proc    tohex
    pusha
    push    es
    mov     ah, al
    mov     cx, 2
    push    ds
    pop     es
    lea     di, hex
hxlp:
    shr     al, 4
    lea     bx, hx_table
    xlat
    stosb
    shl     ah, 4
    mov     al, ah
    loop    hxlp

    lea     dx, hex
    mov     ah, 09h
    int     21h
    pop     es
    popa
    ret
endp    tohex

    nl      db 13,10,'$'
    vec     dd ?,'$'
    hex     db ?,?,'$'
    hx_table db '0123456789ABCDEF'

end     main

这是DOS Box屏幕截图https://www.dropbox.com/s/v1olsalhzgnyyfv/int09h_problem.png

2 个答案:

答案 0 :(得分:2)

你的源代码有很多东西让我皱眉;我不知道DOS Box是多么宽容,但是在安装了MS-DOS的真正的IBM-PC兼容机器上,我希望这个程序能够挂起。

  1. 中断处理程序不会将端口61h切换到第7位;这可能是键盘事件重新出现的原因。
  2. 中断处理程序不会通过将20h写入端口20h来重新启用中断控制器。
  3. exit分支不pop dx ax cx bx,以ret结尾(应为iret);返回时,它可能会任何地方
  4. 中断处理程序修改寄存器(尤其是tohex)而不恢复其原始值:essidi
  5. 中断处理程序假定寄存器具有特定值:ds和方向标志(影响stosb);这是一个危险的假设。
  6. DOS不是可重入的;我不确定是否允许从中断处理程序调用DOS中断。考虑将tohex的输出推送到键盘缓冲区,而不是自己打印。让主线程调用DOS中断01h,使键盘缓冲区的内容回显到屏幕。在那里恢复中断向量;这不是中断处理程序本身应该做的事情。
  7. 修改 谢谢你的编辑。似乎还有两个单独的问题。

    1。当程序终止

    时,先前的按键被转储到屏幕上

    有趣的是,原始的Win95机器上没有出现问题;只在DOSBox上!有人可能会认为这是DOSBox中的一个错误,但是当之前没有人抱怨时,通常意味着你正在做一些与众不同的事情。

    解决方案: not 在您自己的处理程序结束时调用原始中断处理程序;只需iret

    2。程序终止后,键盘似乎已经死了

    在Win95和DOSBos上都会出现此问题;当用户按 Esc 时,代码中有两个错误。

    1. 中断处理程序终止程序(DOS函数4Ch);只需在内存中设置一个标志,指示主线程退出。
    2. 以下两条说明顺序错误; loading ds将替换下一条指令的操作数的地址。

      mov     ds, word ptr [vec + 2]
      mov     dx, word ptr [vec]
      
    3. 我做了一些重构,并想出了以下内容;适用于DOSBox和Win95。

      然而,这种方法仍然远非理想;调用DOS函数09h从中断处理程序中打印一个字符串似乎非常有害。如果主线程本身会调用DOS函数(在实际应用程序中并不常见),整个程序可能因DOS不可重入而崩溃和烧毁。

      对于寻址模式中微妙的语法差异感到抱歉;我使用了一个古老的Borland汇编程序。

      IDEAL
      
      MODEL tiny
      
      CODESEG
      
      ORG 100h
      
      main:
          cli
          mov ax,3509h
          int 21h
          mov [WORD LOW  vec],bx
          mov [WORD HIGH vec],es
          mov ax,2509h
          mov dx,OFFSET handler
          int 21h
          sti
      lp:
          ;mov    ah,01h
          ;int    21h       ; uncomment this and the program will crash
          mov al,[scancode]
          cmp al,81h
          jne lp
      
          push    ds
          mov ax,2509h
          mov dx,[WORD LOW  vec]
          mov ds,[WORD HIGH vec]
          int 21h
          pop ds
          mov ax,4C00h
          int 21h
      
      handler:
          push    ax
          push    bx
          push    cx
          push    dx
          push    ds
          mov ax,cs
          mov ds,ax
      
          in  al,60h
          mov [scancode],al
      
          in  al,61h
          or  al,80h
          out 61h,al
          and al,7Fh
          out 61h,al
          mov al,20h
          out 20h,al
      
          call    tohex
      
          pop ds
          pop dx
          pop cx
          pop bx
          pop ax
          iret
      
      tohex:
          mov bx,OFFSET hx_table
          mov al,[scancode]
          and al,0Fh
          xlat
          mov ah,al
          mov al,[scancode]
          shr al,4
          xlat
          mov [WORD PTR hex],ax
          mov dx,OFFSET hex
          mov ah,09h
          int 21h
          ret
      
      DATASEG
      
      hex      db ?,?,13,10,'$'
      hx_table db '0123456789ABCDEF'
      scancode db 0
      
      UDATASEG
      
      vec      dd ?
      
      END main
      

答案 1 :(得分:1)

按下的键仍保留在缓冲区中。你需要调用原始的int 09h来检查是否有等待的密钥并使用相同的原始int 09h(GetKey)获取它们。

其他可能性是在不调用原始int 09h的情况下结束中断调用。但是这个解决方案需要在其中一个键上取消(或者它会挂起计算机/ DOSbox)并支持端口20h处理(因为我记得这个端口需要知道app / BIOS获取了密钥)。

您可以创建获取密钥并打印扫描码的应用程序,而无需更改处理程序的中断地址。但它应该在其中一个键上退出(以避免无休止地打印 - 当你检查81h键时)。

此外,您可以观看60小时的扫描码端口,并获得更多(Ctrl,Alt,Shift),即使左右区别(其他端口,我记得64小时)。不要写这些端口!您可能希望查看旧的TechHelp应用程序(有4.1版本)。

有更多信息here