;*****************************************************
;*
;*	Process Routines
;*
;*****************************************************

;======		=========================
freepd:		; Free Process Descriptor
;======		=========================
;	entry:	SI = PD address

; Assumes no memory and on no list except thread.
; Called only from TERM_ACT in the dispatcher

	mov di,(offset thrdrt)-p_thread
freepd_npd:
	mov bx,p_thread[di]	;find pd on thread
	cmp bx,si ! je freepd_trd
	    mov di,bx ! jmps freepd_npd
freepd_trd:
	mov ax,p_thread[si] ! mov p_thread[di],ax
	mov ax,p_flag[si] ! and ax,pf_table
	cmp ax,0 ! jz freepd_exit
	    mov bx,pul ! mov p_link[si],bx
	    mov pul,si
freepd_exit:
	ret

;==========		================
proc_creat:		; Create Process
;==========		================
;		DX = pd address in u_wrkseg

	cmp dx,0 ! jne cp_doit
	    sub bx,bx ! ret
cp_doit:
	call getpdadr		;si->pdaddr in rtm
	jcxz cp_gpd
	    mov bx,0ffffh ! ret
cp_gpd:
	mov dx,p_link[si]
	push dx ! push si
		; init uda fields
cp_uda:
		;set Parent

	mov bx,rlr
	mov p_parent[si],bx
	mov p_conmode[si],0		;console mode - not inherited
					;unless RSX which aren't yet
					;implemented
	mov p_tkcnt[si],0		;temp keep count
	and p_flag[bx],not (pf_childabort + pf_resource)
	mov al,p_lst[si]
	cmp al,nlstdev ! jb cp_slst
	    mov al,0			;make sure its a legal list device
cp_slst:
if mpm
	add al,ncondev
endif
	mov p_lst[si],al		;list device is relative to 0 in
					;CCP/M

		;share memory

	cmp p_mem[bx],0 ! je cp_nm
	    cmp p_mem[si],0 ! jne cp_nm
		lea di,p_mem[bx]
cp_mnxt:	mov di,ms_link[di]
		cmp di,0 ! je cp_nm
		    push di
		    push ms_start[di] ! push si ! push bx
		    mov cx,f_share ! mov dx,sp
		    push ds ! mov ax,ss ! mov ds,ax
		    call osif ! pop ds
		    pop bx ! pop si ! pop ax ! pop di
		    jmps cp_mnxt
cp_nm:
		;set physical UDA segment

	mov ax,u_wrkseg
	mov dx,p_uda[si] ! add dx,ax
	mov p_uda[si],dx

		;inherit password

	push es ! push ds
	mov cx,es ! mov es,dx ! mov ds,cx
	mov si,offset u_df_password ! mov di,si
	mov cx,4 ! rep movsw

		;set initial segment values

	mov ds,dx ! xor dx,dx
	cmp ds:u_initcs,dx ! jne cp_uda1
	    mov ds:u_initcs,ax
cp_uda1:cmp ds:u_initds,dx ! jne cp_uda2	;DX=0
	    mov ds:u_initds,ax
cp_uda2:cmp ds:u_initss,dx ! jne cp_uda3	;DX=0
	    mov ds:u_initss,ax
cp_uda3:cmp ds:u_inites,dx ! jne cp_uda4	;DX=0
	    mov ds:u_inites,ax
