;/* himem5.asm
; *
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1988-1991
; * All Rights Reserved.
; *
; * Modification History
; *
; * Sudeepb 14-May-1991 Ported for NT XMS support
; */
	page	95,160
	title	himem5.asm - Extended Memory Moves

;
;----------------------------------------------------------------------------
;
; M001 : inserted a jmp $+2 between an out & in while reading the ISR
; M003 : fixed bug to do with not returning int 15h errors on a blockmove
;	call.
;
;----------------------------------------------------------------------------
;
	.xlist
	include	himem.inc
        include xmssvc.inc
        include vint.inc
	.list


	extrn	TopOfTextSeg:word
	extrn	hiseg:word
	extrn	pReqHdr:dword
	extrn	dd_int_loc:word
	extrn	interrupt:word


	extrn	fInHMA:byte
	extrn	EndText:byte
_text	ends

funky	segment	word public 'funky'
	assume	cs:funky

	extrn	KiddValley:word
	extrn	KiddValleyTop:word
	extrn	end_of_hiseg:word
	extrn	textseg:word
	extrn	LEnblA20:dword
        extrn   LDsblA20:dword
        extrn   FunkyCLI:near
        extrn   FunkySTI:near


;******************************************************************************
;
; MoveBlock
;	XMM Move Extended Memory Block
;
; Entry:
;	ES:SI	Points to structure containing:
;		bCount		dd	?	; Length of block to move
;		SourceHandle	dw	?	; Handle for souce
;		SourceOffset	dd	?	; Offset into source
;		DestHandle	dw	?	; Handle for destination
;		DestOffset	dd	?	; Offset into destination
;
; Return:
;	AX = 1	Success
;	AX = 0	Failure
;		Error code in BL
;
; Registers Destroyed:
;	Flags
;
;------------------------------------------------------------------------------

    public MoveBlock

MoveBlock proc	far
	assume	ds:_text

        call    FunkySTI                        ; Be nice
	push	bp				; Set up stack frame so we
	mov	bp, sp				; can have local variables
	sub	sp, 18				; Space for local variables

; Following Ordering is used in xms.dll and should be retained
; as is or changed in both places.

Count	  = -4					; Local DWORD for byte count
SrcLinear = -8
DstLinear = -12
MEReturn  = -14				; Local WORD for return code
SrcHandle = -16
DstHandle = -18
	push	bx
	push	dx

	xor	ax, ax
	mov	[bp.MEReturn], ax		; Assume success
	mov	[bp.SrcHandle], ax
	mov	[bp.DstHandle], ax
	mov	ax, word ptr es:[si].bCount	; Pick up length specified
	mov	word ptr [bp.Count], ax
	mov	cx, word ptr es:[si].bCount+2
	mov	word ptr [bp.Count+2], cx
	or	cx, ax
	jcxz	MEM2_Exit			; Exit immediately if zero

	lea	bx, [si].SourceHandle		; Normalize Source
	call	GetLinear			; Linear address in DX:AX
	jc	MEM2_SrcError			; Have Dest Error Code

	mov	word ptr [bp.SrcLinear], ax	; Save Linear address
	mov	word ptr [bp.SrcLinear+2], dx
	mov	[bp.SrcHandle], bx		; Save Handle for Unlock

	lea	bx, [si].DestHandle		; Normalize Destination
	call	GetLinear
	jc	MEM2_Error

	mov	word ptr [bp.DstLinear], ax	; Save Linear address
	mov	word ptr [bp.DstLinear+2], dx
	mov	[bp.DstHandle], bx		; Save Handle for Unlock

	shr	word ptr [bp.Count+2], 1	; Make word count
	rcr	word ptr [bp.Count], 1
	jc	MEM2_InvCount			; Odd count not allowed

	call	LEnblA20
	cmp	ax, 1
	jne	MEM2_Error

	XMSSVC	XMS_MOVEBLOCK			; Call Worker
						; Parameters on the stack

	call	LDSblA20
	cmp	ax, 1
	jne	MEM2_Error

MEM2_Exit:
	mov	bx, [bp.SrcHandle]		; Unlock Handles if necessary
	or	bx, bx
	jz	NoSrcHandle
	dec	[bx].cLock			; Unlock Source
NoSrcHandle:
	mov	bx, [bp.DstHandle]
	or	bx, bx
	jz	NoDstHandle
	dec	[bx].cLock			; Unlock Destination
NoDstHandle:
	pop	dx
	pop	bx
	mov	ax, 1
	cmp	word ptr [bp.MEReturn], 0
	jz	MEM2_Success
	dec	ax
	mov	bl, byte ptr [bp.MEReturn]
MEM2_Success:
	mov	sp, bp				; Unwind stack
	pop	bp
	ret

MEM2_SrcError:
	cmp	bl, ERR_LENINVALID		; Invalid count
	je	MEM2_Error			;  yes, no fiddle
	sub	bl, 2				; Convert to Source error code
	jmp	short MEM2_Error
MEM2_InvCount:
	mov	bl, ERR_LENINVALID
MEM2_Error:
	mov	byte ptr [bp.MEReturn], bl	; Pass error code through
	jmp	short MEM2_Exit
MoveBlock endp

;*******************************************************************************
;
; GetLinear
;	Convert Handle and Offset (or 0 and SEG:OFFSET) into Linear address
;	Locks Handle if necessary
;
; Entry:
;	ES:BX	Points to structure containing:
;			Handle	dw
;			Offset	dd
;	[BP.Count]	Count of bytes to move
;
; Return:
;	BX	Handle of block (0 if conventional)
;	AX:DX	Linear address
;	CARRY	=> Error
;		Error code in BL
;
; Registers Destroyed:
;	Flags, CX, DI
;
;-------------------------------------------------------------------------------

GetLinear	proc	near
	push	si
        call    FunkyCLI                        ; NO INTERRUPTS
	mov	si, word ptr es:[bx+2]		; Offset from start of handle
	mov	di, word ptr es:[bx+4]		; in DI:SI
	mov	bx, word ptr es:[bx]		; Handle in bx
	or	bx, bx
	jz	GL2_Conventional

	test	[bx].Flags, USEDFLAG		; Valid Handle?
	jz	GL2_InvHandle

	mov	ax, [bx].Len			; Length of Block
	mov	cx, 1024
	mul	cx				; mul is faster
	sub	ax, si
	sbb	dx, di				; DX:AX = max possible count
	jc	GL2_InvOffset			; Base past end of block
	sub	ax, word ptr [bp.Count]
	sbb	dx, word ptr [bp.Count+2]
	jc	GL2_InvCount			; Count too big

	inc	[bx].cLock			; Lock the Handle
	mov	ax, [bx].Base
	mul	cx
	add	ax, si				; Linear address
	adc	dx, di				; in DX:AX

GL2_OKExit:
	clc
GL2_Exit:
        call    FunkySTI
	pop	si
	ret

GL2_Conventional:
	mov	ax, di				; Convert SEG:OFFSET into
	mov	dx, 16				; 24 bit address
	mul	dx
	add	ax, si
	adc	dx, 0				; DX:AX has base address
	mov	di, dx
	mov	si, ax
	add	si, word ptr [bp.Count]		; Get End of Block + 1 in DI:SI
	adc	di, word ptr [bp.Count+2]

	cmp	di, 010h			; Make sure it doesn't wrap
	ja	GL2_InvCount			;  past the end of the HMA
	jb	GL2_OKExit
	cmp	si, 0FFF0h
	jbe	GL2_OKExit			; Must be < 10FFF0h
GL2_InvCount:
	mov	bl, ERR_LENINVALID
	jmp	short GL2_Error

GL2_InvHandle:
	mov	bl, ERR_DHINVALID		; Dest handle invalid
	jmp	short GL2_Error

GL2_InvOffset:
	mov	bl, ERR_DOINVALID		; Dest Offset invalid
GL2_Error:
	stc
	jmp	short GL2_Exit

GetLinear	endp


;*----------------------------------------------------------------------*
;*									*
;*   pack_and_truncate - packs everything down into the			*
;*	lowest available memory and sets up variable for driver		*
;*	truncation, then terminates.					*
;*									*
;*----------------------------------------------------------------------*

	public	pack_and_truncate
pack_and_truncate	proc	far

	assume	ds:_text,es:nothing
	push	ds
	mov	dx, offset _text:EndText	; end of text seg
	add	dx, 15
	and	dx, not 15		; size of text seg including init code

	mov	ax, TopOfTextSeg	; end of resident text seg
	or	ax, ax
	jnz	@f
	xor	di, di
	pop	es
	jmp	short InitFailed
	
@@:
	add	ax, 15
	and	ax, not 15		; size of resident text seg

	sub	dx, ax			; size of memory whole between
	shr	dx, 4			;  resident text seg and funky seg
					;  The funky seg should be moved down
					;  'dx' number of paragraphs
	mov	ax, hiseg		; Get the current seg at which funky
					;  is running from

	cmp	ax, dx			; If funky is already running from a
					;  segment value less than 'dx'
					;  number of paras funky can be
					;  moved to zero segment only
	jbe	@f
	mov	ax, dx			; ax has min of seg of funky
					;             & memory whole size in para
