Geoff Chappell - Software Analyst
This function provides a prospective client of the DOS Protected Mode Interface (DPMI) with an address to call for stepping up to protected-mode execution. The subfunction number, 87h, is defined symbolically as W386_Get_PM_Switch_Addr in a header named INT2FAPI.INC which Microsoft distributed with the Device Driver Kit at least as early as for Windows 3.1.
Among Microsoft’s DPMI hosts, int 2Fh function 1687h is implemented by both the DOS extenders that Microsoft distributed with Windows:
The function uses registers for both input and output. Far pointers have real-mode addressing.
ax | 1687h |
ax | 0000h | |
bx | bit flags | |
cl | processor type | |
ch | processor flags | 4.0 and higher |
dx | DPMI version number; major and minor version in high and low byte, respectively |
|
si | size of private data area, in 16-byte paragraphs | |
es:di | address to call for protected-mode execution |
A DPMI host must support 16-bit protected-mode execution. If it also supports 32-bit DPMI clients, bx on output has the 0001h bit set.
The processor type can be 02h for an 80286, 03h for an 80386, else is 04h for any more advanced processor. Continuation of the series for specific advances was perhaps anticipated but is not known in any Windows implementation. Lesser processors, of course, have no protected mode.
The VMM from Windows 95 extends the function by clearing ch ordinarily but setting its 01h bit if the processor has the cpuid instruction. This is presently thought not to have been documented anywhere.
All Windows implementations produce 005Ah for the output in dx, meaning DPMI version 0.90.
The amount of memory described by si on output is required by the DPMI host in the DPMI client’s real-mode address space. Where this memory is placed is up to the DPM client, who tells of its real-mode segment address when switching to protected mode.
DOSX implements int 2Fh function 1687h only in its hook of the real-mode interrupt vector. Its handler of int 2Fh as set into the protected-mode Interrupt Descriptor Table (IDT) does not know this function and returns the interrupt with no registers changed.
The VMM has common handling of int 2Fh function 1687h in a V86 Interrupt Chain or as a PM Fault. This handling distinguishes the interrupt’s origin according to the VMSTAT_PM_EXEC flag in the CB_VM_Status member of the Virtual Machine Control Block (VMCB but formally a cb_s) for the current VM. If the flag is set, the caller already executes with protected-mode addressing and the VMM returns the interrupt with no registers changed.
Neither DPMI host knows of any processor more capable than the 80486, which is distinguished from the 80386 by having a working AC bit (18) in the eflags. The VMM takes as granted that it executes on at least an 80386, this having been established by the DOS-hosted loader, e.g., WIN386.EXE. Indeed, the VMM does none of this processor identification by itself.
Detection of the cpuid instruction in Windows 95 is also carried through to the VMM from the loader, which checks for a working ID bit (21) in the eflags but does not use the cpuid instruction for distinguishing processors even by family.
DOSX keeps its own data about its one DPMI client and thus returns si as zero.
The VMM has possibly many DPMI clients. It keeps data separately for each as a Protected Mode Application Control Block and allows that each Virtual Device Driver (VxD) can add to it by calling the Allocate_PM_App_CB_Area service during initialisation. The total size is fixed by the time that any DPMI client can execute. This size, rounded up to a mulitple of 16, is returned in si. It is perhaps not obvious in the VMM documentation but this control block must be in the DPMI client’s virtual-8086 address space. The DPMI client gets to choose where and must provide the address when calling for the transition to protected mode.
The address that int 2Fh function 1687h returns in es:di is for the DPMI client to execute, when ready, by a far call. The DPMI client executes this Switch to Protected Mode with real-mode addressing. If the called routine succeeds, the client continues with protected-mode addressing. The segment registers on output now hold protected-mode selectors. For cs, ds and ss, the selectors describe the same memory that these registers addressed before the switch. The es register now addresses the caller’s Program Segment Prefix (PSP).
The VMM allocates the returned address during the VMM’s initialisation before even any VxD executes in protected mode. This one address is returned for all DPMI clients for all remaining VMM execution. This behaviour is presumably an implementation detail. The interface itself would seem to allow different addresses for different DPMI clients (but the one address for all calls by any one DPMI client).