windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/2ginterf.asm
2020-09-26 16:20:57 +08:00

2040 lines
52 KiB
NASM

page ,132
TITLE GINTERF - Global Memory Manager interface procedures
.sall
.xlist
include kernel.inc
include pdb.inc
include tdb.inc
include newexe.inc
include protect.inc
ifdef WOW
include wowkrn.inc
include vint.inc
endif
.list
CheckHeap MACRO name
local a
if KDEBUG
extrn CheckGlobalHeap :near
call CheckGlobalHeap
jnc a
or ax,ERR_GMEM
xor bx,bx
kerror <>,<&name: Invalid global heap>,dx,bx
a:
endif
endm
PROFILE MACRO function
pushf
add word ptr ds:[di.gi_stats][c&function], 1
adc word ptr ds:[di.gi_stats][c&function][2], 0
popf
ENDM
ifdef WOW
externFP WowCursorIconOp
externFP WowDdeFreeHandle
endif
externW pStackTop
externW pStackMin
externW pStackBot
DataBegin
externB Kernel_Flags
externB fBooting
externW hGlobalHeap
externW pGlobalHeap
externW curTDB
externW loadTDB
externW hExeHead
GSS_SI dw 0
GSS_DS dw 0
GSS_RET dd 0
DataEnd
sBegin CODE
assumes CS,CODE
if SDEBUG
externNP DebugFreeSegment
endif
externNP galloc
externNP grealloc
externNP gfree
externNP glock
externNP gunlock
externNP gfreeall
externNP galign
externNP gcompact
externNP gmovebusy
externNP gsearch
externNP genter
externNP gleave
externNP gavail
externNP glrutop
externNP glrubot
externNP glrudel
externNP glruadd
externNP gmarkfree
;externNP gdiscard
externNP get_arena_pointer
externNP pdref
externNP cmp_sel_address
externNP get_physical_address
externNP set_physical_address
externNP set_sel_limit
externNP alloc_data_sel
externFP FreeSelector
externNP GetAccessWord
externNP MyGetAppCompatFlags
if ALIASES
externNP add_alias
externNP delete_alias
externNP get_alias_from_original
externNP get_original_from_alias
externNP wipe_out_alias
endif
externNP ShrinkHeap
externNP DpmiProc
externNP HackCheck
if KDEBUG
externFP OutputDebugString
ThisIsForTurboPascal:
db "A program has attempted an invalid selector-to-handle conversion.",13,10,"Attempting to correct this error.",13,10,0
endif
if ROM
externNP GetOwner
endif
if KDEBUG
externNP xhandle_norip
endif
;-----------------------------------------------------------------------;
; gbtop ;
; ;
; Converts a 32-bit byte count to a 16-bit paragraph count. ;
; ;
; Arguments: ;
; AX = allocation flags or -1 if called from GlobalCompact ;
; BX = stack address of 32-bit unsigned integer ;
; DX = handle being reallocated or zero ;
; DS:DI = address of GlobalInfo for global heap ;
; ;
; Returns: ;
; AX = updated allocation flags ;
; BX = #paragraphs needed to contain that many bytes ;
; CX = owner value to use ;
; DX = handle being reallocated or zero ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Wed Dec 03, 1986 10:20:01p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc gbtop,<PUBLIC,NEAR>
cBegin nogen
push dx
mov dx,ss:[bx][2]
mov bx,ss:[bx]
mov cx,4
add bx,15
adc dx,0
jnc gbtop1
dec dx
dec bx
gbtop1:
shr dx,1
rcr bx,1
loop gbtop1
or dx,dx ; Requesting more than 1 meg?
jz gbtop2
mov bx,0FFFFh ; Yes, set to bogus value - this can NEVER succeed
gbtop2:
pop dx
inc ax
jnz gbtop2a
ret ; All done if called from GlobalCompact
gbtop2a:
dec ax
push ax
if ROM
cCall GetOwner,<[bp].savedCS>
mov es,ax ; ES has owner exe hdr selector
else
cCall get_arena_pointer,<[bp].savedCS>
mov es,ax ; ES has arena of calling CS (if known)
endif
pop ax
push ds
SetKernelDS
cmp fBooting,0 ; Done booting?
jne gbtop3 ; No, must be KERNEL allocating then
if ROM
mov cx,es
cmp cx,hExeHead ; Is the KERNEL calling us?
else
mov cx,hExeHead ; CX = KERNEL exe header
cmp cx,es:[di].ga_owner ; Is the KERNEL calling us?
endif
je gbtop3 ; Yes, let him party
and ax,not GA_INTFLAGS ; No, then cant use these flags
gbtop3:
pop ds
UnSetKernelDS
test ah,GA_ALLOC_DOS ; Dos land allocations can never ever
jz gbtop3b ; be moved once allocated--make sure
and al,not GA_MOVEABLE ; caller isn't confused about this
gbtop3b:
mov cl,GA_SEGTYPE ; Isolate segment type bits in CL
and cl,al
mov [di].gi_cmpflags,al ; Save flags for gcompact
and [di].gi_cmpflags,CMP_FLAGS
push ds
SetKernelDS
test al, GA_MOVEABLE ; Is this fixed?
jz gbtop4 ; yes, must go low
ife ROM
cmp fBooting, 1 ; Booting?
je @F ; yes, allocate high
endif
test cl, GA_DISCCODE ; no, only discardable code goes high
jz gbtop4
@@:
or al, GA_ALLOCHIGH
gbtop4:
pop ds
UnSetKernelDS
push ax ; Under Win1.0x ANY bit in 0Fh meant
mov al,HE_DISCARDABLE ; make discardable.
and ah,al ; Under Win2.0x ONLY 01h or 0Fh means
cmp ah,al ; discardable.
pop ax
jnz gbtop4a
and ah,not HE_DISCARDABLE ; Yes, convert to boolean value
or ah,GA_DISCARDABLE
gbtop4a:
and ah,NOT GA_SEGTYPE ; Clear any bogus flags
or ah,cl ; Copy segment type bits
test ah,GA_SHAREABLE ; Shared memory request?
jz GetDefOwner ; No, default action
mov cx, es ; Arena of calling CS
jcxz no_owner_yet
ife ROM
mov cx,es:[di].ga_owner ; owner of calling code segment
endif
no_owner_yet:
ret
cEnd nogen
cProc GetDefOwner,<PUBLIC,NEAR>
cBegin nogen
push ds
SetKernelDS
mov cx,curTDB
jcxz xxxx
mov es,cx
mov cx,loadTDB
jcxz xxx
mov es,cx
xxx: mov cx,es:[TDB_PDB]
inc cx
xxxx: dec cx
pop ds
UnSetKernelDS
ret
cEnd nogen
; The remainder of this file implements the exported interface to the
; global memory manager. A summary follows:
; HANDLE far PASCAL GlobalAlloc( WORD, DWORD );
; HANDLE far PASCAL GlobalReAlloc( HANDLE, DWORD, WORD );
; HANDLE far PASCAL GlobalFree( HANDLE );
; HANDLE far PASCAL GlobalFreeAll( WORD );
; char far * far PASCAL GlobalLock( HANDLE );
; BOOL far PASCAL GlobalUnlock( HANDLE );
; DWORD far PASCAL GlobalSize( HANDLE );
; DWORD far PASCAL GlobalCompact( DWORD );
; #define GlobalDiscard( h ) GlobalReAlloc( h, 0L, GMEM_MOVEABLE )
; HANDLE far PASCAL GlobalHandle( WORD );
; HANDLE far PASCAL LockSegment( WORD );
; HANDLE far PASCAL UnlockSegment( WORD );
cProc IGlobalAlloc,<PUBLIC,FAR>,<si,di>
parmW flags
parmD nbytes
cBegin
call genter ; About to modify memory arena
PROFILE GLOBALALLOC
cCall MyGetAppCompatFlags ; Ignore the NODISCARD flag
test al, GACF_IGNORENODISCARD ; for selected modules
mov ax, flags
jz @f
call IsKernelCalling ; needs caller's CS @ [bp+4]
jz @f ; skip hack if kernel calling us
and al, NOT GA_NODISCARD
@@:
ifdef WOW
; compatibility: amipro calls globalallocs some memory for storing one
; of its ini files and accesses the lpstring[byte after the null char].
; This happens to be harmless on most occasions because we roundoff the
; allocation to next 16byte boundary. However if the allocation request
; is for exactly 0x10 bytes we allocate a selector of exactly 0x10 bytes
; and thus amipro GPs when it access the byte seg:0x10
;
; So here is a cheap fix.
; - nanduri
cmp word ptr nbytes+2, 0
jnz @F
cmp word ptr nbytes, 010h
jne @F
inc word ptr nbytes
@@:
endif
xor dx,dx ; No handle
lea bx,nbytes ; Convert requested bytes to paragraphs
call gbtop ; ... into BX
call galloc
CheckHeap GlobalAlloc
call gleave
mov es,di
cEnd
cProc IGlobalReAlloc,<PUBLIC,FAR>,<si,di>
parmW handle
parmD nbytes
parmW rflags
cBegin
;
; Does this thing have any ring bits or LDT bit? If not, then it
; could be a selector incorrectly converted to a handle.
;
test byte ptr handle,7
jnz @F
if KDEBUG
Trace_Out "GlobalReAlloc:"
push seg ThisIsForTurboPascal
push offset ThisIsForTurboPascal
cCall OutputDebugString
INT3_WARN
endif
dec handle
@@:
call genter ; About to modify memory arena
PROFILE GLOBALREALLOC
cCall MyGetAppCompatFlags ; Ignore the NODISCARD flag
test al, GACF_IGNORENODISCARD ; for selected modules
mov ax, rflags
jz @f
call IsKernelCalling ; needs caller's CS @ [bp+4]
jz @f ; skip hack if kernel calling us
and al, NOT GA_NODISCARD
@@:
mov dx,handle
;mov ax,rflags
lea bx,nbytes ; Convert requested bytes to paragraphs
call gbtop ; ... into BX
call grealloc
gr_done:
CheckHeap GlobalReAlloc
call gleave
mov es,di
cEnd
cProc DiscardTheWorld,<PUBLIC,NEAR>
cBegin
call genter
mov [di].gi_cmpflags, GA_DISCCODE
mov dx, -1
Trace_Out "Discarding the World."
call gcompact
call gleave
cEnd
; Returns with Z flag set if ss:[bp+4] is a kernel code segment selector.
; Uses: DX, flags.
cProc IsKernelCalling,<PUBLIC,NEAR>
cBegin nogen
mov dx, [bp+4] ; CS of GlobalAlloc caller
cmp dx, IGROUP
jz @f
cmp dx, _NRESTEXT
jz @f
cmp dx, _MISCTEXT
@@:
ret
cEnd nogen
;-----------------------------------------------------------------------;
; GlobalFree ;
; ;
; Frees the given object. If the object lives in someone elses banks ;
; then the argument MUST be a handle entry. ;
; ;
; Arguments: ;
; parmW handle ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
; Added the zero'ing of ES on exit. ;
; ;
; Sat Apr 25, 1987 10:23:13p -by- David N. Weise [davidw] ;
; Added support for EMS and added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc IGlobalFree,<PUBLIC,FAR>,<si,di>
parmW handle
ifdef WOW
DsOnStack equ [bp][-2]
endif
; if you add any local params or make this nogen or something similar,
; the references to [bp][-2] to access DS on stack will need to change!
cBegin
call genter ; About to modify memory arena
PROFILE GLOBALFREE
xor ax,ax ; In case handle = 0.
mov dx,handle
or dx,dx
jnz @F
jmp nothing_to_free
@@:
;
; Does this thing have any ring bits or LDT bit? If not, then it
; could be a selector incorrectly converted to a handle.
;
test dl,7
jnz @F
if KDEBUG
Trace_Out "GlobalFree:"
push seg ThisIsForTurboPascal
push offset ThisIsForTurboPascal
cCall OutputDebugString
INT3_WARN
endif
dec dx
mov handle,dx
@@:
if ALIASES
call wipe_out_alias
endif
push dx
call pdref ; returns dx=handle, ax=selector
pushf ; save pdref Z flag return
ifdef WOW
;
; [bp][-2] has been changed to DsOnStack
;
endif
cmp ax,DsOnStack ; Are we about to free the DS on
jz short yup ; the stack and GP?
cmp dx,DsOnStack
jnz short nope
yup: xor dx,dx ; Yup, zero DS image on stack...
mov DsOnStack,dx
nope:
popf ; flags from pdref, Z set if discarded
pop dx
jz @f ; discarded can be freed, but has
; no arena pointer
mov bx, es ; Invalid handle if arena ptr = 0
or bx, bx
jz nothing_to_free
@@:
if KDEBUG
or si,si
jz freeo
or ch,ch ; Debugging check for count underflow
jz freeo
pusha
xor bx,bx
kerror ERR_GMEMUNLOCK,<GlobalFree: freeing locked object>,bx,handle
popa
freeo:
endif
ifdef WOW
test cl, GAH_CURSORICON ; call to pdref above sets cl
jz gf_wowdde
push ax ; save
push bx
push dx
push es
push handle
push FUN_GLOBALFREE
call WowCursorIconOp
or ax, ax ; if TRUE 'free' else 'dont free, fake success'
pop es
pop dx
pop bx
pop ax ; restore
jnz gf_notglobalicon
xor ax, ax ; fake success
xor cx, cx
jmps nothing_to_free
gf_wowdde:
test cl, GAH_WOWDDEFREEHANDLE ; call to pdref above sets cl
jz gf_noticon
push ax ; save
push bx
push dx
push es
push handle
call WowDdeFreeHandle
or ax, ax ; if TRUE 'free' else 'dont free, fake success'
pop es
pop dx
pop bx
pop ax ; restore
jnz gf_notglobalicon
xor ax, ax ; fake success
xor cx, cx
jmps nothing_to_free
gf_notglobalicon:
gf_noticon:
endif
xor cx,cx ; Dont check owner field
call gfree
nothing_to_free:
CheckHeap GlobalFree
call gleave
mov es,di
cEnd
;-----------------------------------------------------------------------;
; GlobalFreeAll ;
; ;
; Frees all of the global objects belonging to the given owner. ;
; ;
; Arguments: ;
; parmW id ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
; Added the zero'ing of ES on exit. ;
; ;
; Sat Apr 25, 1987 10:23:13p -by- David N. Weise [davidw] ;
; Added support for EMS and added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc GlobalFreeAll,<PUBLIC,FAR>,<si,di>
parmW id
cBegin
call genter ; About to modify memory arena
PROFILE GLOBALFREEALL
mov cx,1
push cx
mov dx,id ; Get id to match with
or dx,dx ; Is it zero?
jnz all1 ; No, continue
call GetDefOwner ; Yes, CX = default task owner to free
mov dx,cx
all1:
if SDEBUG
mov es,[di].hi_first ; ES:DI points to first arena entry
mov cx,[di].hi_count ; CX = #entries in the arena
all2:
cmp es:[di].ga_owner,dx
jne all3
mov ax, es:[di].ga_handle
Handle_To_Sel al
push cx
push dx
cCall DebugFreeSegment,<ax,0>
pop dx
pop cx
all3:
mov es,es:[di].ga_next ; Move to next block
loop all2 ; Back for more if there (may go extra times
; because of coalescing, but no great whoop)
endif
call gfreeall
pop cx
CheckHeap GlobalFreeAll
call gleave
mov es,di
cEnd
;-----------------------------------------------------------------------;
; xhandle ;
; ;
; Returns the handle for a global segment. ;
; ;
; Arguments: ;
; Stack = sp -> near return return address ;
; sp+2 -> far return return address of caller ;
; sp+6 -> segment address parameter ;
; ;
; Returns: ;
; Old DS,DI have been pushed on the stack ;
; ;
; ZF= 1 if fixed segment. ;
; AX = handle ;
; ;
; ZF = 0 ;
; AX = handle ;
; BX = pointer to handle table entry ;
; CX = flags and count word from handle table ;
; DX = segment address ;
; ES:DI = arena header of object ;
; DS:DI = master object segment address ;
; ;
; Error Returns: ;
; AX = 0 if invalid segment address ;
; ZF = 1 ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Thu Oct 16, 1986 02:40:08p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
cProc xhandle,<PUBLIC,NEAR>
cBegin nogen
pop dx ; Get near return address
mov bx,sp ; Get seg parameter from stack
mov ax,ss:[bx+4]
cmp ax,-1 ; Is it -1?
jnz xh1
mov ax,ds ; Yes, use callers DS
xh1: inc bp
push bp
mov bp,sp
push ds ; Save DS:DI
push di
call genter
push dx
mov dx,ax
push si
call pdref
mov dx,ax ; get seg address in DX
jz xhandle_ret ; invalid or discarded handle
mov bx,si
or si,si
jz xhandle_ret
mov ax,si
xhandle_ret:
pop si
ret
cEnd nogen
cProc GlobalHandleNorip,<PUBLIC,FAR>
; parmW seg
cBegin nogen
if KDEBUG
call xhandle_norip
jmp xhandlex
endif
cEnd nogen
cProc IGlobalHandle,<PUBLIC,FAR>
parmW selector
cBegin
cCall MyLock,<selector>
xchg ax, dx
cEnd
cProc MyLock,<PUBLIC,NEAR>
; parmW selector
cBegin nogen
mov bx, sp
xor ax, ax ; In case LAR fails
xor dx, dx
lar ax, ss:[bx+2]
jnz ML_End ; LAR failed, get out
test ah, DSC_PRESENT
jz @F
push ds ; Do quick conversion for present
SetKernelDS ; selector
mov ds, pGlobalHeap
UnSetKernelDS
cCall get_arena_pointer,<ss:[bx+2]>
;** Fix for bugs #9106 and (I think) #9102
or ax,ax ;Did get_arena_pointer fail?
jnz ml_got_arena ;No, skip this
ife ROM
;** If we get here, it's only because get_arena_pointer failed.
;** This happens with any non-heap selector.
pop ds
jmps ML_End ;Return NULL instead of GP faulting
else
;** get_arena_pointer fails when called with a ROM segment selector
;** so just assume that's what happened and return the selector
mov ax,ss:[bx+2] ; Assume that's what happened and
jmps ml_ret ; just return the selector
endif
ml_got_arena:
mov ds, ax
mov ax, ds:[ga_handle]
ml_ret:
pop ds
mov dx, ax
Handle_To_Sel al
ML_End:
ret 2
@@:
pop ax ; Convert to far call for xhandle
push cs
push ax
call xhandle ; Go around the houses
PROFILE GlobalHandle
xchg ax, dx
jmp xhandlex
cEnd nogen
cProc ILockSegment,<PUBLIC,FAR>
; parmW seg
cBegin nogen
call xhandle ; Get handle
PROFILE LOCKSEGMENT
jz @F ; Ignore invalid or discarded objects
test cl,GA_DISCARDABLE
jz @F
call glock
@@:
jmp xhandlex
cEnd nogen
cProc IGlobalFix,<PUBLIC,FAR>
; parmW seg
cBegin nogen
call xhandle ; Get handle
PROFILE GLOBALFIX
jnz igf5
jmp xhandlex ; Ignore invalid or discarded objects
igf5:
call glock
jmp xhandlex
cEnd nogen
cProc IUnlockSegment,<PUBLIC,FAR>
; parmW seg
cBegin nogen
call xhandle ; Get handle
PROFILE UNLOCKSEGMENT
jz xhandlex ; Ignore invalid or discarded objects
test cl,GA_DISCARDABLE
jz xhandlex
call gunlock
jmps xhandlex
cEnd nogen
cProc IGlobalUnfix,<PUBLIC,FAR>
; parmW seg
cBegin nogen
call xhandle ; Get handle
PROFILE GLOBALUNFIX
jz xhandlex ; Ignore invalid or discarded objects
call gunlock
jmps xhandlex
cEnd nogen
cProc IGlobalSize,<PUBLIC,FAR>
; parmW handle
cBegin nogen
call xhandle ; Call ghandle with handle in DX
PROFILE GLOBALSIZE
jnz gs1 ; Continue if valid handle
or dx,dx
jnz gs1
xor ax,ax ; Return zero if invalid handle
jmps xhandlex
gs1: mov ax, es ; Invalid handle if arena ptr = 0
or ax, ax
jz gs4
gs2: mov ax,es:[di].ga_size ; Get size in paragraphs
gs2a: push ax
xor dx,dx ; Returning a long result
mov cx,4
gs3: shl ax,1
rcl dx,1
loop gs3
if 0
; This hack should be enabled for Simcity when its other problems
; are fixed on RISC (aka with krnl286).
push ds
push dx
push ax
cCall hackcheck,<handle>
or ax,ax
jz gsN
pop ax
pop dx
mov ax,02000h
xor dx,dx
push dx
push ax
gsN:
pop ax
pop dx
pop ds
endif
pop cx ; Return number paragraphs in CX
jmps xhandlex
gs4: xor dx, dx
jmps xhandlex
cEnd nogen
cProc IGlobalFlags,<PUBLIC,FAR>
; parmW handle
cBegin nogen
call xhandle ; Call ghandle with handle in DX
PROFILE GLOBALFLAGS
xchg cl,ch ; Return lock count in low half
mov ax,cx ; Let caller do jcxz to test failure
xhandlex:
call gleave
mov es,di ; don't return arbitrary selector
pop di
pop ds
pop bp
dec bp
ret 2
cEnd nogen
cProc IGlobalLock,<PUBLIC,FAR>
parmW handle
ifdef WOW
localW gflags
localW accword
endif
cBegin
ifdef WOW
mov gflags,0
endif
xor dx, dx ; Assume failure
cmp handle, -1
jne @F
mov handle, ds
@@:
cCall GetAccessWord,<handle>
ifdef WOW
mov accword, ax
endif
test al, DSC_PRESENT ; Is it present?
jz GL_exit
mov dx, handle ; OK, will return something
Handle_To_Sel dl ; Turn parameter into a selector
ifndef WOW
test ah, DSC_DISCARDABLE ; Is it discardable
jz GL_exit ; no, Lock is a nop
endif
cCall get_arena_pointer,<dx> ; Discardable, get its arena
or ax, ax
jz GL_exit ; No arena, assume an alias
mov es, ax
ifdef WOW
mov al, es:[ga_flags]
mov byte ptr gflags, al
test accword, DSC_DISCARDABLE SHL 8
jz GL_exit
endif
inc es:[ga_count] ; Finally, do the lock
;;; jz GL_rip ; Rip if we overflow
GL_exit:
ifdef WOW
test gflags, GAH_CURSORICON
jz GL_NotIcon
push dx ; save
push handle ; arg for CursorIconLockOp
push FUN_GLOBALLOCK ; func id
call WowCursorIconOp
pop dx ; restore
GL_NotIcon:
endif
xor ax, ax
mov es, ax ; Clean out ES
mov cx, dx ; HISTORY - someone probably does a jcxz
cEnd
cProc IGlobalUnlock,<PUBLIC,FAR>
parmW handle
ifdef WOW
localW gflags
localW accword
endif
cBegin
mov gflags,0
cmp handle, -1
jne @F
mov handle, ds
@@:
;
; Does this thing have any ring bits or LDT bit? If not, then it
; could be a selector incorrectly converted to a handle.
;
test byte ptr handle,7
jnz @F
if KDEBUG
Trace_Out "GlobalUnlock:"
push seg ThisIsForTurboPascal
push offset ThisIsForTurboPascal
cCall OutputDebugString
INT3_WARN
endif
dec handle
@@:
xor cx, cx ; Assume zero lock count
cCall GetAccessWord,<handle>
ifdef WOW
mov accword, ax
endif
test al, DSC_PRESENT ; Is it present?
jz GU_exit ; no, must be discarded, return 0:0
ifndef WOW
test ah, DSC_DISCARDABLE ; Is it discardable
jz GU_exit ; no, Lock is a nop
endif
cCall get_arena_pointer,<handle> ; Discardable, get its arena
or ax, ax
jz GU_exit ; No arena, assume an alias
mov es, ax
ifdef WOW
mov al, es:[ga_flags]
mov byte ptr gflags, al
test accword, DSC_DISCARDABLE SHL 8
jz GU_exit
endif
mov cl, es:[ga_count] ; Get current count
dec cl
cmp cl, 0FEh
jae @F
dec es:[ga_count] ; Finally, do the unlock
jmps GU_Exit
@@:
;;; ; Rip if we underflow
xor cx, cx ; Return zero on underflow
GU_exit:
ifdef WOW
test gflags, GAH_CURSORICON
jz GUL_NotIcon
push cx ; save
push handle ; arg for CursorIconLockOp
push FUN_GLOBALUNLOCK ; UnLocking
call WowCursorIconOp
pop cx ; restore
GUL_NotIcon:
endif
xor ax, ax
mov es, ax ; Clean out ES
mov ax, cx
cEnd
;-----------------------------------------------------------------------;
; GlobalWire ;
; ;
; Locks a moveable segment and moves it down as low as possible. ;
; This is meant for people who are going to be locking an object ;
; for a while and wish to be polite. It cannot work as a general ;
; panacea, judgement is still called for in its use! ;
; ;
; Arguments: ;
; WORD object handle ;
; ;
; Returns: ;
; DWORD object address ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; xhandle ;
; gmovebusy ;
; ;
; History: ;
; ;
; Wed Dec 03, 1986 01:07:13p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
cProc IGlobalWire,<PUBLIC,FAR>
; parmW handle
cBegin nogen
SetKernelDS es
or Kernel_Flags[1],kf1_MEMORYMOVED
UnSetKernelDS es
if KDEBUG
push ds
SetKernelDS
cmp [fBooting], 0
jnz shutup
push bx
mov bx, sp
mov bx, ss:[bx+8]
krDebugOut <DEB_WARN OR DEB_KrMemMan>, "GlobalWire(#BX of %BX2) (try GlobalLock)"
pop bx
shutup:
pop ds
UnSetKernelDS
endif
call xhandle
push si
jz gw_done ; Ignore invalid or discarded objects
push bx ; Save handle
push cx
test cl,GA_DISCARDABLE
jz @F
inc es:[di].ga_count ; don't want to discard if discardable
@@: xor ax,ax ; Try to get a fixed segment.
mov bx,es:[di].ga_size
mov cx,es:[di].ga_owner
call gsearch ; AX = segment
pop cx
pop bx ; Object handle.
push ax ; Return from gsearch
cCall get_arena_pointer,<bx> ; Get arena header, gsearch may
mov es,ax ; have moved the global object!
test cl,GA_DISCARDABLE
jz @F
dec es:[di].ga_count ; undo lock
@@:
;;; mov es, es:[di].ga_next
;;; mov ax, es:[di].ga_prev ; REAL arena header
mov si,ax
;;; mov es,ax
pop ax
or ax,ax
push bx ; Handle
jz lock_in_place ; Couldn't get memory.
push ax ; New Block
mov bx,ax
cCall cmp_sel_address,<bx,si> ; Flags set as if cmp bx,si
ja oh_no_mr_bill ; Let's not move it up in memory!!
pop es
; mov bx,ga_next ; This is always an exact fit.
call gmovebusy ; Wire it on down.
lock_in_place:
pop bx ; Handle
inc es:[di].ga_count ; Lock it down.
test es:[di].ga_flags,GA_DISCCODE
jz not_disccode
call glrudel
and es:[di].ga_flags,NOT GA_DISCCODE
not_disccode:
mov ax,es
mov ax, es:[di].ga_handle
Handle_To_Sel al
gw_done:
mov dx,ax
xor ax,ax ; Make address SEG:OFF.
pop si
gw_ret: jmp xhandlex
oh_no_mr_bill:
pop bx ; kill what's on stack
push es
mov es, ax
xor si, si
call gmarkfree
pop es
jmp lock_in_place
cEnd nogen
;-----------------------------------------------------------------------;
; GlobalUnWire ;
; ;
; ;
; Arguments: ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Wed Sep 16, 1987 04:28:49p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
cProc IGlobalUnWire,<PUBLIC,FAR>
; parmW handle
cBegin nogen
call xhandle
jnz guw_go
jmp xhandlex
guw_go:
cCall GetAccessWord,<bx>
test ah, DSC_DISCARDABLE
jz guw_not_disccode
test al, DSC_CODE_BIT
jz guw_not_disccode
or es:[di].ga_flags,GA_DISCCODE
call glruadd
guw_not_disccode:
if KDEBUG
cmp ch,00h ; Debugging check for count underflow
jne unlock1
push bx ; then the count is wrong.
push cx
push dx
xor cx,cx
kerror ERR_GMEMUNLOCK,<GlobalUnWire: Object usage count underflow>,cx,bx
pop dx
pop cx
pop bx
unlock1:
endif
call gunlock
mov ax, 0FFFFh ; TRUE
jcxz guw_done
inc ax ; FALSE
guw_done:
jmp xhandlex
cEnd nogen
;-----------------------------------------------------------------------;
; GlobalCompact ;
; ;
; Compacts the global arena until a free block of the requested size ;
; appears. Contrary to the toolkit it ALWAYS compacts! ;
; ;
; Arguments: ;
; DWORD minimum bytes wanted ;
; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
; Added the zero'ing of ES on exit. ;
; ;
; Wed Dec 03, 1986 01:09:02p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalCompact,<PUBLIC,FAR>,<bx,si,di>
parmD minBytes
cBegin
call genter ; About to modify memory arena
PROFILE GLOBALCOMPACT
CheckHeap GlobalCompact
cCall DpmiFreeSpace
cmp dx,seg_minBytes
jb GCReallyCompact
ja GCWorked
cmp ax,off_minBytes
jnb GCWorked
GCReallyCompact:
if KDEBUG
push ax
push bx
mov ax, seg_minBytes
mov bx, off_minBytes
krDebugOut DEB_TRACE, "%SS2 GlobalCompact(#ax#BX), discarding segments"
pop bx
pop ax
endif
mov ax,-1
lea bx,minBytes
call gbtop
assumes es, nothing
clc ; galign should be called with CF = 0
call galign
call gavail ; Returns paragraphs in DX:AX
mov cx,4 ; Convert paragraphs to bytes
push ax
gcsize1:
shl ax,1
rcl dx,1
loop gcsize1
pop cx ; Let caller do jcxz to test failure.
jmp GCDone
GCWorked:
cmp dx,0fh ; make sure return value not too large
jb GCAlmostDone
ja GCAD1
cmp ax,0ffb0h
jb GCAlmostDone
GCAD1:
mov dx,0fh
mov ax,0ffb0h
GCAlmostDone:
mov cx,dx
mov bx,ax
shr bx,4
shl cx,12
or cx,bx
GCDone:
call ShrinkHeap
call gleave
mov es,di
cEnd
;-----------------------------------------------------------------------;
; GlobalNotify ;
; ;
; This sets a procedure to call when a discardable segment belonging ;
; to this task gets discarded. The discardable object must have been ;
; allocated with the GMEM_DISCARDABLE bit set. ;
; ;
; Arguments: ;
; parmD NotifyProc ;
; ;
; Returns: ;
; nothing ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; AX,CX,DX,DI,SI,DS ;
; ;
; Registers Destroyed: ;
; BX,ES ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Tue Jun 23, 1987 10:16:32p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
cProc IGlobalNotify,<PUBLIC,FAR>
parmD NotifyProc
cBegin
push ds
les bx,NotifyProc ; verify pointer
SetKernelDS
mov ds,curTDB
UnsetKernelDS
mov word ptr ds:[TDB_GNotifyProc][2],es
mov word ptr ds:[TDB_GNotifyProc][0],bx
pop ds
cEnd
cProc GlobalMasterHandle,<PUBLIC,FAR>
cBegin nogen
push ds
SetKernelDS
mov ax,hGlobalHeap
mov dx,pGlobalHeap
UnSetKernelDS
pop ds
ret
cEnd nogen
;-----------------------------------------------------------------------;
; GetTaskDS ;
; ;
; Gets the segment of the current task's DS. ;
; ;
; Arguments: ;
; none ;
; ;
; Returns: ;
; AX = selector. ;
; DX = selector. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Thu Jun 25, 1987 10:52:10p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
cProc GetTaskDS,<PUBLIC,FAR>
cBegin nogen
push ds
SetKernelDS
mov ds,curTDB
UnsetKernelDS
mov ax,ds:[TDB_Module]
mov dx,ax
pop ds
ret
cEnd nogen
assumes ds, nothing
assumes es, nothing
cProc IGlobalLRUOldest,<PUBLIC,FAR>
; parmW handle
cBegin nogen
call xhandle ; Call ghandle with handle in DX
jz xhandlex2
call glrubot
xhandlex2:
jmp xhandlex
cEnd nogen
cProc IGlobalLRUNewest,<PUBLIC,FAR>
; parmW handle
cBegin nogen
call xhandle ; Call ghandle with handle in DX
jz xhandlex2
call glrutop
jmp xhandlex
cEnd nogen
;-----------------------------------------------------------------------;
; SwitchStackTo ;
; ;
; Switched to the given stack, and establishes the BP chain. It also ;
; copies the last stack arguments from the old stack to the new stack. ;
; ;
; Arguments: ;
; parmW new_ss ;
; parmW new_sp ;
; parmW stack_top ;
; ;
; Returns: ;
; A new stack! ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; DI,SI,DS ;
; ;
; Registers Destroyed: ;
; AX,BX,CX,DX,ES ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Tue Sep 22, 1987 08:42:05p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProcVDO SwitchStackTo,<PUBLIC,FAR>
; parmW new_ss
; parmW new_sp
; parmW stack_top
cBegin nogen
SetKernelDS es
FCLI
mov GSS_SI,si
mov GSS_DS,ds
pop word ptr GSS_RET[0] ; get the return address
pop word ptr GSS_RET[2]
assumes es, nothing
pop ax ; stack_top
pop bx ; new_sp
pop dx ; new_ss
mov si,bp ; Calculate # of parameters on stack.
dec si ; remove DS
dec si
mov cx,si
sub cx,sp
shr cx,1
push bp ; save BP
smov es,ss
mov ds,dx ; new_ss
mov ds:[2],sp
mov ds:[4],ss
mov ds:[pStackTop],ax
mov ds:[pStackMin],bx
mov ds:[pStackBot],bx
; switch stacks
mov ss,dx
mov sp,bx
mov bp,bx
xor ax,ax
push ax ; null terminate bp chain
jcxz no_args
copy_args:
dec si
dec si
push es:[si]
loop copy_args
no_args:
SetKernelDS
mov es,curTDB
mov es:[TDB_taskSS],ss
mov es:[TDB_taskSP],sp
push GSS_RET.sel
push GSS_RET.off ; get the return address
mov si,GSS_SI
mov ds,GSS_DS
FSTI
ret
cEnd nogen
;-----------------------------------------------------------------------;
; SwitchStackBack ;
; ;
; Switches to the stack stored at SS:[2], and restores BP. Preserves ;
; AX and DX so that results can be passed back from the last call. ;
; ;
; Arguments: ;
; none ;
; ;
; Returns: ;
; The old stack! ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; AX,DX,DI,SI,DS ;
; ;
; Registers Destroyed: ;
; BX,CX,ES ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Tue Sep 22, 1987 09:56:32p -by- David N. Weise [davidw] ;
; Wrote it. ;
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc SwitchStackBack,<PUBLIC,FAR>
cBegin nogen
push ds
SetKernelDS
FCLI
pop GSS_DS
pop GSS_RET.off ; get the return address
pop GSS_RET.sel
xor bx,bx
xor cx,cx
xchg bx,ss:[4]
xchg cx,ss:[2]
mov ss,bx
mov sp,cx
mov es,curTDB
mov es:[TDB_taskSS],ss
mov es:[TDB_taskSP],sp
pop bp
push GSS_RET.sel
push GSS_RET.off ; get the return address
mov ds,GSS_DS
UnSetKernelDS
FSTI
ret
cEnd nogen
;
; GetFreeMemInfo - reports Free and Unlocked pages
; in paging systems. -1 for non paging system.
;
cProc GetFreeMemInfo,<PUBLIC,FAR>
cBegin nogen
mov ax, -1
mov dx, ax
ret
cEnd nogen
;-----------------------------------------------------------------------;
; GetFreeSpace ;
; ;
; Calculates the current amount of free space ;
; ;
; Arguments: ;
; flags - ignored for non-EMS system ;
; ;
; Returns: ;
; DX:AX Free space in bytes ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; DI,SI,DS ;
; ;
; Registers Destroyed: ;
; BX,CX,ES ;
; ;
; Calls: ;
; nothing ;
; ;
; History: ;
; ;
; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
; Added the zero'ing of ES on exit. ;
; ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc IGetFreeSpace,<PUBLIC,FAR>,<si,di>
parmW flags
localV MemInfo,30h
cBegin
call genter
xor si, si
xor dx, dx
mov es, [di].hi_first
gfs_loop:
mov es, es:[di].ga_next
cmp es:[di].ga_sig, GA_ENDSIG
je gfs_last ; End of heap
mov ax, es:[di].ga_owner
cmp ax, GA_NOT_THERE
je gfs_loop ; Nothing there
or ax, ax ; Free?
jz gfs_freeblock
test flags, 2 ; Ignore discardable?
jnz gfs_loop
mov bx, es:[di].ga_handle
test bl, GA_FIXED
jnz gfs_loop ; Fixed block if odd
cmp es:[di].ga_sig, 0
jne gfs_loop ; skip if locked
cCall GetAccessWord,<bx>
test ah, DSC_DISCARDABLE
jz gfs_loop
gfs_freeblock:
mov ax, es:[di].ga_size
inc ax
add si, ax
adc dx, 0 ; Keep 32 bit total
jmps gfs_loop
gfs_last:
test flags, 2 ; No fence stuff if ignoring discardable
jnz @F
sub si, [di].gi_reserve ; Subtract out that above fence
sbb dx, 0
@@:
mov ax, si ; Return in DX:AX
; Convert to bytes
REPT 4
shl ax, 1
rcl dx, 1
ENDM
;
; Get the ammount of free memory
;
push bx
push cx
push ax
push dx
call DpmiFreeSpace
pop dx
pop ax
add ax,bx
adc dx,cx
pop cx
pop bx
@@: call gleave
mov es,di
cEnd
;-----------------------------------------------------------------------;
; GlobalDOSAlloc
;
; Allocates memory that is accessible by DOS.
;
; Entry:
; parmD nbytes number of bytes to alloc
;
; Returns:
; AX = memory handle
; DX = DOS segment paragraph address
;
; History:
; Tue 23-May-1989 11:30:57 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalDOSAlloc,<PUBLIC,FAR>,<di,si>
parmD nbytes
cBegin
mov ax,GA_ALLOC_DOS shl 8
cCall IGlobalAlloc,<ax,nbytes>
xor dx,dx ; In case of error return
or ax,ax
jz short gda_exit
push ax
cCall get_physical_address,<ax>
REPT 4
shr dx,1
rcr ax,1
ENDM
xchg dx,ax
pop ax
gda_exit:
cEnd
;-----------------------------------------------------------------------;
; GlobalDOSFree
;
; Frees memory allocated by GlobalDOSAlloc.
;
; Entry:
; parmW handle
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Tue 23-May-1989 17:48:03 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalDOSFree,<PUBLIC,FAR>
parmW handle
cBegin nogen
jmp IGlobalFree
cEnd nogen
if ALIASES
;-----------------------------------------------------------------------;
; GlobalAllocHuge
;
;
; Entry:
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Sun 21-Jan-1990 16:35:10 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalAllocHuge,<PUBLIC,FAR>,<di,si>
parmW flags
parmD nbytes
parmW maxsegs ; !!! check for maxsegs = 0
localW hMem
localW hAlias
cBegin
cCall GlobalAlloc,<0,nbytes>
or ax,ax
jz gah_exit
mov hMem,ax
cCall get_physical_address,<ax>
mov cx,maxsegs
cmp cx,0Fh
jb @F
mov cx,0Fh
@@: shl cx,12
or cx,0FFFh
cCall alloc_data_sel,<dx,ax,cx>
or ax,ax
jz gah_error_return
mov hAlias,ax
mov bx,hMem
call add_alias ; the key point!
mov bx,ax
mov ax,maxsegs ; the only way to remember
call add_alias ; the number of selectors
mov cx,nbytes.hi
mov bx,nbytes.lo
cCall set_sel_limit,<hAlias>
mov ax,hAlias
jmps gah_exit
gah_error_return:
cCall GlobalFree,<hMem>
xor ax,ax
gah_exit:
cEnd
;-----------------------------------------------------------------------;
; GlobalReAllocHuge
;
;
; Entry:
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Sun 21-Jan-1990 16:35:10 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalReAllocHuge,<PUBLIC,FAR>,<si,di>
parmW handle
parmD nbytes
cBegin
mov ax,handle
call get_alias_from_original
cmp bx,nbytes.hi
jb grh_error_exit
call get_original_from_alias
push es
or bx,SEG_RING
cCall GlobalRealloc,<bx,nbytes,0>
pop es
or ax,ax ; did we get the memory?
jz grh_exit
cmp ax,es:[di].sae_sel ; did the selector change?
jz grh_exit
mov es:[di].sae_sel,ax
cCall get_physical_address,<ax>
cCall set_physical_address,<handle>
mov ax,handle
jmps grh_exit
grh_error_exit:
xor ax,ax
grh_exit:
cEnd
;-----------------------------------------------------------------------;
; GlobalFreeHuge
;
;
; Entry:
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Mon 22-Jan-1990 21:24:02 -by- David N. Weise [davidw]
; Wrote it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalFreeHuge,<PUBLIC,FAR>,<di,si>
parmW handle
cBegin
mov ax,handle
call get_alias_from_original
mov es:[di].sae_sel,0
mov es:[di].sae_alias,0
mov cx,bx
mov bx,0FFFFh
cCall set_sel_limit,<ax>
mov dx,ax
mov ax,handle
call get_original_from_alias
push bx
push ax
call delete_alias
pop ax ; wastes a couple of bytes
cCall FreeSelector,<ax>
pop ax
cCall GlobalFree,<ax>
cEnd
endif ; ALIASES
;-----------------------------------------------------------------------;
; GlobalHuge
;
; Random place holder of an entry point.
;
; Entry:
;
; Returns:
;
; Registers Destroyed:
;
; History:
; Tue 23-Jan-1990 00:53:59 -by- David N. Weise [davidw]
; Stubbed it!
;-----------------------------------------------------------------------;
assumes ds,nothing
assumes es,nothing
cProc GlobalHuge,<PUBLIC,FAR>
cBegin nogen
ret 10
cEnd nogen
cProc DpmiFreeSpace,<PUBLIC,NEAR>,<di,si,es>
localV MemInfo,30h
cBegin
;
; Get Memory Info
;
mov ax,ss
mov es,ax
lea di,MemInfo
DPMICALL 500h
jc dfs30
;
; Convert pages to bytes
;
mov bx,MemInfo[14h]
mov cx,MemInfo[16h]
REPT 12
shl bx,1
rcl cx,1
ENDM
;
; Get the rest of the info
;
mov ax,MemInfo[0]
mov dx,MemInfo[2]
jmp dfs40
dfs30: xor ax,ax
mov bx,ax
mov cx,ax
mov dx,ax
dfs40:
cEnd
ifdef WOW
;--------------------------------------------------------------------------;
;
; Similar to GlobalFlags
;
;--------------------------------------------------------------------------;
cProc SetCursorIconFlag,<PUBLIC,FAR>
parmW handle
parmW fSet
cBegin
cCall get_arena_pointer,<handle> ; get the owner
mov es,ax
or ax,ax
jz sf_error
mov ax,fSet
or ax,ax
jz sf_unset
or es:[ga_flags], GAH_CURSORICON
jmps sf_error
sf_unset:
and es:[ga_flags], NOT GAH_CURSORICON
sf_error:
xor ax,ax
mov es,ax
cEnd
;--------------------------------------------------------------------------;
;
; Stamp the 01h in globalarena for DDE handles. This is GAH_PHANTOM flag
; which is not used any longer.
;
;--------------------------------------------------------------------------;
cProc SetDdeHandleFlag,<PUBLIC,FAR>
parmW handle
parmW fSet
cBegin
cCall get_arena_pointer,<handle> ; get the owner
mov es,ax
or ax,ax
jz sd_error
mov ax,fSet
or ax,ax
jz sd_unset
or es:[ga_flags], GAH_WOWDDEFREEHANDLE
jmps sd_error
sd_unset:
and es:[ga_flags], NOT GAH_WOWDDEFREEHANDLE
sd_error:
xor ax,ax
mov es,ax
cEnd
endif
sEnd CODE
end