;
;	mreal.asm - Real mode assembler code for MDRAW
;
;************************************************************************/
;*	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	*/
;************************************************************************/

;
; Set segment ordering for segments.  By giving our real mode segments
; unique names, and then
; making this the first file input to the linker, the linker will order
; these segments first in memory.  This will ensure they will end up in
; the first 64K of the protected mode program's segment, which is required.
;
; Since both Microsoft 32-bit C/C++ and Watcom C/386 want the first
; segment class to be the CODE class, we put all our real mode segments
; in that class.
;
REALSTART segment public byte 'CODE'
	public	StartReal,_StartReal,StartReal_
StartReal label	near		; beginning of real mode code & data
_StartReal label near
StartReal_ label near
REALSTART ends
REALCODE segment public byte use16 'CODE'
REALCODE ends
REALDATA segment public dword 'CODE'
REALDATA ends
REALEND segment public byte 'CODE'
	public	EndReal,_EndReal,EndReal_
EndReal label	near		; end of real mode code & data
_EndReal label	near
EndReal_ label	near
REALEND ends
_TEXT segment public byte use32 'CODE'
_TEXT ends
_DATA segment public dword 'DATA'
_DATA ends

;
; Global data in our prot mode data segment
;
_DATA segment
	public	ProtMouHandp,_ProtMouHandp,ProtMouHandp_
_ProtMouHandp label dword
ProtMouHandp_ label dword
ProtMouHandp dd	?	; NEAR addr of protected mode mouse handler, init'd
				; by C code

;
; 8K stack for use on calls from real mode to protected mode
;
	align	4
	db	2000h dup (?)	
ProtTopOfStack label dword

_DATA ends

;
; Global data in our real mode data segment
;
REALDATA segment
	public	CallProtFuncp,_CallProtFuncp,CallProtFuncp_
_CallProtFuncp label dword
CallProtFuncp_ label dword
CallProtFuncp dd ?	; FAR addr of real mode 386|DOS-Extender routine to
				; use to call thru to prot mode.  This is
				; initialized by the C code in MDRAW.C

	public	ProtCodeSeg,_ProtCodeSeg,ProtCodeSeg_
_ProtCodeSeg label word
ProtCodeSeg_ label word
ProtCodeSeg dw	?	; Protected mode CS value.  Initialized by C code.

REALDATA ends

	assume	cs:REALCODE,ds:REALDATA
REALCODE segment
	public	RealMouHand,_RealMouHand,RealMouHand_
RealMouHand label near	; 32-bit NEAR offset for protected mode
_RealMouHand label near
RealMouHand_ label near
Handler proc	far	; FAR proc in real mode
;
; Note the mouse driver only preserves the 16-bit registers around the
; call to this handler.  Since we use 32-bit registers, we have to save
; the registers ourselves.
;
	pushad			; save all regs
	push	ds			;

;
; Since the real mode code & data is all linked together as one segment in 
; prot mode, all offsets are relative to the same base, and DS is the same
; as CS
;
	push	cs
	pop	ds

;
; Call prot mode "glue" routine
;
	and	edx,0FFFFh		; vertical (Y) cursor position
	push	edx				;
	and	ecx,0FFFFh		; horizontal (X) cursor position
	push	ecx				;
	and	eax,0FFFFh		; condition mask
	push	eax				;
	push	dword ptr 3		; number of DWORD parameters
	push	dword ptr 0		; use default prot mode seg regs
	push	ProtCodeSeg		; addr of prot mode "glue" routine
	lea	eax,ProtGlue			;
	push	eax				;
	call	CallProtFuncp		; call prot mode routine
	add	sp,26			; pop parameters

	pop	ds		; restore all regs
	popad				;
	ret			; return to mouse driver
Handler endp

REALCODE ends

	assume	cs:_TEXT,ds:_DATA,es:_DATA
_TEXT segment

;
; void ProtGlue(ULONG nDwordParams, ...)
;
; We need an assembly language "glue" routine on the protected mode side
; to deal with two things:
;	1.  It gets called with a FAR procedure call
;	2.  Switch back to a stack in the data segment (32-bit C code
;		requires SS and DS to be the same).
; Note this routine takes in the number of stack parameters to copy to
; the protected mode stack, so it can be used as a general-purpose protected
; mode gateway.  
;
; NOTE:	This implementation always uses the same stack buffer for every 
;	call, so it is NOT reentrant.  If you need reentrant calls to
; 	protected mode, you'll have to dynamically obtain a valid protected 
; 	mode stack pointer on each call to protected mode.  (For this sample
;	program, it's OK to not be reentrant, because the real mode mode
;	driver prevents reentering a mouse handler).
;
	public	ProtGlue
ProtGlue proc	far

;
; Make sure Direction Flag is clear for C code
;
	cld

;
; Switch stacks, and copy parameters to new stack.  We can freely use
; the general registers here, since they are all saved in the real mode
; handler.  We have to preserve any segment registers.
;
	mov	dx,ss		; save current stack pointer
	mov	esi,esp			;
	mov	ax,ds		; switch to new stack
	lea	ebx,ProtTopOfStack	;
	mov	ss,ax			;
	mov	esp,ebx			;
	push	edx		; save old stack pointer on top of new stack
	push	esi			;
	assume	ds:nothing
	mov	ds,dx		; set DS:ESI to params on old stack
	add	esi,8			;
	mov	ecx,ds:[esi]	; get DWORD param count
	inc	ecx			;
	mov	eax,ecx		; allocate space on stack
	shl	eax,2			;
	sub	esp,eax			;
	mov	edi,esp		; copy the parameters to the new stack
	rep movsd			;
	mov	ax,ss		; restore DS
	mov	ds,ax			;
	assume	ds:_DATA		;

	call	ProtMouHandp	; call the C handler function

	pop	eax		; pop the params off the stack
	shl	eax,2			;
	add	esp,eax			;
	lss	esp,pword ptr [esp] ; switch back to original stack
	ret			; return to real mode code
ProtGlue endp

_TEXT ends

end
