You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
674 lines
17 KiB
674 lines
17 KiB
;/* himem4.asm
|
|
; *
|
|
; * Microsoft Confidential
|
|
; * Copyright (C) Microsoft Corporation 1988-1991
|
|
; * All Rights Reserved.
|
|
; *
|
|
; * Modification History
|
|
; *
|
|
; * Sudeepb 14-May-1991 Ported for NT XMS support
|
|
; *
|
|
; * williamh 25-Sept-1992 Added RequestUMB and ReleaseUMB
|
|
; *
|
|
; * daveh 1-Feb-1994 Changed to do mem management on 32 bit side
|
|
; */
|
|
page 95,160
|
|
title himem4 - block allocation stuff
|
|
|
|
.xlist
|
|
include himem.inc
|
|
include xmssvc.inc
|
|
include vint.inc
|
|
.list
|
|
|
|
; The stuff we provide:
|
|
|
|
public Version
|
|
public QueryExtMemory
|
|
public AllocExtMemory
|
|
public FreeExtMemory
|
|
public LockExtMemory
|
|
public UnlockExtMemory
|
|
public GetExtMemoryInfo
|
|
public ReallocExtMemory
|
|
public end_of_hiseg
|
|
public textseg
|
|
public KiddValley
|
|
public KiddValleyTop
|
|
public cHandles
|
|
public RequestUMB
|
|
public ReleaseUMB
|
|
|
|
; externals from himem.asm
|
|
|
|
extrn PrevInt15:dword
|
|
extrn Moveit:word
|
|
extrn fHMAMayExist:byte
|
|
extrn fHMAExists:byte
|
|
extrn winbug_fix:word
|
|
extrn FLclEnblA20:far
|
|
extrn FLclDsblA20:far
|
|
_text ends
|
|
|
|
funky segment word public 'funky'
|
|
assume cs:funky,ds:_text
|
|
|
|
extrn end_of_funky_seg:near
|
|
|
|
org HISEG_ORG
|
|
|
|
public LEnblA20
|
|
public LDsblA20
|
|
|
|
end_of_hiseg dw end_of_funky_seg
|
|
textseg dw _text
|
|
KiddValley dw end_of_funky_seg; The address of the handle table
|
|
KiddValleyTop dw 0 ; end of handle table
|
|
cHandles dw DEFHANDLES ; number of handles
|
|
LEnblA20 dd _text:FLclEnblA20
|
|
LDsblA20 dd _text:FLclDsblA20
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* Get XMS Version Number - FUNCTION 00h *
|
|
;* *
|
|
;* Returns the XMS version number *
|
|
;* *
|
|
;* ARGS: None *
|
|
;* RETS: AX = XMS Version Number *
|
|
;* BX = Internal Driver Version Number *
|
|
;* DX = 1 if HMA exists, 0 if it doesn't *
|
|
;* REGS: AX, BX and DX are clobbered *
|
|
;* *
|
|
;* INTERNALLY REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
|
|
Version proc far
|
|
|
|
mov ax,XMSVersion
|
|
mov bx,HimemVersion
|
|
xor dh,dh
|
|
|
|
; Is Int 15h hooked?
|
|
|
|
cmp word ptr [PrevInt15][2],0 ; Is the segment non-zero?
|
|
jne VHooked
|
|
mov dl,[fHMAMayExist] ; No, return the status at
|
|
ret ; init time.
|
|
|
|
VHooked:
|
|
mov dl,[fHMAExists] ; Yes, return the real status
|
|
ret
|
|
|
|
Version endp
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* QueryExtMemory - FUNCTION 08h *
|
|
;* *
|
|
;* Returns the size of the largest free extended memory block in K *
|
|
;* *
|
|
;* ARGS: None *
|
|
;* RETS: AX = Size of largest free block in K. BL = Error code *
|
|
;* DX = Total amount of free extended memory in K *
|
|
;* REGS: AX, BX, DX, DI, SI and Flags clobbered *
|
|
;* *
|
|
;* INTERNALLY REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
QueryExtMemory proc far
|
|
|
|
mov bl,0 ; assume no error
|
|
XMSSVC XMS_QUERYEXTMEM
|
|
test dx,dx
|
|
jne QEM20
|
|
|
|
mov bl,ERR_OUTOMEMORY
|
|
QEM20:
|
|
ret
|
|
|
|
QueryExtMemory endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* AllocExtMemory - FUNCTION 09h *
|
|
;* *
|
|
;* Reserve a block of extended memory *
|
|
;* *
|
|
;* ARGS: DX = Amount of K being requested *
|
|
;* RETS: AX = 1 of successful, 0 otherwise. BL = Error Code *
|
|
;* DX = 16-bit handle to the allocated block *
|
|
;* REGS: AX, BX, DX and Flags clobbered *
|
|
;* *
|
|
;* Notice: called internally from ReallocExtMemory *
|
|
;* *
|
|
;* INTERNALLY NON-REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
hFreeBlock dw ?
|
|
hUnusedBlock dw ?
|
|
|
|
AllocExtMemoryNear proc near
|
|
AllocExtMemoryNear endp
|
|
AllocExtMemory proc far
|
|
|
|
call FunkyCLI ; This is a non-reentrant function
|
|
|
|
; Scan the handle table looking for an unused handle
|
|
|
|
xor ax,ax
|
|
mov [hUnusedBlock],ax
|
|
mov bx,[KiddValley]
|
|
mov cx,[cHandles] ; Loop through the handle table
|
|
|
|
; Have we already found a free block which is large enough?
|
|
|
|
AEMhLoop:
|
|
|
|
cmp [bx].Flags,UNUSEDFLAG ; Is this block unused?
|
|
jne AEMNexth ; No, get the next handle
|
|
|
|
mov [hUnusedBlock],bx ; save this guy away
|
|
jmp AEMGotHandle
|
|
|
|
AEMNexth:
|
|
add bx,SIZE Handle ; go check the next handle
|
|
loop AEMhLoop
|
|
|
|
; We are at the end of the handle table and we didn't an unused
|
|
; handle
|
|
|
|
jmp AEMOOHandles ; No, Case 4 - We're out of handles
|
|
|
|
AEMGotHandle:
|
|
|
|
mov di,[hUnusedBlock]
|
|
|
|
XMSSVC XMS_ALLOCBLOCK ; ax=Base and dx=Size
|
|
or ax,ax
|
|
jz AEMOOMemory
|
|
|
|
mov [di].Base,ax
|
|
mov [di].Len,dx
|
|
mov [di].Flags,USEDFLAG ; New.Flags = USED
|
|
|
|
if keep_cs
|
|
mov ax,callers_cs
|
|
mov [si].Acs,ax ; keep track of allocator's cs:
|
|
endif
|
|
|
|
mov dx,[hUnusedBlock]
|
|
mov ax,1
|
|
xor bl,bl
|
|
ret
|
|
|
|
AEMOOMemory:
|
|
mov bl,ERR_OUTOMEMORY
|
|
jmp short AEMErrRet
|
|
|
|
AEMOOHandles:
|
|
mov bl,ERR_OUTOHANDLES
|
|
AEMErrRet:
|
|
xor ax,ax ; Return failure
|
|
mov dx,ax
|
|
ret
|
|
AllocExtMemory endp
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* FreeExtMemory - FUNCTION 0Ah *
|
|
;* *
|
|
;* Frees a block of extended memory *
|
|
;* *
|
|
;* ARGS: DX = 16-bit handle to the extended memory block *
|
|
;* RETS: AX = 1 if successful, 0 otherwise. BL = Error code *
|
|
;* REGS: AX, BX, CX, DX, SI, DI and Flags clobbered *
|
|
;* *
|
|
;* called internally from ReallocExtMemory *
|
|
;* *
|
|
;* INTERNALLY NON-REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
FreeExtMemoryNear proc near
|
|
FreeExtMemoryNear endp
|
|
|
|
FreeExtMemory proc far
|
|
call FunkyCLI ; This is a non-reentrant function
|
|
|
|
call ValidateHandle ; Make sure handle is valid
|
|
jnc FEMBadh
|
|
mov si,dx ; Move the handle into SI
|
|
|
|
cmp [si].cLock,0 ; make sure it points to unlocked block
|
|
jne FEMLockedh
|
|
|
|
mov [si].Flags,UNUSEDFLAG ; mark it as UNUSED
|
|
cmp [si].Len,0 ; if zero length block
|
|
jz FEMExit ; done if it was zero length
|
|
|
|
mov ax,[si].Base
|
|
mov dx,[si].Len
|
|
XMSSVC XMS_FREEBLOCK ; ax=base dx=size in k
|
|
or ax,ax
|
|
je FEMBadh
|
|
|
|
FEMExit:
|
|
|
|
mov ax,1 ; Return success
|
|
xor bl,bl
|
|
ret
|
|
|
|
FEMBadh:
|
|
mov bl,ERR_INVALIDHANDLE
|
|
jmp short FEMErrExit
|
|
|
|
FEMLockedh:
|
|
mov bl,ERR_EMBLOCKED
|
|
FEMErrExit:
|
|
xor ax,ax ; Return failure
|
|
ret
|
|
FreeExtMemory endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* LockExtMemory - FUNCTION 0Ch *
|
|
;* *
|
|
;* Locks a block of extended memory *
|
|
;* *
|
|
;* ARGS: DX = 16-bit handle to the extended memory block *
|
|
;* RETS: AX = 1 of successful, 0 otherwise. BL = Error code *
|
|
;* DX:BX = 32-bit linear address of the base of the memory block *
|
|
;* REGS: AX, BX, DX and Flags clobbered *
|
|
;* *
|
|
;* INTERNALLY NON-REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
LockExtMemory proc far
|
|
|
|
call FunkyCLI ; This is a non-reentrant function
|
|
|
|
call ValidateHandle ; Is the handle valid?
|
|
jnc LEMBadh
|
|
mov bx,dx ; Move the handle into BX
|
|
|
|
; Are we at some preposterously large limit?
|
|
|
|
cmp [bx].cLock,0FFh
|
|
je LEMOverflow
|
|
|
|
inc [bx].cLock ; lock the block
|
|
|
|
mov dx,[bx].Base ; return the 32-bit address of base
|
|
mov bx,dx
|
|
shr dx,6
|
|
shl bx,10
|
|
|
|
mov ax,1 ; return success
|
|
ret
|
|
|
|
LEMBadh:
|
|
mov bl,ERR_INVALIDHANDLE
|
|
jmp short LEMErrExit
|
|
|
|
LEMOverflow:
|
|
mov bl,ERR_LOCKOVERFLOW
|
|
LEMErrExit:
|
|
xor ax,ax ; Return failure
|
|
mov dx,ax
|
|
ret
|
|
|
|
LockExtMemory endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* UnlockExtMemory - FUNCTION 0Dh *
|
|
;* *
|
|
;* Unlocks a block of extended memory *
|
|
;* *
|
|
;* ARGS: DX = 16-bit handle to the extended memory block *
|
|
;* RETS: AX = 1 if successful, 0 otherwise. BL = Error code *
|
|
;* REGS: AX, BX and Flags clobbered *
|
|
;* *
|
|
;* INTERNALLY NON-REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
UnlockExtMemory proc far
|
|
|
|
call FunkyCLI ; This is a non-reentrant function
|
|
|
|
call ValidateHandle ; Is the handle valid?
|
|
jnc UEMBadh
|
|
mov bx,dx ; Move the handle into BX
|
|
|
|
cmp [bx].cLock,0 ; is handle locked?
|
|
je UEMUnlocked ; No, return error
|
|
|
|
dec [bx].cLock ; Unlock the block
|
|
|
|
mov ax,1 ; Return success
|
|
xor bl,bl
|
|
ret
|
|
|
|
UEMUnlocked:
|
|
mov bl,ERR_EMBUNLOCKED
|
|
jmp short UEMErrExit
|
|
|
|
UEMBadh:
|
|
mov bl,ERR_INVALIDHANDLE
|
|
UEMErrExit:
|
|
xor ax,ax
|
|
ret
|
|
|
|
UnlockExtMemory endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* GetExtMemoryInfo - FUNCTION 0Eh *
|
|
;* *
|
|
;* Gets other information about an extended memory block *
|
|
;* *
|
|
;* ARGS: DX = 16-bit handle to the extended memory block *
|
|
;* RETS: AX = 1 if successful, 0 otherwise. BL = Error code *
|
|
;* BH = EMB's lock count *
|
|
;* BL = Total number of unused handles in the system *
|
|
;* DX = EMB's length *
|
|
;* REGS: AX, BX, CX, DX and Flags clobbered *
|
|
;* *
|
|
;* INTERNALLY NON-REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
GetExtMemoryInfo proc far
|
|
|
|
call FunkyCLI ; This is a non-reentrant function
|
|
|
|
call ValidateHandle ; is the handle valid?
|
|
jnc GEMBadh
|
|
mov si,dx ; Move the handle into SI
|
|
|
|
xor al,al ; count number of UNUSED handles
|
|
mov bx,[KiddValley]
|
|
mov cx,[cHandles] ; Loop through the handle table
|
|
GEMLoop:
|
|
cmp [bx].Flags,USEDFLAG ; Is this handle in use?
|
|
je GEMNexth ; Yes, continue
|
|
inc al ; No, increment the count
|
|
GEMNexth:
|
|
add bx,SIZE Handle
|
|
loop GEMLoop
|
|
|
|
mov dx,[si].Len ; Length in DX
|
|
mov bh,[si].cLock ; Lock count in BH
|
|
mov bl,al
|
|
mov ax,1
|
|
ret
|
|
|
|
GEMBadh:
|
|
mov bl,ERR_INVALIDHANDLE
|
|
xor ax,ax
|
|
ret
|
|
|
|
GetExtMemoryInfo endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* ReallocExtMemory - FUNCTION 0Fh *
|
|
;* *
|
|
;* Reallocates a block of extended memory *
|
|
;* *
|
|
;* ARGS: DX = 16-bit handle to the extended memory block *
|
|
;* BX = new size for block *
|
|
;* RETS: AX = 1 if successful, 0 otherwise. BL = Error code *
|
|
;* REGS: trashes si,di,bx,cx,dx *
|
|
;* *
|
|
;* INTERNALLY NON-REENTRANT *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
; Define our memory move structure for calling the move function
|
|
|
|
ReallocExtMemory proc far
|
|
|
|
call FunkyCLI ; This is a non-reentrant function
|
|
|
|
call ValidateHandle ; is the handle valid?
|
|
mov si,dx ; Move the handle into SI
|
|
mov dx,bx ; Move the new length into dx
|
|
mov bl,ERR_INVALIDHANDLE
|
|
jnc REMError
|
|
|
|
cmp [si].cLock,0 ; We can only work on unlocked EMBs
|
|
mov bl,ERR_EMBLOCKED
|
|
jnz REMError
|
|
|
|
mov bx,dx
|
|
cmp [si].Len,bx
|
|
je REMExit
|
|
|
|
mov ax,[si].Base
|
|
mov dx,[si].Len
|
|
XMSSVC XMS_REALLOCBLOCK ; ax = old base, dx = old size
|
|
cmp cx,0 ; cx = new base, bx = new size
|
|
je REM20
|
|
|
|
mov [si].Base,cx
|
|
mov [si].Len,bx
|
|
REMExit:
|
|
mov ax,1 ; succesful return
|
|
xor bl,bl ; non-documented no-error return
|
|
ret
|
|
|
|
REM20:
|
|
mov bl,ERR_OUTOMEMORY
|
|
REMError:
|
|
xor ax,ax
|
|
ret
|
|
|
|
ReallocExtMemory endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* FindAdjacent unused blocks *
|
|
;* *
|
|
;* Scan through handle list looking for blocks adjacent *
|
|
;* to a given handle. *
|
|
;* *
|
|
;* ARGS: SI handle of original block *
|
|
;* RETS: DI = handle of adjacent block below or zero if none *
|
|
;* BP = handle of adjacent block above or zero if none *
|
|
;* *
|
|
;* TRASHES: AX,BX,CX,DX *
|
|
;* *
|
|
;* messes with handle table - not reentrant - assumes ints disabled *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
FindAdjacent proc near
|
|
|
|
mov ax,[si].Base ; look for blocks ending here
|
|
mov dx,[si].Len
|
|
add dx,ax ; and ending here
|
|
|
|
xor di,di ; initialize to fail condition
|
|
mov bp,di
|
|
|
|
mov bx,[KiddValley] ; prepare to loop thru handle tab
|
|
mov cx,[cHandles]
|
|
|
|
push si ; preserve original handle
|
|
|
|
FindAdj1:
|
|
cmp [bx].Flags,FREEFLAG
|
|
jnz FindAdj3 ; ignore blocks that aren't UNUSED
|
|
mov si,[bx].Base
|
|
cmp dx,si ; found beg block?
|
|
jnz FindAdj2 ; skip if not
|
|
mov bp,bx ; remember the handle
|
|
or di,di ; did we already find a follower?
|
|
jnz FindAdj9 ; we're done if so
|
|
|
|
FindAdj2:
|
|
add si,[bx].Len ; find length
|
|
cmp si,ax ; does this block end at spec addr?
|
|
jnz FindAdj3 ; skip if not
|
|
mov di,bx ; remember the handle
|
|
or bp,bp ; did we already find a leader?
|
|
jnz FindAdj9 ; we're done if so
|
|
|
|
FindAdj3:
|
|
add bx,SIZE handle
|
|
loop FindAdj1
|
|
|
|
FindAdj9:
|
|
pop si ; restore original handle
|
|
ret
|
|
;
|
|
|
|
FindAdjacent endp
|
|
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* ValidateHandle - *
|
|
;* *
|
|
;* Validates an extended memory block handle *
|
|
;* *
|
|
;* ARGS: DX = 16-bit handle to the extended memory block *
|
|
;* RETS: Carry is set if the handle is valid *
|
|
;* REGS: Preserved except the carry flag *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
ValidateHandle proc near
|
|
|
|
pusha ; Save everything
|
|
mov bx,dx ; Move the handle into BX
|
|
|
|
; The handle must be equal to or above "KiddValley".
|
|
|
|
cmp bx,[KiddValley]
|
|
jb VHOne
|
|
|
|
; The handle must not be above "KiddValleyTop".
|
|
|
|
cmp bx,[KiddValleyTop]
|
|
ja VHOne
|
|
|
|
; (The handle-"KiddValley") must be a multiple of a handle's size.
|
|
|
|
sub dx,[KiddValley]
|
|
mov ax,dx
|
|
xor dx,dx
|
|
mov cx,SIZE Handle
|
|
div cx
|
|
or dx,dx ; Any remainder?
|
|
jnz VHOne ; Yup, it's bad
|
|
|
|
; Does the handle point to a currently USED block?
|
|
|
|
cmp [bx].Flags,USEDFLAG
|
|
jne VHOne ; This handle is not being used.
|
|
|
|
; The handle looks good to me...
|
|
|
|
popa ; Restore everything
|
|
stc ; Return success
|
|
ret
|
|
|
|
VHOne:
|
|
|
|
; It's really bad.
|
|
popa ; Restore everything
|
|
clc ; Return failure
|
|
ret
|
|
|
|
ValidateHandle endp
|
|
|
|
BlkMovX proc near
|
|
assume ds:_text
|
|
jmp MoveIt
|
|
BlkMovX endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;This is the routine for XMS function 16, request UMB.
|
|
;
|
|
; Input:
|
|
; (DX) = requested size in paragraphs
|
|
;
|
|
; Output:
|
|
; (AX) = 1 if request is granted and
|
|
; (BX) = segment address of the requested block
|
|
; (DX) = actual size allocated in paragraphs
|
|
; = 0 if requtest failed and
|
|
; (BL) = 0B0h if a smaller UMB is available
|
|
; (BL) = 0B1h if no UMBs are available
|
|
; (DX) = largest UMB available.
|
|
;Modified: AX, BX, DX
|
|
;
|
|
;NOTE:
|
|
;The funcition was implemented in the 32bits xms because
|
|
;any memory we need for house keeping purpose are kept in extented memory
|
|
;rather than in the UMB itself(DOS arena). Of course, it has the penalty
|
|
;of ring transition each time a request being made. However, the major
|
|
;allocator of UMBs is IO.SYS, the device driver of MS-DOS for devicehigh
|
|
;and loadhigh during bootstrap. This should adjust the penalty a little bits.
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
RequestUMB proc far
|
|
XMSSVC XMS_REQUESTUMB
|
|
ret
|
|
RequestUMB endp
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
;This is the routine for XMS function 17, release UMB
|
|
;
|
|
; Input:
|
|
; (DX) = segment of the UMB block to be released
|
|
;
|
|
; Output:
|
|
; (AX) = 1 if the block was released successfully.
|
|
; (AX) = 0 if the block couldn't be released and
|
|
; (BL) = 0B2h if the given segment is invalid
|
|
; Modified: AX, BX
|
|
;
|
|
;Note:
|
|
; See note in RequestUMB
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ReleaseUMB proc far
|
|
XMSSVC XMS_RELEASEUMB
|
|
ret
|
|
ReleaseUMB endp
|
|
|
|
PUBLIC FunkyCLI
|
|
FunkyCLI:
|
|
FCLI
|
|
ret
|
|
|
|
PUBLIC FunkySTI
|
|
FunkySTI:
|
|
FSTI
|
|
ret
|
|
|
|
;*----------------------------------------------------------------------*
|
|
;* *
|
|
;* NOTE: RequestUMB and ReleaseUMB will not be implemented by HIMEM. *
|
|
;* *
|
|
;*----------------------------------------------------------------------*
|
|
|
|
funky ends
|
|
end
|
|
|