The DPMI real mode callback mechanism allows a DPMI protected mode client to be called as a subroutine by real mode programs in a transparent manner. That is, a real mode program can use a real mode callback to pass information to the DPMI client, or obtain services provided by the DPMI client, without necessarily being aware of protected mode or extended memory in any way. The callback mechanism can be thought of as the converse of DPMI Int 31H Functions 0300H, 0301H, and 0302H, which allow a DPMI client to pass information to a real mode program, or obtain services from a real mode program, in a manner that is similarly transparent to the real mode program.

In order to make a real mode callback available, the DPMI client must first call Int 31H Function 0303H with the selector and offset of the protected mode routine which will receive control when the callback is entered, and the selector and offset of a real mode register data structure (in the same format as used for Int 31H Functions 0300H, 0301H, and 0302H). Function 0303H will return a real mode address (segment and offset) for the callback entry point that can be passed to a real mode program via a software interrupt or far call (Int 31H Functions 0300H, 0301H, or 0302H), a DOS memory block, or any other convenient mechanism.

When the real mode program executes a FAR CALL to the real mode callback address supplied to it by the DPMI client, the DPMI host saves the contents of all real mode registers into the DPMI client's real mode register data structure, switches the CPU into protected mode, and enters the DPMI client's callback routine with the following conditions:

The format of the real mode register data structure is as follows: (Note that the content of the 32H bytes data structure are undefined at the time of the original Int 31H Function 0303H call.)

OffsetLengthContents
00H4DI or EDI
04H4SI or ESI
08H4BP or EBP
0CH4reserved, should be zero
10H4BX or EBX
14H4DX or EDX
18H4CX or ECX
1CH4AX or EAX
20H2CPU status flags
22H2ES
24H2DS
26H2FS
28H2GS
2AH2IP
2CH2CS
2EH2SP
30H2SS
The callback procedure can then extract its parameters from the real mode register data structure and/or copy parameters from the real mode stack to the protected mode stack. Recall that the segment register fields of the real mode register data structure contain segment or paragraph addresses that are not valid in protected mode. Far pointers passed in the real mode register data structure must be translated to virtual addresses before they can be used. The recommended procedure is for the DPMI client to allocate a selector for this purpose during its initialization, then use Int 31H Function 0007H within the callback procedure to set the segment base to 16 times the value found in the real mode segment register. The DPMI client should not use Int 31H Function 0002 for this purpose, because selectors allocated by Function 0002 can never be freed.

The callback procedure exits by executing an IRET with the address of the real mode register data structure in ES:(E)DI, passing information back to the real mode caller by modifying the contents of the real mode register data structure and/or manipulating the contents of the real mode stack. The callback procedure is responsible for setting the proper address for resumption of real mode execution into the real mode register data structure; typically, this is accomplished by extracting the return address from the real mode stack and placing it into the CS:IP fields of the real mode register data structure. After the IRET, the DPMI host switches the CPU back into real mode, loads all registers (including CS:IP) with the contents of the real mode register data structure, and finally returns control to the real mode program.

Since the real mode call structure and the selector used for the real mode SS are static, care must be taken when writing DPMI client callback procedures that may be reentered (for example, by a real mode program that services hardware interrupt). The simplest method of avoiding reentrancy is to leave interrupts disabled throughout the entire callback procedure. However, if the amount of code executed by the callback is large, the client may find it more desirable to copy the real mode register data structure into a dynamically allocated buffer and then re-enable interrupts and not use the incoming DS any more. The real mode register data structure pointed to by ES:(E)DI upon return from the callback procedure is not required to be at the same address as the original real mode register data structure.

DPMI hosts must provide a minimum of 16 callback addresses per virtual machine. Real mode callbacks are a limited system resource. A DPMI client should always use Int 31H Function 0304H to free any callbacks that it is no longer using.

Example: The following code is an example of a real mode interrupt hook. It hooks the DOS Int 21h and returns an error for the delete file function (AH=41H). Other calls are passed through to DOS. This example demonstrates the techniques used to hook a real mode interrupt. Note that since DOS calls are reflected from protected mode to real mode, the following code will intercept all DOS calls from both real mode and protected mode.

;******************************************************
;
; This procedure gets the current Int 21H real mode
; Seg:Offset, allocates a real mode call-back address,
; and sets the real mode Int 21h vector to the call-
; back address.
;
;******************************************************

Initialization_Code:
			; Create a code segment alias to save data in
			;
	mov ax, 000Ah
	mov	bx, cs
	int	31h
	jc	ERROR
	mov	ds, ax

	assume ds:_TEXT
			; Get current Int 21h real mode SEG:OFFSET
			;
	mov	ax, 0200h
	mov	bl, 21h
	int	31h
	jc	ERROR
	mov	[Orig_Real_Seg], cx
	mov	[Orig_Real_Offset], dx

			; Allocate a real mode call-back
			;
	mov	ax, 0303h
	push	ds
	mov	bx, cs
	mov	ds, bx
	mov	si, OFFSET My_Int_21_Hook
	pop	es
	mov	di, OFFSET My_Real_Mode_Call_Struc
	int	31h
	jc	ERROR

			; Hook real mode int 21h with the call-back
			; address
			;
	mov	ax, 0201h
	mov	bl, 21h
	int	21h
	jc	ERROR

;******************************************************
;
; This is the actual Int 21h hook code.  It will return
; an "access denied" error for all calls made in real
; mode to delete a file.  Other calls will be passed
; through to DOS.
;
; ENTRY:
;    DS:SI -> Real mode SS:SP
;    ES:DI -> Real mode call structure
;    Interrupts disabled
;
; EXIT:
;    ES:DI -> Real mode call structure
;
******************************************************

My_Int_21_Hook:
	cmp	es:	[di.RealMode_AH], 41h
	jne	Chain_To_DOS
			;
			; This is a delete file call (AH=41h).  Simulate
			; an iret on the real mode stack, set the real
			; mode carry flag, and set the real mode AX to 5
			; to indicate an access denied error.
			;
	cld
	lodsw		; Get real mode ret IP
	mov	es:[di.RealMode_IP], ax
	lodsw		; Get real mode ret CS
	mov	es:[di.RealMode_CS], ax
	lodsw		; Get real mode flags
	or	ax,1	; St carry flag
	mov	es:[di.RealMode_Flags], ax
	add	es:[di.RealMode_SP], 6
	mov	es:[di.RealMode_AX], 5
	jmp	My_Hook_Exit
			;
			; Chain to original Int 21h vector by replacing
			; the real mode CS;IP with the original Seg:Offset.
			;
Chain_To_Dos:
	mov	ax, cs:[Orig_Real_Seg]
	mov	es:[di.RealMode_CS], ax
	mov	ax, cs:[Orig_Real_Offset]
	mov	es:[di.RealMode_IP], ax

My_Hook_Exit:
	iret