为什么 INT 31H 没有正确设置,即使 DPMI 主机处于活动状态?

Why isn't INT 31H set up properly even with a DPMI host active?

我一直在 MS-DOS 中进行大量的汇编编程试验。我读过 Windows 3.1 作为 DOS 程序的 DPMI 主机,并且 DPMI 使用中断 31h 进行函数调用。

让我们试一试。我在 Windows 3.1...

中打开 DOS 提示符
C:\WINDOWS>debug
-a100
23A4:0100 mov ax,0400
23A4:0103 int 31
23A4:0105
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=23A4  ES=23A4  SS=23A4  CS=23A4  IP=0100   NV UP EI PL NZ NA PO NC
23A4:0100 B80004        MOV     AX,0400
-p

AX=0400  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=23A4  ES=23A4  SS=23A4  CS=23A4  IP=0103   NV UP EI PL NZ NA PO NC
23A4:0103 CD31          INT     31
-p

所以显然有些东西不起作用。

我再试一次,使用 Trace 命令而不是 Proceed。这样它实际上会进入中断处理程序而不是跳过它。

AX=0400  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=23A4  ES=23A4  SS=23A4  CS=23A4  IP=0103   NV UP EI PL NZ NA PO NC
23A4:0103 CD31          INT     31
-t

AX=0400  BX=0000  CX=0000  DX=0000  SP=FFE8  BP=0000  SI=0000  DI=0000
DS=23A4  ES=23A4  SS=23A4  CS=F000  IP=FF01   NV UP DI PL NZ NA PO NC
F000:FF01 7261          JB      FF64
-

让我们看看要执行什么...

-u
F000:FF01 7261          JB      FF64
F000:FF03 63            DB      63
F000:FF04 6C            DB      6C
F000:FF05 65            DB      65
F000:FF06 20564D        AND     [BP+4D],DL
F000:FF09 205669        AND     [BP+69],DL
⋮
F000:FF18 53            PUSH    BX
F000:FF19 0000          ADD     [BX+SI],AL
F000:FF1B 0000          ADD     [BX+SI],AL
F000:FF1D 0000          ADD     [BX+SI],AL
F000:FF1F 0000          ADD     [BX+SI],AL
-

...是的,这看起来不像是应该执行的任何操作。事实上,字节码看起来很像 ASCII 文本。果然...

-df000:ff01
F000:FF00     72 61 63 6C 65 20 56-4D 20 56 69 72 74 75 61    racle VM Virtua
F000:FF10  6C 42 6F 78 20 42 49 4F-53 00 00 00 00 00 00 00   lBox BIOS.......
F000:FF20  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
F000:FF30  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
F000:FF40  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
F000:FF50  00 58 4D CF CF 89 C0 89-C0 89 C0 89 C0 89 C0 FC   .XM.............
F000:FF60  5F 53 4D 5F 7D 1F 02 05-FF 00 00 00 00 00 00 00   _SM_}...........
F000:FF70  5F 44 4D 49 5F 58 C2 01-00 10 0E 00 0A 00 25 00   _DMI_X........%.
F000:FF80  00                                                .
-

这显然不是 DPMI 处理程序。无论如何,如果我越过 JB FF64,它将继续到 DB 63(“Oracle”中的 'c'),这就是导致无效指令错误的原因。或者,如果设置了进位标志,它将进行跳转并遇到它解释为 JGE FF85 指令的内容。如果标志是这样的,它不会跳转,它最终会到达另一个无效指令。否则,它将[BX+SI]处的字节增加AL中的值105次,之后的字节77字节增加BL中的值一次,最后重启VM,因为下一条指令是实模式复位向量。 (在 v86 模式下,但我猜 Windows 3.1 允许。)

长话短说,很明显在 INT 31H 没有安装 DPMI 处理程序,这显然应该是这样。一些额外的信息:

考虑到这一点,谁能告诉我我做错了什么?

DPMI的Real/Virtual86模式接口只有中断2Fh服务1687h。 returns 一个可以用来进入保护模式的入口点。中断 31h 服务仅在保护模式下可用。这是小型 DPMI 客户端的 an example。进入保护模式相关代码:

        mov ax, 1687h
        int 2Fh
        test ax, ax             ; DPMI host installed?
        jnz nohost
        push es                 ; save DPMI entry address
        push di
        test si, si             ; host requires client-specific DOS memory?
        jz .nomemneeded         ; no -->
        mov bx, si
        mov ah, 48h
        int 21h                 ; allocate memory
        jc nomemory
        mov es, ax
.nomemneeded:
        ; (message and breakpoint omitted)
        mov bp, sp
        mov ax, 0001h           ; start a 32-bit client
        call far [bp]           ; initial switch to protected-mode
        jnc initsuccessful
initfailed:

保护模式一般通过执行PM interrupt 21h service 4Ch(随后也传递给DOS 86M handler,从而终止DOS进程)退出保护模式。

顺便说一句,要调试 DPMI 客户端,您可能需要使用 FreeDOS DebugX 或 my fork lDebugX。