DOS Protected Mode Interface
The DOS Protected Mode Interface (DPMI) is a software specification defining an application programming interface (API) that enables DOS programs to execute in protected mode on Intel 80286, 80386, 80486, and compatible processors, facilitating access to extended memory beyond the conventional 1 MB limit while ensuring system stability and hardware independence.[1][2] Introduced in 1989 as an evolution from earlier standards like the Virtual Control Program Interface (VCPI), DPMI was developed through collaboration among industry leaders to standardize protected mode operations under DOS, addressing the limitations of real-mode programming in accessing advanced CPU features such as multitasking and large memory blocks.[1][3] The DPMI Committee, formed in February 1990 with founding members including Borland International, IBM Corporation, Intel Corporation, Lotus Development Corporation, Microsoft Corporation, Phar Lap Software, and Rational Systems, released the initial version 0.9 specification in May 1990, followed by the more comprehensive version 1.0 on March 12, 1991.[1] This committee effort built on a Microsoft prototype initially created for Windows 3.0 in collaboration with Lotus and Rational Systems, aiming to unify disparate DOS extender technologies and promote interoperability.[1] The specification uses software interrupt 31h to provide services from a DPMI host (such as an operating system or extender) to client applications, allowing seamless transitions between real mode and protected mode without disrupting the DOS environment.[1][3] Key features of DPMI include memory management for allocating and locking extended memory blocks, local descriptor table (LDT) handling for segment management, interrupt and exception vector control, real-mode call simulation for legacy DOS API access, and support for virtual memory and debugging services, all designed to enable 16-bit and 32-bit applications in a virtualized, multitasking-capable setup.[1] These capabilities allowed developers to create more efficient, memory-intensive DOS software, such as compilers and games, without requiring full system reboots or custom hardware configurations.[2] Notable DPMI hosts include Microsoft Windows 3.0 and later versions in enhanced mode, which provided DPMI services to run protected-mode DOS applications within virtual DOS machines; OS/2, offering a highly compatible DPMI virtual host; and standalone DOS extenders like DOS/4GW from Tenberry Software, Phar Lap TNT, and CWSDPMI for DJGPP.[4][5][6] DPMI's standardization significantly influenced late-era DOS development, enabling titles like Doom and compilers like Watcom C to leverage extended memory until the transition to 32-bit operating systems in the mid-1990s.[4][7]Introduction
Definition and Purpose
The DOS Protected Mode Interface (DPMI) is a specification that defines an application programming interface (API) for enabling DOS applications to switch x86 processors from real mode to protected mode while operating under MS-DOS or compatible operating systems.[1] It provides a standardized set of services, accessed primarily through interrupt 31h, allowing protected-mode programs to interact with the host DOS environment without requiring a full operating system replacement.[1] Initial drafts of the specification were published in 1989, targeting Intel 80286 and later CPUs to leverage their advanced addressing and protection features, with version 0.9 supporting 16-bit protected mode on the 80286 and version 1.0 adding 32-bit capabilities on the 80386 and above.[4] The primary purpose of DPMI is to permit protected-mode applications, including 16-bit and 32-bit, to access extended memory beyond the 640 KB conventional memory limit imposed by DOS's real-mode architecture, using techniques such as virtual memory mapping and execution in ring 3 user mode.[1] This interface facilitates mode switching via a DPMI host—typically a DOS extender or multitasking environment—that manages the transition and maintains system protection in ring 0 supervisor mode, ensuring the client application cannot destabilize the host.[4] By abstracting hardware resources, DPMI allows DOS programs to operate in protected mode while remaining compatible with the DOS ecosystem, addressing the need for larger memory spaces in applications like games and utilities without disrupting legacy real-mode software. Key benefits of DPMI include significantly improved memory efficiency through descriptor-based allocation of extended memory above 1 MB, support for running under multitasking hosts that manage multiple DOS applications within virtual machines, such as in enhanced mode of Windows 3.x, and hardware abstraction for interrupts and I/O operations to prevent direct hardware conflicts.[1] These features enable developers to build more sophisticated protected-mode programs that scale beyond DOS's inherent constraints, such as the 1 MB address limit, while preserving the simplicity of the DOS environment for deployment.[4]Background in DOS Memory Limitations
The MS-DOS operating system, designed for the Intel 8086 and 8088 processors, operated exclusively in real mode, which restricted the addressable memory space to 1 MB due to the 20-bit external address bus.[8] Within this 1 MB limit, only the first 640 KB—known as conventional memory—was available for running application programs and DOS itself, while the remaining 384 KB (the upper memory area, or UMA) was reserved for hardware adapters, video memory, BIOS routines, and other system functions.[9] This architectural constraint, inherited from the original IBM PC design in 1981, initially sufficed for simple 16-bit applications but quickly proved inadequate as software complexity increased. To mitigate these restrictions, developers introduced partial workarounds like upper memory blocks (UMBs) and expanded memory via the Expanded Memory Specification (EMS), as well as extended memory via the Extended Memory Specification (XMS), which enabled software-based access to memory above 1 MB on 80286 and later processors. UMBs allowed unused portions of the UMA (typically between 640 KB and 1 MB) to be reclaimed for DOS device drivers and terminate-and-stay-resident (TSR) programs through extended memory managers such as HIMEM.SYS, introduced in MS-DOS 5.0 in 1991, though the concept emerged earlier in third-party tools.[10] EMS, jointly specified by Lotus, Intel, and Microsoft (LIM) starting with version 3.0 in 1985[11] and updated to version 4.0 by 1987, enabled access to additional memory beyond 1 MB using dedicated expansion cards that paged 16 KB blocks into the UMA via a dedicated memory manager driver.[12] However, these solutions were limited: UMBs provided only fragmented, small blocks unsuitable for large programs, while EMS's page-swapping mechanism was inefficient for linear 32-bit addressing, often causing performance overhead and incompatibility with applications needing contiguous memory spaces exceeding 640 KB. XMS improved on this by allowing direct access to extended memory but still required real-mode limitations. DOS's single-tasking design exacerbated these issues through memory fragmentation and lack of true multitasking support. As device drivers, TSR programs (like SideKick or mouse drivers), and utilities loaded into conventional memory, they divided the 640 KB space into non-contiguous blocks, leaving insufficient large segments for new applications despite overall free memory availability—a classic external fragmentation problem inherent to DOS's first-fit allocation strategy.[13] Multitasking was impossible natively, as DOS relinquished control to one program at a time without memory protection or preemptive scheduling, forcing developers to rely on cooperative TSRs that further fragmented memory and risked system instability if a program hung.[14] This demand for protected mode access—enabling 32-bit addressing of up to 4 GB on 80386 processors—grew without abandoning DOS compatibility, as real-mode limitations hindered advanced features. By the late 1980s, the shift toward 32-bit computing amplified these constraints, driven by resource-intensive software. Spreadsheets like Lotus 1-2-3 Release 3.0 (1989) required at least 1 MB of total RAM (combining 640 KB conventional with extended memory via workarounds), while early CAD programs such as AutoCAD Release 10 (1988) demanded 512 KB minimum but benefited significantly from more to handle complex drawings without swapping. Even games, such as Sierra's King's Quest IV (1988), pushed beyond 640 KB using EMS for larger worlds and graphics, underscoring the need for seamless access to greater memory volumes in a DOS environment.[15]History
Early Development
The early development of the DOS Protected Mode Interface (DPMI) originated in 1989 through collaborations between Microsoft and Intel, primarily to support protected mode operations in Microsoft's Windows 3.0 enhanced mode environments.[1] Microsoft's initial prototype, developed as part of efforts to enable DOS applications to access extended memory beyond the 640 KB conventional limit, incorporated input from Lotus Corporation and Rational Systems to enhance performance for large-scale applications.[1] Phar Lap Software and Rational Systems contributed prototypes via their DOS extenders, such as Phar Lap's 386|DOS Extender and Rational Systems' early 386|DOS Extender implementations, which demonstrated protected mode execution under DOS and influenced the emerging standard.[1] These efforts addressed the fragmentation caused by proprietary extender interfaces, with a core goal of standardizing protected mode service calls to prevent vendor lock-in and enable developer portability across environments.[1] Intel facilitated the transition by working with extender vendors to build on the 1987 Virtual Control Program Interface (VCPI), co-developed by Phar Lap Software and Quarterdeck Office Systems, toward a more comprehensive specification.[1] The first informal version, DPMI 0.9, emerged in late 1989 as draft specifications and was publicly released in May 1990; it was promptly tested with tools like the Watcom C compiler, which integrated support for protected mode DOS programming.[1]Specification and Standardization
The DOS Protected Mode Interface (DPMI) was formalized through the efforts of the DPMI Committee, an ad-hoc industry group established in February 1990 to develop a unified standard for enabling protected-mode execution of DOS applications on Intel 80286 and later processors. Founding members included major software and hardware companies such as Borland International, IBM Corporation, Ergo Computer Solutions, Intelligent Graphics Corporation, Intel Corporation, Locus Computing Corporation, Lotus Development Corporation, Microsoft Corporation, Phar Lap Software, Phoenix Technologies Ltd., Quarterdeck Office Systems, and Rational Systems, Inc.[1][16] This collaboration addressed the fragmentation caused by proprietary DOS extenders, aiming to create a common application programming interface (API) that would promote interoperability and wider adoption of extended memory access beyond the 640 KB conventional limit of MS-DOS.[1] The committee's first milestone was the release of the DPMI version 0.9 specification in May 1990, which outlined preliminary services for switching between real and protected modes, allocating memory, and handling interrupts under DOS. Building on this foundation, the group published the DPMI 1.0 specification on March 12, 1991, marking the standard's maturation into a robust framework.[1] This version explicitly defined the division between the DPMI host—responsible for initializing protected mode, managing system resources, and providing DOS compatibility—and the DPMI client—the application leveraging these services for tasks like large memory allocation and direct hardware access without compromising system stability.[1] Key enhancements in 1.0 included refined interrupt reflection mechanisms and expanded real-mode callback support, ensuring seamless integration with existing DOS environments.[1] No subsequent official versions were issued after 1.0; subsequent implementations prioritized full backward compatibility with the 1.0 specification to maintain ecosystem stability.[17] This standardization effort significantly influenced DOS extender development, enabling applications like early 32-bit games and utilities to access extended memory—typically up to 16 MB in early implementations—reliably across vendors.[16]Technical Overview
Core Architecture
The DOS Protected Mode Interface (DPMI) employs a host-client architecture where the host, typically a DOS extender or multitasking environment operating in protected mode, manages system resources and provides services to clients—DOS applications that execute in protected mode. The host handles memory allocation, descriptor management, and hardware access, ensuring system stability while allowing clients to leverage extended memory beyond the 1 MB limit of real-mode DOS. This model enables clients to run within virtual machines, sharing the DOS address space while maintaining isolation through privilege levels.[1] Clients switch between real mode and protected mode using interrupt 31h (INT 31h), with the initial transition initiated via interrupt 2Fh (INT 2Fh) function 1687h to locate the host's entry point, followed by a far call that sets mode flags for 16-bit or 32-bit operation. This switching mechanism allows applications to perform DOS calls in real mode for compatibility while executing performance-critical code in protected mode, with the host saving and restoring processor state to prevent disruptions. Raw mode switches are also supported via INT 31h function 0306h, facilitating direct control over the transition process.[1] At its core, DPMI utilizes a linear memory model providing a 4 GB virtual address space, mapped to physical RAM through paging mechanisms on 32-bit hosts. This model supports both flat (unsegmented) and segmented addressing, where memory is organized as a contiguous array or divided into segments defined by selectors, enabling efficient access to extended memory without the fragmentation issues of real-mode segmented addressing. Paging ensures committed pages are backed by physical memory, while uncommitted pages allow for demand allocation, optimizing resource use in memory-constrained environments.[1] To enforce security and prevent client faults from crashing the host, DPMI operates with a ring-based protection scheme derived from the Intel 80386 architecture: clients execute in Ring 3 (user mode) with limited privileges, restricting direct access to hardware and kernel resources, while the host and supervisors run in Ring 0 (supervisor mode) to manage interrupts, I/O, and critical operations. This separation isolates application errors, such as invalid memory accesses, allowing the host to terminate faulty clients without affecting the overall system.[1] Initialization begins with the client detecting the presence of a DPMI host through INT 2Fh function 1687h, which returns the host's capabilities, including the size of a required private data area in the SI register. Upon confirmation, the client allocates this area, performs the initial mode switch via the far call, and then uses INT 31h function 0000h to allocate selectors and descriptors for essential segments such as code (CS), data (DS), stack (SS), the program segment prefix (PSP), and the environment block. These descriptors define the client's address space boundaries and access rights, establishing the foundation for subsequent protected-mode operations.[1]Provided Services
The DOS Protected Mode Interface (DPMI) provides a standardized set of services through interrupt 31h, enabling protected-mode clients to manage resources while maintaining compatibility with the DOS environment. These services are grouped into categories such as memory allocation, interrupt handling, descriptor manipulation, and mode switching, allowing applications to access extended memory and hardware without direct real-mode dependencies. All services are invoked via INT 31h with specific values in the AX register to select the function, and they return status codes in the carry flag and AX for error handling.[1]Memory Services
DPMI's memory services facilitate the allocation and management of linear memory blocks beyond the 1 MB DOS limit, supporting both committed and page-aligned allocations for efficient use in protected mode. The core functions include:- Allocate Memory Block (INT 31h, AX=0501h): Requests a block of linear memory of a specified size in paragraphs; returns a handle and linear address if successful, enabling clients to access up to gigabytes of extended memory depending on host availability.[1]
- Free Memory Block (INT 31h, AX=0502h): Releases a previously allocated block using its handle, returning the memory to the host's pool.[1]
- Resize Memory Block (INT 31h, AX=0503h): Modifies the size of an existing block, either expanding or shrinking it while preserving data if possible.[1]
- Get Free Memory Information (INT 31h, AX=0500h): Queries the largest available block, total free memory, and physical address range, aiding in allocation planning.[1]
- Map Physical to Linear Address (INT 31h, AX=0800h): Maps a physical memory region to a linear address, useful for direct hardware I/O without page faults.[1]
- Unmap Physical Address (INT 31h, AX=0801h): Releases the mapping to free resources.[1]
Interrupt Services
Interrupt services allow protected-mode code to interact with real-mode DOS and BIOS calls seamlessly, preventing protection violations during simulation. Key functions enable vector management and simulation:- Simulate Real-Mode Interrupt (INT 31h, AX=0300h): Executes a real-mode interrupt (e.g., INT 21h for DOS services) from protected mode, passing parameters via a structure and returning results; this is essential for legacy API calls without mode switching overhead.[1]
- Get Real-Mode Interrupt Vector (INT 31h, AX=0200h): Retrieves the current real-mode handler address for a specified interrupt number.[1]
- Set Real-Mode Interrupt Vector (INT 31h, AX=0201h): Installs a client-provided real-mode handler, with the host emulating calls if needed.[1]
- Get Protected-Mode Interrupt Vector (INT 31h, AX=0204h): Obtains the protected-mode selector and offset for an interrupt.[1]
- Set Protected-Mode Interrupt Vector (INT 31h, AX=0205h): Sets a protected-mode handler for hardware or software interrupts.[1]
- Get Exception Handler Address (INT 31h, AX=0203h): Retrieves or sets handlers for CPU exceptions like divide-by-zero, ensuring protected-mode fault recovery.[1]
Descriptor Management
Descriptor services manage the local descriptor table (LDT) for segment selectors, allowing clients to create and modify memory segments without host intervention. This is crucial for the flat memory model in protected mode:- Allocate LDT Descriptors (INT 31h, AX=0000h): Requests one or more consecutive LDT entries, returning the base selector.[1]
- Free LDT Descriptors (INT 31h, AX=0001h): Releases allocated selectors to the host.[1]
- Get Segment Base Address (INT 31h, AX=0006h): Returns the 32-bit linear base of a selector.[1]
- Set Segment Base Address (INT 31h, AX=0007h): Updates the base address of an existing selector for dynamic mapping.[1]
- Set Segment Limit (INT 31h, AX=0008h): Adjusts the size limit of a segment in bytes.[1]
- Set Segment Access Rights (INT 31h, AX=0009h): Modifies protection attributes like read/write and privilege level.[1]
- Get Descriptor (INT 31h, AX=000Ah): Retrieves the full descriptor contents for a selector.[1]
- Set Descriptor (INT 31h, AX=000Bh): Sets the complete descriptor, including base, limit, and rights.[1]
Raw Mode Switching
For low-level control, DPMI offers functions to switch CPU modes directly, bypassing some host mediation:- Get Raw Mode Switch Addresses (INT 31h, AX=0306h): Returns client-callable addresses for entering and exiting protected mode, along with real-mode entry point; this enables "raw" switching for performance-critical code without full host involvement.[1]
Version-Specific Additions
DPMI 1.0 includes virtual memory features such as page locking services to prevent swapping of critical regions and ensure interrupt safety:- Lock Linear Region (INT 31h, AX=0600h): Locks a linear memory range against paging.[1]
- Unlock Linear Region (INT 31h, AX=0601h): Releases the lock on a region.[1]
- Relock Real-Mode Region (INT 31h, AX=0603h): Relocks conventional memory accessed from protected mode.[1]