	.386r
	.387
;
;	real.asm - Real mode assembler code for gserver
;
;************************************************************************/
;*	Copyright (C) 1986-1993 Phar Lap Software, Inc.			*/
;*	Unpublished - rights reserved under the Copyright Laws of the	*/
;*	United States.  Use, duplication, or disclosure by the 		*/
;*	Government is subject to restrictions as set forth in 		*/
;*	subparagraph (c)(1)(ii) of the Rights in Technical Data and 	*/
;*	Computer Software clause at 252.227-7013.			*/
;*	Phar Lap Software, Inc., 60 Aberdeen Ave., Cambridge, MA 02138	*/
;************************************************************************/


	extrn	_gserver:far,_exit:far

	assume	cs:codeseg,ds:nothing

codeseg	segment public byte 'code'


;
;	Variables used by this assembly language code, kept in code segment
;

dssave	dw	?		; Real mode DS register
sssave	dw	?		; Real mode SS register
essave	dw	?		; Real mode ES register
spsave	dw	?		; Real mode SP register
bpsave	dw	?		; Real mode BP register

realpsp	dw	?		; Real mode program's PSP pointer
protpsp	dw	?		; Protected mode program's PSP pointer

spsave2 dw	?		; SP register provided by DOS-Extender
sssave2	dw	?		; SS register provided by DOS-Extender

TRUE	equ	1
FALSE	equ	0
fp387f	dw	?		; T ==> 387 present, F ==> not present
real_387state db 94 dup (?)	; real mode program's floating point state
prot_387state db 94 dup (?)	; protected mode program's floating point state

reptr	dd	_reenter	; Far pointer to _reenter

;
;	protret - Return from real mode back to protected mode
;
;	This routine is called by the real mode server when
;	initialization of the server has been completed.  It returns
;	to the protected mode code which loaded the real mode server.
;	It returns by calling the 386|DOS-Extender protected mode
;	call function.  The address of this function as well as the
;	protected mode return address are taken from the parameter
;	block that is passed into the real mode server as the command
;	tail by the protected mode code.
;

	public	_protret

_protret proc	far

;	First, the real mode PSP segment pointer, the real mode segment
;	registers, and the real mode stack are saved for future calls
;	to the real mode server.

	mov	ah,51h		; Get the address of the PSP into ES.
	int	21h		;
	mov	es,bx		;

	mov	realpsp,bx	; Save the real mode PSP pointer.

	mov	dssave,ds	; Save the current real mode registers.
	mov	sssave,ss	;
	mov	essave,es	;
	mov	bpsave,bp	;
	mov	ax,sp		;
	sub	ax,20h		;
	mov	spsave,ax	;

;
; If we have a 387 present, save the floating point state so we can restore
; it again each time the real mode program is called.  (It's not necessary
; to save the state if there's no coprocessor and we're emulating, since
; the real mode and prot mode emulators won't interfere with each other.
; Since we don't unconditionally do an FSAVE/FRSTOR, someone could pick up
; this glue code and use it with a non-floating-point program without
; having it break on a machine without a coprocessor).
;
	mov	fp387f,FALSE	; assume no coprocessor
	int	11h		; branch if no coprocessor
	test	ax,2			;
	jz	short #no_87		;
	mov	fp387f,TRUE	; flag coprocessor present
	fsave	real_387state	; save current coprocessor state
#no_87:

; 	The following sanity check is done to make sure that the
;	we were called by a protected mode program

	mov	al,es:80h	; Branch if the length of the command
	cmp	al,12		;    tail is not 12.
	jne	#err		;

;	Save the segment address of the protected mode PSP for future
;	calls into the real mode code.

	mov	ax,es:8bh	; Save the protected mode PSP.
	mov	protpsp,ax	;

;	Return to protected mode by calling the 386|DOS-Extender service
;	that calls through to protected mode

	xor	ax,ax		; Zero the parameter block pointer on
	push	ax		;    the stack.
	push	ax		;

	mov	ax,es:89h	; Push the prot mode CS onto
	push	ax		;    the stack.

	mov	ax,es:87h	; Push the protected mode return address
	push	ax		;    onto the stack.
	mov	ax,es:85h	;
	push	ax		;

	mov	eax,reptr	; Load a far pointer to the real mode re-enter 
				;    routine into EAX.

	call	es:(dword ptr 81h) ; Call 386|DOS-X service to call back into 
				   ;      protected mode.

;	When the protected mode code returns to this point, it wants us
;	to exit.

;	Switch to the real mode PSP so that MS-DOS is all happy.

	mov	ah,50h		; Restore the real mode PSP.
	mov	bx,realpsp	;
	int	21h		;

;	Call the C exit routine to terminate and go back to protected mode
;	forever.

	push	0		; Call the C exit routine.
	call	_exit		;


;	Fatal error handler.

#err:	mov	dx,offset #errmsg; Output a fatal error message.
	push	cs		;
	pop	ds		;
	mov	ah,9h		;
	int	21h		;

	mov	ax,4c01h	; Abort.
	int	21h		;

#errmsg	db	'Fatal error: Bad call to real mode server.',0dh,0ah,'$'

_protret endp


;
;	_reenter - Re-enter point for real mode
;
;	This routine is called from protected mode.  Its job is
;	to restore the real mode segment registers, stack, and PSP
;	and then to call the server.
;

	public	_reenter

_reenter proc	far

;
; Switch to the real mode program's floating point state
;
	cmp	fp387f,FALSE	; branch if no 387
	je	short #no_87	;
	fsave	prot_387state	; save prot mode coprocessor state
	frstor	real_387state	; restore real mode coprocessor state
#no_87:

;	First load the segment:offset address of the graphics commands buffer
;	into EDX.  We do this now because the address is on the stack and
;	we are about to switch stacks.

	mov	bp,sp		; Load from the stack, the far pointer to 
	mov	edx,4[bp]	;    graphics commands buffer into EDX.

;	Now switch stacks and restore the real mode segment registers.

	mov	spsave2,sp	; Save the stack pointer (SS:SP) given to us 
	mov	sssave2,ss	;    by 386|DOS-Extender.

	mov	ds,dssave	; Restore the real mode registers and switch
	mov	es,essave	;    stacks.
	mov	ss,sssave	;
	mov	sp,spsave	;
	mov	bp,bpsave	;

;	Switch to the real mode PSP so that MS-DOS is all happy.

	mov	ah,50h		; Restore the real mode PSP.
	mov	bx,realpsp	;
	int	21h		;

;	Call the server with the address of the graphics commands buffer
;	pushed onto the stack as an argument

	push	edx		; Call the graphics server.
	call	_gserver	;

;	Switch back to the protected mode PSP so that MS-DOS stays happy

	mov	ah,50h		; Switch back to the protected mode PSP.
	mov	bx,protpsp	;
	int	21h		;

;	Switch back to the stack provided by 386|DOS-Extender and then
;	return back to the caller that is running in protected mode.

	mov	ss,sssave2	; Switch back to the stack provided by
	mov	sp,spsave2	;    386|DOS-Extender.

;
; Switch back to the protected mode program's floating point state.
;
	cmp	fp387f,FALSE	; branch if no 387
	je	short #no_87_rst ;
	fsave	real_387state	; save real mode coprocessor state
	frstor	prot_387state	; restore prot mode coprocessor state
#no_87_rst:

	ret			; Return back to protected mode caller.

_reenter endp

codeseg	ends

	end
