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

📄 xmsutils.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 2 页
字号:
.386p
page	58,132
;******************************************************************************
	title	xmsutils.asm - XMS utility functions
;******************************************************************************
;
; (C) Copyright MICROSOFT Corp. 1992
;
; Title:	EMM386.EXE - MICROSOFT Expanded Memory Manager 386 Driver
;
; Module:	XMS memory utility functions
;
; Date: 	May 18, 1992
;
;******************************************************************************
;
;   Change log:
;
;     DATE    REVISION			DESCRIPTION
;   --------  --------	-------------------------------------------------------
;   5/18/92	1	initial code
;******************************************************************************
;
;   Functional Description:
;	This module implements utilities for the EMS/XMS pool sharing code
;	added to EMM386.
;
;******************************************************************************

page
;******************************************************************************
; INCLUDES
;******************************************************************************
include	vdmseg.inc
include vdmsel.inc
include vm386.inc
include	page.inc
include	emmfunct.inc
include	emmdata.inc
include emm386.inc
include debmac.inc

;******************************************************************************
; EXTERNALS
;******************************************************************************

_TEXT	segment
	extrn	CallRealModeRtn:near
ifdef DEBUG
	extrn	pTestDbgIns:far
	extrn	pDebugPrintf:far
endif
_TEXT	ends

R_CODE	segment
	extrn	XMMcontrol:DWORD
ifdef DEBUG
	extrn	rTestDbgIns:far
	extrn	rDebugPrintf:far
endif
R_CODE	ends

;******************************************************************************
; EQUATES / STRUCTURES
;******************************************************************************

MAX_NUM_XMS_BLKS   equ	20	; Really weird to have more XMS blocks than this
MIN_XMS_BLK_SIZE   equ	36	; Don't use XMS blocks smaller than this (in k)
MIN_XMS_ALLOC_SIZE equ	256	; Try to alloc at least 256k XMS blocks

; Control structure for each XMS block allocated

XMS_Block	struc
XMS_Next	dd	?	; next XMS_Block in linked list
XMS_Handle	dw	?	; XMS handle to block
XMS_Base_Page	dd	?	; address of 1st aligned 4k page in block
XMS_Total_Pages dw	?	; total # 4k pages in block
XMS_Free_Pages	dw	?	; # 4k pages currently free in block
XMS_Free_Head	dw	?	; index of 1st/next free 4k page in block
XMS_Free_List	dw	?	; linked list of free 4k pages in block
XMS_Block	ends


;******************************************************************************
; LOCAL DATA
;******************************************************************************

_DATA	segment

XMS_Block_List	dd	0	; head of XMS_Block struc linked list
XMS_Block_Cnt	dw	0	; # XMS blocks allocated

; Sizes of XMS blocks to allocate in 16k EMS pages

XMS_Block_Size	label	word
		dw	256 / 16		; 256 k bytes / 16 k pages
		dw	512 / 16
		dw	1024 / 16
		dw	2048 / 16
		dw	4096 / 16
		dw	8192 / 16
		dw	16384 / 16
XMS_SIZE_ENTRIES equ	($ - XMS_Block_Size) / 2


_DATA	ends

page
;=============================================================================
;==	C O D E  S E G M E N T
;=============================================================================
_TEXT	segment
assume	cs:_TEXT,ds:_DATA,ss:STACK,es:ABS0,gs:R_CODE
page
align 16

;***********************************************************************
; QueryXMSpages:    This routine determines if a specified number of
;	XMS "pages" (16k each) are available.
;
; Entry: (Protected Mode)
;	BX = Number of XMS pages desired.
; Exit:
;	CY = clear if desired # XMS pages are available,
;	CY = set if not enough XMS pages available, plus
;		AX = number of XMS pages actually available
; Used:
;	AX
;***********************************************************************
	public	QueryXMSpages

QueryXMSpages proc  near

	AssertSegReg	ds, VDMD_GSEL
	AssertSegReg	es, DATA32_GSEL
	AssertSegReg	gs, RCODEA_GSEL

	;pDebugF "QueryXMSpages: wanted %d, found ", bx

	push	bx
	push	cx
	push	dx
	push	esi

;  See if there are enough free pages in already allocated XMS blocks

	xor	ax, ax

