DRAFT: Take more than your usual care.

Switch to Protected Mode

A prospective client of the DOS Protected Mode Interface (DPMI) will have called int 2Fh functon 1687h to register its interest in protected-mode execution. The interrupt tells a little of the DPMI host and provides the address of a routine to call for the transition from real (or virtual-8086) mode 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. Segment registers hold real-mode segment addresses on input but protected-mode selectors as successful ouput.

The interrupt can have set si to count 16-byte paragraphs that the DPMI host requires as one block of real-mode address space. The client chooses where, subject only to 16-byte alignment. The size is not repeated.


ax flags
es segment address for DPMI host’s data area, if required;
else ignored

The only defined bit for the flags in ax is 0001h. It is set or clear to request execution as a 32-bit or 16-bit DPMI client, respectively.


flags carry flag clear;
other bits may be corrupt
cs selector for 64KB at input cs
ds selector for 64KB at input ds
es selector for 0100h bytes at caller’s Program Segment Prefix (PSP)
fs 0000h, if 80386 or higher
gs 0000h, if 80386 or higher
ss selector for 64KB at input ss

If ds and ss are equal on input, they are equal on output.

The caller’s PSP is changed non-trivially. At offset 002Ch, what had been a segment address for the process’s environment is now a selector. Other changes are apparently implementation-dependent.


flags carry flag set;
other bits may be corrupt


Segment descriptors are prepared such that the selector in cs allows execute/read access and the selectors for ds, es and ss allow read/write access. Whether the selectors must select from the LDT or can select from the GDT is unclear, but both Microsoft’s implementations in all versions produce LDT selectors. Privilege levels both in the selectors and the corresponding descriptors are possibly not intrinsic to the interface except that they must be set consistently: the caller on return must be able to use all these selectors. Among Microsoft’s implementations, the VMM from Windows 3.0 sets the privilege level to 1, but later implementations to 3.


DOSX can support only 16-bit DPMI clients. It explicitly fails any request to execute as a 32-bit DPMI client. This constraint is disclosed through int 2Fh function 1687h by its returning a clear 0001h bit in ax.

DOSX allows only one DPMI client. Transition to protected-mode execution is not repeatable. Once this routine has succeeded, subsequent calls fail, e.g., if contrived to be attempted during the real-mode handling of an interrupt.

This determination to have only one DPMI client goes as far as arranging that the DPMI client’s termination forces DOSX’s own termination. This is done by an additional modification of the caller’s PSP. Specifically, the far pointer at offset 0Ah that records where execution is to resume when the caller terminates (as a DOS process) is set to the same address in DOSX that is already the return address of the int 21h function 4B00h that DOSX called to execute its child process.

A surely intended effect, despite its dangers, is that if the DPMI client is not the immediate child of DOSX, then the DPMI client’s termination by-passes the intermediate processes on the way to exiting from DOSX. For some sign that the effect can surprise, look at Unauthorized Windows 95 (ISBN 1-56884-305-4) by Andrew Schulman. At the end of page 155 is a demonstration that contrives to have DOSX first run COMMAND.COM as its immediate child and then to attempt two executions of a small DPMI client. That the second attempt fails is supposedly because “After switching a program into protected mode, DOSX unhooks itself from real-mode INT 2Fh.” In reality, it fails because DOSX is gone (until it is re-run).

As if to compound the surprise, the next page elaborates that the same supposed explanation is also “why DOS programs running under Windows Standard mode cannot use the Windows DPMI server or DOS extender”. The supposition is again that “After DOSX sees KRNL286.EXE or KRNL386.EXE switch into protected mode, it unhooks itself from INT 2Fh, so no other programs can call DPMI to switch into protected mode.” In reality, running a DOS program from Windows Standard Mode reaches past DOSX to the WSWAP task switcher which then swaps out all of DOSX and its children, and itself, to run the DOS program under DSWAP. The DOS program sees no DPMI host because DOSX is gone (but now only until it is switched back).