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