;EnterCrit				; BEGIN CRITICAL SECTION
pushf
cli
	mov	esi, [XMS_Block_List]
QFXp_scan:
	or	esi, esi
	jz	short QFXp_not_enough

	add	ax, es:[esi].XMS_Free_Pages
	cmp	ax, bx
	jae	short QFXp_got_them

	mov	esi, es:[esi].XMS_Next
	jmp	short QFXp_scan

;  Find out how may pages the XMS driver can give us

QFXp_not_enough:

;ExitCrit				; END CRITICAL SECTION
popf
	sub	bx, ax				; need this many more pages
	mov	dx, ax				; this many we already have
	mov	ax, QUERY_XMS_PAGES
	call	CallRealModeRtn

	cmp	ax, bx				; get all we needed?
	jae	short QFXp_got_them2

	add	ax, dx				; what is avail + what we have
	stc
	jmp	short QFXp_exit

QFXp_got_them:

;ExitCrit				; END CRITICAL SECTION
popf

QFXp_got_them2:
	clc

QFXp_exit:
	;pDebugF "%d\n", ax

	pop	esi
	pop	dx
	pop	cx
	pop	bx

	ret

QueryXMSpages endp


;***********************************************************************
; AllocateXMSpages:	This routine allocates a requested number of XMS
;	"pages" (16k each) and fills in page table entries with their
;	address.
;
; Entry: (Protected Mode)
;	BX = Number of 16k XMS pages desired.
; Exit:
;	CY = clear if desired # XMS pages allocated.
;		Page table entries set.
;		[TopOfFreeEMSspace] updated.
;	CY = set if not enough XMS pages available.
; Used:
;
;***********************************************************************
	public	AllocateXMSpages

AllocateXMSpages proc	near

	AssertSegReg	ds, VDMD_GSEL
	AssertSegReg	es, DATA32_GSEL
	AssertSegReg	gs, RCODEA_GSEL

	;;;pDebugF "AllocateXMSPages: %d pages\n", bx

	pushad
	mov	bp, sp

AXp_scan_again:

;  Find out how many pages are available in existing XMS blocks

	xor	ax, ax

;EnterCrit				; BEGIN CRITICAL SECTION
pushf
cli
	mov	esi, [XMS_Block_List]
	or	esi, esi		; Q: any XMS blocks yet?
	jz	AXp_not_enough		; N:

AXp_scan:
	add	ax, es:[esi].XMS_Free_Pages
	mov	esi, es:[esi].XMS_Next
	or	esi, esi
	jnz	short AXp_scan

;  If there are enough free pages, allocate them

	mov	bx, word ptr [bp].Pushad_ebx	; # pages to assign

	cmp	ax, bx			; Q: enough pages available?
	jb	AXp_not_enough		; N:

	mov	ax, [BotOfVCPIspace]	; double check that there is enough
	sub	ax, [TopOfFreeEMSspace] ;   handle space for this allocation
	shr	ax, 2			; 4k to 16k pages
	cmp	ax, bx
	jb	AXp_no_handles

	mov	esi, [XMS_Block_List]
	mov	ecx, [page_directory]
	movzx	edi, [TopOfFreeEMSspace]
	lea	edi, [ecx][edi*4]	; es:[edi] -> TopOfFreeEMSspace

AXp_alloc_block:

	mov	cx, es:[esi].XMS_Free_Pages
	jcxz	AXp_next_block

	cmp	cx, bx				; Q: enough free pages in this
	jbe	short AXp_take_pages		;    block for remainder?
	mov	cx, bx				; Y: just take what we need
AXp_take_pages:
	sub	bx, cx
	sub	es:[esi].XMS_Free_Pages, cx

	push	bx				; remaining page count
	mov	ebx, es:[esi].XMS_Base_Page
	or	bx, P_AVAIL OR fXMSPageAllocated

	movzx	edx, es:[esi].XMS_Free_Head	; index of 1st free page

	cld

AXp_set_PTE_loop:

IFDEF DEBUG
	cmp	dword ptr es:[edi], 0
	jz	short @f
	INT	3
