📄 xmsutils.asm
字号:
.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 + -