675 lines
17 KiB
NASM
675 lines
17 KiB
NASM
;/* 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
|
||
|