⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmsutils.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 2 页
字号:
	shr	eax, 14
	cmp	ax, es:[esi].XMS_Total_Pages
	jae	short FXp_try_next_block
	jmp	DebFar FXp_got_block		 ; Y:

FXp_free_done:

;ExitCrit				; END CRITICAL SECTION
popf
	call	ReleaseXMSblocks

	popad

	ret

FreeXMSpages	endp


;========================================================================


;***********************************************************************
; AllocateXMSblock:	This routine allocates a block of XMS memory
;	and adds it to the XMS_Block linked list.  Note that this
;	routine tries to allocate an XMS block that will hold the
;	desired number of pages, but may not be able to do so if there
;	is not a single large enough XMS block available.  If there
;	is not enough memory, the largest available block will be
;	allocated.  The return value (CY flag set or clear) indicates
;	if any XMS memory was allocated.
;
; Entry: (Protected Mode)
;	BX = # 16k pages needed
; Exit:
;	CY clear if an XMS block allocated
;	CY set if nothing allocated
; Used:
;	EAX, EBX, ECX, DX
;***********************************************************************
	public	AllocateXMSblock

AllocateXMSblock proc	near

	AssertSegReg	es, DATA32_GSEL
	AssertSegReg	gs, RCODEA_GSEL

	push	esi
	push	edi

;  Make sure the number of pages to allocate is at least our min allocation
;  block size and still small enough to be mapped with EMS handle space.

	cmp	bx, MIN_XMS_ALLOC_SIZE / 16 ; asking for our min block size?
	jae	short AXb_big_enough	    ; (bx in 16k pages, not k)
	movzx	ebx, [XMS_Block_Cnt]
	cmp	bx, XMS_SIZE_ENTRIES
	jb	AXb_get_size
	mov	bx, XMS_SIZE_ENTRIES - 1
AXb_get_size:
	mov	bx, [XMS_Block_Size][ebx*2]
AXb_big_enough:

	mov	ax, [BotOfVCPIspace]
	sub	ax, [TopOfFreeEMSspace] ; ax = # additional XMS pages that
	shr	ax, 2			;   can be added to EMS pool

	cmp	ax, bx
	jae	short AXb_small_enough
	mov	bx, ax
AXb_small_enough:

;  Add overhead pages to contain the XMS_Block structure and free page list.
;  We always add one 4k page (which is usually enough) to hold XMS_Block and
;  the free list, and to make sure that the free XMS 16k pages start on a
;  4k page boundry (XMS blocks are 1k aligned).  The overhead size in bytes
;  is SIZE XMS_Block + 2 * (number usable pages + 1)

	mov	cx, 4			; always add 4k for overhead/alignment

	movzx	eax, bx
	inc	ax
	lea	eax, [eax*2+SIZE XMS_Block]	; actual overhead size

	sub	ax, 1024		; alignment page gives 1k overhead--
	jb	short AXb_overhead_set	;   which is enough for most cases

	pDebugF "AllocXMSBlock: large overhead block, untested code"
	pDebugBreak

	add	ax, PAGE_SIZE - 1	; otherwise add enough 4k pages to
	shr	ax, 10			;   cover additional overhead
	add	cx, ax
AXb_overhead_set:

	shl	bx, 4			; 16k pages to k
	add	bx, cx			; add overhead / alignment size

ifdef DEBUG
	push	bx			; save requested size
endif
	mov	ax, ALLOC_XMS_BLOCK
	call	CallRealModeRtn

ifdef DEBUG
	pop	cx
	cmp	ax, cx
	jz	short AXb_got_em_all
	pDebugF "AllocXMSblock: requested %d, got %d\n", <cx, ax>
AXb_got_em_all:
endif

	; ax=block size (in k), ebx = physical address, dx=XMS handle

	or	ax, ax			; returns 0 size if failed
	jz	AXb_failed