@@:
ENDIF
	mov	eax, edx
	shl	eax, 14 			; free page index to offset
	add	eax, ebx			; page = base + free page offset

	STOS_DWORD_PTR_ES_EDI			; store PTE
	add	eax, PAGE_SIZE
	STOS_DWORD_PTR_ES_EDI			; store PTE
	add	eax, PAGE_SIZE
	STOS_DWORD_PTR_ES_EDI			; store PTE
	add	eax, PAGE_SIZE
	STOS_DWORD_PTR_ES_EDI			; store PTE

	movzx	edx, es:[esi][edx*2].XMS_Free_List ; index of nxt free page

	loop	AXp_set_PTE_loop

	mov	es:[esi].XMS_Free_Head, dx	; update free page list

	pop	bx				; remaining page count
	or	bx, bx				; Q: all pages assigned?
	jz	short AXp_assigned_all		; Y:

AXp_next_block:

	mov	esi, es:[esi].XMS_Next

ifdef DEBUG
	or	esi, esi
	jnz	AXp_alloc_block
	; something wrong if we get here!
	pDebugBreak
else
	jmp	short AXp_alloc_block
endif

AXp_no_handles:
;ExitCrit				; END CRITICAL SECTION
popf
	jmp	short AXp_alloc_failed

AXp_assigned_all:

	sub	edi, [page_directory]
	shr	di, 2			; index back to PTE
	mov	[TopOfFreeEMSspace], di ; update top of EMS memory

;ExitCrit				; END CRITICAL SECTION
popf
	clc
	jmp	short AXp_exit


;  Try to get new XMS_Block(s) for the remaining pages

AXp_not_enough:

;ExitCrit				; END CRITICAL SECTION
popf
	mov	bx, word ptr [bp].Pushad_ebx
	sub	bx, ax			; number additional 16k pages needed

	call	AllocateXMSblock
	jnc	AXp_scan_again		; if alloc'd something, see if we can
					;   fulfill the page request now

;  Couldn't get all the pages wanted, but some XMS may have been allocated so
;  check the XMS_Block list and free any with no used pages

AXp_alloc_failed:

	call	ReleaseXMSblocks

AXp_fail:
	stc

AXp_exit:
	popad

	ret

AllocateXMSpages endp


;***********************************************************************
; FreeXMSpages: This routine scans free EMS space and releases free pages
;	that were dynamically allocated from XMS memory.
;
; Entry: (Protected Mode)
;
; Exit:
;	Page table entries cleared.
;	[TopOfFreeEMSspace] updated.
; Used:
;
;***********************************************************************
	public	FreeXMSpages

FreeXMSpages	proc	near

	AssertSegReg	ds, VDMD_GSEL
	AssertSegReg	es, DATA32_GSEL
	AssertSegReg	gs, RCODEA_GSEL

	pushad

;  Pack all free XMS page PTEs at the top of free space so their pages
;  can be released.  This has to be done so [TopOfFreeEMSspace] can be
;  moved down.

	xor	edi, edi
	mov	edx, [page_directory]

;EnterCrit				; BEGIN CRITICAL SECTION
pushf
cli
	; Scan EMS space top down to find the 1st non XMS allocated page

	movzx	esi, [TopOfFreeEMSspace]
	mov	bx, [TopOfUsedEMSspace]

FXp_scan_non_xms:
	cmp	si, bx				; Q: out of free space?
	jbe	short FXp_pack_done		; Y: finished
	bt	dword ptr es:[edx][esi*4-4*4], fXMSPageAllocatedBit
	jnc	short FXp_got_non_xms
	sub	si, 4
	jmp	short FXp_scan_non_xms

	; Scan for the first/next XMS page

FXp_got_non_xms:
	or	di, di				; Q: 1st time?
	jz	short FXp_1st_non_xms		; Y:

FXp_scan_xms:
	cmp	di, bx				; Q: out of free space?
	jbe	short FXp_pack_done		; Y: finished
	bt	dword ptr es:[edx][edi*4-4*4], fXMSPageAllocatedBit
	jc	short FXp_swap_PTE
	sub	di, 4
	jmp	short FXp_scan_xms

	; Swap XMS/non XMS entries so XMS entries at top

FXp_swap_PTE:
	mov	cx, 4				; 4 PTE entries per EMS page