@@:
	or	ax, ax			; if funky is to be moved by zero
					;  paras our job is over
	jnz	@f
	mov	es, hiseg
	assume es:funky
	mov	di, es:KiddValleyTop
	jmp	NoMoveEntry
@@:
	mov	dx, hiseg		; current segment value of funky
	push	ds
	pop	es
	assume	es:_text
	mov	ds, dx			; which is our source for move
	assume	ds:nothing
	sub	dx, ax			; less the 'paras' to be shrinked
	mov	hiseg, dx		; is the new seg value of funky
	mov	es, dx			; which is our dest. for the move
	assume	es:nothing
	mov	si, HISEG_ORG
	mov	di, si
	mov	cx, end_of_hiseg
	sub	cx, si			; size of funky without ORG
	cld
	rep	movsb			; move it!!!

;;
MoveHandleTable:
	inc	di			; round to word value
	and	di,0fffeh

	mov	si,di
	assume	es:funky
	xchg	si,es:KiddValley	; replace KiddValley with new location
	mov	cx,es:KiddValleyTop
	sub	cx,si

	rep	movsb			; move the handle table down
	mov	es:KiddValleyTop,di	; update end of table
	assume	es:nothing

NoMoveEntry:
	pop	ds			; restore _text segment
	assume	ds:_text
	add	di,15			; round new segment to paragraph
	and	di,not 15

InitFailed:
	ifdef	debug_tsr
	mov	ax,ds			; # paragraphs to keep =
	mov	dx,es			;   (ES - DS) +
	sub	dx,ax			;      (DI >> 4) +
	mov	ax,di			;	 10h
	shr	ax,4
	add	dx,ax
	add	dx,10h			; PSP size
	mov	ax,3100h
	int	21h
	else
	lds	si,[pReqHdr]		; discard the initialization code
	mov	word ptr ds:[si].Address[0],di
	mov	word ptr ds:[si].Address[2],es
	mov	ds:[si].Status,100h ; Store return code - DONE

	pop	ax		; throw away return from InitDriver

	push	cs
	call	an_iret		; call an iret in our segment

	or	di, di
	jz	we_are_quitting

	mov	ds, textseg
	assume	ds:_text
	mov	ax, hiseg
	mov	dd_int_loc,offset Interrupt	; replace Interrupt with
						; tiny permanent stub

	mov	ax, KiddValleyTop
	sub	ax, KiddValley
	add	ax, end_of_hiseg
	sub	ax, HISEG_ORG		; size of resident funky including
	mov	cs:HMALen, ax

	mov	ax, ((multMULT shl 8)+multMULTGETHMAPTR)
	xor	bx, bx			; in case there is no HMA handler
	int	2fh
	cmp	cs:HMALen, bx
	ja	we_are_quitting

	cmp	di, HISEG_ORG
	ja	we_are_quitting

	mov	bx, cs:HMALen
	mov	ax, ((multMULT shl 8)+multMULTALLOCHMA)
	int	2fh
	cmp	di, 0ffffh
	je	we_are_quitting

	call	MoveHi

we_are_quitting:
	pop	bp
	pop	si
	pop	di
	pop	es
	pop	ds
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret				; far return from driver init
	endif

pack_and_truncate	endp

HMALen		dw	?		; Length of funky (without init code)


;
;---------------------------------------------------------------------------
;
; procedure : MoveHi
;
;---------------------------------------------------------------------------
;
MoveHi	proc	near
	push	di			; remember offset in HMA
	mov	si, HISEG_ORG
	mov	cx, cs:HMALen
	mov	ax, textseg
	mov	ds, ax
	assume	ds:_text
	mov	ds, hiseg
	assume	ds:nothing
	rep	movsb			; move it to HMA
	pop	di			; get back offset in HMA
	mov	ax, HISEG_ORG
	sub	ax, di
	shr	ax, 1
	shr	ax, 1
	shr	ax, 1
	shr	ax, 1
	mov	bx, es
	sub	bx, ax


	mov	ax, textseg
	mov	ds, ax			; get addressability to text seg		
	assume	ds:_text
	mov	fInHMA, 1		; Flag that we are running from HMA

	mov	hiseg, bx
	mov	es, bx

	mov	di, TopOfTextSeg	; end of resident text code
	mov	ax, textseg
	lds	si, pReqHdr
	assume	ds:nothing

	mov	word ptr ds:[si].Address[0],di
	mov	word ptr ds:[si].Address[2],ax
	
	ret
MoveHi	endp

;
an_iret proc near
        FIRET
an_iret	endp

	public	end_of_funky_seg
end_of_funky_seg:
funky	ends
	end


