At one point in its execution or another, every DPMI client runs on four different stacks: an application stack, a locked protected mode stack, a real mode stack, and a DPMI host stack. It is important to understand how the host maintains these stacks to fully understand the protected mode environment.

The application stack is the primary stack that the DPMI client executes on. It is initially the real mode stack that the client was on when it switched into protected mode, although nothing prevents the client from switching protected mode stacks at any point after the initial mode switch. Th application stack can be unlocked if desired. Software interrupts executed in protected mode are reflected on this stack.

The locked protected mode stack is provided by the DPMI host. The host automatically switches to this stack during servicing of hardware interrupts, software interrupts 1CH, 23H, and 24H, all exceptions, and during the execution of real mode callbacks. Subsequent nested interrupts or calls will not cause a stack switch. If the client switches off this stack, the new stack must also be locked and will become the protected mode stack until it switches back. When the interrupt or call returns, the host switches back to the original protected mode stack. Note that the host must provide a minimum of one 4 KB locked stack, and that software interrupts other than 1CH, 23H, and 24H do not use this stack. (Refer Appendix D for descriptor usage rule of locked stack.)

The real mode stack is also provided by the DPMI host, and is usually located in the DPMI host data area allocated by the client prior to its initial switch into protected mode. The real mode stack is at least 200H bytes in size and is always located in locked memory. Interrupts that are reflected to real mode, as well as calls to real mode interrupt handlers or procedures via Int 31H Functions 0300H, 0301H, or 0302H, will use this stack.

A DPMI host stack is only accessible to the DPMI host; it is used by the host to handle interrupts and exceptions that occur while the host is executing on behalf of the client. For example, when the client requests a mode switch, the original SS:(E)SP of the protected mode program can be saved on the host stack while the DPMI host switches onto the locked protected mode stack.

There are four different ways that a client can force a mode switch between protected and real mode:

All of these mode switches except for the raw mode switches may save some information on the DPMI host's stack. This means that clients should not terminate within nested mode switches unless they are using the raw mode switching services. However, even clients that use raw mode switches should not attempt to terminate from a hardware interrupt or exception handler or real mode callback because the DPMI host performs automatic mode and stack switching during these events.

Clients that use the raw mode switch services and perform nested mode switches must use the DPMI state save/restore functions (whose addresses may be obtained with Int 31H Function 0305H), causing the host to maintain information on the "other" mode's current state. This information includes the CS:(E)IP, SS:(E)SP, and other segment register contents; values that the client has no way to access directly. For example, during the service of a hardware interrupt that occurs in real mode, the DPMI host may preserve the real mode CS:(E)IP, SS:(E)SP, and segment registers on the host stack, causing a return to the wrong address when the handler finally executes the IRET.

Example: This example illustrates code that saves the state of the real mode registers using the DPMI save/restore function, switches to real mode using the raw mode switch service, issues a DOS call to open a file, switches back to protected mode using the raw mode switch service, and restores the state of the real mode registers using the save/restore function. The protected mode registers are saved by pushing them on the stack in the usual fashion. The example is intended only to show the logical sequence of execution; in a real program, the real mode and protection mode variables and functions would likely reside in separate segments.


savsiz	dw	0			; size of state information
realsrs	dd	0			; far pointer to real mode
					; save/restore state entry point
protsrs	dd	0			; far pointer to protected mode
					; save/restore state entry point
realrms	dd	0			; far pointer to real mode
					; raw mode switch entry point
protrms	dd	0			; far pointer to protected mode
					; raw mode switch entry point

protdw	dw	0			; placeholder for protected mode DS
protip	dw	0			; placeholder for protected mode IP
protcs	dw	0			; placeholder for protected mode CS
protsp	dw	0			; placeholder for protected mode SP
protss	dw	0			; placeholder for protected mode SS
	.
	.
	.

					; this code is executed during
					; application initialization

	mov	ax,305h			; get addresses of DPMI host's
	int	31h			; state save/restore entry points
	mov	savsiz,ax		; save state info buffer size
	mov	word ptr realsrs,cx	; BX:CX = state save/restore
	mov	word ptr realsrs+2,bx	; entry point for real mode
	mov	word ptr protsrs,di	; SI:DI = state save/restore
	mov	word ptr protsrs+2,si	; entry point for protected mode

	mov	ax,306h			; get address of DPMI host's
	int	31h			; raw mode switch entry points
	mov	savsiz,ax		; save state info buffer size
	mov	word ptr realrms,cx	; BX:CX = raw mode switch
	mov	word ptr realrms+2,bx	; entry piont for real mode
	mov	word ptr protrms,di	; SI:DI = raw mode switch
	mov	word ptr protrms+2,si	; entry point for protected mode
					; must also initialize the
					; sp and realss variables
	.
	.
	.

					; this code is executed during
					; program execution
callopenfile proc
	pusha				; save protected mode registers
	push	es

	sub	sp,savsiz		; allocate space on current stack
	mov	di,sp			; to save real mode state
	mov	ax,ss			; set ES:DI = address of buffer
	mov	es,ax			; to receive state information
	xor	al,al			; AL=0 for save state request
	call	protsrs			; call state save/restore routine

	mov	protds,ds		; save current DS for switch back
	mov	protss,ss		; save current SS
	mov	protsp,sp		; save current SP
	mov	protip,offset returnfromreal ; save return IP
	mov	protcs,cs		; save return CS

	mov	ax,seg filename		; load real mode DS
	mov	ds,realss		; load real mode SS
	mov	bx,realsp		; load real mode SP
	mov	si,seg openfile		; load real mode CS
	mov	di,offset openfile	; load real mode IP
	
	jmp	protrms			; go to openfile

returnfromreal:
	mov	ax,ss			; let ES:DI = address of buffer
	mov	es,ax			; holding state information
	mov	di,sp
	mov	al,1			; AL=1 to restore state
	call	protsrs			; call state restore routine
	add	sp,savsiz		; discard state info buffer
	pop	es
	popa				; restore protected mode registers
	ret
callopenfile endp

	.
	.
	.
	
					; this code is executed in real mode
openfile proc
	mov	dx,offset filename
	mov	ah,3dh			; issue Open File DOS call
	int	21h
	jc	openerr			; check for error (not shown here)
	mov	filehandle,bx		; save file handle
	mov	ax,protds		; load protected mode DS
	mov	dx,protss		; load protected mode SS
	mov	bx,protsp		; load protected mode SP
	mov	si,protcs		; load protected mode CS
	mov	di,protip		; load protected mode IP
	jmp	realrms

openfile endp