
;*****************************************************
;*
;*	MEM Entry Points
;*
;*	Each process descriptor points to a linked
;*	list of MDs that describe memory segments that  
;*	it owns.  The MDs note the starting paragraph
;*	and a MAU that the Memory Segment is in.
;*
;*	Format of MDs on p_mem lists:
;*
;*	+----+----+----+----+----+----+----+----+
;*	|  link   |  start  |  flags  |   mau   |
;*	+----+----+----+----+----+----+----+----+
;*
;*	link	link field for p_mem list
;*	start	starting paragraph of memory segment
;*	flags	load,code,and share as in MPB
;*	mau	offset of MAU in SYSDAT that segment is
;*		allocated from
;*
;*****************************************************

;============
malloc_entry:
;============
; Allocate Memory - memory is allocated from MAUs.
; First we try to allocate memory from MAUs that has
; memory segments already allocated by this process.
; If that fails, we try to create a new MAU from the
; Memory Free List (MFL).  If both fails, an error is
; is returned to the user.
;
; (Future - if MPB flags indicate load shared code,
; we try to allocate from MAU's used by another process
; of the same name and from the same load file.)
;
;	input:	DX = MPB in u_wrkseg
;	output:	BX = 0 if successful (unused memory)
;		   = 1 if successful (shared code)
;		   = 0ffffh if failure
;		CX = error code
;
; Format of MPB:
;
;	+----+----+----+----+----+----+----+----+----+----+
;	|  start  |   min   |   max   |  pdadr  |  flags  |
;	+----+----+----+----+----+----+----+----+----+----+
;
;	start - if non-zero, an absolute request
;	min -	minimum length that will satisfy the request
;	max -	maximum length wanted
;		We will try to allocate the maximum
;		but will be satisfied with as little as the
;		minimum.
;	pdadr - Process Descriptor to allocate memory to.
;		Note - PD can not be a current process unless
;		it is the calling process.
;		The Calling process must explicitly release
;		the memory if the PD never becomes a process.
;		Otherwise, memory is released upon termination.
;		If pdadr is 0, then calling process allocates
;		the memory.
;	flags - 00001h Load	This segment initialized from
;				a disk file
;		00002h Shared	This is a sharable segment
;		00004h Code	This is a Code segment

		; Get a MD for use in the p_mem list

					; DX -> MPB (u_wrkseg)
	push dx ! call getmd ! pop dx	; BX -> MD
	jcxz mall_gmd
	    mov bx,0ffffh ! ret
mall_gmd:
		; fill PDADR field in case its zero

	push es ! mov es,u_wrkseg
	mov di,dx ! mov ax,es:mpb_pdadr[di]
	cmp ax,0 ! jne mall_gpd
	    mov ax,rlr
	    mov es:mpb_pdadr[di],ax
mall_gpd:
	pop es
	cmp ax,rlr ! je mall_pdver
	    mov si,(offset thrdrt)-p_thread
mall_pdnxt: mov si,p_thread[si]
	    cmp si,0 ! je mall_pdver
		cmp si,ax ! jne mall_pdnxt
		    cmp si,rlr ! je mall_pdver
			mov bx,0ffffh
			mov cx,e_active_pd
			ret
mall_pdver:
		; try to allocate memory

	mov si,ax ! add si,(p_mem - ms_link)
	mov cx,0				;CX=last MAU we've tried
  mall_next:
	mov si,ms_link[si]
	cmp si,0 ! je mall_ml
	    cmp cx,ms_mau[si] ! je mall_next
			; here's a MAU we haven't tried...
			; CX=last MAU tried
			; DX=MPB adr in u_wrkseg
			; BX=New MD
			; SI=current MD
		push cx ! push dx ! push bx ! push si
		mov bx,ms_mau[si]
		push bx ! call mall_try_mau ! pop di
		pop si ! pop bx ! pop dx
			; Plus DI=MAU address
		cmp cx,0 ! pop cx ! jne mall_next
			; succesful allocation
		    jmp mall_linkit
mall_ml:		; We must create a new MAU from MFL
	push bx ! push dx
	mov ds,u_wrkseg
	mov bx,offset mfl ! mov cx,f_mlalloc
	call mpmif
	mov ds,sysdat
		;BX=MAU, (New MD,MPB on stack)
	jcxz mall_ml0
	    pop dx ! pop bx ! jmp mall_err
mall_ml0:		; We have a new MAU
		;place MAU on MAL
	mov si,mal
	mov m_link[bx],si
	mov mal,bx
		;allocate memory
	pop dx ! push dx
	push bx ! call mall_try_mau ! pop di
	pop dx ! pop bx
		;DI=MAU, BX=New MD, DX=MPB in u_wrkseg
	cmp cx,0 ! jne mall_err
			; Successful allocation
	    mov si,0
	    jmps mall_linkit
