mirror of https://github.com/microsoft/MS-DOS.git
371 lines
11 KiB
NASM
371 lines
11 KiB
NASM
|
;
|
|||
|
; xenix memory calls for MSDOS
|
|||
|
;
|
|||
|
; CAUTION: The following routines rely on the fact that arena_signature and
|
|||
|
; arena_owner_system are all equal to zero and are contained in DI.
|
|||
|
;
|
|||
|
INCLUDE DOSSEG.ASM
|
|||
|
|
|||
|
CODE SEGMENT BYTE PUBLIC 'CODE'
|
|||
|
ASSUME SS:DOSGROUP,CS:DOSGROUP
|
|||
|
|
|||
|
.xlist
|
|||
|
.xcref
|
|||
|
INCLUDE DOSSYM.ASM
|
|||
|
INCLUDE DEVSYM.ASM
|
|||
|
.cref
|
|||
|
.list
|
|||
|
|
|||
|
TITLE ALLOC.ASM - memory arena manager
|
|||
|
NAME Alloc
|
|||
|
|
|||
|
SUBTTL memory allocation utility routines
|
|||
|
PAGE
|
|||
|
;
|
|||
|
; arena data
|
|||
|
;
|
|||
|
i_need arena_head,WORD ; seg address of start of arena
|
|||
|
i_need CurrentPDB,WORD ; current process data block addr
|
|||
|
i_need FirstArena,WORD ; first free block found
|
|||
|
i_need BestArena,WORD ; best free block found
|
|||
|
i_need LastArena,WORD ; last free block found
|
|||
|
i_need AllocMethod,BYTE ; how to alloc first(best)last
|
|||
|
|
|||
|
;
|
|||
|
; arena_free_process
|
|||
|
; input: BX - PID of process
|
|||
|
; output: free all blocks allocated to that PID
|
|||
|
;
|
|||
|
procedure arena_free_process,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
MOV DI,arena_signature
|
|||
|
MOV AX,[arena_head]
|
|||
|
CALL Check_Signature ; ES <- AX, check for valid block
|
|||
|
|
|||
|
arena_free_process_loop:
|
|||
|
retc
|
|||
|
PUSH ES
|
|||
|
POP DS
|
|||
|
CMP DS:[arena_owner],BX ; is block owned by pid?
|
|||
|
JNZ arena_free_next ; no, skip to next
|
|||
|
MOV DS:[arena_owner],DI ; yes... free him
|
|||
|
|
|||
|
arena_free_next:
|
|||
|
CMP BYTE PTR DS:[DI],arena_signature_end
|
|||
|
; end of road, Jack?
|
|||
|
retz ; never come back no more
|
|||
|
CALL arena_next ; next item in ES/AX carry set if trash
|
|||
|
JMP arena_free_process_loop
|
|||
|
|
|||
|
arena_free_process ENDP
|
|||
|
|
|||
|
;
|
|||
|
; arena_next
|
|||
|
; input: DS - pointer to block head
|
|||
|
; output: AX,ES - pointers to next head
|
|||
|
; carry set if trashed arena
|
|||
|
;
|
|||
|
procedure arena_next,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
MOV AX,DS ; AX <- current block
|
|||
|
ADD AX,DS:[arena_size] ; AX <- AX + current block length
|
|||
|
INC AX ; remember that header!
|
|||
|
;
|
|||
|
; fall into check_signature and return
|
|||
|
;
|
|||
|
; CALL check_signature ; ES <- AX, carry set if error
|
|||
|
; RET
|
|||
|
arena_next ENDP
|
|||
|
|
|||
|
;
|
|||
|
; check_signature
|
|||
|
; input: AX - address of block header
|
|||
|
; output: ES=AX, carry set if signature is bad
|
|||
|
;
|
|||
|
procedure check_signature,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
MOV ES,AX ; ES <- AX
|
|||
|
CMP BYTE PTR ES:[DI],arena_signature_normal
|
|||
|
; IF next signature = not_end THEN
|
|||
|
JZ check_signature_ok ; GOTO ok
|
|||
|
CMP BYTE PTR ES:[DI],arena_signature_end
|
|||
|
; IF next signature = end then
|
|||
|
JZ check_signature_ok ; GOTO ok
|
|||
|
STC ; set error
|
|||
|
return
|
|||
|
|
|||
|
check_signature_ok:
|
|||
|
CLC
|
|||
|
return
|
|||
|
Check_signature ENDP
|
|||
|
|
|||
|
;
|
|||
|
; Coalesce - combine free blocks ahead with current block
|
|||
|
; input: DS - pointer to head of free block
|
|||
|
; output: updated head of block, AX is next block
|
|||
|
; carry set -> trashed arena
|
|||
|
;
|
|||
|
procedure Coalesce,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
CMP BYTE PTR DS:[DI],arena_signature_end
|
|||
|
; IF current signature = END THEN
|
|||
|
retz ; GOTO ok
|
|||
|
CALL arena_next ; ES, AX <- next block, Carry set if error
|
|||
|
retc ; IF no error THEN GOTO check
|
|||
|
|
|||
|
coalesce_check:
|
|||
|
CMP ES:[arena_owner],DI
|
|||
|
retnz ; IF next block isnt free THEN return
|
|||
|
MOV CX,ES:[arena_size] ; CX <- next block size
|
|||
|
INC CX ; CX <- CX + 1 (for header size)
|
|||
|
ADD DS:[arena_size],CX ; current size <- current size + CX
|
|||
|
MOV CL,ES:[DI] ; move up signature
|
|||
|
MOV DS:[DI],CL
|
|||
|
JMP coalesce ; try again
|
|||
|
Coalesce ENDP
|
|||
|
|
|||
|
SUBTTL $Alloc - allocate space in memory
|
|||
|
PAGE
|
|||
|
;
|
|||
|
; Assembler usage:
|
|||
|
; MOV BX,size
|
|||
|
; MOV AH,Alloc
|
|||
|
; INT 21h
|
|||
|
; AX:0 is pointer to allocated memory
|
|||
|
; BX is max size if not enough memory
|
|||
|
;
|
|||
|
; Description:
|
|||
|
; Alloc returns a pointer to a free block of
|
|||
|
; memory that has the requested size in paragraphs.
|
|||
|
;
|
|||
|
; Error return:
|
|||
|
; AX = error_not_enough_memory
|
|||
|
; = error_arena_trashed
|
|||
|
;
|
|||
|
procedure $ALLOC,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
|
|||
|
XOR AX,AX
|
|||
|
MOV DI,AX
|
|||
|
|
|||
|
MOV [FirstArena],AX ; init the options
|
|||
|
MOV [BestArena],AX
|
|||
|
MOV [LastArena],AX
|
|||
|
|
|||
|
PUSH AX ; alloc_max <- 0
|
|||
|
MOV AX,[arena_head] ; AX <- beginning of arena
|
|||
|
CALL Check_signature ; ES <- AX, carry set if error
|
|||
|
JC alloc_err ; IF error THEN GOTO err
|
|||
|
|
|||
|
alloc_scan:
|
|||
|
PUSH ES
|
|||
|
POP DS ; DS <- ES
|
|||
|
CMP DS:[arena_owner],DI
|
|||
|
JZ alloc_free ; IF current block is free THEN examine
|
|||
|
|
|||
|
alloc_next:
|
|||
|
CMP BYTE PTR DS:[DI],arena_signature_end
|
|||
|
; IF current block is last THEN
|
|||
|
JZ alloc_end ; GOTO end
|
|||
|
CALL arena_next ; AX, ES <- next block, Carry set if error
|
|||
|
JNC alloc_scan ; IF no error THEN GOTO scan
|
|||
|
|
|||
|
alloc_err:
|
|||
|
POP AX
|
|||
|
|
|||
|
alloc_trashed:
|
|||
|
error error_arena_trashed
|
|||
|
|
|||
|
alloc_end:
|
|||
|
CMP [FirstArena],0
|
|||
|
JNZ alloc_do_split
|
|||
|
|
|||
|
alloc_fail:
|
|||
|
invoke get_user_stack
|
|||
|
POP BX
|
|||
|
MOV [SI].user_BX,BX
|
|||
|
error error_not_enough_memory
|
|||
|
|
|||
|
alloc_free:
|
|||
|
CALL coalesce ; add following free block to current
|
|||
|
JC alloc_err ; IF error THEN GOTO err
|
|||
|
MOV CX,DS:[arena_size]
|
|||
|
|
|||
|
POP DX ; check for max found size
|
|||
|
CMP CX,DX
|
|||
|
JNA alloc_test
|
|||
|
MOV DX,CX
|
|||
|
|
|||
|
alloc_test:
|
|||
|
PUSH DX
|
|||
|
CMP BX,CX ; IF BX > size of current block THEN
|
|||
|
JA alloc_next ; GOTO next
|
|||
|
|
|||
|
CMP [FirstArena],0
|
|||
|
JNZ alloc_best
|
|||
|
MOV [FirstArena],DS ; save first one found
|
|||
|
alloc_best:
|
|||
|
CMP [BestArena],0
|
|||
|
JZ alloc_make_best ; initial best
|
|||
|
PUSH ES
|
|||
|
MOV ES,[BestArena]
|
|||
|
CMP ES:[arena_size],CX ; is size of best larger than found?
|
|||
|
POP ES
|
|||
|
JBE alloc_last
|
|||
|
alloc_make_best:
|
|||
|
MOV [BestArena],DS ; assign best
|
|||
|
alloc_last:
|
|||
|
MOV [LastArena],DS ; assign last
|
|||
|
JMP alloc_next
|
|||
|
|
|||
|
;
|
|||
|
; split the block high
|
|||
|
;
|
|||
|
alloc_do_split_high:
|
|||
|
MOV DS,[LastArena]
|
|||
|
MOV CX,DS:[arena_size]
|
|||
|
SUB CX,BX
|
|||
|
MOV DX,DS
|
|||
|
JE alloc_set_owner ; sizes are equal, no split
|
|||
|
ADD DX,CX ; point to next block
|
|||
|
MOV ES,DX ; no decrement!
|
|||
|
DEC CX
|
|||
|
XCHG BX,CX ; bx has size of lower block
|
|||
|
JMP alloc_set_sizes ; cx has upper (requested) size
|
|||
|
|
|||
|
;
|
|||
|
; we have scanned memory and have found all appropriate blocks
|
|||
|
; check for the type of allocation desired; first and best are identical
|
|||
|
; last must be split high
|
|||
|
;
|
|||
|
alloc_do_split:
|
|||
|
CMP BYTE PTR [AllocMethod], 1
|
|||
|
JA alloc_do_split_high
|
|||
|
MOV DS,[FirstArena]
|
|||
|
JB alloc_get_size
|
|||
|
MOV DS,[BestArena]
|
|||
|
alloc_get_size:
|
|||
|
MOV CX,DS:[arena_size]
|
|||
|
SUB CX,BX ; get room left over
|
|||
|
MOV AX,DS
|
|||
|
MOV DX,AX ; save for owner setting
|
|||
|
JE alloc_set_owner ; IF BX = size THEN (don't split)
|
|||
|
ADD AX,BX
|
|||
|
INC AX ; remember the header
|
|||
|
MOV ES,AX ; ES <- DS + BX (new header location)
|
|||
|
DEC CX ; CX <- size of split block
|
|||
|
alloc_set_sizes:
|
|||
|
MOV DS:[arena_size],BX ; current size <- BX
|
|||
|
MOV ES:[arena_size],CX ; split size <- CX
|
|||
|
MOV BL,arena_signature_normal
|
|||
|
XCHG BL,DS:[DI] ; current signature <- 4D
|
|||
|
MOV ES:[DI],BL ; new block sig <- old block sig
|
|||
|
MOV ES:[arena_owner],DI
|
|||
|
|
|||
|
alloc_set_owner:
|
|||
|
MOV DS,DX
|
|||
|
MOV AX,[CurrentPDB]
|
|||
|
MOV DS:[arena_owner],AX
|
|||
|
MOV AX,DS
|
|||
|
INC AX
|
|||
|
POP BX
|
|||
|
transfer SYS_RET_OK
|
|||
|
|
|||
|
$alloc ENDP
|
|||
|
|
|||
|
SUBTTL $SETBLOCK - change size of an allocated block (if possible)
|
|||
|
PAGE
|
|||
|
;
|
|||
|
; Assembler usage:
|
|||
|
; MOV ES,block
|
|||
|
; MOV BX,newsize
|
|||
|
; MOV AH,setblock
|
|||
|
; INT 21h
|
|||
|
; if setblock fails for growing, BX will have the maximum
|
|||
|
; size possible
|
|||
|
; Error return:
|
|||
|
; AX = error_invalid_block
|
|||
|
; = error_arena_trashed
|
|||
|
; = error_not_enough_memory
|
|||
|
; = error_invalid_function
|
|||
|
;
|
|||
|
procedure $SETBLOCK,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
MOV DI,arena_signature
|
|||
|
MOV AX,ES
|
|||
|
DEC AX
|
|||
|
CALL check_signature
|
|||
|
JNC setblock_grab
|
|||
|
|
|||
|
setblock_bad:
|
|||
|
JMP alloc_trashed
|
|||
|
|
|||
|
setblock_grab:
|
|||
|
MOV DS,AX
|
|||
|
CALL coalesce
|
|||
|
JC setblock_bad
|
|||
|
MOV CX,DS:[arena_size]
|
|||
|
PUSH CX
|
|||
|
CMP BX,CX
|
|||
|
JBE alloc_get_size
|
|||
|
JMP alloc_fail
|
|||
|
$setblock ENDP
|
|||
|
|
|||
|
SUBTTL $DEALLOC - free previously allocated piece of memory
|
|||
|
PAGE
|
|||
|
;
|
|||
|
; Assembler usage:
|
|||
|
; MOV ES,block
|
|||
|
; MOV AH,dealloc
|
|||
|
; INT 21h
|
|||
|
;
|
|||
|
; Error return:
|
|||
|
; AX = error_invalid_block
|
|||
|
; = error_arena_trashed
|
|||
|
;
|
|||
|
procedure $DEALLOC,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
MOV DI,arena_signature
|
|||
|
MOV AX,ES
|
|||
|
DEC AX
|
|||
|
CALL check_signature
|
|||
|
JC dealloc_err
|
|||
|
MOV ES:[arena_owner],DI
|
|||
|
transfer SYS_RET_OK
|
|||
|
|
|||
|
dealloc_err:
|
|||
|
error error_invalid_block
|
|||
|
$DEALLOC ENDP
|
|||
|
|
|||
|
SUBTTL $AllocOper - get/set allocation mechanism
|
|||
|
PAGE
|
|||
|
;
|
|||
|
; Assembler usage:
|
|||
|
; MOV AH,AllocOper
|
|||
|
; MOV BX,method
|
|||
|
; MOV AL,func
|
|||
|
; INT 21h
|
|||
|
;
|
|||
|
; Error return:
|
|||
|
; AX = error_invalid_function
|
|||
|
;
|
|||
|
procedure $AllocOper,NEAR
|
|||
|
ASSUME DS:NOTHING,ES:NOTHING
|
|||
|
CMP AL,1
|
|||
|
JB AllocOperGet
|
|||
|
JZ AllocOperSet
|
|||
|
error error_invalid_function
|
|||
|
AllocOperGet:
|
|||
|
MOV AL,BYTE PTR [AllocMethod]
|
|||
|
XOR AH,AH
|
|||
|
transfer SYS_RET_OK
|
|||
|
AllocOperSet:
|
|||
|
MOV [AllocMethod],BL
|
|||
|
transfer SYS_RET_OK
|
|||
|
$AllocOper ENDP
|
|||
|
|
|||
|
do_ext
|
|||
|
|
|||
|
CODE ENDS
|
|||
|
END
|
|||
|
|