cp_uda4:

		;Interrupt vector save areas:
		;Get parent's interrupt vectors 0,1,3,4,224,225
		;into child's UDA, if the
		;interrupt vector is not initialized in the
		;child's UDA.

	mov ds,dx			;DX,DS=0,ES=child's UDA
	mov si,dx			;divide error vector, #0
	mov di,offset u_ivectors
	call cp_icopy
	call cp_icopy			;single step, #1
	add si,4 ! add di,4		;skip NMI, #2
	call cp_icopy			;1-byte, #3
	call cp_icopy			;overflow, #4
	mov si,offset i_os_ip
	mov di,offset u_os_ip
	call cp_icopy			;O.S. entry, #224
	call cp_icopy			;debugger entry, #225

		; set user's stack

	push es ! pop ds
	mov ax,ds:u_initss
	mov ds:u_ss,ax
	mov ax,ds:u_stack_sp
	mov ds:u_sp,ax

		; set other uda values

	xor dx,dx
	mov ds:u_delim,'$'			;console mode init
	mov ds:u_error_mode,dl
	mov ds:u_pd_cnt,dl
	mov ds:u_mult_cnt,1
	mov ds:u_in_int,true
	;mov ds:u_insys,dl			;don't set insys
	mov bx,ds:u_initds
	mov ds:u_ds_sav,bx
	mov ds:u_dma_seg,bx
	mov ax,ds:u_inites
	mov ds:u_es_sav,ax
	mov ds:u_dparam,dx
	mov ds:u_flag_sav,dx
	mov ds:u_conccb,dx
	mov ds:u_lstccb,dx

		; setup user stack for iret

	mov ds,ds:u_ss
	mov di,u_sp			;sp->offset
	mov ax,u_initcs
	mov 2[di],ax			;  ->segment
	mov word ptr 4[di],0200h	;  ->flags, interrupts on
	pop ds ! pop es			; DS=SYSDAT, ES=UDA

		; put on thread list

	pop si ! pushf ! cli		; don't need SYNC here
	mov dx,thrdrt			; but this code cannot
	mov p_thread[si],dx		; be reentrant
	mov thrdrt,si

		; put on dispatcher ready list

	mov dx,drl ! mov p_link[si],dx
	mov drl,si ! popf

		; do the next process

	pop dx ! jmp proc_creat



cp_icopy:
;--------
;	Entry:	ES:DI = UDA ivector location to store
;		DS:SI = ivector to copy
;		DX = 0
;	Exit:
;		DI,SI = incremented by 4

	cmp es:word ptr 0[di],dx	;DX=0, DI=UDA ivector to copy
	jne cp_nocopy			;don't copy interrupt vector
	  cmp es:word ptr 2[di],dx	;if it is <> 0 in the UDA
	  jne cp_nocopy
	     mov cx,2			;move two words
	     rep movsw			;copy to UDA
	     ret
cp_nocopy:
	add si,4 ! add di,4
	ret


getpdadr:
;--------
;	entry:	DX = PD address in U_WRKSEG
;	exit:	CX = 0 successful 
;		SI = PD address in SYSDAT if success
;		CX = 
;	Make sure PD address is in SYSDAT.  If not, copy into
;	one in PD table.  Make address relative to SYSDAT

	push dx			;save PD in U_WRKSEG
	mov bx,pdlen
	call sysdat_chk
	jcxz gpd_bad
	  mov ax,u_wrkseg	;PD is within SYSDAT
	  mov bx,ds
	  sub ax,bx		;U_WRKSEG-SYSDAT
	  mov cl,4 ! shl ax,cl	;make into bytes
	  pop si		;SI relative to U_WRKSEG
	  add si,ax		;SI->PD relative to SYSDAT
	  jmps gpd_done

gpd_bad:
	pop si				;U_WRKSEG:SI->PD to copy
	pushf ! cli			;turn off interrupts while
	mov di,pul			;changing the PUL
	test di,di
	jnz gpd_have
	  mov cx,e_no_pd		;no free PDs left
	  popf ! ret
gpd_have:				;DI->PD in SYSDAT
	mov ax,p_link[di]
	mov pul,ax			;update PUL
	popf				;allow interrupts
	push di				;save address of PD in SYSDAT
	push es				;save UDA
	push ds				;SYSDAT
	mov ds,u_wrkseg			;DS=U_WRKSEG
	pop es				;ES=SYSDAT
	mov cx,pdlen/2
	rep movsw			;copy PD into SYSDAT PD
	push es ! pop ds		;DS=SYSDAT
	pop es				;ES=UDA
	pop si				;SI=PD in SYSDAT
	or p_flag[si],pf_table		;got it from PD table

gpd_done:
	  xor cx,cx
	  ret
