There are a few basic differences between real mode and protected mode that need to be addressed to convert a real mode program to run in protected mode.
Programs run at a protection level that prevents them from executing privileged instructions such as lgdt, lidt, etc. The DPMI interface is the only method application programs have for modifying system structures such as descriptors.
While DPMI defines a specific set of functions that will be supported by all implementations, there may be minor differences in individual implementations. Programmers should refer to the notes for their DPMI implementation for documentation on detecting the presence of and calling vendor specific extensions. However, any application that is written to adhere only to standard DPMI calls should work correctly under all implementations of DPMI.
Many DPMI implementations are simulated "virtual DOS" sessions. In other words, the DOS interface and environment presented to the program are not actually the native interface of the operating system. Hardware interrupts, I/O, and processor exceptions will be virtualized by the operating system. This means, for example, that a DPMI program may receive a simulated keyboard interrupt and read simulated I/O from the keyboard controller ports.
In these environments, actual hardware interrupts will be handled by the operating system. The physical interrupts will be invisible to the DPMI application program. If the operating system so chooses, it may reflect a virtual interrupt to the DPMI program. The DPMI program does not need to know, nor should it care, if this is the case. From the program's point of view, the interrupt looks exactly like a "real" interrupt. The operating system will also virtualize I/O to the interrupt controller ports and any other simulated devices.
There are basically three levels of virtualization that DPMI implementations can provide:
In general, stand-alone single tasking DPMI implementations will not virtualize any hardware devices. These hose extension programs will execute as standard DOS real mode drivers or programs. Extenders which use the services provided by these DPMI host drivers will translate protected mode DOS calls to real mode DOS calls. Normally these extenders will invoke DPMI services to return the processor to real mode (instead of virtual 8086 mode) when calling DOS.
Some environments that execute under DOS will virtualize hardware devices, provide virtual memory, or provide other services that require virtualization of some hardware devices. Under these environments, DPMI applications will always run at a non-privileged ring (usually ring 3). Some or all hardware interrupts will be virtualized, some or all I/O will be virtualized, and virtual memory may be supported. Under these implementations, page locking services usually must be used to lock interrupt and exception handling code.
These environments provide a completely simulated DOS environment. The native operating system is something other than MS-DOS. Under these implementations of DPMI, all devices will be virtualized to some extent. Normally, page locking services will be ignored by these implementations since all physical device interrupt and I/O handling will be performed by the operating system. Programs will always run at a non-privileged ring.
Protected mode code segments can not be modified. This requires programs to allocate an alias data descriptor if they need to store data in a code segment.
Segment arithmetic that works in real mode does not work in protected mode.
Some calls will return a range of descriptors. For example, if a 16-bit mode program allocates a block of memory larger than 64K, the call will allocate several, contiguous descriptors. Each descriptor will have a 64K limit except for the final descriptor which will have a limit that contains the remainder of the block. The call will return the first selector in the array. To get to the next selector, your program must add the value returned by Int 31h call 0003h (see section 8.5).
The popf and iret instructions may not modify the state of the interrupt flag since most DPMI implementations will run programs with IOPL < DPL. Programs must execute cli or sti to modify the interrupt flag state.
This means that the following code sequence will leave interrupts disabled:
; ; (Assume interrupts are enabled at this point) ; pushf cli . . popf ; Interrupts are still OFF!
Note that since some implementations of DPMI will maintain a virtual interrupt state for protected mode DOS programs, the current value of the interrupt flag may not reflect the current virtual interrupt state. Protected mode programs should use the virtual interrupt state services to determine the current interrupt flag state (see section 17.1).
Since cli and sti are privileged instructions, they will cause a protection violation and the DPMI provider will simulate the instruction. Because of the overhead involved in processing the exception, cli and sti should be used as little as possible. In general, you should expect either of these instructions to require at least 300 clocks.
Protected mode programs can hook both hardware and software interrupts using the DPMI get and set protected mode interrupt vector functions (see section 10.6). All interrupts from hardware devices such as the timer or keyboard controller will always be reflected to the protected mode interrupt handler first. If the protected mode handler jumps to or calls the previous interrupt handler then the interrupt will be reflected to real mode.
As in real mode, interrupt procedures can either service the interrupt and iret or they can chain to the next handler in the interrupt chain by executing pushf/call or by jumping to the next handler. The final handler for all protected mode interrupts will reflect the interrupt to real mode.
When an interrupt is reflected to real mode, the EAX, EBX, ECX, EDX, ESI, EDI, EBP registers, and flags will all be passed from protected to real mode unaltered. The segment registers will contain undefined values unless an API translator (such as a DOS or BIOS translator) explicitly sets a real mode segment register. DPMI will automatically provide a real mode stack for interrupts that are reflected to real mode.
The interrupt controllers are mapped to the system's default interrupts. On an IBM AT-compatible system, for example, the master interrupt controller is programmed with a base interrupt of 8 and the slave controller has a base of 70h. The virtualized interrupt controllers can be reprogrammed; the base setting may be examined in protected mode with Int 31h function 0400h.
Hardware interrupt procedures and all of their data must reside in locked memory. All memory that is touched by hardware interrupt hooks must be locked. The handler will always be called on a locked stack. See section 3 for more details.
As in real mode, hardware interrupt handlers are called with interrupts disabled. Since iret will not restore the interrupt flag, hardware interrupt hooks must execute an sti before executing iret or else interrupts will remain disabled.
Protected mode hardware interrupt handlers will always be called even for interrupts that occur in real mode. The last hook on the protected mode interrupt chain will reflect the interrupt to real mode.
Protected mode hardware interrupt handlers that need to call software running in real mode must either be sure that the real mode software that they are calling will not modify segment registers or they must use the state save service (see section 11.6) to save and restore the real mode segment registers. However, any interrupt handler that executes completely in protected mode, or uses translation services 0300h, 0301h, or 0302h does not need to save the real mode register state. Therefore, this is not an issue for most interrupt handlers.
For compatibility with older systems, computers with two interrupt controllers have the BIOS redirect one of the interrupts from the slave controller into the range of the master controller. For example, devices jumpered for IRQ 2 on IBM AT-compatible computers actually interrupt on IRQ 9 (interrupt 71h). In real mode, the BIOS on these systems will convert interrupt 71h to Int 0Ah and EOI the slave controller. A protected mode program that needs access to the redirected interrupt may use variations on either of these techniques:
Most software interrupts executed in real mode will not be reflected to the protected mode interrupt hooks. However, some software interrupts are also reflected to protected mode programs when they are called in real mode. These are:
INT DESCRIPTION 1Ch BIOS timer tick interrupt 23h DOS Ctrl+C interrupt 24h DOS critical error interruptPrograms should not terminate during interrupts that were reflected from real mode. Terminating the program at this point may prevent the DPMI host from cleaning up properly.
Of all software interrupts, only Ints 00h-07h will be called with virtual interrupts disabled. For these interrupts, the handler should return with interrupts enabled. All other interrupts will not modify the interrupt flag state.
Since most software interrupts that are executed in real mode are not reflected to protected mode interrupt hooks, programs would be required to install a real mode interrupt hook to monitor these interrupts.
Many implementations of DPMI support virtual memory. In these environments, it will be necessary to lock any memory that can be touched while executing inside of DOS. This is necessary because it may not be possible for the operating system to demand load a page if DOS is busy.
Some DPMI implementations will not call DOS to read or write virtual memory to disk and under these implementations the page locking services may be ignored. Since the entire DPMI session is virtualized, a page fault can be handled at any point while executing the program. However, under all implementations, DPMI applications should lock interrupt code and data. The lock calls will always return success under implementations that ignore these calls.