;  We may not have gotten a block as large as we wanted, so recalculate the
;  amount of overhead needed to control the actual block.

	movzx	ecx, ax
	shr	cx, 4			  ; size in k to # 16k pages
	inc	cx			  ; overhead (bytes) = SIZE XMS_Block +
	lea	ecx, [ecx*2+SIZE XMS_Block] ;		       2 * (# pages + 1)

	mov	edi, ebx		; edi -> XMS_Block struc for this block
	lea	ebx, [ebx+ecx+PAGE_SIZE-1]
	and	bx, NOT (PAGE_SIZE - 1) ; ebx -> 1st page after overhead area

	movzx	eax, ax
	shl	eax, 10 		; size in k to bytes
	lea	ecx, [eax+edi]		; end of block
	sub	ecx, ebx		; size of free page area in bytes
	shr	ecx, 14 		; ...................... in 16k pages

;  Initialize XMS_Block fields

	mov	es:[edi].XMS_Next, 0
	mov	es:[edi].XMS_Handle, dx
	mov	es:[edi].XMS_Total_Pages, cx
	mov	es:[edi].XMS_Free_Pages, cx
	mov	es:[edi].XMS_Base_Page, ebx

;  Initialize the block's list of free pages

	xor	ax, ax
	push	edi
	add	edi, XMS_Free_Head
	.errnz	XMS_Free_List - XMS_Free_Head - 2

	cld
AXb_set_free_list:
	STOS_WORD_PTR_ES_EDI
	inc	ax
	loop	AXb_set_free_list

	mov	ax, -1				; one more to terminate list
	STOS_WORD_PTR_ES_EDI

	pop	edi

;  Add new XMS block to list of other blocks

;EnterCrit				; BEGIN CRITICAL SECTION
pushf
cli
	inc	[XMS_Block_Cnt]
	mov	esi, [XMS_Block_List]
	or	esi, esi
	jnz	short AXb_find_end

	mov	[XMS_Block_List], edi	; 1st XMS block allocated
	jmp	short AXb_done

AXb_find_end:
	mov	ebx, esi
	mov	esi, es:[esi].XMS_Next
	or	esi, esi
	jnz	short AXb_find_end

	mov	es:[ebx].XMS_Next, edi	; add to end of list

AXb_done:

;ExitCrit				; END CRITICAL SECTION
popf
	clc				; Success!
	jmp	short AXb_exit

AXb_failed:
	stc				; Failure

AXb_exit:
	pop	edi
	pop	esi
	ret

AllocateXMSblock endp


;***********************************************************************
;  ReleaseXMSblocks:	This routine scans the list of XMS_Blocks and
;	frees any that have no allocated pages.
;
;  Entry: (Protected mode)
;	None.
;  Exit:
;	None.
;  Used:
;	AX
;***********************************************************************
	public	ReleaseXMSblocks

ReleaseXMSblocks proc	near

	AssertSegReg	es, DATA32_GSEL
	AssertSegReg	gs, RCODEA_GSEL

	push	ebx
	push	edx
	push	esi

RXb_scan_list:

;EnterCrit				; BEGIN CRITICAL SECTION
pushf
cli
	mov	ebx, [p_data]
	add	ebx, offset _DATA:XMS_Block_List    ; EBX -> [XMS_Block_List]
	.errnz	XMS_Next
	mov	esi, [XMS_Block_List]

RXb_check_block:
	or	esi, esi
	jz	short RXb_none_to_free

	mov	ax, es:[esi].XMS_Free_Pages
	cmp	ax, es:[esi].XMS_Total_Pages	; Q: all pages free in block?
	jne	short RXb_check_next		; N:

	mov	edx, es:[esi].XMS_Next
	mov	es:[ebx].XMS_Next, edx
	dec	[XMS_Block_Cnt]

;ExitCrit				; END CRITICAL SECTION
popf
	mov	dx, es:[esi].XMS_Handle

	pDebugF "ReleaseXMSblocks: freeing block %lxh handle %xh\n", <esi, dx>

	mov	ax, FREE_XMS_BLOCK
	call	CallRealModeRtn

	jmp	short RXb_scan_list

RXb_check_next:
	mov	ebx, esi
	mov	esi, es:[esi].XMS_Next
	jmp	short RXb_check_block

RXb_none_to_free:

;ExitCrit				; END CRITICAL SECTION
popf
	pop	esi
	pop	edx
	pop	ebx

	ret

ReleaseXMSblocks endp

_TEXT	ends

;========================================================================

R1_CODE segment
	assume	cs:R1_CODE, ds:NOTHING, es:NOTHING, fs:NOTHING, gs:NOTHING

;***********************************************************************
; rQueryXMSpages:   This routine checks free XMS blocks to see if a
;	specific number of 16k pages are available.  This routine only
;	looks for the requested number of pages, the returned value
;	may be less than the total number free as long as the requested
;	number are found.  If the total number of requested pages are
;	not free, the returned value will be the total number of free
;	pages.	In other words, this routine looks for free pages until
;	it either finds the number wanted, or it runs out of free pages.
;
; Entry: (Virtual Mode)
;	BX = Number of 16k XMS pages desired.
; Exit:
;	AX = # XMS pages available
; Used:
;
;***********************************************************************
	public	rQueryXMSpages

rQueryXMSpages proc near

	call	SetIFflag	; invoked like an int routine, enable ints
				;   if caller had them enabled
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	ds
	mov	ax, seg R_CODE
	mov	ds, ax
	assume	ds:R_CODE

	xor	si, si			; # free 16k pages found so far
	mov	di, MAX_NUM_XMS_BLKS	; limit how far we'll look

	push	0		; null handle to end free block loop

;  Get size of largest free XMS block and determine the number of 16k
;  pages it can contain.  Each block will contain at least one page of
;  overhead for alignment and the free page list.

rQF_next:
	push	bx		; XMS calls return error code in BL
	mov	ah, 08h 	; query free extended memory
	call	[XMMcontrol]	; sets ax=largest free, dx=total free
	pop	bx

	cmp	ax, MIN_XMS_BLK_SIZE	; don't mess with tiny XMS blocks
	jb	short rQF_done

	push	ax			; save size in k
	shr	ax, 4			; k to 16k pages
	mov	cx, 4			; always sub 4k for overhead/alignment
	movzx	eax, ax
	inc	ax
	lea	eax, [eax*2+SIZE XMS_Block]	; actual overhead size

	sub	ax, 1024		; alignment page gives 1k overhead--
	jb	short rQF_overhead_set	;   which is enough for most cases

	add	ax, PAGE_SIZE - 1	; otherwise sub enough 4k pages to
	shr	ax, 10			;   cover additional overhead
	add	cx, ax
rQF_overhead_set:

	pop	ax		; block size in k
	neg	cx
	add	cx, ax		; less overhead / alignment size

	shr	cx, 4		; k to 16k pages
	add	si, cx		; accumulate free 16k pages

	cmp	si, bx		; quicker exit if found enough free
	jae	short rQF_done

	cmp	ax, dx		; if largest == total, this is the last block
	je	short rQF_done	;   available so don't need to allocate it

;  Allocate largest block to find out what the next largest block is

	mov	dx, ax		; allocate the largest free block
	push	bx		; XMS calls return error code in BL
	mov	ah, 09h 	; allocate extended memory block
	call	[XMMcontrol]
	pop	bx

	or	ax, ax		; ax = 0 if allocation failed, shouldn't
	jz	short rQF_done	;   happen, but...

	push	dx		; save handle to this XMS block

	dec	di		; look for another block if there aren't too
	jnz	short rQF_next	;   many of them

	;fall through to rQF_done

;  Free the blocks allocated above

rQF_done:

	pop	dx		; XMS handle or terminating 0
	or	dx, dx
	jz	short rQF_exit

	mov	ah, 0Ah 	; free extended memory block
	call	[XMMcontrol]
	jmp	short rQF_done

rQF_exit:
	mov	ax, si		; accumulated free pages

	pop	ds
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx

	iret			; NOTE: IRET, not ret

rQueryXMSpages endp

;***********************************************************************
; rAllocateXMSblock:	This routine allocates a block of XMS memory
;	and returns info about the block.
;
; Entry:
;	BX = max block size wanted, in k
; Exit:
;	AX = block size allocated, in k
;	EBX= physical address of block
;	DX = XMS handle to block
; Used:
;
;***********************************************************************
	public rAllocateXMSblock

rAllocateXMSblock   proc    near

	call	SetIFflag	; invoked like an int routine, enable ints
				;   if caller had them enabled
	push	ds
	mov	ax, seg R_CODE
	mov	ds, ax
	assume	ds:R_CODE

	push	bx
	mov	ah, 08h 		; query free XMS memory
	call	[XMMcontrol]
	pop	bx

	cmp	ax, bx			; Q: can we get all that's wanted?
	jae	short rAXb_get_it_all	; Y:
	cmp	ax, MIN_XMS_BLK_SIZE	; N: Q: is there at least the min?
	jae	short rAXb_get_biggest	;    Y: get that amount
	jmp	DebFar rAXb_fail

rAXb_get_it_all:
	mov	ax, bx

rAXb_get_biggest:
	push	ax			; save size to alloc

	mov	dx, ax
	mov	ah, 09h 		; allocate extended memory block
	call	[XMMcontrol]
	or	ax, ax
	jz	short rAXb_fail_alloc

	push	dx			; save block handle

	mov	ah, 0Ch 		; lock extended memory block
	call	[XMMcontrol]
	or	ax, ax
	jz	short rAXb_fail_lock	; shouldn't happen, but...

	xchg	bx, dx
	shl	ebx, 16
	mov	bx, dx			; ebx = physical address of block

	pop	dx			; dx = XMS handle
	pop	ax			; ax = block size

	rDebugF "rAllocXMSblock: %dk @ %lxh handle %xh\n", <ax, ebx, dx>

	pop	ds

	iret			; NOTE: IRET, not ret

rAXb_fail_lock:
	pop	dx			; XMS handle
	mov	ah, 0Ah 		; free extended memory block
	call	[XMMcontrol]

	rDebugF "rAllocXMSblock: lock failed!\n"

rAXb_fail_alloc:
	pop	ax			; size to alloc

	rDebugF "rAllocXMSblock: alloc of %dk failed!\n", ax

rAXb_fail:
	xor	ax, ax			; 0 allocated size means failure

	pop	ds

	iret			; NOTE: IRET, not ret

rAllocateXMSblock   endp

;***********************************************************************
; rFreeXMSblock:	This routine returns an XMS block to the XMS
;	memory manager.
;
; Entry: (Virtual mode)
;	DX = handle of XMS block to free
; Exit:
;
; Uses:
;	AX, BX
;***********************************************************************
	public rFreeXMSblock

rFreeXMSblock	proc	near

	call	SetIFflag	; invoked like an int routine, enable ints
				;   if caller had them enabled
	push	ds
	mov	ax, seg R_CODE
	mov	ds, ax
	assume	ds:R_CODE

	;;;rDebugF "rFreeXMSblock: freeing handle %xh\n", dx

	mov	ah, 0Dh 	; unlock extended memory block
	call	[XMMcontrol]
	mov	ah, 0Ah 	; free extended memory block
	call	[XMMcontrol]

ifdef DEBUG
	cmp	ax, 1
	jz	short @f
	rDebugF "rFreeXMSblock: free handle %xh failed!\n", dx
	rDebugBreak
@@:
endif
	pop	ds

	iret

rFreeXMSblock	endp


;***********************************************************************
; SetIFflag:	Helper routine to set IF flag based on flags in IRET
;	frame on stack.
;
; Entry: (Virtual mode)
;	SP-> [IP] [IP] [CS] [FL]
; Exit:
;	Interrupts may be enabled.
; Uses:
;	AX, BX
;***********************************************************************
	public SetIFflag

SetIFflag proc	near

	push	bp			;	 0    2    4	6    8
	mov	bp, sp			; bp -> [bp] [ip] [ip] [cs] [fl]

	test	byte ptr [bp+9], 2	; Q: int's enabled in stack image of
	jz	short IF_set		;    flags?

	sti				; Y:
IF_set:
	pop	bp
	ret

SetIFflag endp


R1_CODE ends

END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -