1322 lines
54 KiB
NASM
1322 lines
54 KiB
NASM
TITLE GMEM - Register interface to global memory allocator
|
|
|
|
.xlist
|
|
include kernel.inc
|
|
include tdb.inc
|
|
include protect.inc
|
|
.list
|
|
|
|
externFP SetSelectorLimit
|
|
|
|
DataBegin
|
|
|
|
externB fBooting
|
|
;externW curTDB
|
|
;externW pGlobalHeap
|
|
externW SelTableStart
|
|
externW SelTableLen
|
|
|
|
ifdef WOW
|
|
globalB fInAlloc, 0
|
|
globalW UserSelArray, 0
|
|
globalW SelectorFreeBlock, 0
|
|
endif
|
|
|
|
DataEnd
|
|
|
|
sBegin CODE
|
|
assumes CS,CODE
|
|
|
|
externNP DPMIProc
|
|
DPMICALL MACRO callno
|
|
mov ax, callno
|
|
call DPMIProc
|
|
ENDM
|
|
|
|
;externW gdtdsc
|
|
|
|
|
|
externNP gsplice
|
|
externNP gjoin
|
|
externNP gzero
|
|
externNP gsearch
|
|
externNP gmarkfree
|
|
;externNP gcheckfree
|
|
externNP gmovebusy
|
|
externNP gcompact
|
|
externNP glruadd
|
|
externNP glrudel
|
|
externNP glrutop
|
|
externNP gnotify
|
|
externNP henum
|
|
externNP is_there_theoretically_enough_space
|
|
externNP can_we_clear_this_space
|
|
|
|
externNP get_physical_address
|
|
externNP set_physical_address
|
|
externNP alloc_sel
|
|
externNP alloc_data_sel_above
|
|
externNP pdref
|
|
externNP set_sel_limit
|
|
externNP mark_sel_PRESENT
|
|
externNP mark_sel_NP
|
|
externNP free_sel
|
|
externNP FreeSelArray
|
|
externNP GrowSelArray
|
|
externNP get_arena_pointer
|
|
externNP get_temp_sel
|
|
externNP get_blotto
|
|
;externNP get_sel
|
|
externNP PreallocSel
|
|
externNP AssociateSelector
|
|
externNP GetAccessWord
|
|
externNP SetAccessWord
|
|
externFP set_discarded_sel_owner
|
|
|
|
if ROM
|
|
externNP IsROMObject
|
|
endif
|
|
|
|
if KDEBUG
|
|
externNP CheckGAllocBreak
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; galign ;
|
|
; ;
|
|
; Aligns the size request for a global item to a valid para boundary. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; BX = #paras ;
|
|
; CF = 1 if #paras overflowed. ;
|
|
; ;
|
|
; Returns: ;
|
|
; DX = #paras aligned, to next higher multiple of 2 ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; DX = FFFFh ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; all ;
|
|
; Registers Destroyed: ;
|
|
; none ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; History: ;
|
|
; ;
|
|
; Mon Sep 22, 1986 03:14:56p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc galign,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
jc align_error ; Overflow occur?
|
|
lea dx,[bx+GA_ALIGN] ; No, add alignment amount
|
|
and dl,GA_MASK ; ...modulo alignment boundary
|
|
cmp dx,bx ; Test for overflow
|
|
jnb align_exit ; Yes, continue
|
|
align_error:
|
|
mov dx,0FFFFh ; Return impossible size
|
|
align_exit:
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; galloc ;
|
|
; ;
|
|
; Allocates global memory. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; AX = allocation flags ;
|
|
; BX = #paragraphs ;
|
|
; CX = owner field ;
|
|
; DS:DI = address of global heap info ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = handle to object or zero ;
|
|
; BX = size of largest free block if AX = 0 ;
|
|
; CX = AX ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; DX = 0 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; gsearch ;
|
|
; ghalloc ;
|
|
; glruadd ;
|
|
; gmarkfree ;
|
|
; History: ;
|
|
; ;
|
|
; Wed Jun 24, 1987 03:04:32a -by- David N. Weise [davidw] ;
|
|
; Added support for Global Notify. ;
|
|
; ;
|
|
; Mon Sep 22, 1986 02:38:19p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
AccessWord dw DSC_DATA+DSC_PRESENT
|
|
dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
|
|
dw DSC_CODE+DSC_PRESENT
|
|
dw (DSC_DISCARDABLE SHL 8) + DSC_CODE+DSC_PRESENT
|
|
dw DSC_DATA+DSC_PRESENT
|
|
dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
|
|
dw DSC_DATA+DSC_PRESENT
|
|
dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
|
|
|
|
cProc galloc,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
if ROM and KDEBUG
|
|
if 1
|
|
%out Remove me someday
|
|
endif
|
|
or cx,cx ; had trouble with owner == 0
|
|
jnz @f ; too many times!
|
|
Debug_Out "ROMKRNL: galloc with owner = 0!"
|
|
@@:
|
|
endif
|
|
|
|
if KDEBUG
|
|
test al,GA_DISCCODE ; If discardable code, allow alloc
|
|
jnz @F
|
|
call CheckGAllocBreak
|
|
jnc @F
|
|
jmp gaerr
|
|
@@:
|
|
endif
|
|
|
|
or bx,bx ; Allocating zero size?
|
|
jnz @F
|
|
jmp allocate_zero_size
|
|
@@:
|
|
|
|
ifdef WOW
|
|
push ds
|
|
SetKernelDS
|
|
mov fInAlloc, 1
|
|
mov SelectorFreeBlock, 0
|
|
mov UserSelArray, 0
|
|
UnSetKernelDS
|
|
pop ds
|
|
endif
|
|
call gsearch ; Search for block big enough
|
|
jnz bleech
|
|
mov cx, ax
|
|
|
|
ifdef WOW
|
|
push ds
|
|
SetKernelDS
|
|
mov fInAlloc, 0
|
|
mov SelectorFreeBlock, 0
|
|
mov UserSelArray, 0
|
|
UnSetKernelDS
|
|
pop ds
|
|
endif
|
|
|
|
ret ; Done, if couldn't get enough
|
|
bleech:
|
|
mov es,ax
|
|
push dx
|
|
|
|
ifdef WOW
|
|
|
|
push ds
|
|
SetKernelDS
|
|
mov fInAlloc, 0
|
|
mov SelectorFreeBlock, 0
|
|
mov ax, UserSelArray
|
|
UnSetKernelDS
|
|
pop ds
|
|
or ax, ax
|
|
jnz got_Sel
|
|
mov ax, es
|
|
|
|
old_path:
|
|
|
|
endif
|
|
mov bx,dx
|
|
cCall get_physical_address,<ax>
|
|
add ax,10h ; Calculate address of object
|
|
adc dx,0
|
|
mov cx, ax ; in DX:CX
|
|
|
|
and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
|
|
or bl, bh
|
|
xor bh, bh
|
|
shl bx, 1
|
|
mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
|
|
cCall alloc_sel,<dx,cx,es:[di].ga_size>
|
|
|
|
got_sel:
|
|
pop dx
|
|
or ax, ax
|
|
jz short gaerr1
|
|
cCall AssociateSelector,<ax,es>
|
|
test dl,GA_MOVEABLE ; Is this a moveable object?
|
|
jnz moveable
|
|
test dh, GA_DISCARDABLE ; We have a fixed block
|
|
jnz not_moveable ; Not interested in discardable blocks
|
|
mov bx, ax
|
|
%out THIS IS WRONG!!!
|
|
ifdef WOW
|
|
; the following dpmicall is basically a NOP. so just
|
|
; avoid the call altogether.
|
|
; - Nanduri Ramakrishna
|
|
else
|
|
mov ax, 4 ; Lock the WIN386 pages
|
|
;bugbugbugbug
|
|
DPMICALL ax ; int 31h
|
|
mov ax, bx
|
|
endif
|
|
jmps not_moveable
|
|
moveable:
|
|
mov es:[di].ga_count,0 ; Initialize lock count to 0
|
|
StoH al ; Mark as moveable block
|
|
not_moveable:
|
|
mov es:[di].ga_handle,ax ; Set handle in arena
|
|
mov bx, ax ; AX and BX handle
|
|
|
|
call glruadd ; Yes, Add to LRU chain
|
|
mov cx, ax
|
|
ret
|
|
|
|
allocate_zero_size:
|
|
test al,GA_MOVEABLE ; Yes, moveable?
|
|
jz gaerr ; No, return error (AX = 0)
|
|
|
|
mov bx, ax
|
|
and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
|
|
or bl, bh ; Above bits are exclusive
|
|
xor bh, bh
|
|
shl bx, 1
|
|
mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
|
|
and al, NOT DSC_PRESENT ; These are NOT present
|
|
xor dx, dx ; Base of zero for now
|
|
cCall alloc_sel,<dx,dx,cx>
|
|
or ax, ax
|
|
jz gaerr
|
|
|
|
cCall AssociateSelector,<ax,cx>
|
|
StoH al ; Handles are RING 2
|
|
mov bx,ax
|
|
ga_exit:
|
|
mov cx, ax
|
|
ret
|
|
|
|
gaerr1:
|
|
xor si,si
|
|
call gmarkfree
|
|
gaerr:
|
|
KernelLogError DBF_WARNING,ERR_GALLOC,"GlobalAlloc failed"
|
|
xor dx,dx ; DX = 0 means NOT out of memory
|
|
xor ax,ax ; Return AX = 0 to indicate error
|
|
jmps ga_exit
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; grealloc ;
|
|
; ;
|
|
; Reallocates the given global memory object. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; AX = allocation flags ;
|
|
; BX = #paragraphs for new size ;
|
|
; CX = new owner field value ;
|
|
; DX = existing handle ;
|
|
; DS:DI = address of global heap info ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = handle to object or zero ;
|
|
; DX = size of largest free block if AX = 0 ;
|
|
; CX = AX ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; SI ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Mon 05-Feb-1990 21:07:33 -by- David N. Weise [davidw] ;
|
|
; Got rid of the spagetti code. ;
|
|
; ;
|
|
; Mon Sep 22, 1986 10:11:48a -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc grealloc,<PUBLIC,NEAR>,<si>
|
|
|
|
localW rflags
|
|
localW hMem
|
|
localW oldhMem
|
|
localW owner
|
|
localW rsize
|
|
localW canmove
|
|
localB locked
|
|
localB mflags
|
|
localW numsels
|
|
cBegin
|
|
mov rflags,ax
|
|
mov hMem,dx
|
|
mov oldhMem,dx
|
|
mov owner,cx
|
|
mov rsize,bx
|
|
call pdref
|
|
mov dx,bx ; save owner if discarded
|
|
mov word ptr mflags,cx
|
|
mov bx,rsize
|
|
jnz handle_ok
|
|
jmp racreate ; Do nothing with 0, free or discarded handles
|
|
handle_ok:
|
|
test byte ptr rflags,GA_MODIFY ; Want to modify table flags?
|
|
jnz ramodify ; Yes go do it
|
|
or bx,bx ; Are we reallocing to zero length?
|
|
jz radiscard
|
|
jmp ra_shrink_grow ; No, continue
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; Here to discard object, when reallocating to zero size. This ;
|
|
; feature is only enabled if the caller passes the moveable flag ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
radiscard:
|
|
or ch,ch ; Is handle locked?
|
|
jnz radiscard_fail
|
|
test byte ptr rflags,GA_MOVEABLE ; Did they want to discard?
|
|
jz radiscard_fail ; No, then return failure.
|
|
mov al,GN_DISCARD ; AL = discard message code
|
|
xor cx,cx ; CX = means realloc
|
|
mov bx,hMem ; BX = handle
|
|
push es
|
|
call gnotify ; See if okay to discard
|
|
pop es
|
|
jz radiscard_fail ; No, do nothing
|
|
call glrudel ; Yes, Delete handle from LRU chain
|
|
|
|
cCall mark_sel_NP,<si,es:[di].ga_owner>
|
|
|
|
xor si,si
|
|
call gmarkfree ; Free client data
|
|
mov ax,0 ; don't change flags
|
|
jz @F ; Return NULL if freed a fixed block
|
|
mov bx, si
|
|
mov ax,hMem ; Return original handle, except
|
|
@@: jmp raexit ; GlobalLock will now return null.
|
|
|
|
radiscard_fail:
|
|
KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
|
|
xor dx,dx
|
|
xor ax,ax
|
|
jmp raexit
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; There are 2 attributes that can change: ;
|
|
; 1) Fixed -> moveable - added in 2.x, probably not used by many ;
|
|
; 2) nondiscardable <-> discardable ;
|
|
; 3) non-shared -> shared, i.e., the owner changes ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ramodify:
|
|
if ROM
|
|
cCall IsROMObject,<hMem> ; If someone is trying to modify a
|
|
jc ramod_done ; ROM object, just pretend it worked
|
|
endif
|
|
mov ax,rflags ; Get new flags
|
|
mov dx,owner ; Get new owner field value
|
|
or si,si ; Moveable object?
|
|
jnz is_moveable ; yes, change discardability/owner
|
|
test al,GA_MOVEABLE ; Make fixed into moveable?
|
|
jz ra_mod_owner ; Fixed, can ONLY change owner
|
|
|
|
push ax
|
|
push cx
|
|
mov ax, es:[di].ga_handle ; Turn selector into handle
|
|
StoH al
|
|
mov bx, ax
|
|
mov es:[di].ga_handle, ax
|
|
mov es:[di].ga_count, 0 ; 0 lock count for new movable obj
|
|
pop cx
|
|
pop ax
|
|
mov si,bx
|
|
|
|
; fall through to code that makes [non]discardable and may change owner
|
|
|
|
is_moveable:
|
|
call glrudel ; Remove from lru chain, even though
|
|
push bx
|
|
mov bx, ax
|
|
cCall GetAccessWord,<si>
|
|
and ah, not DSC_DISCARDABLE ; Clear discard bit
|
|
test bh, GA_DISCARDABLE
|
|
jz ra_notdiscardable
|
|
or ah, DSC_DISCARDABLE
|
|
ra_notdiscardable:
|
|
cCall SetAccessWord,<si,ax>
|
|
mov ax, bx
|
|
pop bx
|
|
test cl,HE_DISCARDED ; Is this a discarded handle?
|
|
jz ramod1 ; No, continue
|
|
test ah,GA_SHAREABLE ; Only change owner if making shared
|
|
jz ramod_done
|
|
|
|
push bx
|
|
push es
|
|
mov bx, si
|
|
mov es, dx
|
|
call set_discarded_sel_owner
|
|
pop es
|
|
pop bx
|
|
jmps ramod_done
|
|
|
|
ramod1: call glruadd ; only adds to list IF object is disc
|
|
|
|
ra_mod_owner:
|
|
test ah,GA_SHAREABLE ; Only change owner if making shared
|
|
jz ramod_done
|
|
mov es:[di].ga_owner,dx ; Set new owner value
|
|
ramod_done:
|
|
mov ax,hMem ; Return the same handle
|
|
jmp raexit ; All done
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; We are here to grow a 0 sized object up big. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
racreate:
|
|
test cl,HE_DISCARDED ; Is this a discarded handle?
|
|
jz racre_fail ; No, return error
|
|
or bx,bx ; Are we reallocing to zero length?
|
|
mov ax,hMem
|
|
jz racre_done ; Yes, return handle as is.
|
|
if KDEBUG
|
|
test cl,GA_DISCCODE ; if discardable code, allow realloc
|
|
jnz @F
|
|
call CheckGAllocBreak
|
|
jc racre_fail
|
|
@@:
|
|
endif
|
|
mov ax,GA_MOVEABLE ; Reallocating a moveable object
|
|
or ax,rflags ; ...plus any flags from the caller
|
|
|
|
and cl,GA_SEGTYPE
|
|
or al,cl
|
|
mov cx,dx ; get owner
|
|
push ds
|
|
SetKernelDS
|
|
ife ROM
|
|
cmp fBooting, 1 ; Allocate high while booting
|
|
je @F
|
|
endif
|
|
test al,GA_DISCCODE ; Discardable code segment?
|
|
jz ranotcode
|
|
@@:
|
|
or al,GA_ALLOCHIGH ; Yes, allocate high
|
|
ranotcode:
|
|
pop ds
|
|
UnSetKernelDS
|
|
mov [di].gi_cmpflags,al ; Save flags for gcompact
|
|
and [di].gi_cmpflags,CMP_FLAGS
|
|
push si ; save handle
|
|
call gsearch ; Find block big enough
|
|
pop si ; restore existing handle
|
|
jz racre_fail1
|
|
|
|
mov bx,ax ; save new block
|
|
cCall mark_sel_PRESENT,<ax,si> ; sets a new set of sels if necessary
|
|
or si,si
|
|
jz racre_worst_case
|
|
xchg ax,si ; Return original/new handle
|
|
; Set back link to handle in new block
|
|
cCall AssociateSelector,<ax,si>
|
|
mov es,si
|
|
mov es:[di].ga_handle,ax
|
|
mov es:[di].ga_count,0
|
|
call glruadd ; Add to LRU chain
|
|
jmps racre_done
|
|
|
|
racre_worst_case:
|
|
mov es,bx ; Free block if no handles available.
|
|
xor si,si
|
|
call gmarkfree
|
|
|
|
racre_fail:
|
|
xor dx,dx
|
|
racre_fail1:
|
|
push dx
|
|
KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
|
|
pop dx
|
|
xor ax,ax ; Yes, return failure
|
|
racre_done:
|
|
jmp raexit
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; This is what most would have thought is the guts of GlobalRealloc. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
ra_shrink_grow:
|
|
|
|
if KDEBUG
|
|
test es:[di].ga_flags,GA_DISCCODE
|
|
jz ok
|
|
INT3_WARN ; GlobalRealloc of discardable code!
|
|
ok:
|
|
endif
|
|
cmp bx,es:[di].ga_size
|
|
jz rasame
|
|
|
|
add bx,1 ; add room for header, set carry bit
|
|
jc ra_s_g_fail
|
|
call galign ; assuming there is room.
|
|
dec dx ; Exclude header again
|
|
mov si,dx
|
|
|
|
; Here if not trying to realloc this block to zero
|
|
; ES:0 = arena header of current block
|
|
; AX:0 = client address of current block
|
|
; CH = lock count of current block
|
|
; DX = new requested size of block
|
|
; SI = new requested size of block
|
|
|
|
mov bx,es:[di].ga_next ; Get address of current next header
|
|
cmp si,es:[di].ga_size ; Are we growing or shrinking?
|
|
ja raextend ; We are growing
|
|
|
|
call rashrink
|
|
rasame: mov ax,hMem ; Return the same handle
|
|
jmp raexit ; All done
|
|
|
|
raextend:
|
|
test rflags,GA_DISCCODE ; Not allowed to grow a disccode seg
|
|
jnz ra_s_g_fail
|
|
if KDEBUG
|
|
call CheckGAllocBreak
|
|
jc ra_s_g_fail
|
|
endif
|
|
push ax
|
|
call GrowSelArray
|
|
mov numsels, cx ; Save how many to free just in case
|
|
mov cx, ax
|
|
pop ax
|
|
jcxz ra_s_g_fail ; Didn't get selectors
|
|
mov hMem, cx ; We have a new handle
|
|
call ragrow
|
|
jnc rasame
|
|
test mflags,GA_DISCARDABLE ; if discardable, just stop now
|
|
jz ramove ; since it might get discarded!
|
|
ra_s_g_fail:
|
|
KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
|
|
xor ax,ax ; Yes, return failure
|
|
xor dx,dx
|
|
jmp raexit
|
|
|
|
|
|
; Here to try to move the current block
|
|
; AX = client address of current block
|
|
; ES:0 = arena header of current block
|
|
; CH = lock count of current block
|
|
; SI = new requested size of block
|
|
|
|
ramove: mov canmove, 1
|
|
mov dx,rflags ; get the passed in flags
|
|
test dx,GA_MOVEABLE ; Did they say OK to move
|
|
jnz ramove1 ; Yes, try to move even iflocked or fixed
|
|
cmp locked, 0 ; Locked?
|
|
jnz racompact ; Continue if this handle not locked
|
|
; yes, try to find space to grow in place
|
|
or dx,GA_MOVEABLE ; If moveable, make sure bit set.
|
|
test hMem,GA_FIXED ; Is this a moveable handle?
|
|
jz ramove2 ; Yes, okay to move
|
|
racompact:
|
|
xor dx,dx ; No, get size of largest free block
|
|
call gcompact
|
|
jmps racantmove
|
|
|
|
ramove1:
|
|
test hMem, GA_FIXED
|
|
jz ramove2
|
|
and dx, NOT GA_MOVEABLE
|
|
ramove2:
|
|
mov ax,dx ; AX = allocation flags
|
|
mov bx,si ; BX = size of new block
|
|
call PreAllocSel ; for gmovebusy later
|
|
jz racantmove
|
|
mov cx,bx ; CX = owner (use size for now)
|
|
call gsearch ; Find block big enough
|
|
jz racantmove ; Cant find one, grow in place now?
|
|
mov cx,hMem
|
|
|
|
push ax
|
|
cCall get_arena_pointer,<cx>
|
|
;;; mov es,ax
|
|
;;; mov es,es:[di].ga_next ; get real arena header
|
|
;;; mov si,es:[di].ga_prev
|
|
mov si, ax ; SI = source arena
|
|
pop es ; ES = destination arena
|
|
|
|
call gmovebusy ; Call common code to move busy block
|
|
; (AX destroyed)
|
|
push bx
|
|
push cx
|
|
mov bx, es:[di].ga_size
|
|
xor cx,cx
|
|
REPT 4
|
|
shl bx,1
|
|
rcl cx,1
|
|
ENDM
|
|
cCall set_sel_limit, <es:[di].ga_handle>
|
|
|
|
pop cx
|
|
pop bx
|
|
mov ax,cx ; Return new handle
|
|
raexit:
|
|
mov cx,ax
|
|
jcxz ra_done
|
|
test hMem,GA_FIXED ; Is this a moveable object?
|
|
jz ra_done ; no, don't lock
|
|
mov bx, ax
|
|
ifdef WOW
|
|
; the following dpmicall is basically a NOP. so just
|
|
; avoid the call altogether.
|
|
; - Nanduri Ramakrishna
|
|
else
|
|
mov ax, 4 ; Lock the WIN386 pages
|
|
; bugbugbugbug
|
|
DPMICALL ax ; int 31h
|
|
mov ax, bx
|
|
endif
|
|
jmps ra_done
|
|
|
|
racantmove:
|
|
mov dx, hMem
|
|
call pdref
|
|
|
|
mov bx,rsize
|
|
add bx,1 ; add room for header, set carry bit
|
|
call galign ; assuming there is room.
|
|
dec dx ; Exclude header again
|
|
mov si,dx
|
|
|
|
mov bx,es:[di].ga_next ; Get address of current next header
|
|
call ragrow
|
|
jc racmove3
|
|
jmp rasame
|
|
|
|
racmove3:
|
|
xor dx,dx ; No, get size of largest free block
|
|
call gcompact
|
|
mov dx,ax ; DX = size of largest free block
|
|
|
|
rafailmem:
|
|
cCall get_arena_pointer,<hMem>
|
|
mov es,ax
|
|
mov ax,es:[di].ga_size ; AX = size of current block
|
|
mov es,es:[di].ga_next ; Check following block
|
|
cmp es:[di].ga_owner,di ; Is it free?
|
|
jne rafailmem0 ; No, continue
|
|
add ax,es:[di].ga_size ; Yes, then include it as well
|
|
inc ax
|
|
rafailmem0:
|
|
cmp ax,dx ; Choose the larger of the two
|
|
jbe rafailmem1
|
|
mov dx,ax
|
|
rafailmem1:
|
|
push dx ; Save DX
|
|
KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
|
|
pop dx ; RestoreDX
|
|
xor ax,ax
|
|
jmps raexit
|
|
|
|
ra_done: ; 3 feb 1990, this
|
|
push ax ; is a last minute hack
|
|
push bx
|
|
push cx
|
|
push dx
|
|
mov bx,hMem
|
|
mov cx,oldhMem
|
|
ife RING-1
|
|
inc bx
|
|
and bl,NOT 1
|
|
inc cx
|
|
and cl,NOT 1
|
|
else
|
|
or bl, 1
|
|
or cl, 1
|
|
endif
|
|
cmp bx,cx ; was a new selector allocated?
|
|
jz ra_really_done ;
|
|
or ax,ax ; figure out if we suceeded
|
|
jz ra_ra
|
|
cCall FreeSelArray,<cx> ; free the original selector
|
|
jmps ra_really_done
|
|
|
|
ra_ra: cCall get_physical_address,<bx>
|
|
cCall set_physical_address,<oldhMem>
|
|
cCall get_arena_pointer,<hMem>
|
|
INT3_ANCIENT
|
|
cCall AssociateSelector,<cx,es>
|
|
push ax
|
|
|
|
mov cx, numsels
|
|
mov ax, hMem
|
|
fsloop:
|
|
cCall free_sel,<ax>
|
|
add ax, 8
|
|
loop fsloop
|
|
|
|
pop es
|
|
mov ax,oldhMem
|
|
mov es:[ga_handle],ax
|
|
cCall AssociateSelector,<ax,es>
|
|
|
|
ra_really_done:
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; rashrink ;
|
|
; ;
|
|
; Shrinks the given block ;
|
|
; ;
|
|
; Arguments: ;
|
|
; Here to shrink a block ;
|
|
; ES:0 = arena header of current block ;
|
|
; DX = new requested size of block ;
|
|
; SI = new requested size of block ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ALL but DS, DI ;
|
|
; ;
|
|
; Calls: ;
|
|
; gsplice ;
|
|
; gmarkfree ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue 06-Feb-1990 01:03:54 -by- David N. Weise [davidw] ;
|
|
; I got no clue what the history of this thing is, all I know is ;
|
|
; that I got to fix it fast to prevent selector leak. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc rashrink,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
mov bx,si
|
|
xor cx,cx
|
|
REPT 4
|
|
shl bx,1
|
|
rcl cx,1
|
|
ENDM
|
|
mov ax,es:[di].ga_handle
|
|
or ax,ax
|
|
jz ra_free
|
|
|
|
; !! the following was added Tue 06-Feb-1990 01:47:12
|
|
; it doesn't belong here really but it is the only way to
|
|
; prevent selector leak.
|
|
|
|
push bx
|
|
push cx
|
|
push si
|
|
|
|
mov si,ax
|
|
cCall GetAccessWord,<si>
|
|
mov bl, ah
|
|
mov ax, si
|
|
and bl, 0Fh ; Current hlimit
|
|
inc bl ; number of selectors there now
|
|
mov cx,dx
|
|
|
|
add cx, 0FFFh
|
|
rcr cx, 1 ; 17 bitdom
|
|
shr cx, 11
|
|
sub bl, cl
|
|
jbe ignore_this_shi
|
|
|
|
xor bh,bh ; BX = number of selectors to free
|
|
shl cx,3
|
|
.errnz SIZE DscPtr - 8
|
|
add cx,si ; CX = selector to start to free
|
|
xchg bx,cx
|
|
@@: cCall free_sel,<bx>
|
|
add bx,SIZE DscPtr
|
|
loop @B
|
|
|
|
ignore_this_shi:
|
|
pop si
|
|
pop cx
|
|
pop bx
|
|
|
|
; end of shi
|
|
|
|
Handle_To_Sel al
|
|
cCall set_sel_limit,<ax>
|
|
ra_free:
|
|
inc dx ; Test for small shrinkage
|
|
inc dx
|
|
.errnz GA_ALIGN - 1
|
|
|
|
cmp dx,es:[di].ga_size ; Enough room from for free block?
|
|
ja rashrunk ; No, then no change to make
|
|
|
|
; !! why isn't the PreAllocSel done before the set_sel_limit?
|
|
; Because it belongs with the 'gsplice'.
|
|
|
|
call PreallocSel ; Must be able to get selector
|
|
jz rashrunk
|
|
; Yes, ES:DI = cur block, SI=new block
|
|
inc si ; Include header in size of block
|
|
call gsplice ; splice new block into the arena
|
|
mov es,si ; ES:DI = new free block
|
|
xor si,si
|
|
call gmarkfree ; Mark it as free
|
|
rashrunk:
|
|
ret
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; ragrow ;
|
|
; ;
|
|
; Tries to grow the given global memory object in place ;
|
|
; ;
|
|
; Arguments: ;
|
|
; AX:0 = client address of current block ;
|
|
; ES:0 = arena header of current block ;
|
|
; BX:0 = arena header of next block ;
|
|
; DX = SI = new requested size of block ;
|
|
; ;
|
|
; Returns: ;
|
|
; CY = 0 Success ;
|
|
; ;
|
|
; CY = 1 Failed ;
|
|
; ES preserved ;
|
|
; DX contains free memory required ;
|
|
; ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ALL but DS, DI ;
|
|
; ;
|
|
; Calls: ;
|
|
; is_there_theoretically_enough_space ;
|
|
; can_we_clear_this_space ;
|
|
; gjoin ;
|
|
; gzero ;
|
|
; rashrink ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Mon 05-Sep-1988 20:10:15 -by- David N. Weise [davidw] ;
|
|
; Made ragrow be more intelligent by trying to extend into moveable ;
|
|
; blocks. ;
|
|
;-----------------------------------------------------------------------;
|
|
cProc ragrow,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push si
|
|
push es ; Save current block address
|
|
sub dx, es:[di].ga_size ; compute amount of free space wanted
|
|
mov es,bx ; ES = next block address
|
|
mov cx,[di].hi_count
|
|
push cx
|
|
push es
|
|
call is_there_theoretically_enough_space
|
|
pop es
|
|
pop cx
|
|
cmp ax,dx
|
|
jb ragx
|
|
call can_we_clear_this_space
|
|
jz ragx
|
|
pop cx ; clear the stack
|
|
pop si
|
|
push si
|
|
call gjoin ; and attach to end of current block
|
|
pop si ; (will free a selector)
|
|
test byte ptr rflags,GA_ZEROINIT ; Zero fill extension?
|
|
jz ranz ; No, continue
|
|
|
|
mov bx, dx ; number of paragraphs to fill
|
|
mov dx, si ; New size of block
|
|
sub dx, bx ; Old size of block
|
|
inc dx ; Paragraph offset of where to zero
|
|
cCall alloc_data_sel_above,<es,dx>
|
|
push bx
|
|
push ax ; set the limit really big
|
|
push es
|
|
cCall SetSelectorLimit,<ax,0Fh,0FFFFh>
|
|
pop es
|
|
pop ax
|
|
pop cx ; Number of paragraphs to zero
|
|
mov bx, ax ; Selector to fill
|
|
call gzero ; zero fill extension
|
|
cCall free_sel,<bx>
|
|
ranz:
|
|
mov dx, si
|
|
mov bx,es:[di].ga_next ; Pick up new next block address
|
|
call rashrink ; Now shrink block to correct size
|
|
clc
|
|
ret
|
|
ragx:
|
|
pop es ; Recover current block address
|
|
pop si
|
|
stc
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gfree ;
|
|
; ;
|
|
; Frees a global object. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DX = global memory object handle ;
|
|
; CX = owner field value to match or zero if dont care ;
|
|
; DS:DI = address of global heap info ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = 0 ;
|
|
; CX = 0 ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = -1 ;
|
|
; CX = -1 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ? ;
|
|
; Calls: ;
|
|
; gdref ;
|
|
; free_object ;
|
|
; hfree ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Sat Sep 20, 1986 11:48:38a -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block and restructured. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gfree,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push cx
|
|
call pdref
|
|
|
|
pop dx
|
|
jz object_discarded
|
|
call free_object
|
|
jmps gfree_exit
|
|
object_discarded:
|
|
|
|
cCall AssociateSelector,<si,di>
|
|
cCall FreeSelArray,<si>
|
|
xor ax,ax ;!!! just for now force success
|
|
|
|
gfree_exit:
|
|
mov cx,ax
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; free_object ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DX = owner field value to match or zero if dont care ;
|
|
; DS:DI = address of global heap info ;
|
|
; ES:DI = address of arena header ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = 0 ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = -1 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; glrudel ;
|
|
; gmarkfree ;
|
|
; hfree ;
|
|
; History: ;
|
|
; ;
|
|
; Sat Sep 20, 1986 02:59:06p -by- David N. Weise [davidw] ;
|
|
; Moved it from gfree. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc free_object,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
or dx,dx
|
|
jz free_it
|
|
cmp es:[di].ga_owner,dx
|
|
je free_it
|
|
mov ax,-1
|
|
jmps free_object_exit
|
|
free_it:
|
|
call glrudel ; delete object from LRU chain
|
|
xor si,si
|
|
call gmarkfree ; free the object
|
|
cCall AssociateSelector,<si,di>
|
|
cCall FreeSelArray,<si>
|
|
xor ax,ax ;!!! just for now force success
|
|
free_object_exit:
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; free_handle ;
|
|
; ;
|
|
; Frees the given handle. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DS:SI = handle table entry address ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = 0 ;
|
|
; CX = AX ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = -1 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; BX ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ? ;
|
|
; Calls: ;
|
|
; hfree ;
|
|
; History: ;
|
|
; ;
|
|
; Sat Sep 20, 1986 02:30:32p -by- David N. Weise [davidw] ;
|
|
; Moved it from gfree. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;cProc free_handle,<PUBLIC,NEAR>
|
|
;cBegin nogen
|
|
; xor ax,ax
|
|
; or si,si
|
|
; jz free_handle_exit
|
|
; push bx
|
|
; mov bx,si
|
|
; call hfree
|
|
; pop bx
|
|
;free_handle_exit:
|
|
; ret
|
|
;cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gfreeall ;
|
|
; ;
|
|
; Frees all global objects that belong to the given owner. It first ;
|
|
; loops through the global heap freeing objects and then loops through ;
|
|
; the handle table freeing handles of discarded objects. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DX = owner field value to match ;
|
|
; DS:DI = address of global heap info ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; CX,ES,SI ;
|
|
; ;
|
|
; Calls: ;
|
|
; free_object ;
|
|
; henum ;
|
|
; hfree ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Fri Sep 19, 1986 05:46:52p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gfreeall,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
mov es,[di].hi_first ; ES:DI points to first arena entry
|
|
mov cx,[di].hi_count ; CX = #entries in the arena
|
|
free_all_objects:
|
|
push cx
|
|
call free_object ; Free object if matches owner
|
|
pop cx
|
|
mov es,es:[di].ga_next ; Move to next block
|
|
loop free_all_objects
|
|
|
|
; may go extra times, as CX does not track coalescing done by gfree,
|
|
; but no big whoop
|
|
|
|
|
|
push ax
|
|
push bx
|
|
push di
|
|
SetKernelDS es
|
|
mov si, SelTableStart
|
|
mov cx, SelTableLen
|
|
shr cx, 1
|
|
mov di, si
|
|
smov es, ds
|
|
UnSetKernelDS es
|
|
|
|
free_all_handles_loop:
|
|
mov ax, dx
|
|
repne scas word ptr es:[di] ; Isn't this easy?
|
|
jne short we_be_done
|
|
lea bx, [di-2]
|
|
sub bx, si
|
|
shl bx, 2
|
|
or bl, SEG_RING
|
|
|
|
if KDEBUG
|
|
lsl ax, bx
|
|
cmp ax, dx
|
|
je @F
|
|
INT3_ANCIENT
|
|
@@:
|
|
endif
|
|
|
|
cCall GetAccessWord,<bx>
|
|
test al,DSC_PRESENT ; segment present?
|
|
jnz short free_all_handles_loop ; yes, not a handle
|
|
test ah,DSC_DISCARDABLE ; discardable?
|
|
jz short free_all_handles_loop ; no, nothing to free
|
|
cCall free_sel,<bx>
|
|
mov word ptr [di-2], 0 ; Remove owner from table
|
|
jcxz we_be_done
|
|
jmps free_all_handles_loop
|
|
we_be_done:
|
|
pop di
|
|
pop bx
|
|
pop ax
|
|
|
|
|
|
gfreeall_done:
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; glock ;
|
|
; ;
|
|
; Increment the lock count of an object in handle table entry ;
|
|
; ;
|
|
; Arguments: ;
|
|
; BX = handle to global object ;
|
|
; CH = handle table flags ;
|
|
; CL = lock count for moveable objects ;
|
|
; DX = segment address of object ;
|
|
; DS:DI = address of master object ;
|
|
; ES:DI = arena header ;
|
|
; ;
|
|
; Returns: ;
|
|
; CX = updated lock count ;
|
|
; DX = pointer to client area ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ZF = 1 if count overflowed. ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; History: ;
|
|
; ;
|
|
; Fri Sep 19, 1986 05:38:57p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc glock,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ax
|
|
inc ch ; Increment lock count
|
|
jz overflow ; All done if overflow
|
|
mov es:[di].ga_count,ch ; Update lock count
|
|
glockerror:
|
|
overflow:
|
|
pop ax
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gunlock ;
|
|
; ;
|
|
; Decrement the lock count of an object. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; BX = handle to global object ;
|
|
; CH = handle table flags ;
|
|
; CL = lock count for moveable objects ;
|
|
; CX = handle table flags and lock count for moveable objects ;
|
|
; DS:DI = address of master object ;
|
|
; ES:DI = arena header ;
|
|
; ;
|
|
; Returns: ;
|
|
; CX = updated lock count, no underflow ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; glrutop ;
|
|
; History: ;
|
|
; ;
|
|
; Fri Sep 19, 1986 04:39:01p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gunlock,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ax
|
|
mov ax,bx
|
|
dec ch ; Decrement usage count
|
|
cmp ch,0FFh-1 ; ff -> fe, 0 -> ff
|
|
jae count_zero ; Return if pinned, or was already 0
|
|
dec es:[di].ga_count ; Non-zero update lock count
|
|
jnz count_positive ; All done if still non-zero
|
|
test cl,GA_DISCARDABLE ; Is this a discardable handle?
|
|
jz count_zero ; No, all done
|
|
call glrutop ; Yes, bring to top of LRU chain
|
|
count_zero:
|
|
xor cx,cx
|
|
count_positive:
|
|
pop ax
|
|
ret
|
|
cEnd nogen
|
|
|
|
sEnd CODE
|
|
|
|
end
|