mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 07:54:28 +00:00
522 lines
13 KiB
Plaintext
522 lines
13 KiB
Plaintext
; File : $DOSMEM.A86$
|
|
;
|
|
; Description :
|
|
;
|
|
; Original Author : DIGITAL RESEARCH
|
|
;
|
|
; Last Edited By : $CALDERA$
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
; Copyright Work of Caldera, Inc. All Rights Reserved.
|
|
;
|
|
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
|
|
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
|
|
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
|
|
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
|
|
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
|
|
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
|
|
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
|
|
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
|
|
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
|
|
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
|
|
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
|
|
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
|
|
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
|
|
; CIVIL LIABILITY.
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; *** Current Edit History ***
|
|
; *** End of Current Edit History ***
|
|
; $Log$
|
|
; DOSMEM.A86 1.13 94/12/01 10:05:21
|
|
; now freeing UMBs also during program termination
|
|
; DOSMEM.A86 1.12 93/07/20 22:46:25
|
|
; dmd_upper_root defaults to FFFF
|
|
; DOSMEM.A86 1.10 93/06/18 21:00:11
|
|
; Remove historic CDOS comment
|
|
; ENDLOG
|
|
;
|
|
include pcmode.equ
|
|
include i:msdos.equ
|
|
include i:mserror.equ
|
|
|
|
BEST_FIT equ 01h ; allocate BEST match memory block
|
|
LAST_FIT equ 02h ; allocate LAST matching memory block
|
|
UPPER_FIT equ 80h ; preferably allocate from upper memory
|
|
UPPER_ONLY_FIT equ 40h ; only allocate from upper memory
|
|
|
|
FIRST_FIT equ 04h ; we use this internally...
|
|
|
|
PCM_CODE CSEG BYTE
|
|
extrn error_exit:near ; Standard Error Handler
|
|
extrn return_AX_CLC:near
|
|
extrn return_BX:near
|
|
extrn reload_ES:near
|
|
extrn toupper:near
|
|
|
|
; *****************************
|
|
; *** DOS Function 48 ***
|
|
; *** Allocate Memory Block ***
|
|
; *****************************
|
|
;
|
|
Public func48
|
|
func48: ; bx = request size
|
|
callf lock_tables ; lock global tables
|
|
call search_mem ; look for block bx or bigger
|
|
jc memory_avbl_error ; skip on error
|
|
test mem_strategy,LAST_FIT ; is it last fit ?
|
|
jz f48_10 ; no, use from begining
|
|
mov ax,cx ; work out how much we have
|
|
sub ax,bx ; to leave free
|
|
je f48_10
|
|
dec ax
|
|
mov bx,ax
|
|
call make_dmd ; allocate this DMD as free
|
|
mov bx,cx ; real block is the next one
|
|
f48_10:
|
|
mov ax,current_psp ; Change the Owner
|
|
mov DMD_PSP,ax ; we now own this block
|
|
|
|
push es
|
|
call make_dmd ; make new DMD for allocated mem
|
|
pop ax
|
|
inc ax ; return starting segment
|
|
jmps memory_exit ; unlock global tables
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 49 ***
|
|
; *** Free Memory Block ***
|
|
; *****************************
|
|
;
|
|
Public func49
|
|
func49:
|
|
callf lock_tables ; lock global tables
|
|
call get_dmd ; es -> dmd
|
|
jc memory_error ; skip if block invalid
|
|
mov ax,DMD_PSP ; get owner field
|
|
cmp ax,dmd_owner
|
|
mov ax,es ; return DMD address in AX
|
|
jb func49_10
|
|
mov dx,dmd_address ; nothing below this block get's freed
|
|
cmp ax,dx ; should we free it ?
|
|
jb func49_20 ; no, give it a new owner
|
|
func49_10:
|
|
xor dx,dx ; yes, owner = 0 means free block
|
|
func49_20:
|
|
mov DMD_PSP,dx ; free/set new owner
|
|
; jmps memory_exit
|
|
|
|
; centralised exit point to unlock system tables
|
|
|
|
memory_exit:
|
|
;-----------
|
|
; On Entry:
|
|
; AX = return value
|
|
; On Exit
|
|
; None
|
|
;
|
|
callf unlock_tables ; unlock global tables
|
|
jmp return_AX_CLC ; return DMD address
|
|
|
|
memory_avbl_error:
|
|
mov bx,cx
|
|
call return_BX ; return biggest block available
|
|
memory_error:
|
|
callf unlock_tables ; unlock global tables
|
|
mov locus,LOC_MEMORY
|
|
jmp error_exit ; Jump to error handler
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 4A ***
|
|
; *** Alter Memory Block ***
|
|
; *****************************
|
|
;
|
|
Public func4A
|
|
func4A:
|
|
callf lock_tables ; lock global tables
|
|
call get_dmd ; es -> dmd
|
|
jc memory_error ; skip if block invalid
|
|
|
|
push DMD_LEN ; save the current DMD length
|
|
call merge_mem ; pick up unallocated blocks
|
|
pop ax ; return original DMD length
|
|
jc memory_error ; if dmd's destroyed
|
|
|
|
mov ax,ED_MEMORY ; assume insufficient mem
|
|
mov cx,DMD_LEN ; cx = available size
|
|
cmp cx,bx ; if avail < req, then
|
|
jb memory_avbl_error ; return maximum possible
|
|
|
|
mov ax,current_psp ; Force this block to be owned by the
|
|
mov DMD_PSP,ax ; current PSP. MACE Utilities
|
|
|
|
call make_dmd ; new block on top
|
|
call reload_ES
|
|
mov ax,es
|
|
jmps memory_exit
|
|
|
|
; *****************************
|
|
; *** DOS Function 58 ***
|
|
; *** Get/Set Alloc Strategy***
|
|
; *****************************
|
|
;
|
|
; On Entry:- AL == 0 Get Allocation Strategy
|
|
; AL == 1 Set Allocation Strategy
|
|
; AL == 2 Get Upper Memory Link
|
|
; AL == 3 Set Upper Memory Link
|
|
Public func58
|
|
|
|
func58:
|
|
callf lock_tables ; lock global tables
|
|
cmp al,3
|
|
ja f58_error ; Range Check Sub-Function
|
|
cbw ; AH = 0
|
|
mov si,ax
|
|
add si,si ; SI = word offset of sub-function
|
|
call cs:f58_tbl[si] ; execute the sub-function
|
|
jnc memory_exit ; return the result
|
|
jmps memory_error ; or the error
|
|
|
|
|
|
f58_error:
|
|
mov ax,ED_FUNCTION
|
|
jmps memory_error
|
|
|
|
f58_tbl dw f58_get_strategy
|
|
dw f58_set_strategy
|
|
dw f58_get_link
|
|
dw f58_set_link
|
|
|
|
f58_get_strategy:
|
|
; mov ah,0 ; AX = subfunction = 0-3
|
|
mov al,mem_strategy
|
|
; clc
|
|
ret
|
|
|
|
f58_set_strategy:
|
|
mov ah,MS_M_STRATEGY
|
|
mov mem_strategy,bl
|
|
; clc
|
|
ret
|
|
|
|
f58_get_link:
|
|
mov ah,MS_M_STRATEGY
|
|
mov al,dmd_upper_link
|
|
; clc
|
|
ret
|
|
|
|
f58_set_link:
|
|
mov ax,ED_FUNCTION ; return function not implemented
|
|
mov cx,dmd_upper_root ; if no upper memory chain
|
|
inc cx ; CX = FFFF
|
|
stc
|
|
jcxz f58_set_link20
|
|
dec cx
|
|
mov dmd_upper_link,bl ; set link field
|
|
mov ax,dmd_root ; now find dmd before upper memory root
|
|
mov dl,IDM ; assume we want to link
|
|
test bl,bl ; do we want to link/unlink UMBs?
|
|
jnz f58_set_link10
|
|
mov dl,IDZ ; no, we want to unlink
|
|
f58_set_link10:
|
|
mov es,ax ; point to DMD
|
|
call check_dmd_id ; stop if id is invalid
|
|
jc f58_set_link20 ; and return an error
|
|
push es
|
|
call next_dmd ; does the next DMD match our
|
|
pop es
|
|
cmp ax,cx ; upper memory chain ?
|
|
jne f58_set_link10
|
|
mov DMD_ID,dl ; set appropriate link type
|
|
mov ax,(MS_M_STRATEGY*256)+3; return AX unchanged
|
|
; clc
|
|
f58_set_link20:
|
|
ret
|
|
|
|
|
|
|
|
|
|
eject
|
|
;****************************************
|
|
;* *
|
|
;* Memory Function Subroutines *
|
|
;* *
|
|
;****************************************
|
|
;
|
|
; FREE_ALL takes the PSP passed in the BX register and free's all
|
|
; memory associated with that PSP.
|
|
;
|
|
; entry: bx = requested PSP
|
|
;
|
|
; exit:
|
|
;
|
|
Public free_all
|
|
free_all:
|
|
mov es,dmd_root ; es -> first dmd
|
|
|
|
free_all_loop:
|
|
call check_dmd_id ; if block is invalid
|
|
jc free_all_fail ; then quit now
|
|
|
|
mov dl,al ; dl = id code
|
|
cmp DMD_PSP,bx ; if block is owned by another
|
|
jnz free_all_next ; then check next
|
|
|
|
and DMD_PSP,0 ; Free this partition
|
|
|
|
free_all_next:
|
|
push es
|
|
call next_dmd ; es -> next block up
|
|
pop ax
|
|
cmp dl,IDM ; if previous block wasn't last
|
|
jz free_all_loop ; then keep going
|
|
cmp dmd_upper_root,ax
|
|
jbe free_all_end
|
|
mov ax,dmd_upper_root ; free UMBs as well
|
|
cmp ax,-1 ; if UMB head is valid
|
|
mov es,ax
|
|
jne free_all_loop
|
|
free_all_end:
|
|
xor ax,ax ; Otherwise Stop
|
|
|
|
free_all_fail:
|
|
ret
|
|
|
|
;
|
|
; SET_OWNER allows the OWNING PSP to specify the new owner of
|
|
; the partition. An error is returned if an incorrect partition address
|
|
; is given or the partition is not owned by the current PSP.
|
|
;
|
|
; Entry:- AX == New PSP
|
|
; BX == Partition Start
|
|
;
|
|
; Exit:-
|
|
; no carry AX == Unknown
|
|
; carry AX == Error Code
|
|
;
|
|
Public set_owner
|
|
set_owner:
|
|
push es
|
|
dec bx
|
|
mov es,bx ; ES points at DMD (We Hope)
|
|
xchg ax,bx ; Save the New PSP address in BX
|
|
call check_dmd_id ; Check for a valid DMD
|
|
jc s_o20
|
|
mov ax,current_psp
|
|
cmp ax,DMD_PSP ; Check the Current PSP owns the memory
|
|
jnz s_o10
|
|
mov DMD_PSP,bx ; Set the new owner and return
|
|
jmps s_o20
|
|
|
|
s_o10:
|
|
mov ax,ED_BLOCK
|
|
stc
|
|
s_o20:
|
|
pop es
|
|
ret
|
|
|
|
;
|
|
; Search for a free memory block at least as big as bx
|
|
; entry: bx = requested size
|
|
; success exit: cf clear, es -> dmd
|
|
; cx = block size
|
|
; failure exit: cf set, ax = error code
|
|
; cx = biggest block available
|
|
|
|
search_mem:
|
|
mov ax,ED_DMD ; assume bad DMD chain
|
|
mov cx,dmd_root ; start at the bottom
|
|
jcxz search_mem_exit
|
|
mov es,cx ; lets clean up memory list
|
|
or mem_strategy,FIRST_FIT ; grab 1st block we come to
|
|
search_mem_init:
|
|
xor si,si ; si = max mem available
|
|
mov di,0FFFFh ; di = size of candiate (FFFF=none)
|
|
; dx = dmd of candidate
|
|
search_mem_loop:
|
|
call check_dmd_id ; if block is invalid
|
|
jc search_mem_exit ; then quit now
|
|
|
|
cmp DMD_PSP,0 ; if block is owned
|
|
jnz search_mem_next ; then check another
|
|
|
|
call merge_mem ; group with unallocated blocks
|
|
|
|
mov ax,es ; AX = current DMD
|
|
mov cx,DMD_LEN ; cx = block length
|
|
|
|
cmp cx,si ; is it the biggest block we
|
|
jb search_mem40 ; have found so far ?
|
|
mov si,cx ; if so then save the new size
|
|
search_mem40:
|
|
|
|
cmp cx,bx ; if it's not long enough
|
|
jb search_mem_next ; then try the next block
|
|
|
|
test mem_strategy,FIRST_FIT+LAST_FIT
|
|
jnz search_mem50 ; grab this block ?
|
|
|
|
test mem_strategy,BEST_FIT ; if BEST FIT then we only save this
|
|
jz search_mem_next ; candidate if the previous
|
|
cmp cx,di ; candidate was bigger
|
|
jae search_mem_next
|
|
search_mem50:
|
|
mov dx,es ; save this DMD candidate
|
|
mov di,cx ; along with it's length
|
|
and mem_strategy,not FIRST_FIT
|
|
search_mem_next:
|
|
call search_next_dmd ; try for another DMD
|
|
mov ax,ED_MEMORY ; assume insufficient mem
|
|
jc search_mem_exit ; stop if it's true
|
|
|
|
mov ax,es
|
|
cmp ax,dmd_upper_root ; if we reach the dmd upper root
|
|
jne search_mem_loop ; then we have a special case
|
|
or mem_strategy,FIRST_FIT ; grab 1st high memory block we find
|
|
test mem_strategy,UPPER_ONLY_FIT
|
|
jnz search_mem_init ; upper only is another special case
|
|
jmps search_mem_loop
|
|
|
|
search_mem_exit:
|
|
and mem_strategy,not FIRST_FIT
|
|
mov cx,di ; DX&DI contain our best candidate
|
|
inc di ; if DI=FFFF then we don't have one
|
|
je search_mem_bad ; else we return with CX = size
|
|
mov es,dx ; and ES = DMD
|
|
clc ; clear the error flag
|
|
ret
|
|
|
|
search_mem_bad:
|
|
mov cx,si ; no allocation made, so return
|
|
search_mem_error: ; biggest block and flag the error
|
|
stc
|
|
ret
|
|
|
|
search_next_dmd:
|
|
; On Entry:
|
|
; ES = current DMD
|
|
; On Exit:
|
|
; ES = AX = next DMD
|
|
; DX/DI preserved
|
|
;
|
|
cmp DMD_ID,IDM ; do we have any more blocks ?
|
|
jne search_mem_error ; no, return CY set
|
|
; jmp next_dmd ; else try next DMD
|
|
|
|
; Point to next DOS Memory Descriptor (dmd) in the chain
|
|
; entry: es -> current dmd
|
|
; exit: es -> next dmd
|
|
|
|
next_dmd:
|
|
mov ax,es
|
|
add ax,DMD_LEN
|
|
inc ax ; allow for dmd itself
|
|
mov es,ax
|
|
ret
|
|
|
|
; Increase the size of the current mem block
|
|
; by gobbling all adjacent unallocated blocks
|
|
; entry: es -> dmd
|
|
; exit: cf = 1, al = 7 if chain is broken
|
|
; ES,SI,DI,DX,BX preserved
|
|
|
|
merge_mem:
|
|
push es
|
|
cmp DMD_ID,IDM ; if no more dmd's
|
|
jnz merge_mem_done ; then just quit
|
|
|
|
call next_dmd
|
|
call check_dmd_id ; if id is invalid
|
|
jc merge_mem_quit ; then return an error
|
|
|
|
cmp DMD_PSP,0 ; if next dmd is owned
|
|
jnz merge_mem_done ; then done
|
|
|
|
mov cx,DMD_LEN ; if free, grab its length
|
|
pop es ; restore base dmd
|
|
|
|
mov DMD_ID,al ; use next's id (in case of last)
|
|
inc cx
|
|
add DMD_LEN,cx ; add new memory to base
|
|
jmps merge_mem ; and try again
|
|
|
|
merge_mem_done:
|
|
clc ; clear error flag
|
|
merge_mem_quit:
|
|
pop es ; restore base dmd
|
|
ret ; with cf and error flag
|
|
|
|
|
|
; If needed, create a new dmd on top of allocated memory
|
|
; entry: es -> current block
|
|
; bx = requested block size
|
|
; cx = current block size
|
|
|
|
make_dmd:
|
|
cmp bx,cx ; if request and size match
|
|
jz make_dmd_done ; then that's all we need
|
|
|
|
mov dl,DMD_ID ; get current block id
|
|
mov DMD_LEN,bx ; else shrink this block
|
|
mov DMD_ID,IDM ; not the last now
|
|
call next_dmd
|
|
mov DMD_ID,dl ; our old id for the new dmd
|
|
mov DMD_PSP,0 ; new block is free
|
|
sub cx,bx
|
|
dec cx
|
|
mov DMD_LEN,cx ; length is whatever is left
|
|
|
|
make_dmd_done:
|
|
ret
|
|
|
|
; Get passed value of memory block
|
|
; exit: es -> dmd
|
|
; al = DMD_ID, cf cleared if valid
|
|
; al = 7, cf set if invalid
|
|
|
|
get_dmd:
|
|
call reload_ES
|
|
mov ax,es
|
|
dec ax ; back up to dmd
|
|
mov es,ax
|
|
; jmps check_dmd_id ; fall through
|
|
|
|
; Check first byte in the dmd for a valid id code
|
|
; entry: es -> dmd
|
|
; exit: al = DMD_ID, cf cleared if valid
|
|
; al = 7, cf set if invalid
|
|
|
|
Public check_dmd_id
|
|
|
|
check_dmd_id:
|
|
mov al,DMD_ID
|
|
cmp al,IDM ; if not last
|
|
jz check_dmd_done ; then good
|
|
cmp al,IDZ ; if last
|
|
jz check_dmd_done ; also good
|
|
|
|
mov ax,ED_BLOCK ; Invalid DMD
|
|
check_dmd_error:
|
|
stc ; flag the error
|
|
check_dmd_done:
|
|
ret
|
|
|
|
|
|
PCMODE_DATA DSEG
|
|
|
|
extrn lock_tables:dword
|
|
extrn unlock_tables:dword
|
|
|
|
extrn dmd_address:word ; don't free DMD's with segment under this value
|
|
extrn dmd_owner:word ; don't free DMD's with owner under this value
|
|
extrn dmd_upper_root:word
|
|
extrn dmd_upper_link:byte
|
|
extrn current_psp:word
|
|
extrn locus:byte
|
|
extrn mem_strategy:byte
|
|
extrn dmd_root:word
|
|
|
|
end
|