2442 lines
87 KiB
NASM
2442 lines
87 KiB
NASM
PAGE ,132
|
|
TITLE GALLOC - Global memory allocator
|
|
|
|
.sall
|
|
.xlist
|
|
include kernel.inc
|
|
include protect.inc
|
|
.list
|
|
|
|
.286p
|
|
|
|
DataBegin
|
|
|
|
externB Kernel_flags
|
|
externB fCheckFree
|
|
externW pGlobalHeap
|
|
externW WinFlags
|
|
|
|
gsearch_state_machine dw 0
|
|
GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
|
|
GA_MASK_BYTES = NOT GA_ALIGN_BYTES
|
|
|
|
|
|
ifdef WOW
|
|
externB fInAlloc
|
|
externW SelectorFreeBlock
|
|
endif
|
|
|
|
public DpmiMemory, DpmiBlockCount
|
|
DpmiMemory DpmiBlock NUM_DPMI_BLOCKS dup (<>)
|
|
|
|
DpmiBlockCount dw 0
|
|
|
|
DataEnd
|
|
|
|
sBegin CODE
|
|
assumes CS,CODE
|
|
|
|
externNP gcompact
|
|
externNP gmovebusy
|
|
externNP gmoveable
|
|
externNP gslidecommon
|
|
externNP galign
|
|
|
|
externNP get_physical_address
|
|
externNP set_physical_address
|
|
externNP alloc_data_sel
|
|
externNP set_sel_limit
|
|
externNP free_sel
|
|
externNP get_blotto
|
|
externNP cmp_sel_address
|
|
externNP alloc_data_sel_above
|
|
externNP PreallocSel
|
|
externNP DPMIProc
|
|
ifdef WOW
|
|
externNP alloc_special_sel
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gsearch ;
|
|
; ;
|
|
; Searches from start to finish for a free global object to allocate ;
|
|
; space from. For a fixed request it tries to get the space as low as ;
|
|
; possible, moving movable out of the way if neccessary. For movable ;
|
|
; requests it also starts at the bottom. For discardable code it ;
|
|
; starts from the top, only using the first free block it finds. ;
|
|
; If at first blush it can't find a block it compacts memory and tries ;
|
|
; again. ;
|
|
; When it finally finds a block it gsplices it in, makes sure the ;
|
|
; arena headers are fine, and returns the allocated block. ;
|
|
; Called from within the global memory manager's critical section. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; AX = allocations flags ;
|
|
; BX = #paras ;
|
|
; CX = owner field value ;
|
|
; DS:DI = address of global arena information structure ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = data address of block allocated or NULL ;
|
|
; BX = ga_prev or ga_next ;
|
|
; DX = allocation flags ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ZF = 1 ;
|
|
; AX = 0 ;
|
|
; BX = ga_prev or ga_next ;
|
|
; DX = size of largest free block ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; DI,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; CX,SI,ES ;
|
|
; ;
|
|
; Calls: ;
|
|
; galign ;
|
|
; gfindfree ;
|
|
; fmovebusy ;
|
|
; gcheckfree ;
|
|
; gcompact ;
|
|
; gsplice ;
|
|
; gzero ;
|
|
; gmarkfree ;
|
|
; use_EMS_land ;
|
|
; use_lower_land ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Wed Jul 22, 1987 11:15:19p -by- David N. Weise [davidw] ;
|
|
; Fixed BOGUS BLOCK freeing yet again. ;
|
|
; ;
|
|
; Sun May 10, 1987 11:29:38p -by- David N. Weise [davidw] ;
|
|
; Added the state machine to handle the case of wanting to search ;
|
|
; both global arenas. ;
|
|
; ;
|
|
; Sat Feb 28, 1987 06:31:11p -by- David N. Weise [davidw] ;
|
|
; Putting in support for allocating discardable code from EEMS land. ;
|
|
; ;
|
|
; Tue Dec 30, 1986 01:54:50p -by- David N. Weise [davidw] ;
|
|
; Made sure it freed any bogus blocks created. ;
|
|
; ;
|
|
; Thu Nov 20, 1986 04:00:06p -by- David N. Weise [davidw] ;
|
|
; Rewrote it use the global free list. Also made it put fixed requests ;
|
|
; as low as possible and to search again after a compact. ;
|
|
; ;
|
|
; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
|
|
; Added support for the free list of global partitions. ;
|
|
; ;
|
|
; Tue Sep 23, 1986 04:35:39p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc gsearch,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
SetKernelDS
|
|
mov gsearch_state_machine,codeOFFSET grow_heap
|
|
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
|
|
look_again:
|
|
push bx ; Save requested size
|
|
push cx ; Save owner
|
|
push ax ; Save flags
|
|
add bx,1 ; Room for header (set flags for galign)
|
|
call galign ; Get requested size in DX
|
|
push dx ; Save adjusted requested size
|
|
|
|
inc dx ; Fail quickly if asking for
|
|
jnz @f ; too much memory
|
|
jmp gsearch_fail
|
|
@@:
|
|
dec dx
|
|
|
|
; see if there is any one free space large enough for the request first
|
|
|
|
mov si,dx
|
|
dec si ; Room for header
|
|
mov cx,[di].gi_free_count
|
|
jcxz were_hosed_from_start
|
|
mov es,[di].hi_first
|
|
is_there_one:
|
|
mov es,es:[di].ga_freenext
|
|
cmp si,es:[di].ga_size
|
|
jbe short got_one
|
|
loop is_there_one
|
|
were_hosed_from_start:
|
|
jmp space_not_found
|
|
|
|
got_one:
|
|
mov bx,ga_prev ; search backwards
|
|
test al,GA_ALLOCHIGH
|
|
jz short alloc_low
|
|
|
|
;------ allocate disc code -------
|
|
|
|
public alloc_high
|
|
alloc_high:
|
|
|
|
mov cx,[di].gi_free_count
|
|
mov es,[di].hi_last ; Start with last entry.
|
|
alloc_high_loop:
|
|
mov es,es:[di].ga_freeprev
|
|
cmp si,es:[di].ga_size
|
|
ja short loop_it
|
|
jmp afound ; Yes, exit search loop
|
|
loop_it:
|
|
loop alloc_high_loop
|
|
were_hosed:
|
|
jmps space_not_found
|
|
|
|
;------ allocate moveable ---------
|
|
|
|
public alloc_low
|
|
alloc_low:
|
|
mov bl,ga_next ; Search forwards.
|
|
test al,GA_MOVEABLE
|
|
jz short alloc_fixed
|
|
call gcheckfree ; Room for requested size?
|
|
jb short were_hosed
|
|
jmp afound
|
|
|
|
;------ allocate fixed ------------
|
|
|
|
public alloc_fixed
|
|
alloc_fixed:
|
|
mov es,[di].hi_first ; Start with first entry.
|
|
mov cx,[di].hi_count
|
|
mov es,es:[bx] ; Skip first sentinel
|
|
alloc_fixed_loop:
|
|
push cx
|
|
push es
|
|
call is_there_theoretically_enough_space
|
|
cmp ax,dx
|
|
jb short nope
|
|
pop es
|
|
pop cx
|
|
call can_we_clear_this_space
|
|
jz short anext1
|
|
call gcheckfree ; Yes, room for requested size?
|
|
jb short anext1
|
|
; Now we have enough free space,
|
|
; slide it back as far as possible.
|
|
push ax ; This is to prevent us blocking
|
|
push dx ; the growth of moveable blocks.
|
|
|
|
keep_sliding:
|
|
push es
|
|
mov es,es:[di].ga_prev
|
|
mov ax,es
|
|
mov dx,es:[di].ga_size
|
|
call gmoveable ; Is previous block moveable?
|
|
pop es
|
|
jz short no_slide
|
|
|
|
call PreallocSel
|
|
jz no_slide
|
|
push bx
|
|
mov bx, ga_prev ; Sliding backwards
|
|
push es ; gslide will invalidate this block
|
|
call gslidecommon ; C - calling convention
|
|
call free_sel ; free the pushed selector
|
|
pop bx
|
|
jmps keep_sliding
|
|
|
|
no_slide:
|
|
pop dx ; requested size
|
|
pop ax ; block size
|
|
pop si ; adjusted requested size
|
|
pop cx ; flags
|
|
|
|
push cx ; these two expected on stack later
|
|
push si
|
|
|
|
test ch,GA_ALLOC_DOS ;If this is a DOS land alloc
|
|
jz okey_dokey ; make sure that the block
|
|
push ax ; we found is below the 1 meg
|
|
push dx ; boundry, or fail the request
|
|
cCall get_physical_address,<es>
|
|
cmp dx,0010h ; (0010:0000 = 1024k = 1 meg)
|
|
pop dx
|
|
pop ax
|
|
jae space_not_found
|
|
|
|
okey_dokey:
|
|
jmp afound
|
|
|
|
nope: or ax,ax
|
|
jz short hosed_again
|
|
anext: pop si ; get rid of CX, ES on the stack
|
|
pop si
|
|
anext1: mov es,es:[bx]
|
|
loop alloc_fixed_loop
|
|
jmps and_again
|
|
|
|
hosed_again:
|
|
pop es
|
|
pop cx
|
|
and_again:
|
|
|
|
; no one space big enough, try compacting
|
|
|
|
public space_not_found
|
|
space_not_found:
|
|
pop dx ; get size
|
|
pop ax ; get flags
|
|
push ax
|
|
push dx
|
|
|
|
test al,GA_ALLOCHIGH
|
|
jnz short ask_for_what_we_need
|
|
add dx,0400h ; ask for 16k more
|
|
jnc short ask_for_what_we_need ; no overflow
|
|
mov dx,-1
|
|
|
|
ask_for_what_we_need:
|
|
SetKernelDS
|
|
push gsearch_state_machine
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
retn
|
|
|
|
;------------------------------
|
|
|
|
public do_compact ; for debugging
|
|
|
|
do_compact:
|
|
call gcompact
|
|
SetKernelDS
|
|
mov gsearch_state_machine,codeOFFSET gsearch_fail
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
|
|
over_compact:
|
|
pop dx
|
|
pop ax
|
|
pop cx
|
|
pop bx
|
|
jmp look_again
|
|
|
|
;------------------------------
|
|
|
|
public grow_heap ; for debugging
|
|
|
|
grow_heap:
|
|
SetKernelDS
|
|
mov gsearch_state_machine,codeOFFSET do_compact
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
call GrowHeap
|
|
jmp over_compact
|
|
|
|
;------------------------------
|
|
|
|
public gsearch_fail ; for debugging
|
|
|
|
gsearch_fail: ; get size of largest free block
|
|
xor dx,dx
|
|
mov cx,[di].gi_free_count
|
|
jcxz gs_failure
|
|
mov es,[di].hi_first
|
|
largest_loop:
|
|
mov es,es:[di].ga_freenext
|
|
mov ax,es:[di].ga_size
|
|
cmp dx,ax
|
|
jae short new_smaller
|
|
mov dx,ax
|
|
new_smaller:
|
|
loop largest_loop
|
|
gs_failure:
|
|
pop ax ; adjusted requested size
|
|
pop ax ; AX = flags
|
|
|
|
pop cx ; CX = owner field
|
|
pop ax ; waste requested size
|
|
xor ax,ax ; Return zero, with ZF = 1
|
|
ret
|
|
|
|
; Here when we have a block big enough.
|
|
; ES:DI = address of block
|
|
; AX = size of block, including header
|
|
; DX = requested size, including header
|
|
; BX = ga_prev if backwards search and ga_next if forwards search
|
|
|
|
afound:
|
|
|
|
ifdef WOW ; Optimized path for WOW
|
|
|
|
push ds
|
|
SetkernelDS
|
|
cmp fInAlloc, 1
|
|
UnSetKernelDS
|
|
pop ds
|
|
|
|
jne nothing_special
|
|
|
|
aallocsels:
|
|
pop cx ; adjusted requested size
|
|
pop ax ; get the flags
|
|
|
|
push ax ; restore the stack
|
|
push cx
|
|
|
|
push ax ; allocation flags
|
|
push es ; Selector FreeBlock
|
|
mov ax, es:[di].ga_size
|
|
push ax ; actual size of freeblock
|
|
inc ax
|
|
mov cx, ax ; save in cx too
|
|
sub cx, dx
|
|
push cx ; size new freeblock
|
|
push dx ; adjusted size
|
|
push bx ; bl = ga_prev pr ga_next
|
|
call alloc_special_sel
|
|
jz gs_failure ; no selector
|
|
jmps no_sel_wanted
|
|
|
|
nothing_special:
|
|
|
|
endif ; End Optimized path for WOW
|
|
|
|
mov ax,es:[di].ga_size ; Use actual size of free block
|
|
inc ax
|
|
mov cx,ax ; See how much extra space there is
|
|
sub cx,dx ; (found size - requested size)
|
|
jcxz no_sel_wanted
|
|
call PreallocSel ; Make sure we can splice
|
|
jz gs_failure ; no selector
|
|
no_sel_wanted:
|
|
mov ax,es:[di].ga_freeprev
|
|
xor si,si ; Assume nothing extra to free
|
|
call gdel_free ; remove the alloc block from freelist
|
|
if KDEBUG
|
|
push ds
|
|
SetKernelDS
|
|
cmp fCheckFree,0
|
|
pop ds
|
|
UnSetKernelDS
|
|
jnz short not_during_boot
|
|
call check_this_space
|
|
not_during_boot:
|
|
endif
|
|
jcxz aexit ; No, continue
|
|
cmp bl,ga_prev ; Yes, scanning forwards or backwards?
|
|
je short abackward ; Backwards.
|
|
; mov si,es ; Forwards. Put extra space at end of
|
|
mov si,dx ; free block
|
|
call gsplice ; ES:DI = block we are allocating
|
|
jmps aexit ; SI = block to mark as free
|
|
abackward:
|
|
mov si,es:[di].ga_size ; Scanning backwards. Put extra space
|
|
sub si,dx ; at beginning of free block.
|
|
inc si
|
|
call gsplice
|
|
mov es,si ; ES:DI = block we are allocating
|
|
mov si,es:[di].ga_prev ; SI = block to mark as free
|
|
|
|
; Here with allocated block
|
|
; AX = data address or zero if nothing allocated
|
|
; ES:DI = address of block to mark as busy and zero init if requested
|
|
; SI = address of block to mark as free
|
|
|
|
aexit:
|
|
pop dx ; waste adjusted requested size
|
|
pop dx ; Restore flags
|
|
pop es:[di].ga_owner ; Mark block as busy with owner field value
|
|
pop cx ; waste requested size
|
|
mov es:[di].ga_lruprev,di
|
|
mov es:[di].ga_lrunext,di
|
|
push ax ; previous free block
|
|
mov al,GA_SEGTYPE
|
|
and al,dl
|
|
test dh,GAH_NOTIFY
|
|
jz short no_notify
|
|
or al,GAH_NOTIFY
|
|
no_notify:
|
|
mov es:[di].ga_flags,al ; Store segment type bits
|
|
|
|
mov ax,es ; AX = address of client data
|
|
|
|
test dl,GA_ZEROINIT ; Want it zeroed?
|
|
jz short aexit1 ; No, all done
|
|
|
|
push ax
|
|
cCall get_blotto
|
|
mov cx,es:[di].ga_size ; Yes, zero paragraphs
|
|
; dec cx ; to end of this block
|
|
push bx
|
|
mov bx,ax ; from beginning of client data
|
|
call gzero ; zero them
|
|
pop bx
|
|
pop ax
|
|
aexit1:
|
|
mov es,si ; Free any extra space
|
|
pop si ; previous free block
|
|
dec si ; make it RING 0 for gmarkfree
|
|
call gmarkfree
|
|
|
|
or ax,ax
|
|
ret ; Return AX points to client portion
|
|
; of block allocated.
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; is_there_theoretically_enough_space
|
|
;
|
|
; Starting at the given arena checks to see if there are enough
|
|
; continuous free and unlocked moveable blocks.
|
|
;
|
|
; Entry:
|
|
; CX = arenas to search
|
|
; DX = size requested
|
|
; DS = BurgerMaster
|
|
; ES:DI = arena to start from
|
|
;
|
|
; Returns:
|
|
; AX = 0 => not enough space and no more memory left to search
|
|
; AX = 1 => not enough space in this block, but maybe....
|
|
; otherwise
|
|
; AX = size of block
|
|
;
|
|
; Registers Destroyed:
|
|
; CX,SI
|
|
;
|
|
; Registers Preserved:
|
|
; BX,DX,DI,ES
|
|
;
|
|
; History:
|
|
; Mon 05-Sep-1988 15:21:14 -by- David N. Weise [davidw]
|
|
; Moved it here from gsearch so that grealloc could use it as well.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc is_there_theoretically_enough_space,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
xor ax,ax
|
|
ittes:
|
|
cmp es:[di].ga_owner,di
|
|
jne short is_it_moveable
|
|
add ax,es:[di].ga_size
|
|
push bx
|
|
push cx
|
|
push ax
|
|
push dx
|
|
mov cx,word ptr [di].gi_disfence_hi ; See if begin of reserve area
|
|
mov bx,word ptr [di].gi_disfence_lo ; is above end of free block
|
|
cCall get_physical_address,<es:[di].ga_next>
|
|
sub bx,ax
|
|
sbb cx,dx ; used as cmp ONLY CARRY is VALID
|
|
pop dx
|
|
pop ax
|
|
jb short ittes_above_fence ; All below fence?
|
|
pop cx
|
|
pop bx
|
|
jmps this_ones_free
|
|
ittes_above_fence:
|
|
REPT 4
|
|
shr cx,1
|
|
rcr bx,1
|
|
ENDM
|
|
add ax,bx ; No, Reduce apparent size of free block
|
|
pop cx
|
|
pop bx
|
|
inc ax
|
|
cmp ax,dx
|
|
jae short theoretically_enough
|
|
jmps absolutely_not
|
|
is_it_moveable:
|
|
test es:[di].ga_flags,GA_DISCCODE
|
|
jnz short absolutely_not
|
|
test es:[di].ga_handle,GA_FIXED ; See if movable.
|
|
jnz short theoretically_not
|
|
cmp es:[di].ga_count,0
|
|
jne short theoretically_not ; See if locked.
|
|
add ax,es:[di].ga_size
|
|
this_ones_free:
|
|
inc ax
|
|
cmp ax,dx
|
|
jae short theoretically_enough
|
|
mov es,es:[ga_next]
|
|
loop ittes
|
|
|
|
; For the case of gsearch we should never get here for two reasons.
|
|
; 1) It should be impossible to have no discardable code loaded, in
|
|
; this case we would have failed in the above loop. 2) We checked
|
|
; at the very start for a free block somewhere that could have
|
|
; satisfied the request. In our mucking around to load as low as
|
|
; possible we destroyed this free block and we did not produce a free
|
|
; block we could use. However we know from debugging code in 2.03
|
|
; that this happens extremely rarely. Because of the rareness of
|
|
; this event we will not try to recover, instead we simply fail the call.
|
|
|
|
absolutely_not:
|
|
mov ax,-1 ; return AX = 0
|
|
theoretically_not:
|
|
inc ax ; DX is even, => cmp the same.
|
|
theoretically_enough:
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; can_we_clear_this_space
|
|
;
|
|
; Attempts to make a free space starting at the address moved in.
|
|
; To do this it moves moveable out of the area. The only subtlety
|
|
; involves a free block that stradles the end of wanted area. This
|
|
; may get broken into two pieces, the lower piece gets temporary marked
|
|
; as allocated and BOGUS, the upper piece will remain free.
|
|
;
|
|
; Entry:
|
|
; CX = max number of blocks to look at
|
|
; DX = size wanted in paragraphs
|
|
; DS = BurgerMaster
|
|
; ES:DI = beginning arena
|
|
;
|
|
; Returns:
|
|
; ZF = 0
|
|
; ES:DI points to free space
|
|
; ZF = 1
|
|
; couldn't free the space up
|
|
;
|
|
; Registers Destroyed:
|
|
; AX,SI
|
|
;
|
|
; History:
|
|
; Mon 05-Sep-1988 16:48:31 -by- David N. Weise [davidw]
|
|
; Moved it out of gsearch so that grealloc could use it.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc can_we_clear_this_space,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push cx
|
|
push es
|
|
mov ax, es ; Beginning of space we want.
|
|
cmp di,es:[di].ga_owner ; Is it free?
|
|
jnz short can_we_move_it
|
|
mov cx,dx
|
|
dec cx
|
|
cmp cx,es:[di].ga_size
|
|
ja short asdf
|
|
or ax,ax ; return ZF = 0
|
|
pop es
|
|
pop cx
|
|
ret
|
|
|
|
asdf: mov es,es:[di].ga_next
|
|
|
|
public can_we_move_it
|
|
can_we_move_it:
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push es
|
|
cmp es:[di].ga_owner,GA_BOGUS_BLOCK
|
|
jnz short not_bogus
|
|
xor si,si
|
|
call gmarkfree
|
|
jmp restart
|
|
not_bogus:
|
|
push ax
|
|
cCall alloc_data_sel_above,<ax,dx>
|
|
mov si, ax ; End of space we want.
|
|
pop ax
|
|
or si, si
|
|
jnz got_marker_sel
|
|
pop cx ; Trash es saved on stack
|
|
jmp no_clear
|
|
got_marker_sel:
|
|
mov cx,[di].gi_free_count
|
|
jcxz forget_it ; Nothing is free, so don't bother
|
|
mov dx,es:[di].ga_size ; Yes, try to find a place for the
|
|
mov es,[di].hi_first ; moveable block
|
|
look_loop:
|
|
mov es,es:[di].ga_freenext
|
|
mov bx,es
|
|
cCall cmp_sel_address,<bx,ax> ; It defeats our purpose to move the
|
|
jb short check_this_out ; block to a free space we want.
|
|
cCall cmp_sel_address,<bx,si>
|
|
jb short is_there_hope
|
|
check_this_out:
|
|
push ax
|
|
call gcheckfree
|
|
push cx
|
|
jb short inopportune_free_space
|
|
cCall free_sel,<si>
|
|
pop cx
|
|
pop ax
|
|
|
|
pop si ; SI = moveable block for gmovebusy
|
|
mov bx,ga_next
|
|
call gmovebusy ; Move moveable block out of the way
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop cx ; WAS pop es but es destroyed below
|
|
pop cx
|
|
mov es,si ; Replace the ES on the stack,
|
|
; the free block may have grown
|
|
; downward with the gmovebusy.
|
|
jmp can_we_clear_this_space
|
|
|
|
inopportune_free_space:
|
|
pop cx
|
|
pop ax
|
|
loop look_loop
|
|
forget_it:
|
|
jmp couldnt_clear_it
|
|
|
|
public is_there_hope
|
|
is_there_hope:
|
|
push ax
|
|
push cx
|
|
push dx
|
|
cCall get_physical_address,<es:[di].ga_next>
|
|
mov cx, dx
|
|
mov bx, ax
|
|
cmp cx, [di].gi_disfence_hi
|
|
jb below_reserved
|
|
ja above_reserved
|
|
cmp bx, [di].gi_disfence_lo
|
|
jbe short below_reserved
|
|
above_reserved:
|
|
mov cx, [di].gi_disfence_hi
|
|
mov bx, [di].gi_disfence_lo
|
|
|
|
below_reserved:
|
|
cCall get_physical_address,<si>
|
|
sub bx, ax
|
|
sbb cx, dx ; Check the overlap.
|
|
|
|
jae short overlap
|
|
pop dx
|
|
jmps inopportune_free_space
|
|
overlap:
|
|
REPT 4
|
|
shr cx, 1
|
|
rcr bx, 1
|
|
ENDM
|
|
mov cx, dx
|
|
pop dx
|
|
cmp bx,dx
|
|
jbe short inopportune_free_space
|
|
|
|
mov bx, ax
|
|
cCall get_physical_address,<es>
|
|
sub bx, ax
|
|
sbb cx, dx
|
|
REPT 4
|
|
shr cx, 1
|
|
rcr bx, 1
|
|
ENDM
|
|
cCall free_sel,<si>
|
|
mov si, bx
|
|
pop cx
|
|
pop ax
|
|
|
|
; cut off the first piece for the original alloc
|
|
|
|
push es:[di].ga_freeprev
|
|
call gdel_free
|
|
if KDEBUG
|
|
push ds
|
|
SetKernelDS
|
|
cmp fCheckFree,0
|
|
pop ds
|
|
UnSetKernelDS
|
|
jnz short not_during_boot_1
|
|
call check_this_space
|
|
not_during_boot_1:
|
|
endif
|
|
call gsplice
|
|
|
|
; ES:DI = addr of block to mark as busy, SI = addr of block to mark as free
|
|
|
|
mov es:[di].ga_owner,GA_BOGUS_BLOCK
|
|
mov es:[di].ga_lruprev,di
|
|
mov es:[di].ga_lrunext,di
|
|
mov es,si ; Free any extra space
|
|
pop si ; previous free block
|
|
dec si ; make it RING 0 for gmarkfree
|
|
call gmarkfree
|
|
restart:
|
|
pop dx ; WAS pop es
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop es
|
|
pop cx
|
|
jmp can_we_clear_this_space
|
|
|
|
; If here then failure! see if we made a bogus block!
|
|
|
|
couldnt_clear_it:
|
|
pop es ; recover block we wanted moved
|
|
check_again:
|
|
mov dx,es:[di].ga_next
|
|
cCall cmp_sel_address,<dx,si> ; SI points to where bogus block
|
|
ja short no_bogus_block ; would be.
|
|
je short is_it_bogus
|
|
mov es,dx
|
|
cmp dx, es:[di].ga_next
|
|
je short no_bogus_block
|
|
jmp check_again
|
|
is_it_bogus:
|
|
cmp es:[di].ga_owner,GA_BOGUS_BLOCK
|
|
jnz short no_bogus_block
|
|
push si
|
|
xor si,si
|
|
call gmarkfree
|
|
pop si
|
|
no_bogus_block:
|
|
|
|
if KDEBUG
|
|
mov cx,[di].hi_count
|
|
mov es,[di].hi_first
|
|
bogus_all:
|
|
cmp es:[di].ga_owner,GA_BOGUS_BLOCK
|
|
jnz short not_me
|
|
INT3_ANCIENT
|
|
not_me: mov es,es:[di].ga_next
|
|
loop bogus_all
|
|
endif
|
|
cCall free_sel,<si>
|
|
|
|
no_clear:
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop es
|
|
pop cx
|
|
xor ax,ax ; return ZF = 1
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gfindfree ;
|
|
; ;
|
|
; Searches for a free block that is big enough but does not encroach ;
|
|
; on the area reserved for code swapping. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ES:DI = address of existing block to start looking at ;
|
|
; CX = #arena entries left to look at ;
|
|
; BX = direction of search, ga_next or ga_prev ;
|
|
; DX = #paragraphs needed ;
|
|
; DS:DI = address of global arena information structure ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = address of free block that is big enough ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = 0 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; SI ;
|
|
; ;
|
|
; Calls: ;
|
|
; gcheckfree ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Wed Sep 24, 1986 10:16:38p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gfindfree,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push cx
|
|
push es
|
|
gffloop:
|
|
cmp es:[di].ga_owner,di ; Free block?
|
|
jne short gffnext ; No, continue
|
|
call gcheckfree ; Yes, is it big enough?
|
|
mov ax,es
|
|
jae short gffexit ; Yes, return
|
|
gffnext:
|
|
mov es,es:[bx] ; next or previous block
|
|
loop gffloop
|
|
gfffail:
|
|
xor ax,ax ; No, return zero in AX
|
|
gffexit:
|
|
pop es
|
|
pop cx
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gcheckfree ;
|
|
; ;
|
|
; Checks the size of the passed free block against the passed desired ;
|
|
; size, making sure that the limitations of the code reserve area are ;
|
|
; not violated for objects other than discardable code. It also checks ;
|
|
; for Phantoms. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ES:DI = address of free block ;
|
|
; DX = #paragraphs needed ;
|
|
; DS:DI = address of global arena information structure ;
|
|
; ;
|
|
; Returns: ;
|
|
; CF = 0 block big enough ;
|
|
; AX = apparent size of free block ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; none ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu 27-Apr-1989 10:38:05 -by- David N. Weise [davidw] ;
|
|
; Fixed this to work in pmode. ;
|
|
; ;
|
|
; Thu Apr 02, 1987 10:45:22p -by- David N. Weise [davidw] ;
|
|
; Added Phantom support. ;
|
|
; ;
|
|
; Tue Sep 23, 1986 05:54:51p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gcheckfree,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push si
|
|
mov ax,es:[di].ga_size ; Compute size of free block
|
|
inc ax
|
|
test byte ptr [di].gi_cmpflags,GA_DISCCODE
|
|
jnz short gcftest ; Discardable code not restricted
|
|
|
|
; Due to recent changes in the way disccode is allocated, we must make
|
|
; sure that non-disccode in never allocated above a disccode block.
|
|
|
|
push es
|
|
might_be_code_below:
|
|
mov es,es:[di].ga_prev
|
|
cmp es:[di].ga_owner,GA_NOT_THERE
|
|
jz short might_be_code_below
|
|
cmp es:[di].ga_owner,di ; Free block?
|
|
jz short might_be_code_below
|
|
test es:[di].ga_flags,GA_DISCCODE
|
|
pop es
|
|
jnz short gcfrsrv1
|
|
|
|
push bx
|
|
push cx
|
|
push ax
|
|
push dx
|
|
mov cx,word ptr [di].gi_disfence_hi ; See if begin of reserve area
|
|
mov bx,word ptr [di].gi_disfence_lo ; is above end of free block
|
|
cCall get_physical_address,<es:[di].ga_next>
|
|
sub bx,ax
|
|
sbb cx,dx ; used as cmp ONLY CARRYY is VALID
|
|
pop dx
|
|
pop ax
|
|
jae short gcftest1 ; Yes, return actual size of free block
|
|
REPT 4
|
|
shr cx,1
|
|
rcr bx,1
|
|
ENDM
|
|
neg bx
|
|
sub ax,bx ; No, Reduce apparent size of free block
|
|
ja short gcftest1 ; Is it more than what is free?
|
|
|
|
xor ax,ax ; Yes, then apparent size is zero
|
|
; Nothing left, set apparent size to 0
|
|
gcftest1:
|
|
pop cx
|
|
pop bx
|
|
jmps gcftest
|
|
gcfrsrv1: ; Yes, then apparent size is zero
|
|
xor ax,ax ; Nothing left, set apparent size to 0
|
|
gcftest:
|
|
cmp ax,dx ; Return results of the comparison
|
|
pop si
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gsplice ;
|
|
; ;
|
|
; Splits one block into two. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; SI = size in paragraphs of new block to make ;
|
|
; ES:DI = address of existing block ;
|
|
; DS:DI = address of global arena information structure ;
|
|
; ;
|
|
; Returns: ;
|
|
; SI = address of new block ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; nothing ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,DX,DI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; CX ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; History: ;
|
|
; ;
|
|
; Tue Sep 23, 1986 03:50:30p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gsplice,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push bx
|
|
push dx
|
|
mov dx,si ; save size
|
|
mov bx,es:[di].ga_size
|
|
sub bx,dx ; get size of 2nd new block made
|
|
|
|
push ax
|
|
push bx
|
|
push dx
|
|
|
|
ifdef WOW ; Optimized path for WOW
|
|
|
|
push ds
|
|
SetkernelDS
|
|
mov ax, SelectorFreeBlock ; same as fInAlloc == 1
|
|
or ax, ax
|
|
UnSetKernelDS
|
|
pop ds
|
|
jnz gsplice_oldpath2
|
|
|
|
gsplice_oldpath:
|
|
endif ; end optimized path for WOW
|
|
|
|
mov bx,si
|
|
xor cx,cx
|
|
REPT 4
|
|
shl bx,1
|
|
rcl cx,1
|
|
ENDM
|
|
cCall get_physical_address,<es>
|
|
add ax,bx
|
|
adc dx,cx
|
|
cCall alloc_data_sel,<dx,ax,1>
|
|
|
|
ifdef WOW
|
|
gsplice_oldpath2:
|
|
endif
|
|
mov si,ax
|
|
pop dx
|
|
pop bx
|
|
pop ax
|
|
inc [di].hi_count ; Adding new arena entry
|
|
push si ; save new
|
|
push es ; save old
|
|
mov cx,si ; save old.next
|
|
xchg es:[di].ga_next,cx ; and old.next = new
|
|
mov es,cx
|
|
mov es:[di].ga_prev,si ; [old old.next].prev = new
|
|
mov es,si
|
|
mov es:[di].ga_next,cx ; new.next = old old.next
|
|
mov es:[di].ga_size,bx
|
|
pop cx ; new.prev = old
|
|
mov es:[di].ga_sig,GA_SIGNATURE
|
|
mov es:[di].ga_owner,di ; Zero owner & handle fields
|
|
mov es:[di].ga_flags,0 ; For good measure.
|
|
mov es:[di].ga_prev,cx
|
|
mov es:[di].ga_handle,di
|
|
mov es,cx ; ES = old
|
|
dec dx ; get size of 1st block made
|
|
mov es:[di].ga_size,dx
|
|
pop si ; restore new
|
|
pop dx
|
|
pop bx
|
|
ret
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gjoin ;
|
|
; ;
|
|
; Merges a block into his previous neighbor. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ES:DI = address of block to remove ;
|
|
; DS:DI = address of global arena information structure ;
|
|
; ;
|
|
; Returns: ;
|
|
; nothing ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; nothing ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; SI ;
|
|
; ;
|
|
; Calls: ;
|
|
; gdel_free ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
|
|
; Added support for the free list of global partitions. ;
|
|
; ;
|
|
; Tue Sep 23, 1986 03:58:00p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gjoin,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ax
|
|
push bx
|
|
dec [di].hi_count
|
|
call gdel_free
|
|
mov ax,es:[di].ga_size
|
|
mov si,es:[di].ga_prev ; who points to this block
|
|
mov es,es:[di].ga_next ; Get address of block after
|
|
if KDEBUG
|
|
mov bx, es
|
|
cmp bx, es:[di].ga_prev
|
|
jne short ok
|
|
INT3_FATAL
|
|
ok:
|
|
endif
|
|
cCall free_sel,<es:[di].ga_prev> ; Free selector being removed
|
|
mov es:[di].ga_prev,si ; one we are removing.
|
|
push es ; Change it's back link
|
|
mov es,si
|
|
pop es:[di].ga_next ; and change the forward link
|
|
inc ax ; Recompute size of block
|
|
add es:[di].ga_size,ax
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gzero ;
|
|
; ;
|
|
; Fills the given area with zeros. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; BX = address of first paragraph ;
|
|
; CX = address of last paragraph ;
|
|
; ;
|
|
; Returns: ;
|
|
; BX = 0 ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,DX,DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; CX ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue Sep 23, 1986 04:08:55p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gzero,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
; Assumptions: on entry, BX contains selector to start of block, and is
|
|
; for a scratch descriptor that can be modified. CX contains the # of
|
|
; paragraphs to be zeroed.
|
|
|
|
push es ; Determine if we're running on an
|
|
SetKernelDS es ; 80286. If so, we gotta worry
|
|
test es:WinFlags,WF_CPU286 ; about 64k segments.
|
|
jz its_a_386
|
|
|
|
UnSetKernelDS es ; removes addressibility from es
|
|
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push di
|
|
|
|
cld
|
|
mov es,bx ; address block with es
|
|
mov bx,cx ; bx = total # paras to zero
|
|
jcxz gzexit ; just in case...
|
|
|
|
push bx ; Say it ain't so, Joe...
|
|
xor cx,cx ; force the incoming sel/descriptor to
|
|
mov bx,cx ; a limit of 64k - it might be higher
|
|
inc cx ; which would cause set_physical_adr
|
|
cCall set_sel_limit,<es> ; to destroy following descriptors.
|
|
pop bx
|
|
|
|
jmp short gz_doit
|
|
|
|
next_64k:
|
|
push es
|
|
cCall get_physical_address,<es> ;update selector to next
|
|
inc dl ; 64k block
|
|
cCall set_physical_address,<es>
|
|
pop es ;reload it with new base
|
|
|
|
gz_doit:
|
|
mov cx,1000h ; 1000h paras = 64k bytes
|
|
cmp bx,cx
|
|
jae @f
|
|
mov cx,bx ; less than 64k left
|
|
@@:
|
|
sub bx,cx ; bx = # paras left to do
|
|
shl cx,3 ; cx = # words to zero this time
|
|
xor ax,ax
|
|
mov di,ax
|
|
rep stosw
|
|
|
|
or bx,bx ; more to do?
|
|
jnz short next_64k ; go do the next block
|
|
|
|
gzexit:
|
|
pop di
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
pop es
|
|
ret
|
|
|
|
; The CPU is an 80386 or better, zero the memory a faster way...
|
|
|
|
its_a_386:
|
|
|
|
.386
|
|
|
|
push eax
|
|
push edi
|
|
push ecx
|
|
|
|
movzx ecx, cx
|
|
shl ecx, 2 ; # dwords to clear
|
|
mov es, bx
|
|
xor eax, eax
|
|
xor edi, edi
|
|
|
|
cld
|
|
rep stos dword ptr es:[edi]
|
|
|
|
pop ecx
|
|
pop edi
|
|
pop eax
|
|
pop es
|
|
ret
|
|
|
|
.286p
|
|
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gmarkfree ;
|
|
; ;
|
|
; Marks a block as free, coalesceing it with any free blocks before ;
|
|
; or after it. This does not free any handles. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; SI = the first free object before this one ;
|
|
; 0 if unknown ;
|
|
; Ring 1 if no free list update wanted ;
|
|
; Ring 0 if free list update required ;
|
|
; ES:DI = block to mark as free. ;
|
|
; DS:DI = address of global arena information structure ;
|
|
; ;
|
|
; Returns: ;
|
|
; ZF = 1 if freed a fixed block ;
|
|
; SI = 0 ;
|
|
; ZF = 0 if freed a moveable block ;
|
|
; SI = handle table entry ;
|
|
; ES:DI = block freed (may have been coalesced) ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; none ;
|
|
; ;
|
|
; Calls: ;
|
|
; gjoin ;
|
|
; gadd_free ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
|
|
; Added support for the free list of global partitions. ;
|
|
; ;
|
|
; Sun Nov 09, 1986 01:35:08p -by- David N. Weise [davidw] ;
|
|
; Made the debugging version fill all free space with CCCC. ;
|
|
; ;
|
|
; Wed Sep 24, 1986 10:27:06p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gmarkfree,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
call gadd_free
|
|
mov si,es
|
|
or si,si
|
|
jz short gmf_exit
|
|
|
|
; Mark this block as free by clearing the owner field.
|
|
|
|
mov es:[di].ga_sig,GA_SIGNATURE
|
|
mov es:[di].ga_owner,di ; Mark as free
|
|
mov es:[di].ga_flags,0 ; For good measure.
|
|
|
|
; Remember the handle value in DX, before setting to zero.
|
|
|
|
push dx
|
|
xor dx,dx
|
|
xchg es:[di].ga_handle,dx
|
|
|
|
; Try to coalesce with next block, if it is free
|
|
|
|
push es:[di].ga_prev ; save previous block
|
|
mov es,es:[di].ga_next ; ES = next block
|
|
cmp es:[di].ga_owner,di ; Is it free?
|
|
jne short free2 ; No, continue
|
|
call gjoin ; Yes, coalesce with block we are freeing
|
|
free2:
|
|
pop es ; ES = previous block
|
|
cmp es:[di].ga_owner,di ; Is it free?
|
|
jne short free3 ; No, continue
|
|
mov es,es:[di].ga_next ; Yes, coalesce with block we are freeing;
|
|
call gjoin
|
|
free3:
|
|
mov si,dx ; Return 0 or handle in SI
|
|
pop dx ; restore handle
|
|
cmp es:[di].ga_owner,di ; Point to free block?
|
|
je short free4 ; Yes, done
|
|
mov es,es:[di].ga_next ; No, leave ES pointing at free block
|
|
free4:
|
|
if KDEBUG
|
|
call CCCC
|
|
endif
|
|
gmf_exit:
|
|
or si,si
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gadd_free ;
|
|
; ;
|
|
; Links in the given partition into the global free list. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; SI = the first free object before this one ;
|
|
; 0 if unknown ;
|
|
; odd if no free list update wanted ;
|
|
; DS:DI = BurgerMaster ;
|
|
; ES:DI = free global object to add ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; all ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Sun Nov 09, 1986 02:42:53p -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gadd_free,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
test si,1
|
|
jnz no_update_wanted
|
|
|
|
push ax
|
|
push si
|
|
push ds
|
|
mov ax,es
|
|
or ax,ax ; this happens with gmovebusy
|
|
jz gaf_exit
|
|
|
|
inc [di].gi_free_count
|
|
|
|
;
|
|
; For DPMI compliance, we cannot look at addresses of
|
|
; selectors in the LDT and DPMI calls would be too slow,
|
|
; so we scan forward from the block we are freeing,
|
|
; looking for a free block or the sentinal and insert
|
|
; the new block before it.
|
|
;
|
|
smov ds, es
|
|
need_a_home_loop:
|
|
mov ds, ds:[di].ga_next
|
|
cmp ds:[di].ga_owner, di ; Free?
|
|
je found_a_home
|
|
cmp ds:[di].ga_sig, GA_ENDSIG ; Sentinal
|
|
jne need_a_home_loop
|
|
|
|
found_a_home:
|
|
mov si, ds:[di].ga_freeprev ; Fix up block after free block
|
|
mov ds:[di].ga_freeprev, es
|
|
|
|
mov es:[di].ga_freeprev,si ; Fix up free block
|
|
mov es:[di].ga_freenext,ds
|
|
|
|
mov ds,si ; Fix up block before free block
|
|
mov ds:[di].ga_freenext,es
|
|
|
|
if KDEBUG
|
|
call check_free_list
|
|
endif
|
|
|
|
gaf_exit:
|
|
pop ds
|
|
pop si
|
|
pop ax
|
|
|
|
no_update_wanted:
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gdel_free ;
|
|
; ;
|
|
; Removes a partition from the global free list. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DS:DI = BurgerMaster ;
|
|
; ES:DI = arena header of partition ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Sun Nov 09, 1986 02:43:26p -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc gdel_free,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ax
|
|
push ds
|
|
push es
|
|
mov ds,es:[di].ga_freeprev
|
|
mov es,es:[di].ga_freenext
|
|
mov ds:[di].ga_freenext,es
|
|
mov es:[di].ga_freeprev,ds
|
|
pop es
|
|
pop ds
|
|
|
|
dec [di].gi_free_count
|
|
gfx:
|
|
pop ax
|
|
|
|
if KDEBUG
|
|
call check_free_list
|
|
endif
|
|
ret
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------
|
|
; GrowHeap -- this procedure grows the global heap
|
|
;
|
|
; Input:
|
|
; None
|
|
;
|
|
; Output:
|
|
; carry clear for success
|
|
;
|
|
public GrowHeap
|
|
GrowHeap proc near
|
|
|
|
push si
|
|
push di
|
|
push bx
|
|
push es
|
|
|
|
xor si,si
|
|
|
|
;
|
|
; Request 1 MB
|
|
;
|
|
xor ax,ax
|
|
call AllocDpmiBlock
|
|
|
|
or ax,ax
|
|
jz gh30
|
|
|
|
;
|
|
; Format the block
|
|
;
|
|
or bx,bx
|
|
jnz gh10
|
|
|
|
mov si,1
|
|
gh10: mov dx,ax
|
|
call FormatHeapBlock
|
|
|
|
|
|
;
|
|
; Add the block to the heap
|
|
;
|
|
call AddBlockToHeap
|
|
|
|
clc
|
|
gh20: pop es
|
|
pop bx
|
|
pop di
|
|
pop si
|
|
ret
|
|
|
|
gh30: stc
|
|
jmp gh20
|
|
|
|
GrowHeap endp
|
|
;-----------------------------------------------------------------------
|
|
; FormatHeapBlock -- this procedure initializes three arenas in a
|
|
; global heap block. The first arena is marked as the heap
|
|
; initial sentinel, the second arena is the heap free block, and
|
|
; the third arena at the very end of the block is marked as
|
|
; 'not there'.
|
|
;
|
|
; In: SI:BX - size of block in paragraphs
|
|
; DX - selector pointing to start of block (descriptor is modified!)
|
|
;
|
|
; Out: AX - selector to ending 'not there' block
|
|
; BX - zero
|
|
; SI - selector to initial sentinel
|
|
; DI - selector to free block arena
|
|
; ES:BX -> initial sentinel arena
|
|
;
|
|
; Uses: CX, DX
|
|
public FormatHeapBlock
|
|
FormatHeapBlock proc near
|
|
|
|
; Setup selector to first arena (the new initial sentinel)
|
|
|
|
push bx ;save # paragraphs
|
|
push si
|
|
|
|
mov bx,dx ;get physical address of start
|
|
cCall get_physical_address,<bx>
|
|
|
|
push ax ;save unaligned start address
|
|
push dx
|
|
|
|
add ax,GA_ALIGN_BYTES
|
|
adc dx,0
|
|
and ax,GA_MASK_BYTES
|
|
|
|
cCall set_physical_address,<bx>
|
|
mov si,bx ;si -> initial sentinel
|
|
|
|
mov bx,10h ;set initial selector to
|
|
xor cx,cx ; be just 1 arena long
|
|
cCall set_sel_limit,<si>
|
|
|
|
; Setup selector to second arena (the free block)
|
|
|
|
add ax,10h+GA_ALIGN_BYTES
|
|
adc dx,0
|
|
and ax,GA_MASK_BYTES
|
|
cCall alloc_data_sel,<dx,ax,1>
|
|
mov di,ax ;di -> free block arena
|
|
|
|
; Setup selector to the third arena ('NOT THERE' at end of heap block)
|
|
|
|
pop dx ;recover unaligned start addr
|
|
pop ax
|
|
|
|
pop cx ;recover len in paragraphs
|
|
pop bx
|
|
|
|
sub bx,1
|
|
sbb cx, 0
|
|
rept 4
|
|
shl bx,1
|
|
rcl cx,1 ;cx:bx = len in bytes
|
|
endm
|
|
add ax,bx
|
|
adc dx,cx
|
|
and ax,GA_MASK_BYTES ;dx:ax -> not there arena addr
|
|
|
|
push ax ;save not there arena address
|
|
push dx
|
|
|
|
cCall alloc_data_sel,<dx,ax,1>
|
|
|
|
; Now fill in the arenas
|
|
|
|
mov es,ax
|
|
assumes es,nothing
|
|
|
|
xor bx,bx ;es:bx -> not there arena
|
|
|
|
mov es:[bx].ga_sig,GA_SIGNATURE
|
|
mov es:[bx].ga_owner,GA_NOT_THERE
|
|
mov es:[bx].ga_flags,bl
|
|
mov es:[bx].ga_size,bx
|
|
mov es:[bx].ga_prev,di
|
|
mov es:[bx].ga_handle,bx
|
|
mov es:[bx].ga_lrunext,bx
|
|
mov es:[bx].ga_lruprev,bx
|
|
|
|
mov es,di ;es:bx -> free block
|
|
|
|
mov es:[bx].ga_sig,GA_SIGNATURE
|
|
mov es:[bx].ga_owner,bx
|
|
mov es:[bx].ga_flags,bl
|
|
mov es:[bx].ga_prev,si
|
|
mov es:[bx].ga_next,ax
|
|
mov es:[bx].ga_handle,bx
|
|
mov es:[bx].ga_lrunext,bx
|
|
mov es:[bx].ga_lruprev,bx
|
|
|
|
pop cx ;cx:bx = address of end arena
|
|
pop bx
|
|
push ax ;save not there selector
|
|
|
|
cCall get_physical_address,<di> ;dx:ax = address of free arena
|
|
sub bx,ax
|
|
sbb cx,dx ;cx:bx = length in bytes
|
|
rept 4
|
|
shr cx,1
|
|
rcr bx,1
|
|
endm
|
|
sub bx,1
|
|
sbb cx,0 ;cx:bx = length in paragraphs
|
|
|
|
or cx, cx ; Less than 1024k?
|
|
jz @F ; yes, set correct size
|
|
xor bx, bx ; no, set bogus size
|
|
@@:
|
|
mov cx,bx
|
|
xor bx,bx
|
|
mov es:[bx].ga_size,cx ;save free block size (<1024k)
|
|
|
|
pop ax ;recover end arena selector
|
|
|
|
mov es,si ;es:bx -> initial sentinel
|
|
|
|
mov es:[bx].ga_sig,GA_SIGNATURE
|
|
mov es:[bx].ga_size,bx
|
|
mov es:[bx].ga_owner,GA_NOT_THERE
|
|
mov es:[bx].ga_flags,bl
|
|
mov es:[bx].ga_prev,si ;first.prev = self
|
|
mov es:[bx].ga_next,di
|
|
mov es:[bx].ga_handle,bx
|
|
mov es:[bx].ga_lrunext,bx
|
|
mov es:[bx].ga_lruprev,bx
|
|
|
|
ret
|
|
|
|
FormatHeapBlock endp
|
|
|
|
;-----------------------------------------------------------------------
|
|
;
|
|
; In: AX - selector to ending 'not there' block
|
|
; BX - zero
|
|
; SI - selector to initial sentinel
|
|
; DI - selector to free block arena
|
|
; ES:BX -> initial sentinel arena
|
|
public AddBlockToHeap
|
|
AddBlockToHeap proc near
|
|
|
|
pusha
|
|
push bp
|
|
mov bp,sp
|
|
sub sp,8
|
|
SelFirstBlock equ word ptr [bp - 2]
|
|
SelLastBlock equ word ptr [bp - 4]
|
|
SelFreeBlock equ word ptr [bp - 6]
|
|
SelInsertBlock equ word ptr [bp - 8]
|
|
|
|
mov SelFirstBlock,si
|
|
mov SelLastBlock,ax
|
|
mov SelFreeBlock,di
|
|
|
|
;
|
|
; Get the physical address of this block
|
|
;
|
|
cCall get_physical_address, <si>
|
|
mov bx,ax
|
|
mov cx,dx
|
|
|
|
xor di,di
|
|
;
|
|
; search for the correct place to insert it.
|
|
;
|
|
mov si,[di].hi_first
|
|
|
|
abh20: cCall get_physical_address, <si>
|
|
cmp dx,cx
|
|
jb abh40
|
|
ja abh60
|
|
|
|
cmp ax,bx
|
|
jb abh40
|
|
|
|
;
|
|
; Found our spot
|
|
;
|
|
jmp abh60
|
|
|
|
;
|
|
; Check the next block
|
|
;
|
|
abh40: mov es,si
|
|
;
|
|
; Have we reached the end of the list?
|
|
;
|
|
cmp si,es:[di].ga_next
|
|
mov si,es:[di].ga_next
|
|
jne abh20
|
|
|
|
;
|
|
; es contains the selector of the block to insert this
|
|
; heap partition after
|
|
;
|
|
abh60:
|
|
add [di].hi_count,3 ;three more arenas
|
|
mov ax,GA_SIGNATURE
|
|
cmp es:[di].ga_sig,GA_ENDSIG
|
|
jne abh70
|
|
|
|
;
|
|
; New block will be at the end of the heap
|
|
;
|
|
mov es:[di].ga_sig,GA_SIGNATURE
|
|
mov ax,GA_ENDSIG
|
|
|
|
;
|
|
; make this the next block in the heap
|
|
;
|
|
abh70: mov dx,SelFirstBlock
|
|
mov bx,es:[di].ga_next
|
|
mov es:[di].ga_next,dx
|
|
mov cx,es
|
|
mov SelInsertBlock,cx
|
|
mov es,dx
|
|
mov es:[di].ga_prev,cx
|
|
|
|
;
|
|
; Put the last block last
|
|
;
|
|
mov dx,SelLastBlock
|
|
mov es,dx
|
|
mov es:[di].ga_next,bx
|
|
|
|
;
|
|
; If this block was last, don't update next.prev
|
|
;
|
|
cmp ax,GA_ENDSIG
|
|
je abh75
|
|
|
|
mov es,bx
|
|
mov es:[di].ga_prev,dx
|
|
jmp abh80
|
|
|
|
;
|
|
; Fix the old heap end block
|
|
;
|
|
abh75: mov es,[di].hi_last
|
|
mov es:[di].ga_owner,GA_NOT_THERE
|
|
mov es:[di].ga_sig,GA_SIGNATURE
|
|
mov es:[di].ga_size,di
|
|
mov cx,es:[di].ga_freeprev
|
|
mov es:[di].ga_freeprev,di
|
|
mov es:[di].ga_freenext,di
|
|
|
|
;
|
|
; Turn the new end block into a proper end block
|
|
;
|
|
mov es,SelLastBlock
|
|
mov es:[di].ga_sig,GA_ENDSIG
|
|
mov es:[di].ga_owner,-1
|
|
mov bx,SelFreeBlock
|
|
mov es:[di].ga_freeprev,bx
|
|
mov es:[di].ga_freenext,-1
|
|
mov es:[di].ga_size,GA_ALIGN
|
|
mov ax,SelLastBlock
|
|
mov es:[di].ga_next,ax
|
|
|
|
;
|
|
; Fix the free list
|
|
;
|
|
mov es,cx
|
|
mov es:[di].ga_freenext,bx
|
|
mov es,bx
|
|
mov es:[di].ga_freeprev,cx
|
|
mov ax,SelLastBlock
|
|
mov es:[di].ga_freenext,ax
|
|
|
|
;
|
|
; Fix the discardable code fence
|
|
;
|
|
cCall get_physical_address, <[di].hi_last>
|
|
sub ax,[di].gi_disfence
|
|
sbb dx,[di].gi_disfence_hi
|
|
|
|
mov bx,ax
|
|
mov cx,dx
|
|
cCall get_physical_address, <SelLastBlock>
|
|
|
|
sub ax,bx
|
|
sbb dx,cx
|
|
|
|
mov [di].gi_disfence,ax
|
|
mov [di].gi_disfence_hi,dx
|
|
|
|
;
|
|
; Increment the free block count
|
|
;
|
|
inc [di].gi_free_count
|
|
|
|
;
|
|
; Make this block the last block in the heap
|
|
;
|
|
mov ax,SelLastBlock
|
|
mov [di].hi_last,ax
|
|
jmp abh90
|
|
|
|
;
|
|
; Add the free block to the free list
|
|
;
|
|
abh80: mov es,SelFreeBlock
|
|
mov si,0
|
|
cCall gadd_free
|
|
|
|
abh90: mov sp,bp
|
|
pop bp
|
|
popa
|
|
ret
|
|
|
|
AddBlockToHeap endp
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; AllocDpmiBlock ;
|
|
; ;
|
|
; Allocates a block from DPMI and stores the information in ;
|
|
; DpmiMemory. It also allocates a selector for the beginning of ;
|
|
; the block. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ;
|
|
; AX = size of block to allocate in paragraphs ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = selector to block if allocated ;
|
|
; BX = size of block in paragraphs ;
|
|
; BX = zero if block is 1 megabyte in size. ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = zero if error ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
public AllocDpmiBlock
|
|
AllocDpmiBlock proc near
|
|
push es
|
|
push ds
|
|
push si
|
|
push di
|
|
push cx
|
|
push bp
|
|
mov bp,sp
|
|
sub sp,30h ; space for meminfo structure
|
|
MemInfo equ [bp - 30h]
|
|
SetKernelDS
|
|
;
|
|
; Find an unused Dpmi Block
|
|
;
|
|
mov si,0
|
|
mov cx,NUM_DPMI_BLOCKS - 1
|
|
adb3: cmp DpmiMemory[si].DBSel,0
|
|
je adb5
|
|
|
|
add si,size DpmiBlock
|
|
loop adb3
|
|
|
|
;
|
|
; Did We find one?
|
|
;
|
|
cmp DpmiMemory[si].DBSel,0
|
|
jne adb140
|
|
|
|
;
|
|
; Store expected size
|
|
;
|
|
adb5: mov DpmiMemory[si].DBSize, ax
|
|
|
|
;
|
|
; Convert paragraphs to bytes (if paragraphs = 0, then alloc a
|
|
; megabyte)
|
|
;
|
|
mov cx,ax
|
|
mov bx,10h
|
|
or cx,cx
|
|
jz adb10
|
|
|
|
mov bx,ax
|
|
shr bx,0ch
|
|
shl cx,04h
|
|
|
|
;
|
|
; Attempt to allocate the block
|
|
;
|
|
adb10: push si
|
|
DPMICALL 501h
|
|
mov dx,si
|
|
pop si
|
|
jc adb100
|
|
|
|
;
|
|
; put information into dpmi memory list
|
|
;
|
|
adb20: mov DpmiMemory[si].DBHandleLow,di
|
|
mov DpmiMemory[si].DBHandleHigh,dx
|
|
|
|
;
|
|
; Allocate a selector for the beginning of the block
|
|
;
|
|
cCall alloc_data_sel,<bx,cx,1>
|
|
|
|
;
|
|
; Remember the selector
|
|
;
|
|
mov DpmiMemory[si].DBSel,ax
|
|
|
|
;
|
|
; Update the number of dpmi blocks
|
|
;
|
|
inc DpmiBlockCount
|
|
|
|
;
|
|
; Return the information
|
|
;
|
|
mov bx,DpmiMemory[si].DBSize
|
|
adb40: mov sp,bp
|
|
pop bp
|
|
pop cx
|
|
pop di
|
|
pop si
|
|
pop ds
|
|
pop es
|
|
ret
|
|
|
|
;
|
|
; Couldn't allocate a block the size we wanted. Find the largest
|
|
; block we can allocate
|
|
;
|
|
adb100: mov ax,ss
|
|
mov es,ax
|
|
lea di,MemInfo
|
|
DPMICALL 500h
|
|
jc adb140
|
|
|
|
;
|
|
; Convert block size to paragraphs
|
|
;
|
|
mov ax,es:[di]
|
|
mov dx,es:[di + 2]
|
|
mov bx,dx
|
|
mov cx,ax
|
|
shl dx,0ch
|
|
shr ax,4
|
|
or ax,dx
|
|
|
|
;
|
|
; Store expected size
|
|
; N.B. We don't jump back into the above code, because this
|
|
; could result in an infinite loop if something is seriously
|
|
; wrong with DPMI.
|
|
;
|
|
mov DpmiMemory[si].DBSize, ax
|
|
|
|
;
|
|
; Attempt to allocate the block
|
|
;
|
|
push si
|
|
DPMICALL 501h
|
|
mov dx,si
|
|
pop si
|
|
jnc adb20
|
|
|
|
;
|
|
; We have failed to allocate the memory
|
|
;
|
|
adb140: xor ax,ax
|
|
jmp adb40
|
|
|
|
UnsetKernelDS
|
|
AllocDpmiBlock endp
|
|
if KDEBUG
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; CCCC ;
|
|
; ;
|
|
; Fills the given area with DBGFILL_FREE ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ES:DI = arena header of free area. ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All. ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Sun Nov 09, 1986 01:39:52p -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc CCCC,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ds
|
|
SetKernelDS
|
|
cmp fCheckFree,0
|
|
jnz short dont_CCCC ; not while booting
|
|
test Kernel_flags,kf_check_free
|
|
jz short dont_CCCC
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push di
|
|
push es
|
|
mov bx,es:[di].ga_size
|
|
mov ax,es
|
|
call get_blotto
|
|
mov es,ax
|
|
|
|
;;; mov cx,ss ; make sure we're not wiping
|
|
;;; cmp cx,ax ; out the stack
|
|
;;; jb short by_64Kb_loop
|
|
;;; add ax,bx
|
|
;;; cmp cx,ax
|
|
;;; ja short by_64Kb_loop ; yes it wastes debugging bytes
|
|
;;; jmps no_not_the_stack ; but it's readable
|
|
|
|
push bx ; Say it ain't so, Joe...
|
|
xor cx,cx ; force the incoming sel/descriptor to
|
|
mov bx,cx ; a limit of 64k - it might be higher
|
|
inc cx ; which would cause set_physical_adr
|
|
cCall set_sel_limit,<es> ; to destroy following descriptors.
|
|
pop bx
|
|
|
|
jmp short CC_doit
|
|
|
|
CC_next_64k:
|
|
push es
|
|
cCall get_physical_address,<es> ;update selector to next
|
|
inc dl ; 64k block
|
|
cCall set_physical_address,<es>
|
|
pop es ;reload it with new base
|
|
|
|
CC_doit:
|
|
mov cx,1000h ; 1000h paras = 64k bytes
|
|
cmp bx,cx
|
|
jae @f
|
|
mov cx,bx ; less than 64k left
|
|
@@:
|
|
sub bx,cx ; bx = # paras left to do
|
|
shl cx,3 ; cx = # words to CC this time
|
|
mov ax,(DBGFILL_FREE or (DBGFILL_FREE SHL 8))
|
|
xor di, di
|
|
rep stosw
|
|
|
|
or bx,bx ; more to do?
|
|
jnz short CC_next_64k ; go do the next block
|
|
no_not_the_stack:
|
|
pop es
|
|
pop di
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
dont_CCCC:
|
|
pop ds
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; init_free_to_CCCC ;
|
|
; ;
|
|
; Initializes all of the free space to zero. It speeds booting if ;
|
|
; CCCCing is not done during boot time. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; none ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; CCCC ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Wed Nov 19, 1986 09:41:58a -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc init_free_to_CCCC,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ds
|
|
SetKernelDS
|
|
test Kernel_flags,kf_check_free
|
|
jz short dont_init
|
|
push cx
|
|
push di
|
|
push es
|
|
xor di,di
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
mov cx,[di].gi_free_count
|
|
mov es,[di].hi_first
|
|
mov es,es:[di].ga_freenext
|
|
CCCC_all_loop:
|
|
call CCCC
|
|
mov es,es:[di].ga_freenext
|
|
loop CCCC_all_loop
|
|
|
|
; get EMS land if there
|
|
|
|
mov cx,[di].gi_alt_free_count
|
|
jcxz no_alts
|
|
mov es,[di].gi_alt_first
|
|
mov es,es:[di].ga_freenext
|
|
CCCC_alt_loop:
|
|
call CCCC
|
|
mov es,es:[di].ga_freenext
|
|
loop CCCC_alt_loop
|
|
no_alts:
|
|
pop es
|
|
pop di
|
|
pop cx
|
|
dont_init:
|
|
pop ds
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; check_this_space ;
|
|
; ;
|
|
; Makes sure the given free space is still filled with DBGFILL_FREE ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ES:DI = arena header of space to check ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; all ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue Nov 18, 1986 08:26:52p -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc check_this_space,<PUBLIC,NEAR>,<ax,bx,cx,dx,di,ds,es>
|
|
cBegin
|
|
SetKernelDS
|
|
cmp fCheckFree,0
|
|
jnz short not_while_boot
|
|
test Kernel_flags,kf_check_free
|
|
jnz short cts_check_it_out
|
|
not_while_boot:
|
|
jmps cts_ret
|
|
cts_check_it_out:
|
|
mov bx,es:[di].ga_size
|
|
mov ax,es
|
|
call get_blotto
|
|
mov es,ax
|
|
|
|
push bx ; Say it ain't so, Joe...
|
|
xor cx,cx ; force the incoming sel/descriptor to
|
|
mov bx,cx ; a limit of 64k - it might be higher
|
|
inc cx ; which would cause set_physical_adr
|
|
cCall set_sel_limit,<es> ; to destroy following descriptors.
|
|
pop bx
|
|
|
|
jmp short cts_doit
|
|
|
|
cts_next_64k:
|
|
push es
|
|
cCall get_physical_address,<es> ;update selector to next
|
|
inc dl ; 64k block
|
|
cCall set_physical_address,<es>
|
|
pop es ;reload it with new base
|
|
|
|
cts_doit:
|
|
mov cx,1000h ; 1000h paras = 64k bytes
|
|
cmp bx,cx
|
|
jae @f
|
|
mov cx,bx ; less than 64k left
|
|
@@:
|
|
sub bx,cx ; bx = # paras left to do
|
|
shl cx,3 ; cx = # words to zero this time
|
|
mov ax,(DBGFILL_FREE or (DBGFILL_FREE shl 8))
|
|
xor di, di
|
|
repz scasw ; check it out
|
|
jz short so_far_so_good
|
|
kerror 0FFh,<FREE MEMORY OVERWRITE AT >,es,di
|
|
jmps cts_ret
|
|
so_far_so_good:
|
|
or bx,bx ; more to do?
|
|
jnz short cts_next_64k ; go do the next block
|
|
|
|
cts_ret:
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; check_free_list ;
|
|
; ;
|
|
; Checks the global free list for consistency. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; none ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Wed Oct 29, 1986 10:13:42a -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc check_free_list,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push ds
|
|
push es
|
|
SetKernelDS
|
|
cmp fCheckFree,0
|
|
jnz short cfl_outta_here
|
|
test Kernel_flags,kf_check_free
|
|
jnz short cfl_check_it_out
|
|
cfl_outta_here:
|
|
jmp all_done
|
|
cfl_check_it_out:
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
mov es,[di].hi_first
|
|
mov cx,[di].gi_free_count
|
|
or cx,cx
|
|
jnz short short_relative_jumps
|
|
jmp all_done
|
|
short_relative_jumps:
|
|
mov ax,es:[di].ga_freenext
|
|
mov es,ax
|
|
check_chain_loop:
|
|
mov ds,es:[di].ga_freeprev
|
|
mov es,es:[di].ga_freenext
|
|
cmp ds:[di].ga_freenext,ax
|
|
jnz short prev_bad
|
|
mov bx,ds
|
|
cmp ax,bx
|
|
jmps prev_okay
|
|
prev_bad:
|
|
mov bx, ax
|
|
kerror 0FFh,<free_list: prev bad>,ds,bx
|
|
mov ax, bx
|
|
prev_okay:
|
|
cmp es:[di].ga_freeprev,ax
|
|
jnz short next_bad
|
|
mov bx,es
|
|
cmp ax,bx
|
|
jmps next_okay
|
|
|
|
next_bad:
|
|
mov bx, ax
|
|
kerror 0FFh,<free_list: next bad>,bx,es
|
|
next_okay:
|
|
mov ax,es
|
|
loop check_chain_loop
|
|
SetKernelDS
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
cmp [di].hi_last,ax
|
|
jz short all_done
|
|
mov bx, ax
|
|
kerror 0FFh,<free_list: count bad>,[di].hi_last,bx
|
|
all_done:
|
|
pop es
|
|
pop ds
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; ValidateFreeSpaces ;
|
|
; ;
|
|
; The global free list is gone through to make sure that all free ;
|
|
; partitions are filled with DBGFILL_FREE ;
|
|
; ;
|
|
; Arguments: ;
|
|
; none ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; all ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue Nov 18, 1986 09:46:55a -by- David N. Weise [davidw] ;
|
|
; Wrote it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc ValidateFreeSpaces,<PUBLIC,FAR>
|
|
cBegin nogen
|
|
push ds
|
|
SetKernelDS
|
|
test Kernel_flags,kf_check_free
|
|
jz short dont_validate
|
|
push cx
|
|
push di
|
|
push es
|
|
xor di,di
|
|
mov ds,pGlobalHeap
|
|
UnSetKernelDS
|
|
mov cx,[di].gi_free_count
|
|
mov es,[di].hi_first
|
|
mov es,es:[di].ga_freenext
|
|
jcxz empty_list
|
|
check_all_loop:
|
|
call check_this_space
|
|
mov es,es:[di].ga_freenext
|
|
loop check_all_loop
|
|
empty_list:
|
|
pop es
|
|
pop di
|
|
pop cx
|
|
dont_validate:
|
|
pop ds
|
|
ret
|
|
cEnd nogen
|
|
|
|
else
|
|
|
|
cProc ValidateFreeSpaces,<PUBLIC,FAR>
|
|
cBegin nogen
|
|
ret
|
|
cEnd nogen
|
|
|
|
endif
|
|
|
|
sEnd CODE
|
|
|
|
end
|
|
|