; 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