mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
802 lines
27 KiB
802 lines
27 KiB
.MODEL MEDIUM
|
|
.DOSSEG
|
|
.386
|
|
|
|
jmps equ <jmp short>
|
|
smov macro dst, src
|
|
push src
|
|
pop dst
|
|
endm
|
|
|
|
MASTER_OBJECT_SIZE equ 512
|
|
|
|
LOCALHEAP_SIG EQU 'HL'
|
|
GLOBALHEAP_SIG EQU 'HG'
|
|
|
|
NOT_THERE EQU -4
|
|
BURGERMASTER EQU -3
|
|
|
|
; Data structure that describes an allocation arena. Both the local
|
|
; and global allocators use this structure at the beginning of their
|
|
; information structures.
|
|
;
|
|
HeapInfo STRUC
|
|
hi_check DW ? ; arena check word (non-zero enables heap checking)
|
|
hi_freeze DW ? ; arena frozen word (non-zero prevents compaction)
|
|
hi_count DW ? ; #entries in arena
|
|
hi_first DW ? ; first arena entry (sentinel, always busy)
|
|
DW ?
|
|
hi_last DW ? ; last arena entry (sentinel, always busy)
|
|
DW ?
|
|
hi_ncompact DB ? ; #compactions done so far (max of 3)
|
|
hi_dislevel DB ? ; current discard level
|
|
hi_distotal DD ? ; total amount discarded so far
|
|
hi_htable DW ? ; head of handle table list
|
|
hi_hfree DW ? ; head of free handle table list
|
|
hi_hdelta DW ? ; #handles to allocate each time
|
|
hi_hexpand DW ? ; address of near procedure to expand handles for
|
|
; this arena
|
|
hi_pstats DW ? ; address of statistics table or zero
|
|
HeapInfo ENDS
|
|
|
|
phi_first equ dword ptr hi_first
|
|
phi_last equ dword ptr hi_last
|
|
|
|
; Handle table entry.
|
|
|
|
HandleEntry STRUC
|
|
he_address DW ? ; actual address of object
|
|
he_flags DB ? ; flags and priority level
|
|
he_seg_no DB ? ; 0-based segment number for discardable code
|
|
HandleEntry ENDS
|
|
he_EMSPID_no equ byte ptr he_seg_no
|
|
|
|
FreeHandleEntry STRUC
|
|
he_link DW ?
|
|
he_free DW ?
|
|
FreeHandleEntry ENDS
|
|
|
|
LocalHandleEntry STRUC
|
|
lhe_address DW ? ; actual address of object
|
|
lhe_flags DB ? ; flags and priority level
|
|
lhe_count DB ? ; lock count
|
|
LocalHandleEntry ENDS
|
|
|
|
LocalFreeHandleEntry STRUC
|
|
lhe_link DW ?
|
|
lhe_free DW ?
|
|
LocalFreeHandleEntry ENDS
|
|
|
|
he_owner EQU he_address ; Discarded objects contain owner field
|
|
; here so we know when to free handle
|
|
; table entries of discarded objects.
|
|
|
|
HE_DISCARDABLE EQU 00Fh ; Discard level of this object
|
|
HE_DISCARDED EQU 040h ; Marks objects that have been discarded.
|
|
|
|
HE_FREEHANDLE EQU 0FFFFh ; Use -1 to mark free handle table entries
|
|
|
|
|
|
LHE_DISCARDABLE EQU 00Fh ; Discard level of this object
|
|
LHE_DISCARDED EQU 040h ; Marks objects that have been discarded.
|
|
LHE_USERFLAGS EQU 01Fh ; Mask for user setable flags
|
|
|
|
LHE_FREEHANDLE EQU 0FFFFh ; Use -1 to mark free handle table entries
|
|
|
|
|
|
HE_ALIGN = 4-1
|
|
HE_MASK = NOT HE_ALIGN
|
|
|
|
; Handles are allocated in blocks of N, where N is the hi_hdelta field
|
|
; in the local heap information structure. The last word of each block
|
|
; of handles is used to thread the blocks together, allowing all handles
|
|
; to be enumerated. The first word of every block is the number of
|
|
; handle table entries in the block. Not only does it save us code
|
|
; in henum, but it also has the convenient property of placing all
|
|
; handle entries on 2 byte boundaries (i.e. 2, 6, 10, 14), since the
|
|
; LA_MOVEABLE bit is 02h. Thus the address of the he_address field of
|
|
; a handle table entry is also the address of the handle table entry
|
|
; itself.
|
|
|
|
HandleTable STRUC
|
|
ht_count DW ? ; # handletable entries in this block
|
|
ht_entry DB SIZE HandleEntry DUP (?)
|
|
HandleTable ENDS
|
|
|
|
LocalHandleTable STRUC
|
|
lht_count DW ? ; # handletable entries in this block
|
|
lht_entry DB SIZE LocalHandleEntry DUP (?)
|
|
LocalHandleTable ENDS
|
|
|
|
; Local arena objects are kept in a doubly linked list.
|
|
|
|
LocalArena STRUC
|
|
la_prev DW ? ; previous arena entry (first entry points to self)
|
|
la_next DW ? ; next arena entry (last entry points to self)
|
|
la_handle DW ? ; back link to handle table entry
|
|
LocalArena ENDS
|
|
la_fixedsize = la_handle ; Fixed arena headers stop here
|
|
|
|
LA_MINBLOCKSIZE = la_fixedsize*4 ;*** This must be larger than LocalArenaFree
|
|
|
|
; free blocks have these extra items.
|
|
la_size = la_handle ; size of block (includes header data)
|
|
LocalArenaFree STRUC
|
|
DB SIZE LocalArena DUP (?)
|
|
la_free_prev DW ? ; previous free entry
|
|
la_free_next DW ? ; next free entry
|
|
LocalArenaFree ENDS
|
|
la_freefixedsize = SIZE LocalArenaFree ; Free block header stops here
|
|
|
|
; Local arena objects are aligned on 4 byte boundaries, leaving the
|
|
; low order two bits always zero.
|
|
|
|
LA_ALIGN = 4-1
|
|
LA_MASK = NOT LA_ALIGN
|
|
LA_FREE = 00h
|
|
LA_BUSY = 01h ; Saved in la_prev field of header
|
|
|
|
|
|
; Flags passed to LocalAlloc (zero is the default case)
|
|
|
|
LA_MOVEABLE EQU 02h ; Saved in la_prev field of header
|
|
LA_NOCOMPACT EQU 10h
|
|
LA_ZEROINIT EQU 40h
|
|
LA_MODIFY EQU 80h
|
|
|
|
|
|
; Data structure that describes the local arena. Allocated as the first
|
|
; object in each local heap. _pLocalHeap is a reserved location each
|
|
; automatic data segment that contains the pointer to this structure.
|
|
|
|
LocalInfo STRUC
|
|
DB SIZE HeapInfo DUP (?)
|
|
li_notify DD ? ; Far proc to call whenever a local block is moved
|
|
li_lock DW ? ; arena lock word
|
|
li_extra DW ? ; minimum amount to grow DS by
|
|
li_minsize DW ? ; minimum size of heap
|
|
li_sig DW ? ; signature for local heap
|
|
LocalInfo ENDS
|
|
|
|
; Notify procedure message codes
|
|
|
|
LN_OUTOFMEM = 0 ; Out of memory - arg1 = #bytes needed
|
|
LN_MOVE = 1 ; Object moved - arg1 = handle arg2 = old location
|
|
LN_DISCARD = 2 ; Object discard? - arg1 = handle, arg2 = discard flags
|
|
; Returns new discard flags in AX
|
|
|
|
LocalStats STRUC
|
|
ls_ljoin DW ? ; #calls to ljoin
|
|
ls_falloc DW ? ; #calls to lalloc with forward search
|
|
ls_fexamine DW ? ; #arena entries examined by ls_falloc calls
|
|
ls_fcompact DW ? ; #calls to lcompact by ls_falloc calls
|
|
ls_ffound DW ? ; #ls_falloc calls that found a block
|
|
ls_ffoundne DW ? ; #ls_falloc calls that failed to find a block
|
|
ls_malloc DW ? ; #calls to lalloc with backward search
|
|
ls_mexamine DW ? ; #arena entries examined by ls_malloc calls
|
|
ls_mcompact DW ? ; #calls to lcompact by ls_malloc calls
|
|
ls_mfound DW ? ; #ls_malloc calls that found a block
|
|
ls_mfoundne DW ? ; #ls_malloc calls that failed to find a block
|
|
ls_fail DW ? ; #times lalloc failed because unable to grow DS
|
|
ls_lcompact DW ? ; #calls to lcompact
|
|
ls_cloop DW ? ; #repeated compacts after discarding
|
|
ls_cexamine DW ? ; #entries examined in compaction loop
|
|
ls_cfree DW ? ; #free entries examined in compaction loop
|
|
ls_cmove DW ? ; #moveable entries moved by compaction
|
|
LocalStats ENDS
|
|
|
|
|
|
IncLocalStat MACRO n
|
|
if KDEBUG
|
|
inc ds:[di+SIZE LocalInfo].&n
|
|
endif
|
|
ENDM
|
|
|
|
; Global arena objects are kept in a doubly linked list.
|
|
;
|
|
GlobalArena STRUC
|
|
ga_count DB ? ; lock count for movable segments
|
|
ga_owner DW ? ; DOS 2.x 3.x owner field (current task)
|
|
ga_size DW ? ; DOS 2.x 3.x size, in paragraphs, not incl. header
|
|
ga_flags DB ? ; 1 byte available for flags
|
|
ga_prev DW ? ; previous arena entry (first points to self)
|
|
ga_next DW ? ; next arena entry (last points to self)
|
|
ga_handle DW ? ; back link to handle table entry
|
|
ga_lruprev DW ? ; Previous handle in lru chain
|
|
ga_lrunext DW ? ; Next handle in lru chain
|
|
GlobalArena ENDS
|
|
ga_sig = byte ptr ga_count ; DOS =< 3.x signature byte for fixed segs
|
|
|
|
ga_freeprev = word ptr ga_lruprev ; links for free segs
|
|
ga_freenext = word ptr ga_lrunext ; links for free segs
|
|
|
|
if PMODE32
|
|
|
|
DEFAULT_ARENA_SIZE equ 8000h ; Initial length of arena array
|
|
;
|
|
; 32 bit Protect Mode Arena
|
|
;
|
|
GlobalArena32 STRUC
|
|
pga_next DD ? ; next arena entry (last points to self)
|
|
pga_prev DD ? ; previous arena entry (first points to self)
|
|
pga_address DD ? ; 32 bit linear address of memory
|
|
pga_size DD ? ; 32 bit size in bytes
|
|
pga_handle DW ? ; back link to handle table entry
|
|
pga_owner DW ? ; Owner field (current task)
|
|
pga_count DB ? ; lock count for movable segments
|
|
pga_pglock DB ? ; # times page locked
|
|
pga_flags DB ? ; 1 word available for flags
|
|
pga_selcount DB ? ; Number of selectors allocated
|
|
pga_lruprev DD ? ; Previous entry in lru chain
|
|
pga_lrunext DD ? ; Next entry in lru chain
|
|
GlobalArena32 ENDS
|
|
|
|
.ERRNZ 32-size GlobalArena32
|
|
|
|
pga_sig = word ptr pga_count
|
|
|
|
pga_freeprev = dword ptr pga_lruprev ; links for free segs
|
|
pga_freenext = dword ptr pga_lrunext ; links for free segs
|
|
|
|
endif ; PMODE32
|
|
|
|
GA_SIGNATURE = 04Dh
|
|
GA_ENDSIG = 05Ah
|
|
|
|
; there are many special kinds of blocks, marked in the owner word
|
|
|
|
GA_SENTINAL = -1 ; a sentinal block
|
|
GA_BOGUS_BLOCK = -7 ; a block temporary marked allocated
|
|
GA_BURGERMASTER = -3 ; the master object
|
|
GA_NOT_THERE = -4 ; used with EEMS to link out unallocatable
|
|
; memory such as the EGA etc.
|
|
GA_PHANTOM = -5 ; A block that has no EMS banks banked in.
|
|
GA_WRAITH = -6 ; A block used to hold up partition headers.
|
|
|
|
; Global arena objects are aligned on 2 para. boundaries, leaving the
|
|
; low order bit always zero.
|
|
|
|
GA_ALIGN = 2-1
|
|
GA_MASK = NOT GA_ALIGN
|
|
GA_FIXED = 1
|
|
|
|
; Low byte of flags passed to GlobalAlloc (zero is the default case)
|
|
|
|
GA_ALLOCHIGH EQU 01h ; Flag to indicate allocate high
|
|
GA_MOVEABLE EQU 02h
|
|
GA_SEGTYPE EQU 0Ch ; These 2 bits stored in he_flags field
|
|
GA_DGROUP EQU 04h
|
|
GA_DISCCODE EQU 08h
|
|
GA_NOCOMPACT EQU 10h
|
|
GA_NODISCARD EQU 20h
|
|
GA_ZEROINIT EQU 40h
|
|
GA_MODIFY EQU 80h
|
|
|
|
GA_NEWEXPANDED EQU 80h ; Use new EMS allocation scheme
|
|
|
|
; These flags for use by KERNEL only (caller's CS must match)
|
|
|
|
if PMODE
|
|
GA_INTFLAGS = GA_ALLOCHIGH+GA_SEGTYPE or (GA_CODE_DATA+GA_ALLOC_DOS) shl 8
|
|
else
|
|
GA_INTFLAGS = GA_ALLOCHIGH+GA_SEGTYPE
|
|
endif
|
|
|
|
; High byte of flags remembered in handle table (he_flags field)
|
|
|
|
GA_DISCARDABLE EQU 01h ; Boolean flag for global object, not a level.
|
|
GA_CODE_DATA EQU 02h ; CODE or DATA seg that belongs to a task.
|
|
;GA_DGROUP EQU 04h
|
|
;GA_DISCCODE EQU 08h
|
|
GA_ALLOC_LOW EQU 10h ; Alloc in Lower land, overrides GA_ALLOC_EMS
|
|
GA_SHAREABLE EQU 20h ; Shareable object
|
|
GA_DDESHARE EQU 20h ; A shared memory object used for DDE.
|
|
;HE_DISCARDED EQU 40h ; Marks objects that have been discarded.
|
|
;GAH_NOTIFY EQU 40h
|
|
ife PMODE
|
|
GA_ALLOC_EMS EQU 80h ; Alloc in EMS land if LIM 4.0 around.
|
|
else
|
|
GA_ALLOC_DOS EQU 80h ; Alloc in DOS land if protected mode
|
|
endif
|
|
|
|
GA_USERFLAGS = GA_SHAREABLE + GA_DISCARDABLE
|
|
|
|
; Flags stored in the global arena header
|
|
|
|
GAH_PHANTOM EQU 01h ; This block is either a phantom or a wraith
|
|
GAH_DONT_GROW EQU 02h ; Don't grow this data segment.
|
|
GAH_DGROUP EQU GA_DGROUP
|
|
GAH_DISCCODE EQU GA_DISCCODE
|
|
GAH_NOTIFY EQU 40h
|
|
ife PMODE
|
|
GAH_INEMS EQU 80h ; This is out in EMS
|
|
else
|
|
GAH_FIXED EQU 80h
|
|
endif
|
|
|
|
; Data structure that describes the global arena. Allocated at the end
|
|
; of the local heap information structure. DO NOT CHANGE THE ORDER OF
|
|
; THE ENTRIES! The alt sequence and normal sequence must match!
|
|
|
|
GlobalInfo STRUC
|
|
DB SIZE HeapInfo DUP (?)
|
|
gi_lrulock DW ? ; Lock out access to LRU chain from interrupt level
|
|
ife PMODE32
|
|
gi_lruchain DW ? ; First handle in lru chain (most recently used)
|
|
else
|
|
gi_lruchain DD ? ; First handle in lru chain (most recently used)
|
|
endif
|
|
gi_lrucount DW ? ; #entries in LRU chain
|
|
ife PMODE32
|
|
gi_reserve DW ? ; #paras to reserve for disc code, 0 => not enabled
|
|
gi_disfence DW ? ; Fence for discardable code.
|
|
else
|
|
gi_reserve DD ? ; #paras to reserve for disc code, 0 => not enabled
|
|
gi_disfence DD ? ; Fence for discardable code.
|
|
endif
|
|
gi_free_count DW ? ; Count of all the free partitions.
|
|
|
|
gi_alt_first DW ? ; first entry in alternate arena
|
|
gi_alt_last DW ? ; last entry in alternate arena
|
|
gi_alt_count DW ? ; count of entries in alternate arena
|
|
gi_alt_lruchain DW ? ; First handle in lru chain (most recently used)
|
|
gi_alt_lrucount DW ? ; #entries in LRU chain
|
|
gi_alt_reserve DW ? ; alternate reserve
|
|
gi_alt_disfence DW ? ; Fence for discardable code.
|
|
gi_alt_free_count DW ? ; Count of all the free partitions.
|
|
gi_alt_pPhantom DW ? ; Pointer to the first pPhantom block.
|
|
gi_disfence_hi DW ? ; High word of fence
|
|
gi_flags DW ? ; some flags! !!! should merge with freeze and check
|
|
GlobalInfo ENDS
|
|
gi_cmpflags = byte ptr hi_dislevel ; Flags to control gcompact
|
|
gi_disfence_lo = word ptr gi_disfence
|
|
|
|
GIF_INT2 EQU 01h
|
|
|
|
CMP_FLAGS EQU GA_NODISCARD or GA_NOCOMPACT or GA_DISCCODE
|
|
|
|
BOOT_COMPACT EQU 80h
|
|
COMPACT_ALLOC EQU 40h ; Fast abort in gcompact for allocations
|
|
|
|
; Notify procedure message codes
|
|
|
|
GN_NO_MEMORY = 0
|
|
GN_MOVE = 1 ; Object moved - arg1 = handle arg2 = old location
|
|
GN_DISCARD = 2 ; Object discard? - arg1 = handle, arg2 = discard flags
|
|
; Returns new discard flags in AX
|
|
|
|
pLocalHeap equ 6
|
|
|
|
.DATA
|
|
fCheckFree DB 0
|
|
GlobalMasterHandle DD 0
|
|
|
|
KernelString DB "KERNEL", 0
|
|
|
|
|
|
EXTRN GETMODULEHANDLE:proc
|
|
EXTRN GETPROCADDRESS:proc
|
|
|
|
.CODE
|
|
|
|
PUBLIC CHECKGLOBALHEAP, CHECKLOCALHEAP, FCHECKFREE
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; CheckLocalHeap ;
|
|
; ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue Jan 01, 1980 10:58:28p -by- David N. Weise [davidw] ;
|
|
; ReWrote it from C into assembly. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
CHECKLOCALHEAP PROC
|
|
|
|
local nrefhandles : word
|
|
local nhandles : word
|
|
local nfreehandles : word
|
|
local nusedhandles : word
|
|
local ndishandles : word
|
|
local pbottom : word
|
|
|
|
xor di,di
|
|
xor dx,dx ; For error codes.
|
|
mov bx,[di].pLocalHeap
|
|
or bx,bx
|
|
jnz have_a_heap
|
|
jmp clh_ret
|
|
have_a_heap:
|
|
|
|
;; cmp di,[bx].hi_check
|
|
;; jnz do_heap_check
|
|
;; jmp clh_ret
|
|
;;do_heap_check:
|
|
|
|
mov cx,[bx].hi_count
|
|
mov si,[bx].hi_first
|
|
test [si].la_prev,LA_BUSY
|
|
jnz first_should_be_busy
|
|
or dx,1 ; Forward links invalid.
|
|
first_should_be_busy:
|
|
|
|
check_forward_links:
|
|
mov ax,[si].la_next
|
|
cmp ax,si
|
|
jbe end_of_line
|
|
mov si,ax
|
|
loop check_forward_links
|
|
end_of_line:
|
|
|
|
cmp ax,[bx].hi_last
|
|
jnz forward_bad
|
|
cmp cx,1
|
|
jz forward_good
|
|
; jcxz forward_good
|
|
forward_bad:
|
|
or dx,1 ; Forward links invalid.
|
|
forward_good:
|
|
|
|
mov cx,[bx].hi_count
|
|
mov si,[bx].hi_last
|
|
test [si].la_prev,LA_BUSY
|
|
jnz last_should_be_busy
|
|
or dx,2 ; Backward links invalid.
|
|
last_should_be_busy:
|
|
|
|
check_backward_links:
|
|
mov ax,[si].la_prev
|
|
and ax,0FFFCh
|
|
cmp ax,si
|
|
jae begin_of_line
|
|
mov si,ax
|
|
loop check_backward_links
|
|
begin_of_line:
|
|
|
|
cmp ax,[bx].hi_first
|
|
jnz backward_bad
|
|
cmp cx,1
|
|
jz backward_good
|
|
; jcxz backward_good
|
|
backward_bad:
|
|
or dx,2 ; Backward links invalid.
|
|
backward_good:
|
|
|
|
mov cx,[bx].hi_count
|
|
mov si,[bx].hi_first
|
|
mov nrefhandles,0
|
|
count_referenced_handles:
|
|
test [si].la_prev,LA_BUSY
|
|
jz no_handle
|
|
test [si].la_prev,LA_MOVEABLE
|
|
jz no_handle
|
|
mov di,[si].la_handle
|
|
cmp [di].lhe_free,LHE_FREEHANDLE
|
|
jnz handle_not_free
|
|
or dx,4 ; Block points to free handle.
|
|
jmps no_handle
|
|
handle_not_free:
|
|
mov ax,si
|
|
add ax,SIZE LocalArena
|
|
cmp ax,[di].lhe_address
|
|
jz handle_points_back
|
|
or dx,8 ; Block -> handle but not vice versa
|
|
jmps no_handle
|
|
handle_points_back:
|
|
inc nrefhandles
|
|
no_handle:
|
|
mov si,[si].la_next
|
|
loop count_referenced_handles
|
|
|
|
mov di,[bx].hi_htable
|
|
mov nhandles,0
|
|
mov ndishandles,0
|
|
mov nusedhandles,0
|
|
mov nfreehandles,0
|
|
|
|
handle_block_loop:
|
|
or di,di
|
|
jz no_more_handle_blocks
|
|
lea si,[di].ht_entry[0]
|
|
mov cx,[di].ht_count
|
|
add nhandles,cx
|
|
|
|
handle_entry_loop:
|
|
jcxz next_handle_block
|
|
dec cx
|
|
cmp [si].lhe_free,LHE_FREEHANDLE
|
|
jnz not_free
|
|
inc nfreehandles
|
|
jmps next_handle_entry
|
|
not_free:
|
|
test [si].lhe_flags,LHE_DISCARDED
|
|
jz not_discarded
|
|
inc ndishandles
|
|
jmps next_handle_entry
|
|
not_discarded:
|
|
inc nusedhandles
|
|
next_handle_entry:
|
|
add si,SIZE LocalHandleEntry
|
|
jmp handle_entry_loop
|
|
next_handle_block:
|
|
mov di,[si].lhe_address
|
|
jmp handle_block_loop
|
|
|
|
no_more_handle_blocks:
|
|
|
|
mov ax,nusedhandles
|
|
cmp ax,nrefhandles
|
|
jz handles_match
|
|
or dx,10h ; allocated handles != used handles
|
|
handles_match:
|
|
add ax,nfreehandles
|
|
add ax,ndishandles
|
|
cmp ax,nhandles
|
|
jz total_number_okay
|
|
or dx,20h ; total number of handles dont add up
|
|
total_number_okay:
|
|
|
|
xor cx,cx
|
|
mov si,[bx].hi_hfree
|
|
count_free:
|
|
or si,si
|
|
jz counted_free
|
|
inc cx
|
|
mov si,[si].lhe_link
|
|
jmp count_free
|
|
counted_free:
|
|
cmp cx,nfreehandles
|
|
jz free_add_up
|
|
or dx,40h ; total # of free handles dont add up
|
|
free_add_up:
|
|
|
|
; now check the free block list
|
|
|
|
mov si,[bx].hi_first
|
|
mov si,[si].la_free_next ; Sentinals not free.
|
|
mov ax,[bx].hi_last
|
|
mov pbottom,ax
|
|
|
|
check_free_list:
|
|
cmp si,[si].la_free_next
|
|
jz check_free_list_done
|
|
mov ax,[si].la_next
|
|
sub ax,si
|
|
cmp ax,[si].la_size
|
|
jnz free_list_corrupted ; invalid block size
|
|
|
|
;; SetKernelDS es
|
|
;; test kernel_flags,KF_CHECK_FREE
|
|
;; UnSetKernelDS es
|
|
;; jz dont_check_free
|
|
|
|
cmp fCheckFree,1
|
|
jne dont_check_free
|
|
|
|
mov di,si
|
|
add di,SIZE LocalArenaFree
|
|
mov cx,[si].la_next
|
|
sub cx,di
|
|
mov al,0CCh
|
|
smov es,ds
|
|
repz scasb
|
|
jnz free_list_corrupted ; free block corrupted
|
|
dont_check_free:
|
|
mov ax,[si].la_free_next
|
|
cmp ax,si
|
|
jbe free_list_corrupted
|
|
mov si,ax
|
|
cmp ax,pbottom
|
|
jbe check_free_list
|
|
|
|
free_list_corrupted:
|
|
;; kerror 0FFh,<LOCAL FREE MEMORY OVERWRITE AT >,es,di
|
|
or dx,80h
|
|
check_free_list_done:
|
|
clh_ret:
|
|
mov ax,dx
|
|
ret
|
|
|
|
CHECKLOCALHEAP ENDP
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; CheckGlobalHeap ;
|
|
; ;
|
|
; The Global Heap is checked for consistency. First the forward links ;
|
|
; are examined to make sure they lead from the hi_first to the hi_last. ;
|
|
; Then the backward links are checked to make sure they lead from the ;
|
|
; hi_last to the hi_first. Then the arenas are sequentially checked ;
|
|
; to see that the moveable entries point to allocated handles and that ;
|
|
; said handles point back. The handle table is then checked to see ;
|
|
; that the number of used handles match the number of referenced ;
|
|
; handles, and that the number of total handles matches the sum of the ;
|
|
; free, discarded, and used handles. Finally the free list of handles ;
|
|
; is checked. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; none ;
|
|
; ;
|
|
; Returns: ;
|
|
; CF = 0 everything is just fine ;
|
|
; all registers preserved ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; CF = 1 ;
|
|
; DX = offending arena header ;
|
|
; AX = 01h Forward links invalid ;
|
|
; 02h Backward links invalid ;
|
|
; 04h ga_handle points to free handle ;
|
|
; 08h arena points to handle but not vice versa ;
|
|
; 80h ga_sig is bad ;
|
|
; DX = 0 ;
|
|
; AX = 10h allocated handles don't match used handles ;
|
|
; 20h total number of handles don't match up ;
|
|
; 40h total number of free handles don't match up ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Sat Nov 01, 1986 02:16:46p -by- David N. Weise [davidw] ;
|
|
; Rewrote it from C into assembly. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
CHECKGLOBALHEAP PROC
|
|
|
|
push edx ; save most everything
|
|
push ebx
|
|
push ecx
|
|
push edi
|
|
push esi
|
|
push ebp
|
|
push ds
|
|
push es
|
|
push fs
|
|
push gs
|
|
|
|
cmp word ptr GlobalMasterHandle+2, 0 ; Have we loaded the fn ptr yet?
|
|
jnz have_fn_ptr ; Yep - carry on.
|
|
|
|
push ds ; No, get kernel.exe module handle
|
|
push OFFSET KernelString ;
|
|
call GetModuleHandle ;
|
|
; We assume success!
|
|
push ax
|
|
push 0 ; Ordinal #28 is GetMasterHandle()
|
|
push 28 ;
|
|
call GetProcAddress ; Get the entry point
|
|
mov word ptr GlobalMasterHandle, ax ; and save it.
|
|
mov word ptr GlobalMasterHandle+2, dx ;
|
|
cmp word ptr GlobalMasterHandle+2, 0 ; if GetProcAddress failed,
|
|
jnz have_fn_ptr
|
|
inc ax ; make AX nonzero
|
|
jmp finished ; and bail out
|
|
|
|
have_fn_ptr:
|
|
|
|
call GlobalMasterHandle ; Fetch the Burgermaster segment.
|
|
mov ds, ax ;
|
|
|
|
xor eax, eax
|
|
xor edx, edx
|
|
xor edi, edi
|
|
|
|
mov cx, [di].hi_count
|
|
mov esi, [di].phi_first
|
|
|
|
top_of_loop:
|
|
|
|
push cx
|
|
|
|
mov eax, [esi].pga_address
|
|
mov ecx, [esi].pga_size
|
|
cmp [esi].pga_owner, GA_NOT_THERE
|
|
je finished_handle_check
|
|
cmp [esi].pga_owner, GA_BURGERMASTER
|
|
je finished_handle_check
|
|
cmp [esi].pga_owner, di
|
|
je finished_handle_check
|
|
cmp [esi].pga_handle, di
|
|
je finished_handle_check
|
|
;; cmp ?
|
|
;; je finished_handle_check
|
|
|
|
mov bx, [esi].pga_handle
|
|
dec ecx
|
|
or bl, 1
|
|
lsl ebx, ebx
|
|
jnz failed_handle_check
|
|
cmp ecx, ebx
|
|
jz finished_handle_check
|
|
|
|
failed_handle_check:
|
|
|
|
int 3
|
|
|
|
finished_handle_check:
|
|
|
|
add eax, [esi].pga_size
|
|
mov ebx, [esi].pga_next
|
|
mov edx, [ebx].pga_address
|
|
cmp eax, edx
|
|
|
|
pop cx
|
|
|
|
xchg ebx, esi
|
|
jnz not_adjacent
|
|
cmp ebx, [esi].pga_prev
|
|
jz next_iteration
|
|
|
|
not_adjacent:
|
|
|
|
cmp [esi].pga_owner, GA_NOT_THERE
|
|
jz next_iteration
|
|
cmp cx, 1
|
|
jnz failed_link_check
|
|
|
|
next_iteration:
|
|
|
|
loop jump_to_top
|
|
cmp ebx, [di].phi_last
|
|
je return_success
|
|
|
|
failed_link_check:
|
|
|
|
int 3
|
|
mov edx, ebx
|
|
mov ax, 1
|
|
jmp finished
|
|
|
|
jump_to_top:
|
|
jmp top_of_loop
|
|
|
|
return_success:
|
|
|
|
xor ax, ax
|
|
xor dx, dx
|
|
|
|
finished:
|
|
|
|
pop gs
|
|
pop fs
|
|
pop es
|
|
pop ds
|
|
pop ebp
|
|
pop esi
|
|
pop edi
|
|
pop ecx
|
|
pop ebx
|
|
or ax, ax
|
|
jnz error_return
|
|
pop edx
|
|
ret
|
|
|
|
error_return:
|
|
|
|
int 3
|
|
add sp, 4
|
|
stc
|
|
ret
|
|
|
|
CHECKGLOBALHEAP ENDP
|
|
|
|
end
|