【问题标题】:Wait for Key Press from DOS driver under NTVDM During Initialization在初始化期间等待来自 NTVDM 下 DOS 驱动程序的按键
【发布时间】:2022-02-01 04:02:27
【问题描述】:

在驱动程序初始化期间,在 32 位 Windows 10 21H2(操作系统在 NTVDM.exe 下构建 19044.1466)?此时我只是想模拟“按任意键继续...”

我已经尝试过 DOS API AH=08h INT 21h 和 BIOS API AH=00h INT 16h,但两者似乎都冻结且未检测到输入。

代码:

; *******************************************************************
; * Press Any Key To Continue DRIVER                                *
; *******************************************************************

cseg        segment para    public  'code'
presskey    proc    far
            assume  cs:cseg,es:cseg,ds:cseg

; *******************************************************************
; * MAIN PROCEDURE CODE                                             *
; *******************************************************************

begin:

; *******************************************************************
; * DEVICE HEADER - REQUIRED BY DOS                                 *
; *******************************************************************

next_dev    dd  -1              ; no other device drivers
attribute   dw  8000h           ; character device
strategy    dw  dev_strategy    ; address of 1st dos call
interrupt   dw  dev_interrupt   ; address of 2nd dos call
dev_name    db  'PRESSKEY$ '      ; name of the driver

; *******************************************************************
; * WORK SPACE FOR THE DEVICE DRIVER                                *
; *******************************************************************

rh_ofs      dw  ?               ; request header offset
rh_seg      dw  ?               ; request header segment
msg1        db  07h 
            db  'Press any key to continue...'
            db  0dh,0ah,07h,'$'
        

; *******************************************************************
; * THE STRATEGY PROCEDURE                                          *
; *******************************************************************

dev_strategy:                   ; first call from DOS
    mov     cs:rh_seg,es        ; save request header ptr segment
    mov     cs:rh_ofs,bx        ; save request header ptr offset
    ret

; *******************************************************************
; * THE INTERRUPT PROCEDURE                                         *
; *******************************************************************

dev_interrupt:                  ; second call from DOS
    cld                         ; save machine state on entry
    push    ds
    push    es
    push    ax
    push    bx
    push    cx  
    push    dx
    push    di
    push    si

; perform branch based on the command passed in the req header

    mov     al,es:[bx]+2        ; get command code
    cmp     al,0                ; check for 0
    jnz     exit3               ; no - exit go to error exit
    rol     al,1                ; get offset into table
    lea     di,cmdtab           ; get address of command table
    mov     ah,0                ; clear hi order
    add     di,ax               ; add offset
    jmp     word ptr[di]        ; jump indirect

; command table
;       the command code field of the static request
;       field contains the function to be performed

cmdtab  label   byte            ;
        dw      init            ; initialization

; *******************************************************************
; *     LOCAL PROCEDURES                                            *
; *******************************************************************

initial proc    near
    lea     dx,msg1             ; initialization
    mov     ah,9                ; message
    int     21h                 ; dos call
    mov     ah,0                ; wait for key press
    int     16h
    ret                         ; return
initial endp

; *******************************************************************
; *     DOS COMMAND PROCESSING                                      *
; *******************************************************************

;command    0   initialization

init:   call    initial         ; display a message
        lea     ax,exit         ; get end address (offset)
        mov     es:[bx]+0eh,ax  ; store offset address
        push    cs              ; get end
        pop     ax              ; address (segment)
        mov     es:[bx]+10h,ax  ; store in break address
        jmp     exit2

; *******************************************************************
; *     ERROR EXIT                                                  *
; *******************************************************************

; Set the done flag, error flag, and unknown command error code

exit3:  mov     es:word ptr 3[bx],8103h
        jmp     exit1                   ; restore environment

; *******************************************************************
; *     COMMON EXIT                                                 *
; *******************************************************************

; common exits fall thru code
;   2 sets status to done and no error
;   1 restore callers es:bx
;   0 restore machine state and exit

exit2:                                  ; set done flag and no error
        mov     es:word ptr 3[bx],0100h
exit1:  mov     bx,cs:rh_ofs            ; restore req hdr to bx and es
        mov     es,cs:rh_seg            ; as saved by dev_Strategy
exit0:  pop     si                      ; restore all registers
        pop     di
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     es
        pop     ds
        ret
exit:

; *******************************************************************
; *     END OF PROGRAM                                              *
; *******************************************************************


presskey    endp
cseg        ends
            end     begin

; that's all folks!

我正在使用 masm 构建:

masm presskey.asm
link presskey
exe2bin presskey.exe presskey.sys

【问题讨论】:

  • 如果重要的话,您测试的是哪个版本的 Windows?我对这个问题中的 Windows 和 DOS 细节知之甚少,我自己也没有任何线索。
  • 如果您注释掉对initial 的调用会怎样?如果可行,您可以尝试注释掉调用以打印提示。可能不支持在加载驱动程序时回调到 DOS (int 21h)。但这只是一个模糊的猜测。
  • 调用 int 21h 打印字符串很好,只是从键盘读取似乎冻结了
  • 嗯。从缓冲区(int 16/0)读取输入字符似乎是一项非常简单的任务。我想不出为什么会挂起。但也许将字符添加到缓冲区的 ISR 可以被 cli 阻止?由于我们正在加载设备驱动程序,我想在我们完成之前禁用中断可能是有意义的。你能检查FLAGS吗?出于教育目的:在 INT 16 之前(即不是之前的行)将 STI 称为几个语句怎么样?显然是另一个模糊的猜测。

标签: assembly driver dos x86-16 ntvdm


【解决方案1】:

BIOS.WaitKey 函数 00h 冻结计算机不一定是真的。可能是您的驱动程序冻结了它,因为您忘记设置许多寄存器!

仅此assume cs:cseg,es:cseg,ds:cseg 是不够的。您需要确保DSES 段寄存器获得正确的值。
对于DS,它只是来自CS 的副本:

push    cs
pop     ds

当您的 dev_interrupt 例程被调用时,ES:BX 需要由您的代码设置。这就是为什么我们有一个 dev_strategy 例程。您没有这样做,因此您覆盖了错误的内存,并且没有将“DONE”返回到 RequestHeaderStatusWord 或让 DOS 知道驱动程序的结束位置。

dev_interrupt:                  ; second call from DOS
    cld                         ; save machine state on entry
    push    ds
    push    es
    push    ax
    push    bx
    push    cx  
    push    dx
    push    di
    push    si

    push    cs               ADD THIS
    pop     ds               ADD THIS
    mov     es, rh_seg       ADD THIS    ; request header ptr segment
    mov     bx, rh_ofs       ADD THIS    ; request header ptr offset

; perform branch based on the command passed in the req header

    mov     al,es:[bx]+2        ; get command code
    cmp     al,0                ; check for 0
    jnz     exit3               ; no - exit go to error exit
    rol     al,1                ; get offset into table
    lea     di,cmdtab           ; get address of command table
    mov     ah,0                ; clear hi order
    add     di,ax               ; add offset
    jmp     word ptr[di]        ; jump indirect

为了清楚起见,最好也将 rol al,1 更改为不那么容易混淆的 shl al,1。但那当然是我……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 2012-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 2015-07-27
    • 2015-09-09
    相关资源
    最近更新 更多