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

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