Geoff Chappell - Software Analyst
With this function, a client of the DOS Protected Mode Interface (DPMI) obtains a selector to the client’s Local Descriptor Table (LDT). The selector can then be used for reading and editing LDT entries without having to call the DPMI’s int 31h functions for selector management. The subfunction number, 88h, is defined symbolically as W386_Get_LDT_Base_Sel 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 1688h is implemented by both the DOS extenders that Microsoft distributed with Windows:
For Windows 3.1, int 2Fh function 1688h was superseded by int 2Fh function 168Ah in both implementations.
The function uses registers for both input and output. In the intended circumstances, it is called by a DOS program that is already executing in protected mode as a DPMI client.
ax | 1688h |
bx | 0BADh |
ax | 0000h |
bx | selector for caller’s LDT |
Though the interface itself would seem to allow that different DPMI clients, if the host supports them, can be given different selectors, neither of the known implementations does so. For DOSX, the selector is hard-coded: 0085h in Windows 3.0 but 009Bh in Windows 3.1. The VMM allocates one selector during the VMM’s initialisation and returns this to all DPMI clients in all virtual machines for the remainder of the VMM’s execution. What the selector’s numerical value is fixed to can vary for different executions of the VMM, presumably to discourage programmers from thinking to hard-code any one observed value. The particular implementation constrains the selector to the range 0085h to 00FDh inclusive. The variability is obtained from the timer tick that the BIOS maintains at the real-mode address 0040:006C.
The interface’s usefulness surely lies in what the returned selector is expected to address, which is the caller’s LDT. The VMM allows that this LDT can move and can grow (but not shrink).
The interface looks like it does not itself specify the Table Indicator (TI) or Requested Privilege Level (RPL) bits in the selector’s numerical value or perhaps even the Descriptor Privilege Level (DPL) or Type bits in the selected descriptor. If anything, flexibility on these points is intended: for instance, a DPMI host might restrict one client just to reading its LDT but trust another with both read and write access to its. As it happens, both the known implementations from Windows 3.0 return an LDT selector that requests ring 1 access and that the selected descriptor grants ring 1 access to the corresponding segment as read/write data. See that the one known implementation in Windows 3.1 changes to a GDT selector with ring 3 access.
This function is evidently an early form of what was later developed (or formalised) as a vendor-specific extension of the DPMI. Starting with Windows 3.1, both DOSX and the VMM expose their LDT self-selector through the MS-DOS Extensions API Entry Point whose address is produced by int 2Fh function 168Ah.
The same selector that these functions return to protected-mode DPMI clients is also given to any Virtual Device Driver (VxD) that calls the VMM service _Allocate_LDT_Selector. The allocated selector, which is the service’s immediate reason for existence, is returned in ax (if the service is successful) but opportunity is taken to use edx for a general description of the LDT. The self-selector is returned in the low word. The high word has the LDT’s current capacity as a count of selectors. Documentation notes that “Although this service returns a selector to the LDT, virtual devices should not attempt to edit the LDT directly.”
Possibly just by not explicitly excluding the case, the VMM has int 2Fh function 1688h succeed even when called by virtual-8086 code. The returned selector is not immediately useful. DOSX, by contrast, implements the function only in protected mode.
The one known user is the Windows 3.0 KRNL386.EXE. No matter what’s said to the contrary in both Undocumented Windows (ISBN 0-201-60834-0) on page 203 and Windows Internals (ISBN 0-201-62217-3) on page 8, the KRNL386.EXE from Windows 3.0 starts as a DOS program with the real-mode addressing of virtual-8086 execution under the VMM. After stepping up to protected mode with the help of int 2Fh function 1687h, it calls int 2Fh function 1688h to obtain a selector to its LDT. Failure is fatal, though curiously the complaint is of being “Unable to enter Protected Mode”.
With success of int 2Fh function 1688h enforced during initialisation, code throughout the Windows 3.0 KRNL386 takes as granted that it has this selector for easily reading and editing the LDT. The KRNL386 from Windows 3.1 and higher requires that the function’s more complicated replacement, int 2Fh function 168Ah, succeeds but not that the next step produces a suitable selector. Some KRNL386 code was updated to fall back to using int 31h functions if the selector was not obtained, but much was not.