FXp_swap_loop:
	mov	eax, es:[edx][edi*4-1*4]	; swap PTE entries
	xchg	eax, es:[edx][esi*4-1*4]
	mov	es:[edx][edi*4-1*4], eax
	dec	si
	dec	di
	loop	FXp_swap_loop
	jmp	short FXp_scan_non_xms

FXp_1st_non_xms:
	lea	di, [si-4]			; start looking for XMS pages
	jmp	short FXp_scan_xms		;   from below the non XMS page

FXp_pack_done:

;ExitCrit				; END CRITICAL SECTION
popf
	nop				; interrupt window
	nop
	nop

;  Now free the XMS pages at the top of free space.  We have to scan from
;  top down again because there is the possibility that things changed
;  during the interrupt window above.

;EnterCrit				; BEGIN CRITICAL SECTION
pushf
cli
	; Find the last XMS page in free space from top down

	movzx	esi, [TopOfFreeEMSspace]
	mov	bx, [TopOfUsedEMSspace]

FXp_get_last_xms:
	cmp	si, bx
	jbe	short FXp_got_xms_range
	bt	dword ptr es:[edx][esi*4-4*4], fXMSPageAllocatedBit
	jnc	short FXp_got_xms_range
	sub	si, 4
	jmp	short FXp_get_last_xms

	; Release the pages from PTE esi to [TopOfFreeEMSspace] - 1

FXp_got_xms_range:

	mov	bx, [TopOfFreeEMSspace] ; bx = old TopOfFreeEMSspace
	mov	[TopOfFreeEMSspace], si ; si = new ...

	lea	edi, [edx][esi*4]	; edi -> PTE for 1st page to free
	mov	cx, bx
	sub	cx, si			; cx = # 4k pages to free
	jbe	FXp_free_done

	shr	cx, 2			; cx = # 16k pages to free

	mov	esi, [XMS_Block_List]	; esi -> xms block info
ifdef DEBUG
	or	esi, esi
	jnz	short @f
	pDebugBreak
	jmp	FXp_free_done
@@:
endif
	mov	ebx, es:[esi].XMS_Base_Page	; ebx = base addr 4 this block

	cld

FXp_free_page:
	mov	eax, es:[edi]			; 1st PTE of page to free

ifdef DEBUG
	bt	eax, fXMSPageAllocatedBit
	jnc	short FXp_Bad_PTE
endif
	sub	eax, ebx			; Q: Is the page within the
	jb	short FXp_wrong_block		;    range of this XMS block?
	shr	eax, 14
	cmp	ax, es:[esi].XMS_Total_Pages
	jae	short FXp_wrong_block

FXp_got_block:
	mov	dx, ax				; Y: link it to the head of
	xchg	dx, es:[esi].XMS_Free_Head	;    the free page list
	mov	es:[esi][eax*2].XMS_Free_List, dx

	inc	es:[esi].XMS_Free_Pages 	; another 16k free page

	xor	eax, eax			; zero PTEs for this EMS page
	STOS_DWORD_PTR_ES_EDI
	STOS_DWORD_PTR_ES_EDI
	STOS_DWORD_PTR_ES_EDI
	STOS_DWORD_PTR_ES_EDI

	loop	FXp_free_page
	jmp	short FXp_free_done

FXp_bad_PTE:
ifdef DEBUG
	pDebugF "FreeXMSpages: Non XMS page or bad PTE %lxh @ %lxh\n", <eax, edi>
	pDebugBreak
endif
	add	edi, 4*4		; something screwy, skip this page
	loop	FXp_free_page
	jmp	short FXp_free_done

;  Page is not within the current XMS block, locate the correct block.

FXp_wrong_block:
	mov	edx, esi			; remember where we started

FXp_try_next_block:
	mov	eax, es:[edi]			; PTE of page to locate
	mov	esi, es:[esi].XMS_Next		; try next/first XMS block
	or	esi, esi
	jnz	short FXp_try_this_block
	mov	esi, [XMS_Block_List]

FXp_try_this_block:
	mov	ebx, es:[esi].XMS_Base_Page

	cmp	esi, edx			; Q: back where we started?
	jz	short FXp_bad_PTE		; Y: shouldn't happen...

	sub	eax, ebx			; Q: page within this block?
	jb	short FXp_try_next_block

⌨️ 快捷键说明

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