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, 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, 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, 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, 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, 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, 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, ; It defeats our purpose to move the jb short check_this_out ; block to a free space we want. cCall cmp_sel_address, jb short is_there_hope check_this_out: push ax call gcheckfree push cx jb short inopportune_free_space cCall free_sel, 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, 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, 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, sub bx, ax sbb cx, dx REPT 4 shr cx, 1 rcr bx, 1 ENDM cCall free_sel, 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, ; 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, 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, 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, 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, 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, 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, add ax,bx adc dx,cx cCall alloc_data_sel, 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, 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, ; 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, 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, ; to destroy following descriptors. pop bx jmp short gz_doit next_64k: push es cCall get_physical_address, ;update selector to next inc dl ; 64k block cCall set_physical_address, 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, 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, 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, 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, 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, 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, ; 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, 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, ; 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, ;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, 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, 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, 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, ; ; 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, 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, ; to destroy following descriptors. pop bx jmp short CC_doit CC_next_64k: push es cCall get_physical_address, ;update selector to next inc dl ; 64k block cCall set_physical_address, 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, 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,, 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, ; to destroy following descriptors. pop bx jmp short cts_doit cts_next_64k: push es cCall get_physical_address, ;update selector to next inc dl ; 64k block cCall set_physical_address, 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,,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, 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,,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,,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,,[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, 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, cBegin nogen ret cEnd nogen endif sEnd CODE end