It is possible to access functionality of (appropriately written) native 32-bit Windows drivers from DOS programs. For this, otherwise non-existing CPU instructions - also known as BOP's, for BIOS Operation, from an early PC emulator called SoftPC - have been defined which are processed by the "invalid instruction" routine of the NTVDM (passed to by the kernel's KiTrap06
routine), kind of like a software version of the SYSCALL
instruction of x86-64 CPU's. These instructions are the following:
RegisterModule
: 0xC4, 0xC4, 0x58, 0x00
. Initializes the connection between the DOS program executing this instruction and a VDD (Virtual Device Driver, the "module").
Input:
DS:SI
: Pointer to the DLL name (ASCIIZ string).
ES:DI
: Pointer to the name of the initialization routine (ASCIIZ string). This routine is called when the connection is established. For a NULL
pointer, no initialization takes place.
DS:BX
: Pointer to the name of the dispatch routine (ASCIIZ string); see below.
Output:
Carry flag
: When set, an error occurred; clear indicates success.
AX
: On success, handle to the VDD. On error, the error code: 1
: DLL file not found; 2
: Dispatch routine not found in DLL; 3
: Initialization routine not found in DLL; 4
: Out of memory. Read below for other errors.
UnregisterModule
: 0xC4, 0xC4, 0x58, 0x01
.
Closes the connection.
Input:
AX
: VDD handle, as returned by RegisterModule
.
Output: None.
DispatchCall
: 0xC4, 0xC4, 0x58, 0x02
.
Sends a request to the VDD.
Input:
AX
: VDD handle, as returned by RegisterModule
.
Further arguments as required by the VDD.
Output: As set by the VDD.
For the development of the VDD, the Windows Driver Development Kit (DDK) or its new incarnation, the Windows Driver Kit (WDK), is required. The VDD can use the following API calls, defined in vddsvc.h
, for communication with DOS programs running in the NTVDM:
UCHAR GetAL()
, UCHAR GetAH()
, USHORT GetAX()
, ULONG GetEAX()
, same for BX
, CX
, DX
, SI
, DI
, SP
, BP
, IP
; USHORT GetCS()
, same for DS
, ES
, FS
, GS
, SS
; ULONG GetCF()
, same for PF
, AF
, ZF
, SF
, IF
, DF
, OF
; USHORT GetMSW()
: Read the values of registers, including the Machine Status Word (MSW), and flags at the point where the DOS program executed DispatchCall
.
SetAL(UCHAR Value)
, SetAH(UCHAR Value)
, SetAX(USHORT Value)
, SetEAX(ULONG Value)
, ...; SetCS(USHORT Value)
, ...; SetCF(ULONG Value)
, ...; SetMSW(USHORT Value)
: Write the values of registers and flags, returning information to the DOS program.
PVOID GetVDMPointer(ULONG Address, ULONG Length, BOOL IsProtMode)
: Get a pointer to and lock a memory area in the NTVDM. Obsolete, use VdmMapFlat
instead.
Input:
Address
: Start address of the memory area. The high word of is the segment, the low word is the offset.
Length
: Length of the memory area.
IsProtMode
: FALSE
: The NTVDM is running in real mode, the segment part is a real mode segment; TRUE
: Protected mode, the segment part is a selector from the NTVDM's GDT.
Output: Pointer to the memory area.
VOID FreeVDMPointer(ULONG Address, ULONG Length, PVOID LinearAddress, BOOL IsProtMode)
: Unlock a memory area locked by GetVDMPointer
. Obsolete, use VdmUnmapFlat
instead.
Input:
LinearAddress
: Pointer to memory area, as returned by GetVDMPointer
.
See GetVDMPointer
for the other input arguments.
Output: None.
PVOID VdmMapFlat(USHORT Segment, ULONG Offset, VDM_MODE VDMMode)
: Get a pointer to and lock a memory area in the NTVDM. Supersedes GetVDMPointer
.
Input:
Segment
: Segment part of the address of the memory area.
Offset
: Offset part of the address of the memory area.
VDMMode
: VDM_X86
: The NTVDM is running in real mode, the segment part is a real mode segment and the offset part is 16-bit; VDM_PM
: Protected mode, the segment part is a selector from the NTVDM's GDT and the offset part is 32-bit.
Output: Pointer to the memory area.
BOOL VdmUnmapFlat(USHORT Segment, ULONG Offset, PVOID LinearAddress, VDM_MODE VDMMode)
: Unlock a memory area locked by VdmMapFlat
. Supersedes FreeVDMPointer
.
Input:
LinearAddress
: Pointer to memory area, as returned by VdmMapFlat
.
See VdmMapFlat
for the other input arguments.
Output: TRUE
, if the memory area was successfully unlocked; FALSE
, if an error occurred.
BOOL VdmFlushCache(USHORT Segment, ULONG Offset, ULONG Length, VDM_MODE VDMMode)
: Flushes writes to a memory area locked by VdmMapFlat
. Its use is not necessary on x86 platforms, nevertheless recommended.
Input:
Length
: Length of the memory area.
See VdmMapFlat
for the other input arguments.
Output: TRUE
, if the memory area was successfully flushed; FALSE
, if an error occurred.
Notes about non-trivial behavior:
To support real mode as well as protected mode DOS programs, use the expression (getMSW() & MSW_PE)
rather than a constant FALSE
or TRUE
for the IsProtMode
argument of GetVDMPointer
and FreeVDMPointer
. For the VDMMode
argument of VdmMapFlat
, VdmUnmapFlat
and VdmFlushCache
, the expression getMODE()
is recommended.
Irrespectively of the value of the IsProtMode
argument of GetVDMPointer
, only the low word of Address
is taken for an offset, therefore all offsets must be within the first 64 Kbytes of segments in protected mode (DPMI) DOS programs, including the BOP instruction (at CS:IP
). Without this, weird errors may occur, such as nothing happening at all upon the execution of BOP's, with or without the carry flag set! If and how code and data can be forced to the beginning of segments depends on the assembler/compiler and major hacking may be required. Note that VdmMapFlat
does not suffer from this limitation.
More documentation:
Contact |
Copyright and license |
Blog page | Recent updates |
Title page
(This page best viewed with any browser)