mall_err:		; No memory available
	call freemd	; Free the Memory Descriptor
	mov bx,0ffffh ! ret	; CX=Error Code set previously
mall_linkit:
		;SI = MD addr which MAU came from
		;	if zero, from new MAU
		;BX -> MD
		;DX -> MPB in u_wrkseg
		;DI -> MAU
	push es ! mov es,u_wrkseg
	push di ! mov di,dx
	mov ax,es:mpb_start[di]
	mov ms_start[bx],ax
	mov ax,es:mpb_min[di]
	mov ms_length[bx],ax
	mov ax,es:mpb_flags[di]
	mov ms_flags[bx],ax
	cmp si,0 ! jne mall_l0
	    mov si,es:mpb_pdadr[di]
	    add si,(p_mem-ms_link)
mall_l0:mov ax,ms_link[si] ! mov ms_link[bx],ax
	mov ms_link[si],bx
	pop di ! mov ms_mau[bx],di
	pop es ! sub cx,cx ! mov bx,cx ! ret

mall_try_mau:
;------------
;	input:	BX -> MAU
;		DX -> MPB in u_wrkseg
;	output:	CX = Error Code

	mov ds,u_wrkseg
	mov cx,f_maualloc ! call mpmif
	mov ds,sysdat ! ret

;===========
mfree_entry:		; 130 - Memory Free
;===========
; Free the memory segment with the given segment addr.
;	input:	DX = MFPB in u_wrkseg
;	output:	BX = 0 if successful
;		   = 0ffffh on failure
;		CX = error code
;
; Memory Free Parameter Block (MFPB)
;
;	+----+----+----+----+
;	|  start  |  pdadr  |
;	+----+----+----+----+
;
;	start - starting paragraph of area to be freed.
;	pdadr - PD to free memory from.  If 0, then calling
;		process.  If non-zero, the PD must not be
;		a current process.

	push es ! mov es,u_wrkseg
	mov si,dx
	mov bx,es:mfpb_pd[si]
	mov dx,es:mfpb_start[si]
	pop es
			; BX = pdadr
			; DX = start paragraph
	cmp bx,0 ! jne mfree_chkpd
	    mov bx,rlr
	    jmps mfree_gotpd
mfree_chkpd:
	mov si,(offset thrdrt)-p_thread
mfree_nxtpd:
	mov si,p_link[si]
	cmp si,0 ! je mfree_gotpd
	    cmp si,bx ! jne mfree_nxtpd
		cmp si,rlr ! je mfree_gotpd
		    mov bx,0ffffh
		    mov cx,e_active_pd
		    ret		
mfree_gotpd:
	lea si,p_mem[bx]
mfree_next:
	mov bx,si ! mov si,ms_link[bx]
	cmp si,0 ! je mfree_err
	    cmp ms_start[si],dx ! je mfree_it
		ja mfree_next
		    mov ax,ms_start[si]
		    add ax,ms_length[si]
		    cmp ax,dx ! jbe mfree_next
			push dx ! push si
			call mfree_it
			pop si ! pop dx
			cmp cx,0 ! jne mfree_next
mfree_exit:
	sub bx,bx ! mov cx,bx ! ret
mfree_err:
	mov bx,0ffffh ! mov cx,e_no_memory
	ret

mfree_it:
;--------
;	input:	BX = root
;		SI = MD ([bx])
;		DX = segment to free
;	output: BX = 0,0ffffh (success,failure)
;		CX = Error Code

	push bx ! push si ! push dx
		;push MAF structure
	push dx ! push ms_start[si]
	push ms_mau[si]
	mov dx,sp ! push ss ! pop ds
	mov cx,f_maufree ! call mpmif
	mov bp,bx			;if bp=0,MAU not empty
	mov ds,sysdat
		;pop MAF structure
	pop ax ! pop ax ! pop ax
	pop dx ! pop si ! pop bx	
		;DX=segment to free
		;BX=root
		;SI=MD ( [BX] )
	cmp cx,0 ! jne mfree_r
	    cmp dx,ms_start[si] ! je mfree_off
			;decrease length
		sub dx,ms_start[si]
		mov ms_length[si],dx
mfree_r:	ret
			;take off p_mem list
mfree_off:  mov ax,ms_link[si] ! mov ms_link[bx],ax
			;free MD
	    push ms_mau[si] ! push bp
	    mov bx,si ! call freemd
	    pop bp ! pop dx
			;free MAU if empty
	    cmp bp,0 ! je mfree_exit
				;find it on MAL
		mov di,(offset mal)-m_link
mfree_nmal:	mov si,di ! mov di,m_link[si]
		cmp di,0 ! je mfree_r
		    cmp di,dx ! jne mfree_nmal
				;release from MAL
			mov ax,m_link[di] ! mov m_link[si],ax
			mov m_link[di],0
				;release to MFL
			mov bx,offset mfl ! mov cx,f_mlfree
			jmp mpmif
