Digital Research
This commit is contained in:
2020-11-06 18:50:37 +01:00
parent 621ed8ccaf
commit 31738079c4
8481 changed files with 1888323 additions and 0 deletions

View File

@@ -0,0 +1,538 @@
;*************************************************************
;*
;* Terminate and Abort Specify Process Entry Points
;*
;*************************************************************
;============== ==============
sysreset_entry: ; System Reset
;============== ==============
xor dx,dx
mov cx,f_terminate
jmp osif
;=============== ===============================
terminate_entry: ; Terminate - DX=terminate code
;=============== ===============================
; This entry point is used for a process to terminate itself. The
; code from the label 'TERMINATE:' on, is also used by a process to be
; terminated when it comes back into context, as set up by
; abort specified process.
mov bx,rlr
call abt_chk
jcxz terminate
jmp term_err
terminate: ;process terminated by abort
mov bx,rlr ;spec resumes execution here
cli ;interrupts off during stack switch
mov ss,p_uda[bx] ;reset the stack to top of UDA
mov sp,ulen
sti
mov p_prior[bx],abt_prior ;finish termination quickly
;abort spec can't force us
;to reenter terminate when
;we have best priority
mov bx,offset thrd_spb ;get ownership of thread
call sync_entry ;list before searching
xor dx,dx
mov bx,(offset thrdrt)-p_thread
mov ax,rlr
nxtchld:
mov bx,p_thread[bx] ;set all child process's p_parent
test bx,bx ! jz nochld ;field to 0
cmp p_parent[bx],ax
jne nxtchld
mov p_parent[bx],dx ;found a child, 0 its parent field
jmps nxtchld
nochld:
mov bx,offset thrd_spb
call unsync_entry
;set parent's child abort flag
mov bx,rlr ;if terminating process's
test p_flag[bx],pf_ctlc ;CTL_C flag is on, ie, we are
jz term_r1 ;terminating from an abort spec
and p_flag[bx],not pf_ctlc ;or control C
mov bx,p_parent[bx]
test bx,bx ! jz term_r1
or p_flag[bx],pf_childabort
term_r1:
mov u_error_mode,0feh ;call BDOS termination
if netversion
mov cx, f_netterm
call osif
endif
mov cx,f_bdosterm
call osif
mov bx,offset q_spb
call sync_entry
call rlsmx ;release all MXqueues
mov bx,offset q_spb
call unsync_entry
mov bx,offset mem_spb ;get ownership of MEM
call sync_entry
mov mem_cnt,1 ;keep MEM from freeing
;the MEM_SPB
mov bx,offset thrd_spb ;get the MEM sync BEFORE
call sync_entry ;the THRD sync to avoid
;deadlock
mov cx,f_freeall ;free all memory except
call osif ;load stack and UDA
mov bx,rlr ;dispatcher does rest of
mov p_stat[bx],ps_term ;termination
jmp dsptch
term_err:
;--------
; entry: CX=1 then can't terminate because KEEP or SYS flag
; CX=0ffffh TEMPKEEP on, CTLC turned on
; called from TERMINATE_ENTRY and ABORT_SPEC_ENTRY
; after call to ABT_CHK:
dec cx ! jz term_err1
;TEMPKEEP and CTLC flag on
xor bx,bx ! mov cx,bx ;and process will terminate
ret ;itself, or needs CTLC information
term_err1:
mov cx,e_pd_noterm ;couldn't term because of
mov bx,0ffffh ! ret ;SYS or KEEP flags,
;CTLC is off
;================
abort_spec_entry: ;Abort the specified process
;================
; entry: DX = address of APB in the caller's U_WRKSEG
; exit: BX = 0 if success, 0FFFFH if failure
; CX = 0 " " , error code if failure
; Set up the specified PD for termination when it is next in context.
; If the running PD is the same as the PD to abort, we can just use
; the terminate entry point. Otherwise we use the Abort Parameter Block
; to find it. If it cannot be found, name and console must both match,
; the abort fails. If the TEMPKEEP flag is on, set the CTLC flag
; and return. If the KEEP flag is on and not the TEMPKEEP flag,
; then fail.
; If the terminate code in DL on entry, is not 0ffh
; and the SYS flag is on in the PD to be aborted, then fail.
; The PD is taken off the list it is attached to via its link field.
; The terminating PD's priority is set to ABT_PRIOR,
; and the address of TERMINATE: is put on top of its UDA stack.
; This forces the terminating process to run next (it has the
; best priority in the system) and for it to resume execution
; at TERMINATE: on returning from the dispatcher.
push dx
mov bx,offset thrd_spb ; get ownership of thread
call sync_entry ; while searching
pop si ; U_WRKSEG:SI->APB
push ds ! mov ds,u_wrkseg
mov bx,apb_pd[si] ; get PD adr to abort
mov cx,apb_term[si] ; get termination/memfree code
mov ah,apb_cns[si] ; console from APB
pop ds
push cx ; save termination code
test bx,bx ! jz abt_findit ; got a PD ID, but not verified
call find_pdthrd ; find it on thread
push cx ; save return code
jmps abt_unsync
abt_findit:
add dx,offset apb_pdname ; get adr of named PD
mov bx,offset thrdrt - p_thread ; find it on thread
call findpdnc ; look for PD name and console match
push cx ; save return code
abt_unsync:
push bx ; BX=PD if found
mov bx,offset thrd_spb
call unsync_entry
pop bx
pop cx ; CX=0 if no PD found
jcxz abt_err1
; successfully found PD
pop dx ; DX = terminate code
mov ax,rlr ; we are aborting ourselves
cmp ax,bx ; jump to TERMINATE_ENTRY
jne abt_notus
;if netversion
; jmp sysreset_entry
;endif
;if not netversion
jmp terminate_entry
;endif
abt_notus:
mov indisp,true ; stop dispatching
;pushf ! cli ; do not let process or another
; process (NO_ABORT_SPEC) change the
or p_flag[bx],pf_ctlc ; flags while testing and acting on them.
call abt_chk ; ok to abort this PD ?
jcxz abt_ok
;popf ; can't abort it - return
call ok_disp
jmps term_err
; The interrupt window above may be lessened if the TERMINATE_ENTRY
; code is moved to the dispatcher and the status is set to PS_TERM.
; Turning interrupts back on, the aborting process could come
; back into context. Before turning on TEMPKEEP it would check
; its status, if it is PS_TERM, then it goes to the dispatcher
; to terminate.
abt_ok: ; this process will be aborted
mov dl,p_stat[bx] ; call abort function based on status
mov dh,0 ! mov di,dx
add di,di
call cs:abort_tab[di] ; find via p_link and take PD off its list
;popf
call ok_disp ; process can't come back into context
; so interrupts are ok
jcxz abt_err2 ; couldn't find PD on list by indicated
mov indisp,false ; by P_STAT
mov p_prior[bx],abt_prior
; set to low priority
push es ; save calling process' UDA
mov es,p_uda[bx] ; UDA of PD being aborted
mov si,(ulen-2) ; reset stack to top of UDA
mov u_sp,si
mov u_ss,es
;if netversion
; mov es:[si],offset sysreset_entry
;endif
;if not netversion
mov es:[si],offset terminate
;endif
; TERMINATE: will be executed when
; terminating process comes back into
; context
xor ax,ax ; on exit from dispatcher interrupts
mov u_flag_sav,ax ; will be off
mov u_inint,false ; return into context with a RET and
; not an IRET
if netversion
inc es:byte ptr u_insys
endif
pop es ; ES=calling PD's UDA
call abt_putdrl
xor bx,bx ; indicate sucess
jmp pdisp ; force abort to happen before we return
; since terminating process has better
; priority
abt_err1:
pop dx ; throw out termination code
abt_err2:
mov cx,e_no_pdname ; set TERM_ERR for other returns
mov bx,0ffffh
ret
; The folowing are the abort handlers for a specific PD status.
; These labels are entered in the abort_tab(le) in the RTM data area.
; Interrupts assumed off.
; For all of the following:
; entry: BX = PD addr to be aborted
; AH = cons
; exit: CX=0 if error
; BX preserved
;
; abort_specified process jump table
;
; Status
abort_tab dw abtrun ; 0 = ready list root
dw abtslp ; 1 = poll
dw abtdly ; 2 = delay
dw abtslp ; 3 = swap
dw abttrm ; 4 = term
dw abtrun ; 5 = sleep
dw abtslp ; 6 = dq
dw abtslp ; 7 = nq
dw abtflg ; 8 = flagwait
dw abtslp ; 9 = ciowait
dw abtslp ; 10 = sync
abt_tablen equ offset $ - offset abort_tab
abtrun:
;-------
; On ready list root or dispatcher ready list
mov di,(offset rlr) - p_link
call find_pd
jcxz abtr_drl
jmps snip_it
abtr_drl: ; wasn't on rlr, try drl
mov di,(offset drl) - plink
jmps abt_common
abtslp:
;------
; On list indicated by u_dparam
; Note: a PD in the SY_NEXT field will not be found
; and cannot be terminated. Usually the PD has TEMPKEEP on
; so it never gets this far.
push es ! mov es,p_uda[bx]
mov di,u_dparam
pop es ! jmps abt_common
abtdly:
;------
mov di,offset dlr - p_link
call find_pd
jcxz abt_tab_err
mov si,p_link[si] ; Fix wait field in next PD on dlr
test si,si
jz ad_nofix ; Are there more PDs after the one
mov dx,p_wait[si] ; being aborted on the DLR ?
add dx,p_wait[bx] ; Add wait of aborting PD
mov p_wait[si],dx ; New value in next PD on dlr
ad_nofix:
jmps snip_it
abttrm:
;------
mov indisp,false
call pdisp ; we are terminating already
xor cx,cx ; make sure termination completes
jmps abt_tab_err ; before returning error
abtflg:
;------
xor cx,cx
push es ! mov es, p_uda[bx]
mov di,u_dparam ; flag PD field asleep on
pop es
cmp bx,[di] ; if interrupts are allowed
jne aflg_err ; in this code, check DRL
inc flg_ignore[di] ; and RLR if not in flags
mov flg_pd[di],flag_off
inc cx
aflg_err:
ret
abt_common:
;----------
call find_pd ! jcxz abt_tab_err
;jmps snip_it
snip_it:
;-------
; Take PD out of linked list of PDs
; entry: BX = PD being snipped out
; DI = offset of previous PD or offset of root - p_link.
mov dx,p_link[bx] ; DX = next link
mov p_link[di],dx
ret ; CX<>0
abt_tab_err:
;-----------
ret ; CX = 0
;
; End of abort_tab(le) functions
;
abt_putdrl:
;-------
; Puts PD on DRL
; entry: BX = PD to insert
; exit: BX preserved
pushf ! cli
mov dx,drl
mov p_link[bx],dx
mov drl,bx
popf ! ret
; Utility routines for abort entry point
findpdnc:
;--------
; Find PD by name and console, via thread list.
; entry: BX = offset of thread list root - p_thread
; DX = adr of name in u_wrkseg
; AH = console number
; ownership of thread sync
; exit: BX = PD
; CX = 0 failure
xor cx,cx
nxt_pdname:
push ax ; save console number
call findpdname_entry
pop ax
jcxz fnc_found_one ; CX = 0 is success from findpdname
xor cx,cx
ret ; CX = 0 is failure from this routine
fnc_found_one: ; found PD w/ same name
cmp p_cns[bx],ah ; chk for same console #
jnz nxt_pdname
inc cx ! ret ; success
find_pdthrd:
;-----------
; Find PD on thread list
; entry: BX = PD address we want
; ownership of thread sync
; exit: CX = 0 if not found
; BX prserved
xor cx,cx
mov di,offset thrdrt - p_thread
fp_next:
mov di,p_thread[di]
test di,di
jz fp_err
cmp bx,di
jne fp_next
inc cx
fp_err:
ret
find_pd:
;-------
; Find PD through link field, interrupts assumed off
; entry: BX = PD address
; DI = offset of list root - p_link
; exit: BX = SI = PD address
; DI = Previous PD
; CX = 0 if failure
mov si,p_link[di]
xor cx,cx
fpd_nxt_pd:
test si,si ; SI could be zero to start
jz fpd_not_found
cmp si,bx ; Are addresses the same ?
jz fpd_found
fpd_nxt_lnk:
mov di,si ; Save previous link
mov si,p_link[si]
jmps fpd_nxt_pd
fpd_found:
inc cx
fpd_not_found:
ret
fflgpd:
;-----
; Find offset into flag table of flag waiting PD
; entry: BX = PD
; exit: DI = offset in RTM data of flag
; CX = 0 if failure
; BX preserved
mov cl,nflags
xor ch,ch
mov di,flags
ffp_nxt_flg:
cmp bx,flg_pd[di] ; assume legal flag
jz ffp_pdfound
add di,flglen
loop ffp_nxt_flg
ffp_pdfound:
ret ; CX is 0 at end of loop instr
; CX <> 0 if found
ok_disp:
;-------
mov indisp,false
cmp drl,0
jz od_ret
call pdisp
od_ret:
ret
abt_chk:
;-------
; Check different PD flags for terminate or abort
; CTLC flag is on if called from ABORT_SPEC
; entry: BX = PD to possibly abort
; DL = termination code
; interrupts off if called from ABORT_SPEC
; exit: CX = 00000H if ok to abort
; 00001H IF NOT OK TO ABORT
; 0FFFFH IF TEMPKEEP
; BX = PD as on entry
; interrupts unchanged
xor cx,cx
mov ax,p_flag[bx] ;AX = PD flags
;test TEMPKEEP first
;for signaling KEEP process
;to terminate i.e., the TMP
;while in the CLI
test ax,pf_tempkeep ! jz ac_keep
or ax,pf_ctlc ;signal control C
dec cx ;temp keep return
jmps ac_ret
ac_keep:
test ax,pf_keep ! jnz ac_no
;not KEEP, test SYS
inc dl ! jz ac_ok ;if DL = 0ffh -> ok to terminate
test ax,pf_sys ! jz ac_ok ;DL<>0ffh & not sys-> ok to terminate
ac_no:
and ax,not pf_ctlc ;turn off ctlc
inc cx ;CX=1, can't terminate
ac_ret:
mov p_flag[bx],ax ;new flags if no termination
ac_ok:
ret
rlsmx:
;-----
; Release all MX queues owned by the terminating process
; called only from TERMINATE_ENTRY
; entry: we own the Queue SYNC
; exit: none
; To guard against queue deletes, and to make interrupt
; windows are smaller, we start over from the beginning of
; QLR after we write to an MXqueue that we own.
mov bx,rlr ;BX=running process
; pushf ! cli
mov si,(offset qlr)-q_link
rm_nxt:
mov si,q_link[si] ;SI=QD currently checking
test si,si ;end of list ?
jz rm_done
test q_flags[si],qf_mx ;is it an MX queue ?
jz rm_nxt
cmp bx,q_buf[si] ;do we own it ?
jne rm_nxt
; popf ;allow interrupts
push si ;put 2-word QPB on stack
xor ax,ax
push ax
mov dx,sp
mov cx,f_qwrite
push ds ;save DS
push ss ! pop ds ;DS=SS
call osif
pop ds ;restore DS
pop ax ! pop ax ;throw out 2-word QPB
jmps rlsmx ;start over from
;top of queue list
;a queue could have been
;deleted while we were writing
rm_done:
; popf
ret


View File

@@ -0,0 +1,49 @@
;*****************************************************
;*
;* Base Page Format
;*
;*****************************************************
DSEG
org 0
bpg_clen rb 3
bpg_cseg rw 1
bpg_8080 rb 1
bpg_dlen rb 3
bpg_dseg rw 1
bpg_dxxx rb 1
bpg_elen rb 3
bpg_eseg rw 1
bpg_exxx rb 1
bpg_slen rb 3
bpg_sseg rw 1
bpg_sxxx rb 1
org 050h
bpg_lddsk rb 1
bpg_pw1ptr rw 1
bpg_pw1len rb 1
bpg_pw2ptr rw 1
bpg_pw2len rb 1
org 05ch
bpg_fcb0 rb 0
org 06ch
bpg_fcb1 rb 0
org 80h
bpg_dma rb 0
org 100h
bpg_udata rb 0


View File

@@ -0,0 +1,40 @@
include cpyright.def
;*****************************************************
;*
;* BDOS - Basic Disk Operating System
;*
;*****************************************************
;
; generation of BDOS.CON file
;
; RASM86 bdos
; LINK86 bdos.con = bdos [data[origin[0]]]
;
;*****************************************************
eject ! include equ.bdo ; symbol definitions
eject ! include system.dat
eject ! include pd.def
eject ! include qd.def
eject ! include modfunc.def
eject ! include xioscb.def
eject
PCMODE equ false
include bdosif.bdo ; system initialization
eject ! include file1.bdo ; file system part 1
eject ! include file2.bdo ; file system part 2
eject ! include file3.bdo ; file system part 3
eject ! include file4.bdo ; file system part 4
eject ! include file5.bdo ; file system part 5
eject ! include const.bdo
eject ! include patch.cod
eject ! include uda.cic ; User Data area
eject ! include sysdat.bdo
eject ! include data.bdo
end

View File

@@ -0,0 +1,29 @@
include cpyright.def
;*****************************************************
;*
;* MP/M-86 and Concurrent CP/M-86
;* Character I/O Module
;*
;*****************************************************
eject ! include system.def
eject ! include modfunc.def
eject ! include xioscb.def
eject ! include pd.def
eject ! include err.def
eject ! include qd.def
eject ! include acb.def
eject ! include vccb.def
eject ! include char.def
eject ! include cmode.def
eject ! include cb.def
eject ! include uda.def
eject ! include cioif.cio
eject ! include console.cio
eject ! include chario.cio
eject ! include patch.cod
eject ! include uda.fmt
eject ! include sysdat.dat
eject ! include data.bdo
eject ! end


View File

@@ -0,0 +1,736 @@
;*****************************************************
;*
;* Command Line Interpreter, Program Chain
;*
;*****************************************************
;=========
chain_ent:
;=========
xor dx,dx
;=======
cli_ent:
;=======
; Create a process based on an Ascii Command Line.
; The command Line is first parsed and an FCB is
; initialized as a result.
; An attempt is made to open a queue with the filename
; of the FCB, and with the RSP flag on.
; The command tail is written to the queue if it is found.
; If the queue cannot be opened or is not and RSP type then
; we try and load the command from disk.
; If the write queue fails we return e_q_full error code and
; do not look on the disk.
; After the queue write, an console assign call attempted to
; a process with the same name and the PF_DSKLD flag off.
; Irregardless of the success of the assign we then return.
;
; If the RSP queue cannot be opened, or is not an RSP type queue then
; we make the name type in the
; FCB to be 'CMD' and attempt to open the file. If this fails,
; so do we.
; We then obtain a Process Descriptor from the
; PD table. Again we fail if it does.
; On a successful open, we call the BDOS load function.
; If the load fails, so do we. The PD is
; initialized, the default console is assigned to the
; PD, the PF_DSKLD flag turned on,
; and a create process call is made.
;
; input: DX -> command buffer in u_wrkseg
; It is assumed that the calling process
; is attached to its default console
; and is willing to lose it since it
; will be handed to the newly created
; process.
; if DX = 0, assume chain w/command in DMA
;
; output: BX = 0 if successful
; = 0ffffh if failure has occured
; CX = error code
mov bx,rlr ! mov ax,p_flag[bx]
push ax ;save flags on stack
if netversion
or ax,pf_noctls
endif
if not netversion
or ax,pf_tempkeep + pf_noctls
endif
mov p_flag[bx],ax
if netversion
mov cx,f_no_abort
call osif
endif
push dx ;save parameter
call cli_sync ;rentrancy stops with sync call
pop dx ;we can save the flags
pop cli_pflag ;and other variables in the CLI
;data area
; we have CLI SYNC
; Check for Chain
mov cli_chain,false
cmp dx,0 ! jne cli_cli
mov cli_chain,true
mov cli_term,false
cli_cli:
; initialize defaults from parent PD
mov cli_dfil,false
cmp dayfile,0ffh ! jne nodf
push dx ! mov cx,f_cconattch
call osif ! pop dx
cmp cx,0 ! jne nodf
mov cli_dfil,true
push dx
call prtime
pop dx
nodf: mov bx,rlr
mov cli_ppd,bx
mov cl,p_dsk[bx]
mov cli_dsk,cl
mov cl,p_user[bx]
mov cli_user,cl
mov cl,p_cns[bx]
mov cli_cns,cl
mov cl,u_error_mode
mov cli_err_mode,cl
mov cx,u_dma_ofst
mov cli_dma_ofst,cx
mov cx,u_dma_seg
mov cli_dma_seg,cx
mov clierr,0
; copy command into local area
cmp cli_chain,true ! jne cli_cpy
push es ! push ds
mov es,sysdat
mov si,cli_dma_ofst
mov di,offset cli_cmdtail
mov ds,cli_dma_seg
mov cx,040H
rep movsw
pop ds ! pop es
jmp cli_parse
cli_cpy:
push es ! push ds
mov ds,u_wrkseg ! pop es
; DS=Wrkseg, ES=Sysdat, SP->UDA
; copy clicb_net
mov si,dx ! mov di,offset cli_net
movsb
; copy command
mov si,dx ! add si,clicb_cmd
mov di,offset cli_cmdtail
mov cx,clicblen-clicb_cmd
rep movsb
push es ! pop ds ! pop es
;parse the command
cli_parse:
call pfn ! jcxz cli_gprs
mov clierr,cx
jmp cli_exit
cli_gprs:
call shtal
;fcb has parsed filename
;if not explicit disk then
; if not RSP try CMD
;else try CMD
cmp cli_fcb,0 ! jne cli_ffload
mov bx,(offset cli_fcb)
cmp fcb_plen[bx],0 ! jne cli_ffload
call cli_checkque ! jnz cli_ffload
;successful RSP access
cli_qful:
cmp cli_chain,true ! jne cli_exit2
mov cli_term,true
cli_exit2: jmp cli_exit
cli_ffload:
cmp cx,e_q_full ! jne cli_fload
mov clierr,cx ! jmps cli_qful
cli_checkque:
;------------
; output: z flag on if successful
;copy fcb.name to qpb.name
mov si,(offset cli_fcb)+fcb_name
mov di,(offset cli_cuspqpb)+qpb_name
mov cx,qnamsiz/2 ! push es ! push ds ! pop es
push si ! rep movsw
;copy fcb.name to acb.name
pop si ! mov cx,qnamsiz/2
mov di,(offset cli_acb)+acb_name
rep movsw ! pop es
;open queue
mov cx,f_qopen ! mov dx,(offset cli_cuspqpb)
call osif ! jcxz cli_goodq
retcli1: cmp cx,0 ! ret ;CX = 0ffffh on error
;we successfully opened the queue
;now check RSP flag
cli_goodq:
mov bx,offset cli_cuspqpb
mov bx,qpb_qaddr[bx]
test q_flags[bx],qf_rsp ! jnz cli_gq
mov cx,e_no_queue ! jmps retcli1
;write command tail to queue
cli_gq: mov cx,f_cqwrite ! mov dx,offset cli_cuspqpb
call osif ! jcxz cli_qw
mov cx,e_q_full ! jmps retcli1
;successful queue write, assign console
cli_qw: cmp cli_dfil,true ! jne noqm
call prcusp
noqm: mov bx,offset cli_acb
mov al,cli_cns ! mov acb_cns[bx],al
mov acb_match[bx],false
mov acb_pd[bx],1 ;match on PD with DSKLD flag off
call conasn ! xor cx,cx ! ret
cli_fload:
;---------
; Try to Load a file for execution
; The Command Line Parsed correctly and we have an FCB
; set up. We already know there isn't a queue and a
; process by the same name as the command.
; Obtain a Process Descriptor
pushf ! cli ! mov bx,pul
cmp bx,0 ! jne cli_gpd
popf ! mov clierr,e_no_pd
jmp cli_exit
cli_gpd:
mov si,p_link[bx] ! mov pul,si
popf ! mov cli_pd,bx
; zero PD
push es ! push ds ! pop es
mov di,bx ! mov cx,pdlen/2
xor ax,ax ! rep stosw
pop es
; Initialize the PD for Load
mov bx,cli_pd
mov p_flag[bx],pf_table
mov di,bx ! add di,p_name
mov si,offset cli_fcb ! add si,fcb_name
push es ! mov ax,ds ! mov es,ax
mov cx,pnamsiz/2 ! rep movsw
pop es
mov si,rlr
mov al,cli_dsk ! mov p_dsk[bx],al ;inherit parents drive/user
mov al,cli_user ! mov p_user[bx],al ;even if we load off another
;drive or user
;this should be in
;process create ?
mov al,cli_cns ! mov p_cns[bx],al
mov al,p_lst[si]
;if mpm
; sub al,ncondev
;endif
mov p_lst[bx],al
; 3. Open the file
mov si,(offset cli_fcb)+fcb_pwd
mov di,offset cli_dma
push es ! mov es,sysdat
mov cx,4 ! rep movsw
pop es
mov u_dma_ofst,offset cli_dma
mov u_dma_seg,ds
mov si,offset cli_fcb
mov byte ptr fcb_type[si],'C'
mov byte ptr fcb_type+1[si],'M'
mov byte ptr fcb_type+2[si],'D'
; Open the CMD file
mov u_error_mode,0feh
call flopn
cmp bl,0ffh ! jne cli_gopen
; on failure,
; if default is not system disk
; and not an explicit disk then
; try CMD file on System disk
cmp bh,0 ! jne cli_bo ;extended error
mov cl,srchdisk
cmp cl,cli_dsk ! je cli_bo ;already on system disk
cmp cli_fcb,0 ! jne cli_bo ;check for explicit
;select
; try system disk
; mov bx,rlr
; mov p_dsk[bx],cl
inc cl
mov cli_fcb,cl ;set drive byte to
call flopn ;system disk
cmp bl,0ffh ! je cli_bo
;make sure SYS attribute is on...
mov bx,offset cli_fcb
test byte ptr fcb_type+1[bx],080h ! jnz cli_gopen
;We opened a NON-SYS file. Do explicit open
;on user zero if not already
call flclse
mov bx,rlr
cmp p_user[bx],0 ! je cli_boe
mov p_user[bx],0
call flopn
cmp bl,0ffh ! je cli_bo
mov bx,offset cli_fcb
test byte ptr fcb_type+1[bx],080h
jnz cli_gopen
call flclse
jmps cli_boe
;could not find CMD file
cli_bo: cmp bh,0 ! jne cli_rmpd2
cli_boe: mov clierr,e_bad_open
cli_rmpd2: jmp cli_rmpd
cli_gopen:
; 8. Call the load function
mov bx,rlr
test p_flag[bx],pf_ctlc ! jz cli_ld1
mov bx,0ffffh ! mov cx,e_abort
jmp cli_cl
cli_ld1:
cmp cmod,true ! jne not_cmod
mov bx,cli_pd
mov si,offset cli_fcb
;test F1 bit
mov p_cmod[bx],0
test byte ptr fcb_name[si],080h ! jz not_f1
or p_cmod[bx],080h
;test F2 bit
not_f1: test byte ptr fcb_name+1[si],080h ! jz not_f2
or p_cmod[bx],040h
;test F3 bit
not_f2:
;if mpm dave brown test
test byte ptr fcb_name+2[si],080h
jz not_f3
;endif
or p_cmod[bx],020h
;test F4 bit
not_f3: test byte ptr fcb_name+3[si],80h ! jz not_cmod
or p_cmod[bx],070h
not_cmod:
cmp cli_chain,true ! jne cli_kuda
mov bx,cli_pd
mov p_uda[bx],es
mov ax,offset inituda
mov cl,4 ! shr ax,cl
add ax,sysdat
mov bx,es ! mov es,ax ! mov di,0
mov ds,bx ! mov si,di
mov cx,ulen/2
rep movsw
pushf ! cli ! pop dx
mov ax,es
mov ds,sysdat
mov ss,ax
mov bx,rlr
mov p_uda[bx],ax
push dx ! popf
cli_kuda:
cmp cli_dfil,true ! jne noprfil
call prfilnam
call crlf
noprfil:mov bx,cli_pd
mov dx,offset cli_fcb
mov cx,f_load
cmp cli_chain,true ! jne cli_ld
mov cli_term,true
mov cx,f_cload
call osif
jcxz cli_cl
mov cli_term,false
jmp cli_cl
cli_ld: call osif
cli_cl: push bx ! push cx
mov u_error_mode,0
call flclse
pop cx ! pop bx
jcxz cli_gload
cmp cx,e_abort ! jne cli_lnab
jmp cli_rmpd
cli_lnab: mov clierr,cx
jmp cli_rmpd
cli_gload:
mov cli_bpage,bx
; 9a. Parse Command Tail
; copy cmdtail to user DMA buffer
push es ! mov es,cli_bpage
mov di,offset bpg_dma+1
mov si,offset cli_cmdtail
mov cx,127
rep movsb ! pop es
; count cmd length and convert
; to upper case
push ds ! mov ds,cli_bpage
mov cl,0 ! mov di,offset bpg_dma+1
ncmdchar:
cmp byte ptr [di],0 ! je endtail
; convert CMD tail to UPPER CASE
cmp byte ptr [di],'a' ! jb nlow
cmp byte ptr [di],'z' ! ja nlow
and byte ptr [di],05fh
nlow:
inc di ! inc cl ! jmps ncmdchar
endtail:
mov bpg_dma,cl ! pop ds
; load disk init, location 50H
; of base page is done in LOAD
push es ! mov es,cli_bpage
; init default fcb
mov di,offset bpg_fcb0
xor ax,ax ! stosb ;default disk
mov al,' '
mov cx,11 ! rep stosb ;name,type
xor ax,ax
mov cx,2 ! rep stosw ;other
push ds ! push es ! pop ds
mov si,offset bpg_fcb0
mov cx,8 ! rep movsw
pop ds ! pop es
; if cmdtail, parse
cmp cli_cmdtail,0 ! je ctdone
call pfn
cmp bx,0ffffh ! je ctdone
; copy fcb to user fcb front
push es ! mov es,cli_bpage
mov di,offset bpg_fcb0
mov si,offset cli_fcb
mov ax,fcb_pptr[si]
; AX->password in CLI_CMDTAIL
sub ax,offset cli_cmdtail
add ax,offset bpg_dma + 1
; AX->password in Base Page
mov es:bpg_pw1ptr,ax
mov al,fcb_plen[si]
mov es:bpg_pw1len,al
mov cx,8 ! rep movsw ! pop es
; if more cmdtail, parse
cmp bx,0 ! je ctdone
push cli_pcb ! inc bx
mov cli_pcb,bx
call pfn
pop cli_pcb
cmp bx,0ffffh ! je ctdone
; copy 2nd fcb front
push es ! mov es,cli_bpage
mov di,offset bpg_fcb1
mov si,offset cli_fcb
mov ax,fcb_pptr[si]
; AX->password in CLI_CMDTAIL
sub ax,offset cli_cmdtail
add ax,offset bpg_dma + 1
; AX->password in Base Page
mov es:bpg_pw2ptr,ax
mov al,fcb_plen[si]
mov es:bpg_pw2len,al
mov cx,8
rep movsw
pop es
ctdone:
; 10. Create the process
cmp cli_chain,true ! jne nprior
mov cx,f_setprior
mov dx,1 ! call osif
nprior:
mov si,cli_pd ! or p_flag[si],pf_dskld ;from disk, to differ
mov dx,si ! mov cx,f_createproc ;from RSP with same name
call osif
; 11. Assign Console to new process
mov bx,rlr
and p_flag[bx],not pf_ctlc
; Check to see if user hit CTRL D
test p_flag[bx],pf_ctld ! jz asgn
and p_flag[bx],not pf_ctld
mov bx,cli_pd
or p_flag[bx],pf_ctld
jmp cli_exit
asgn: mov bx,offset cli_acb
mov al,cli_cns ! mov acb_cns[bx],al
mov ax,cli_pd ! mov acb_pd[bx],ax
mov acb_match[bx],true
call conasn
mov clierr,cx
jmps cli_exit
; 12. All Done
cli_rmpd: ; release PD
mov si,cli_pd
; Release any memory that might still be
; associated with the PD. This could
; happen from a CTRL C.
cmp p_mem[si],0 ! je rmpd1
push ds ! push es
push si
mov si,p_mem[si]
push ms_start[si]
mov cx,f_memfree
mov dx,sp
mov ax,ss ! mov ds,ax
call osif
pop ax ! pop si
pop es ! pop ds
jmps cli_rmpd
; Place empty PD on PUL.
rmpd1: pushf ! cli
mov bx,pul
mov p_link[si],bx ! mov pul,si
popf
; Normal EXIT
cli_exit: ; close file and release CLI SYNC
mov bx,rlr
mov cl,cli_dsk ! mov p_dsk[bx],cl
mov cl,cli_user ! mov p_user[bx],cl
mov cl,cli_err_mode ! mov u_error_mode,cl
mov cx,cli_dma_ofst ! mov u_dma_ofst,cx
mov cx,cli_dma_seg ! mov u_dma_seg,cx
cmp cli_chain,true ! jne clirls
mov bx,rlr ! mov si,cli_pd ;inherit calling PD's
mov ax,p_parent[bx] ;parent if chaining
mov p_parent[si],ax
cmp cli_term,true ! jne clirls
and p_flag[bx],not (pf_keep+pf_sys+pf_tempkeep+pf_ctlc)
if netversion
mov p_tkcnt[bx],0
endif
mov cx,f_terminate ;TERM_ACT in dispatcher
jmp osif ;releases CLI_SYNC
clirls:
push cli_pflag
push cli_err
call cli_unsync
if netversion
mov cx,f_ok_abort
call osif
endif
pop dx
if netversion
pop ax ! and ax,pf_noctls
endif
if not netversion
pop ax ! and ax,pf_tempkeep+pf_noctls
endif
mov bx,rlr ! mov cx,p_flag[bx]
if netversion
and cx,not pf_noctls
endif
if not netversion
and cx,not pf_tempkeep+pf_noctls
endif
or cx,ax ! mov p_flag[bx],cx
test p_flag[bx],pf_ctlc ! jz cli_nctl
mov cx,f_terminate ! xor dx,dx
call osif
and p_flag[bx],not pf_ctlc
mov dx,e_abort
; setup error return if needed
cli_nctl:
mov cx,dx
xor bx,bx
jcxz cli_gexit
mov bx,0ffffh
cli_gexit:
ret
shtal:
;---------
; setup command tail to be parsed
; input: AX = output of previous parsefilename
cmp ax,0 ! je ntail
;shift command tail to beginning
;of command buffer
push ax ! sub ax,offset cli_cmdtail
mov cx,128 ! sub cx,ax ! shr cx,1
pop si ! mov di,offset cli_cmdtail
push es ! push ds ! pop es
rep movsw ! pop es
ret
ntail:
mov cli_cmdtail,0
ret
;============================
; Various string subroutines
crlf: mov dl,13 ! call prchar
mov dl,10
;jmps prchar
prchar:
mov si,u_conccb
mov di,rlr
cmp [si],di ! jne prr
mov cx,f_conout ! jmp osif
prr: ret
prtime: mov dl,tod_hr ! call prnum
mov dl,':' ! call prchar
mov dl,tod_min ! call prnum
mov dl,':' ! call prchar
mov dl,tod_sec ! call prnum
mov dl,' ' ! jmps prchar
prnum: push dx ! mov cl,4
shr dl,cl ! add dl,'0'
call prchar
pop dx ! and dl,0fh
add dl,'0' ! jmps prchar
prfilnam:
call prdisk
mov dx,(offset cli_fcb)+fcb_name
call prnam
mov dl,'.' ! call prchar
mov dx,(offset cli_fcb) + fcb_type
call prtyp
mov dl,' ' ! call prchar
mov bx,offset cli_fcb
test byte ptr fcb_name+7[bx],080h ! jnz pruser
cmp cli_user,0 ! je pret
mov bx,rlr
cmp p_user[bx],0 ! je pruser
pret: ret
pruser: mov dx,offset userstr
jmps prcsm
prdisk: mov dl,cli_fcb
cmp dl,0 ! je prpddsk
dec dl ! jmps prdsk1
prpddsk:
mov bx,rlr
mov dl,p_dsk[bx]
prdsk1: add dl,'A' ! call prchar
mov dl,':' ! jmp prchar
prcusp: mov dx,(offset cli_cuspqpb) + qpb_name
call prnam ! mov dx,offset questr
call prcsm ! jmp crlf
prcsm: mov si,u_conccb
mov di,rlr
cmp [si],di ! jne prr1
xor bx,bx ! push ds
mov ax,cs ! mov ds,ax
call cprnt1 ! pop ds
prr1: ret
prtyp: mov bh,3 ! jmps prn1
prnam: mov bh,8
prn1: mov bl,' '
mov si,u_conccb
mov di,rlr
cmp [si],di ! jne prr1
cprnt1: mov cx,f_conprint ! jmps jos
flclse:
mov cx,f_fclose ! mov dx,offset cli_fcb
jmps fo1
flopn:
mov cx,f_fopen
mov si,offset cli_fcb
or byte ptr fcb_name+5[si],080h ;f6`=open read-only
mov dx,si
fo1: push es ! call osif ! pop es ! ret
cli_sync:mov cx,f_sync
jmps mx1
cli_unsync: mov cx,f_unsync
mx1: mov bx,offset cli_spb
jos: jmp osif
pfn: mov dx,offset cli_pcb ! mov cx,f_parsefilename
jmps jos
conasn: mov cx,f_conassign ! mov dx,offset cli_acb
jmps jos
questr db ' Msg Qued',0
userstr db '(User 0)',0


View File

@@ -0,0 +1,246 @@
;*****************************************************
;*
;* MEM Entry Points
;*
;*****************************************************
; Format of Memory Control Block used
; in CP/M-86 Memory Calls (53 - 58)
;
; +-----------+-----------+-----+
; MCB | Base | Length | ext |
; +-----------+-----------+-----+
;
mcb_base equ word ptr 0
mcb_length equ word ptr mcb_base + word
mcb_ext equ byte ptr mcb_length + word
mcblen equ mcb_ext + byte
;============ =====================
maxmem_entry: ; 53 - Get Max Memory
;============ =====================
; input: DX = address of MCB in u_wrkseg
; output: BX = 0ffffh if failure
; 0h if success
; CX = Error Code
; mcb_ext = 0 if no additional mem
; 1 if more available
mov si,dx
push ds ! mov ds,u_wrkseg
mov dx,mcb_length[si] ! pop ds
sub ax,ax ! mov bx,ax
call getmemory ! jcxz mm_gm
mov bx,0ffffh ! ret
mm_gm: push ds ! mov ds,u_wrkseg
mov mcb_length[si],dx
mov mcb_base[si],ax
mov mcb_ext[si],1
pop ds ! sub bx,bx ! ret
;============
absmax_entry: ; 54 - Get Abs Max Mem
;============
; Allocate the largest absolute memory region which
; is less than or equal mcb_length
; input: DX = address of MCB in u_wrkseg
; output: BX = 0ffffh if failure
; 0h if success
; CX = Error Code
mov si,dx
push ds ! mov ds,u_wrkseg
mov ax,mcb_base[si]
mov dx,mcb_length[si] ! pop ds
sub bx,bx
call getmemory ! jcxz am_gm
mov bx,0ffffh ! ret
am_gm: push ds ! mov ds,u_wrkseg
mov mcb_length[si],dx
mov mcb_base[si],ax
pop ds ! sub bx,bx ! ret
;==============
cpmalloc_entry: ; 55 - Alloc Mem
;==============
; Allocate a memory region which is equal to mcb_length
;
; input: DX = address of MCB in u_wrkseg
; output: BX = 0ffffh if failure
; 0h if success
; CX = Error Code
mov si,dx
push ds ! mov ds,u_wrkseg
sub ax,ax ! mov bx,mcb_length[si]
mov dx,bx ! pop ds
call getmemory ! jcxz ca_gm
mov bx,0ffffh ! ret
ca_gm: push ds ! mov ds,u_wrkseg
mov mcb_length[si],dx
mov mcb_base[si],ax
pop ds ! sub bx,bx ! ret
;=============
cpmabsa_entry: ; 56 - Alloc Abs Mem
;=============
; Allocate an absolut memory region which is
; equal to mcb_length. Note: For CP/M-86
; compatibility, this function must return success
; if the memory is already allocated because
; the GET MAX functions allocate memory in MP/M, CCP/M
; and not in CP/M.
;
; input: DX = address of MCB in u_wrkseg
; output: BX = 0ffffh if failure
; 0h if success
; CX = Error Code
mov si,dx
push ds ! mov ds,u_wrkseg
mov ax,mcb_base[si]
mov bx,mcb_length[si]
mov dx,bx ! pop ds
; See if We already own this memory
; SI -> MCB in U_WRKSEG
; AX=Base, BX=Length, DX=Length
xor cx,cx
mov di,rlr
add di,p_mem-ms_link
caa_n: mov di,ms_link[di]
cmp di,0 ! je caa_g
cmp ms_start[di],ax ! jne caa_n
cmp ms_length[di],bx ! jbe caa_gm
mov cx,e_no_memory
mov bx,0ffffh ! ret
; SI -> MCB in U_WRKSEG
; AX=Base, BX=Length, DX=Length
caa_g: call getmemory ! jcxz caa_gm
mov bx,0ffffh ! ret
; Successful allocation
caa_gm: push ds ! mov ds,u_wrkseg
mov mcb_length[si],dx
mov mcb_base[si],ax
pop ds ! sub bx,bx ! ret
getmemory:
;---------
; input: AX = start
; BX = min
; DX = max
; output: AX = start
; DX = length
; CX = error code
; preserve SI
push si
sub cx,cx ! push cx ! push cx ! push dx ! push bx
push ax ! mov dx,sp
push ds ! mov cx,ss ! mov ds,cx
mov cx,f_malloc ! call osif
pop ds ! pop ax ! pop dx ! pop bx ! pop bx ! pop bx
pop si ! ret
;=============
cpmfree_entry: ; 57 - Free Mem
;=============
; Free memory as specified in MCB
; input: DX = offset of MCB in u_wrkseg
; mcb_ext = 0ffh = free all but load mem
; else as specified by mcb_base.
; mcb_base = seg addr of memory segment
; to free. IF in middle of
; existing segment then just free
; the end of the segment.
push ds ! mov ds,u_wrkseg
mov si,dx
mov al,mcb_ext[si]
mov dx,mcb_base[si] ! pop ds
cmp al,0ffh ! jne free_memory
cpmf_root: mov bx,rlr
add bx,p_mem-ms_link
cpmf_next: mov si,ms_link[bx]
cmp si,0 ! jne try_seg
sub bx,bx ! mov cx,bx ! ret
try_seg: test ms_flags[si],mf_load ! jz free_seg
mov bx,si ! jmps cpmf_next
free_seg: mov dx,ms_start[si]
push si ! call free_memory ! pop si
jcxz cpmf_root
jmps cpmf_next
free_memory:
;-----------
; input: DX = start
; output: BX = 0,0ffffh (success,fail)
; CX = Error Code
push ds ! push ss ! pop ds
sub cx,cx ! push cx ! push dx
mov dx,sp
mov cx,f_memfree ! call osif
pop dx ! pop dx ! pop ds
ret
;=============
freeall_entry: ; 58 - Free All Mem
;=============
; Free all memory except LOAD UDA and LDSTK
; If a transient program calls this, it must free up the
; all of the perceived memory. The UDA and LDSTK is not
; perceived by CPM compatible programs. The UDA cannot be
; freed, since it is part of the process descriptor, until
; termination in the dispatcher.
mov si,rlr
mov ax,p_uda[si]
add si,p_mem-ms_link
fam_n: mov si,ms_link[si]
; See if anymore memory to free
cmp si,0 ! je fam_e
mov bx,ms_start[si]
; See if UDA above start
cmp bx,ax ! ja fam_a ;AX=UDA Segment
mov cx,bx
add cx,ms_length[si]
; See if below start+len
cmp cx,ax ! jb fam_a
; WE HAVE A UDA !!!
; see if we already trimmed it
test ms_flags[si],mf_udaonly
jnz fam_n
or ms_flags[si],mf_udaonly
; trim the memory above the UDA
; check if it's an 8087 user
mov bx,rlr ;get process
test p_flag[bx],pf_8087 ;if not an 8087 user
jz med_uda ;try medium uda len
add ax,(lstklen+u8087len)/16 ;else use long uda
jmp done_uda
med_uda: test p_sflag[bx],psf_em87 ;if not 87 emulator
jz norm_uda ;do normal uda len
add ax,(lstklen+em87len)/16 ;else do medium len
jmp done_uda
norm_uda: add ax,(lstklen+ulen)/16 ;CX=# paragraphs
done_uda: mov bx,ax
; Free the segment or after the UDA+LDSTK
fam_a: mov dx,bx
call free_memory
jmps freeall_entry
fam_e: xor bx,bx ! mov cx,bx ! ret


View File

@@ -0,0 +1,689 @@
;*****************************************************
;*
;* Dispatch Routines
;*
;*****************************************************
;=====
fdisp:
;=====
; This entry point used by interrupt routines in XIOS
; Note: if the XIOS is performing memory protection interrupt
; handlers must enable O.S. memory before calling the O.S.
cli
push ds ! mov ds,sysdat
cmp indisp,true ! je nodisp ;if indisp=true then we are
mov ax_sav,ax ;in the dispatcher and
mov al,true ! mov indisp,al ;this code is skipped
mov ax,es ! mov es_sav,ax
mov ax,rlr ! xchg ax,bx ! mov bx_sav,ax
mov es,p_uda[bx]
mov al,true ! mov u_in_int,al
pop ax ! mov u_ds_sav,ax
mov al,p_stat[bx]
mov u_stat_sav,al
mov p_stat[bx],ps_run
mov ax,es_sav
mov u_es_sav,ax
; AX in AX_SAV
; BX in BX_SAV
; ES in U_ES_SAV
; DS in U_DS_SAV
; p_stat in U_STAT_SAV
jmp intdisp
;dispatcher will jump to here if
; u_in_int = true.
int_disp_exit: ;interrupts are off
; AX in AX
; BX in BX
; ES in U_ES_SAV
; DS in U_DS_SAV
; p_stat in U_STAT_SAV
mov ax_sav,ax
mov ax,bx ! mov bx_sav,ax
;check for
cmp drl,0 ! jnz intdisp ;interrupt occurence
;on dispatcher exit
mov al,false ! mov u_in_int,al
mov ax,rlr ! mov bx,ax
mov al,u_stat_sav
mov p_stat[bx],al
mov ax,bx_sav ! mov bx,ax
mov ax,ax_sav
mov indisp,false
mov ds,u_ds_sav
mov es,u_es_sav
iret
nodisp: pop ds
iret
;========
farpdisp:
;========
; Intermodule pdisp (non-interrupt)
call pdisp ! retf
;=====
pdisp:
;=====
; Call dispatcher with no special action
push bx ! mov bx,rlr
mov p_stat[bx],ps_run ! pop bx
;jmp dsptch
;======
dsptch:
;======
; The dispatch function looks like a noop to the
; caller. All flags and registers are maintained.
; No levels of user stack is used.
; (jmp dispatch = ret)
; Interrupt routines enter through fdisp.
;
; Dispatch has two (2) arguments:
; 1. the p_stat field of the process descriptor
; determines the type of action to perform
; for this process.
; 2. the dparam field of the uda is an argument
; to the action.
; The main part of the dispatch routine takes the
; currently running process off the Ready list
; and jmps to a routine which will put it on some
; other list depending on the p_stat argument.
; The subsequent routine will then jump to the
; scheduler which will do polling of devices and
; move processes off the dispatch ready list onto
; the Ready list. The Ready List is maintained
; in priority order with round-robin scheduling
; of processes with equivalent priorities. The
; first process on the ready list will then be
; switched in.
; set indisp flag
pushf ! cli
cmp indisp,true ! jne dispin
popf ! ret
dispin: mov indisp,true
pop u_flag_sav
; assumming bx=RLR:
; if PLR=0 and DRL=0 then
; if p_stat[bx]=PS_RUN then
; if p_link[bx]=0 or
; p_prior[p_link[bx]]<>p_prior[bx] then
; don't do dispatch
mov ax_sav,ax
mov ax,bx ! mov bx_sav,bx
intdisp:
cmp plr,0 ! jne dcont ;if Poll list = 0 and
cmp drl,0 ! jne dcont ;Dsptch Ready list = 0 and
mov ax,rlr ! mov bx,ax ;(RLR can never be 0 here)
cmp p_stat[bx],ps_run ! jne dcont ;our status is run and
cmp p_link[bx],0 ! je no_disp2 ;other PD to ready to run
mov al,p_prior[bx] ;with an equal priority
mov bx,p_link[bx] ;THEN skip the dispatch
cmp al,p_prior[bx] ! je dcont
no_disp2:
mov ax,bx_sav ! mov bx,ax
mov ax,ax_sav
jmp dext
dcont:
mov u_ss,ss ! mov u_sp,sp
mov ss,sysdat ! mov sp,offset dsptchtos
mov ax,bx_sav ! mov bx,ax
mov ax,ax_sav
sti
cld
; save registers
; NOTE: We will use DS instead of ES
; No segment overrides...
push es ! pop ds
mov ds:u_ax,ax
mov ax,bx ! mov ds:u_bx,ax
mov ax,cx ! mov ds:u_cx,ax
mov ax,dx ! mov ds:u_dx,ax
mov ax,di ! mov ds:u_di,ax
mov ax,si ! mov ds:u_si,ax
mov ax,bp ! mov ds:u_bp,ax
; Save interrupt vectors 0,1,3,4 not INT 2 which is NMI
; MP/M-86, CCP/M-86 1.0 on the IBM PC saved NMI
; Block move first 2
xor bx,bx ! mov ds,bx
mov si,bx ! mov di,offset u_ivectors
mov dx,4
mov cx,dx ! rep movsw
mov cx,dx ! add si,dx ;get next 2
add di,dx ;skip INT 2 location documented
rep movsw ;now as reserved word in UDA
; block move osint,debugint
mov si,offset i_os_ip ! mov di,offset u_os_ip
mov cx,dx ! rep movsw
mov ds, sysdat
; if 8087 emulator user,swap extra vectors
mov bx,rlr
test p_sflag[bx],psf_em87
jz u_disp ; not an emulator user
push es ! mov ax,ds ; save segment registers
push cx! push di
mov cx, em_seg ; move 14 vectors from
mov si, em_offs ; low memory to uda extension
mov di, offset u_8087
mov es, p_uda[bx]
mov ds,cx
mov cx, tot_emvecs/2
rep movsw
pop di ! pop cx
pop es ! mov ds,ax ; restore segment registers
; swap out userdisp vectors.
; acts like a nop to non-userdisp processes
u_disp:
mov si,rlr
mov ax,user_save
callf p_userdisp[si]
jmps dcont1
def_emultr: ; this is the default routine for non-userdisp proc's
retf
dcont1: ; take current process off RLR.
;disable memory for the process
;we are taking out of context
;turn off interrupts ?
;dsp_disabled:
nop
mov ax,rlr ! mov si,ax
mov ax,p_link[si] ! mov rlr,ax
mov p_link[si],0
; We are now in NO-MAN's land
; From now until the end of the
; switch routine, There is no
; process in context.
; SI -> PD just taken out of context.
; jump to routine for given status
xor bh,bh ! mov bl,p_stat[si] ! shl bx,1
jmp cs:dsp_table[bx]
org ((offset $)+1) AND 0fffeh
dsp_table dw disp_act ;00 - run
dw disp_act ;01 - (nop)-poll device
dw delay_act ;02 - delay
dw disp_act ;03 - (nop)-swap
dw term_act ;04 - terminate
dw sleep_act ;05 - sleep
dw disp_act ;06 - (nop)-dq
dw disp_act ;07 - (nop)-nq
dw flag_act ;08 - flag wait
dw disp_act ;09 - (nop)-ciowait
dw disp_act ;10 - (nop)-sync
sleep_act:
;---------
; insert running process into list specified by
; u_dparam and set p_stat from p_scratch
; Note: we cannot sleep on the DLR since interrupts are on
; here, and flag_set can change the DLR
mov ax,u_dparam
mov bx,ax
push si ! call insert_process
pop si ! or p_flag[si],pf_resource
mov al,p_scratch[si] ! mov p_stat[si],al
jmp schedule
delay_act:
;---------
; Put the running process on the Delay List. The
; delay list is built such that any process's
; remaining delay time is the additive of the delay
; times of all processes ahead of it plus the # of
; ticks in it's own p_wait field. At each clock tick
; the p_wait field of the top process in the list
; is decremented. If it reaches zero (0), all
; processes with a zero in the p_wait field are
; placed on the dispatch ready list.
; input: SI=pd address
cli ;keep flag set from changing
;if mpm ;TICK, and changing DLR
; push si ! mov al,io_strtclk
; call xiosif ! pop si
;endif
;if ccpm
mov tick,true
;endif
mov bx,(offset dlr)-p_link
mov cx,u_dparam ! inc cx
cmp cx,0 ! jne del_lp
dec cx
del_lp: mov di,p_link[bx]
cmp di,0 ! je del_o
mov ax,p_wait[di]
cmp ax,cx ! ja del_o
sub cx,ax ! mov bx,di ! jmps del_lp
del_o: mov p_link[si],di ! mov p_link[bx],si
mov p_wait[si],cx
cmp di,0 ! je del_e
sub p_wait[di],cx
del_e: jmp schedule
flag_act:
;--------
; place running process in flag table to wait
; for next flag. Note, flag may have been set...
; input: SI=pd address
; U_DPARAM=address of Flag entry
mov ax,u_dparam ! mov bx,ax
cli ;protect from flag set
cmp flg_pd[bx],flag_on ! je gflagon
mov flg_pd[bx],si ! mov p_link[si],0
jmp schedule
gflagon: ; Flag set since wait check
mov flg_pd[bx],flag_off
sti
jmps disp_act
term_act:
;--------
; Terminate the running process, free memory, free pd, free sync
; structures. Can only be called by TERMINATE_ENTRY.
; input: SI=pd address
; MEM_SYNC owned by calling process
; place PD on rlr for now.
mov ax,rlr
mov p_link[si],ax
mov rlr,si
; clean up consoles
mov cx,f_cioterm ! call osif
; clean up memory
; (we own the MXmemory queue)
free_nxt:
mov ax,rlr ! mov si,ax
mov si,p_mem[si]
test si,si ! jz end_free
push ds ! xor cx,cx ! push cx
push ms_start[si]
mov ax,ss ! mov ds,ax ! mov dx,sp
mov cx,f_memfree ! call osif
pop bx ! pop cx ! pop ds
jmps free_nxt
end_free:
;release any sync structures
;after releasing memory
mov mem_cnt,0 ;and MEM_CNT=1
;on entry, also own THRD_SYNC
;so it is safe to call
;FREEPD below,
;ASSIGN_SYNC cannot be called
;with the THRD_SPB
;SI=terminating process
mov bx,offset slr - sy_link ;release any sync structures
t_nsync: ;owned by terminating PD
mov bx,sy_link[bx]
test bx,bx ;end of syncs?
jz t_sync_done
push bx ;PD cannot be allowed to
call unsync_entry ;abort if in SY.NEXT
pop bx
jmps t_nsync
t_sync_done:
; take off RLR
mov si,rlr
mov ax,p_link[si]
mov rlr,ax
mov p_link[si],0
cmp si,owner_8087 ;release 8087 if we owned it
jne t_end ! mov owner_8087,0
t_end:
; free up PD
call freepd ! jmp schedule
disp_act:
;--------
; place process on RLR
; input: SI=pd address
mov p_stat[si],ps_run
mov bx,(offset rlr)-p_link
call insert_process ! jmp schedule
;==============
insert_process:
;==============
;
; put PD# in list ordered by priority
;
; entry: BX = list root
; SI = pd number
; exit: SI is preserved
; interrupt state as on entry
mov cx,pflag[si] ! and cx,pf_resource
;if a process was waiting
ins_npd: mov di,p_link[bx] ;on a resource, insert
test di,di ! jz ins_out ;it ahead of equal priority
mov al,p_prior[di] ;process
cmp al,p_prior[si]
ja ins_out ;lowest priority first
jb ins_nxt ;higher - keep going down list
jcxz ins_nxt ;equal and not resource
jmps ins_out ;equal & resource
ins_nxt: mov bx,di ! jmp ins_npd
ins_out: jcxz ins_exit
and p_flag[si],not pf_resource
ins_exit:
mov p_link[si],di ! mov p_link[bx],si ! ret
;========
schedule:
;========
; poll all required devices and place any ready
; processes on the Ready List
;we can enable interrupts now.
;there MUST be a process on the RLR
;at this point, ie. IDLE...
sti
;go through the Poll List
mov di,(offset plr)-p_link
;get the next PD on list.
;DI is the last one which
;has already been checked.
polld_another:
mov si,p_link[di]
;SI is the next PD to check
test si,si ! jz drltorlr
;SI is valid PD, poll it.
;If top PD on the PLR has a worse
;priority compared to top PD on the RLR,
;there is no reason to call the XIOS
;and poll the device, this time through
;the dispatcher. We must poll on equal
;priority to keep a compute bound
;process and the CLOCK from locking
;out a polling process.
;Note, we stop polling after
;the first process that has polled
;successfully, or we get to the end of
;the PLR. The process is placed on
;the RLR.
mov bx,rlr ! test bx,bx ;if RLR=0: poll
jz poll_it
mov al,p_prior[si] ;priority of 1st poll PD
cmp al,p_prior[bx] ! jbe poll_it ;poll if equal or better
jmps drltorlr ;priority than head of RLR
poll_it:
push di
;if mpm
; mov cx,p_wait[si]
;endif
;if ccpm
mov dx,p_wait[si]
;endif
mov al,io_polldev ! call xiosif
pop di ! mov si,p_link[di]
;if AL=0, device not ready.
cmp al,0 ! je polld_next
;device ready,
;move SI from PLR to RLR
mov ax,p_link[si] ! mov p_link[di],ax
mov bx,(offset rlr)-p_link
mov p_stat[si],ps_run
call insert_process ;got one ready to run:
jmps drltorlr ;stop polling
;p_link[SI]=next PD to check
polld_next: ;SI has been checked
mov di,si ! jmps polld_another
drltorlr:
;--------
; Pull all processes on the dispatch ready list and
; place them on the Ready List.
;We must disable interrupts while
;playing with DRL since interrupts
;doing a Flag_set may also.
;We must competely drain the DRL since
;it is in no particular order.
cli ! mov si,drl ;protect DRL from flag set
test si,si ! jz switch
mov ax,p_link[si] ! mov drl,ax
; test ax,ax ;is this the last PD on DRL?
; jnz drl_noi ;yes - don't turn on interrupts
sti ;interrupts off guarentees
;drl_noi: ;the last DRL PD with the
mov p_stat[si],ps_run ;best priority will run
mov bx,(offset rlr)-p_link ;next and at least until
call insert_process ;it turns on interrupts
jmps drltorlr
switch:
;------
; switch to the first process on the Ready List
sti
mov bx,rlr
; if no next process, go back ;
; to schedule. Gives more immediate ;
; response to polled and interrupt ;
; driven devices ;
switch0:
test bx,bx ! jnz switch1 ;
jmp schedule ;
; Suspendable processes: in order to be suspended, a process
; must be flagged as suspendable, it must be in the background,
; and it must not be in the system (e.g.,owning a system queue).
; It must also not be coming into context to terminate.
switch1:
cli ;check if process should suspend
mov ax,p_sflag[bx]
test ax,psf_suspend
jz switch2 ;no, not at all
mov al,p_cns[bx] ;Check vccb's state word
xor ah,ah ! xor di,di
mov di,ccblen ! mul di
mov di,ccb ! add di,ax
mov ax,c_state[di]
test ax,csm_background ;Has it gone into background ?
jz switch2 ;no, don't need to suspend
push es
mov es,p_uda[bx]
mov al,u_insys ;Is it in the system? If so, don't
test al,al ;suspend.
pop es
jne switch2
test p_flag[bx],pf_ctlc ;Is it terminating ?
jnz switch2 ;Yes, don't put it back on list.
mov ax,p_link[bx] ;All conditions apply; take it off
mov rlr,ax ;the RLR.
mov ax,splr ;Get the suspend list
mov p_link[bx],ax ;link up and
mov splr,bx ;place on top of suspend list.
mov p_stat[bx],ps_ciowait ;change its status
mov ax,c_state[di] ;Turn on suspend if process was
test ax,csm_suspend ;created in the background.
jnz do_dparam
or c_state[di],csm_suspend
do_dparam:
push es ;Put list root into u_dparam
mov es,p_uda[bx] ;for terminate's pd search.
mov u_dparam, offset splr
pop es
mov bx,rlr ;BX = RLR
sti
jmp switch0 ;make sure next process isn't suspendable
;enable memory for this process
;turn on interrupts ?
;
; ;Save and restore the 8087 environment if process to run
; ;uses the 8087 and is not the owner. Interrupts
; ;must be on. Code from Intel Ap. Note. 113 page 29
;
; ;This code shouldn't be added unless interrupt windows in
; ;switch are allowed or the 8087 restore is separated
; ;from the 8086/8088 restore. The switch code without this
; ;commented out 8087 code,
; ;creates an interrupt window approx. 100 to 200 micro
; ;secs on 5 to 4 meg CPU.
; ;Allowing interrupt windows in switch
; ;means we must check on leaving the dispatcher
; ;for an interrupt awakened process (DRL again <> 0)
; ;and call the
; ;dispatcher again to prevent a 16 milli second wakeup time
; ;for a PD doing a flagwait after the interrupt service routine.
; ;Calling the dispatcher at the end of the dispatch
; ;(see commented out code at end of dispatcher and at
; ;INT_DISP_EXIT:)
; ;creates contention problems between PDs waiting for a resource
; ;and PDs waking up from interrupts. It cannot be guarenteed
; ;who will run next. An interrupt awakened process can
; ;get a just freed resource is should have waited for.
; ;The RTM ASSIGN_SYNC_ENTRY is an untested solution
; ;for allowing interrupts in the dispatcher switch code.
switch2:
sti ;BX=PD to run next
test p_flag[bx],pf_8087 ;does this process use the NDP?
jz try_em87 ;if not, see if it emulates 8087
cmp bx,owner_8087 ;do we already own it
je done8087
mov dx,ds ;DX = DS = SYSDAT
fwait ;wait until other process is done
xchg bx,owner_8087 ;new owner, also set by terminate
test bx,bx ! jz get8087 ;no one owns it if BX=0
mov ds,p_uda[bx] ;old owner's UDA
fstcw ds:u_8087 ;save IEM bit status
nop ;delay while 8087 busy saves control reg
fdisi ;disable 8087 busy signal
mov ax,ds:u_8087 ;get original control word
fsave ds:u_8087 ;save NPX context
fwait ;IEM=1.wait for save to finish
mov ds:u_8087,ax ;save original control word
mov ds,dx ;DS = SYSDAT
mov es,p_uda[bx] ;swap out and save this user's
mov di,offset u_ivec87_of ;ndp interrupt vector
mov si,iofs_87 ;DS:SI = system's vector address
mov ds,iseg_87 ;ES:DI = user's UDA save area
mov cx,2! rep movsw
mov ds,dx ;restore DS to SYSDAT
get8087:
mov bx,rlr
mov ds,p_uda[bx] ;PD to run next
frstor ds:u_8087 ;copy in its 8087 environment frsure
push ds ;DS=UDA . UDA on stack.
restore87_int:
mov ds,dx
les di,dword ptr iofs_87 ;restore interrupt vectors
mov ds, p_uda[bx] ;for 8087 user
mov si, offset u_ivec87_of
mov cx, 2 ! rep movsw
jmps restore
try_em87: ;8087 emulator has special vector
test p_sflag[bx],psf_em87 ;set that must be swapped
jz done8087
mov ax,ds ;save DS
mov cx,em_seg ;move 14 vectors from uda extension
mov di,em_offs ;to low memory
mov si,offset u_8087 ;u_8087 -> user save area in uda
mov ds,p_uda[bx]
mov es,cx
mov cx,tot_emvecs/2
rep movsw
mov ds,ax ;restore DS
done8087: ;no more 8087 or emulator business...
;BX=PD to run next
mov dx,p_uda[bx] ! mov ds,dx ;DS=UDA
push dx ;UDA on stack
restore:
mov es, sysdat ;Restore userdisp vectors.
mov ax, es:user_restore ;Acts like a nop to non-userdisp
mov si, es:rlr ;processes.
callf es:p_userdisp[si] ;Default routine does a retf.
xor ax,ax ! mov es,ax ! mov di,ax
mov si,offset u_ivectors
mov dx,4
mov cx,dx ! rep movsw ;restore interrupt vectors 0,1
mov cx,dx ! add di,dx ;don't touch NMI
add si,dx ;skip what was NMI
rep movsw ;restore interupt vectors 3,4
mov si,offset u_os_ip ;DS=UDA
mov di,offset i_os_ip
mov cx,dx ! rep movsw
; restore registers
mov ax,ds:u_bx ! mov bx,ax
mov ax,ds:u_cx ! mov cx,ax
mov ax,ds:u_dx ! mov dx,ax
mov ax,ds:u_si ! mov si,ax
mov ax,ds:u_di ! mov di,ax
mov ax,ds:u_bp ! mov bp,ax
mov ax,ds:u_ax
; restore DS and ES and stack
pop es ;ES=UDA
cli ;turn interrupts off for rest
mov ss,u_ss ;of exit
mov sp,u_sp
mov ds,sysdat
dext:
cmp u_in_int,true ! jne dret
jmp int_disp_exit
dret:
push u_flag_sav
mov indisp,false
cmp drl,0 ! je dd_ret
popf ; someone is on DRL from interrupt during
jmp pdisp ; switch, dispatch now, no 16ms wait
dd_ret:
popf
ret


View File

@@ -0,0 +1,40 @@
;*****************************************************
;*
;* Find Process Descriptor
;*
;*****************************************************
;================ =================================
findpdname_entry: ; Find Process Descriptor by Name
;================ =================================
; Find process by name in thread list
; Before calling this routine, calling process must
; own the THRD_SPB (Thread Sync Parameter Block) as
; interrupts are not turned off.
;
; input: DX->name in u_wrkseg
; BX->thread list root - p_thread
; output: BX=pd if found
; =0ffffh if not found
; CX=0 if found
; =e_no_pdname if not found
push es ! mov es,u_wrkseg
fpn_cmpname:
mov si,dx
mov bx,p_thread[bx]
cmp bx,0 ! je fpn_nomatch
mov cl,0
lea di,p_name[bx]
fpn_cmplet:
cmp cl,8 ! je fpn_found
mov al,es:[si] ! sub al,[di]
shl al,1 ! jnz fpn_cmpname
inc cl ! inc si ! inc di
jmps fpn_cmplet
fpn_found: mov cx,0 ! jmps fpn_exit
fpn_nomatch:
mov cx,e_no_pdname ! mov bx,0ffffh
fpn_exit:
pop es ! ret


View File

@@ -0,0 +1,185 @@
;*****************************************************
;*
;* Flag Management
;*
;* FLAGS-flag table offset NFLAGS-number of flags
;*
;* Format of Flag Table Entry:
;* +-------------+------+
;* | flag |ignore|
;* +-------------+------+
;* flag - 00000h, flag can be allocated
;* flag - 0ffffh, flag is off but is allocated to some
;* function.
;* 0fffeh, flag is set
;* 0xxxxh, PD that is waiting
;* ignore- 0ffh, normal case
;* 0xxh, number of flags to ignore-1
;*
;* GENSYS initializes the flags reserved by the system
;* and the XIOS header to 0ffh's. The rest of the
;* flags are initialized to 0 by GENSYS.
;*
;*****************************************************
;============
;getfree_flag:
;============
; input: DX = 0 then allocate a flag
; else
; if DH = 0FFH then release flag number
; DL (0 relative)
; output:
; BX = flag allocated if getting a flag
; or 0FFFFH if no flag is available
; BX = 0FFFFH if attempting to release a
; no existent flag
; CX = 0 no error
; CX = 4 if illegal flag number
; CX = 27H if no more flags to allocate
;
; Flags reserved by CCP/M or MP/M and the XIOS
; header, cannot be released.
;
;turn off interrupts
;
; test dx,dx ! jz rf_alloc
; inc dh ! jnz rf_enum
; cmp dl,nrsv_flags ! jbe rf_enum
; cmp dl,nflags ! jae rf_enum
; xor ax,ax ! mov bx,ax ! mov cx,ax
; mov al,dl
; add al,dl ! add al,dl
; mov si,ax ! mov word ptr flags[si],0
; mov byte ptr flags 2[si],0
; ret
;rf_alloc:
; mov si,flags ! xor ax,ax
; mov bx,ax ! mov cx,nflags
;rf_nxt:
; cmp ax,[si] ! je rf_foundone ;got one
; add si,3 ! inc bx
; loop rf_nxt
; mov cx,e_noflags ! jmps rf_err
;rf_foundone:
; mov cx,ax ;0 CX
; dec ax
; mov [si],ax ;set the 3 bytes to 0ffh
; mov 2[si],al
; ret
;rf_enum:
; mov cx,e_illflag
;rf_err:
; mov bx,0ffffh
; ret
;============== ==========================
flag_set_entry: ; Set Logical Interrupt Flag
;============== ==========================
; NOTE: the flagset routine can (must?) be called from outside
; the operating system through an interrupt
; routine. UDA variables cannot be used. This
; is the only function an interrupt routine can
; call.
;
; input: DL = flag number
; output: BX = 0 if okay,0ffffh if error
; CX = if error: e_flag_ovrrun
call flag_valid
cmp cl,flag_tick ! jne notick
mov bx,dlr
test bx,bx ! jz dlr_null ;no process waiting
dec p_wait[bx] ! jnz nxt_tick
nxt_tpd:
mov si,p_link[bx] ! mov dlr,si ;SI,DLR=next waiting PD
mov p_stat[bx],ps_run ;put PD done waiting
mov ax,drl ! mov p_link[bx],ax ;on DRL
mov drl,bx
test si,si ! jz dlr_null ;SI=next waiting PD
cmp p_wait[si],0 ! jnz nxt_tick
mov bx,si ! jmps nxt_tpd;another process was waiting
;the same number of ticks
nxt_tick: jmp flag_exit ;wait for next tick
dlr_null: ;DLR is empty turn off
mov tick,false ! jmp flag_exit ;XIOS tick flag
no_tick:
cmp flg_ignore[si],flag_zig ! je fs_set
dec flg_ignore[si] !
mov cx,e_flag_ignr ! jmp flag_bexit
fs_set: cmp bx,flag_on ! jne fs_non
mov cx,e_flag_ovrrun ! jmp flag_bexit
fs_non: cmp bx,flag_off ! jne fs_noff
mov flg_pd[si],flag_on
jmp flag_exit
fs_noff:mov ax,drl ! mov p_link[bx],ax
mov drl,bx ! mov p_stat[bx],ps_run
or p_flag[bx],pf_resource ;12/4/83
mov flg_pd[si],flag_off
jmp flag_exit
;=============== ===============================
flag_wait_entry: ; Wait for Logical Interrupt Flag
;=============== ===============================
; input: DL = flag number
; output: BX = 0 if everything okay
; BX = 0ffffh if Error
; CX = Error Code:0,e_flag_underrun
call flag_valid
cmp bx,flag_on ! jne fw_non
mov flg_pd[si],flag_off
jmp flag_exit
fw_non: cmp bx,flag_off ! jne fw_noff
mov bx,rlr
mov p_stat[bx],ps_flagwait
mov u_dparam,si
call dsptch ! jmp flag_exit
fw_noff:mov cx,e_flag_underrun ! jmp flag_bexit
flag_valid: ; Check validity of flag number
;---------- -----------------------------
; entry: DL = flag number
; output: SI = ptr to flag entry
; BX = contents of flag entry
; CL = flag number
; clear interrupt flag - Flags on stack
pop ax ! pushf ;AX=return address
cmp dl,nflags ! jb flag_good
flag_bad:
mov cx,e_ill_flag ! jmp flag_bexit ;flags and next return
flag_good: ;address on stack
mov cl,dl ;save flag number
xor dh,dh ! push ax ! cli ;return to fset/fwait on stack
mov ax,dx ;multiply flag number
mov bx,ax ;times 3
add ax,ax ;*2
add ax,bx ;*3
mov si,flags ! add si,ax
mov bx,[si]
;test bx,bx ;FLAG field cannot be 0
;jz flag_bad
ret
flag_exit: ; Successful Exit
;--------- ---------------
; entry: flags and return from flagset or flagwait on stack
xor bx,bx ! popf ! ret
flag_bexit: ; Exit with Error
;---------- ---------------
; entry: flags and return from flagset or flagwait on stack
xor bx,bx ! dec bx
popf ! ret


View File

@@ -0,0 +1,29 @@
;*****************************************************
;*
;* Idle Process
;*
;*****************************************************
;====
idle: ;Idle Process
;====
; Jump to the XIOS idle routine
;if mpm
; mov ds,sysdat
; mov bx,rlr
; mov es,p_uda[bx]
; mov ax,io_idle
; jmp xiosif
;endif
;if ccpm ;we could move idle to the RTM
mov ds,sysdat ;and initialize its IP:CS to
mov bx,rlr
mov ax,p_uda[bx] ;point to the dispatcher
mov es,ax ;and get rid of this
mov cx,f_dispatch ;code since idle will never
call osif ;come out of the dispatcher
jmps idle
;endif


View File

@@ -0,0 +1,123 @@
;*****************************************************
;*
;* Concurrent CP/M-86 Supervisor Initialization
;*
;*****************************************************
cseg
org 0
jmp init ;system initialization
jmp entry ;intermodule entry pt.
;next 3 words are set by GENSYS
sysdat dw 0 ;segment
supervisor dw entry ;offset
dw 0 ;segment
org 0ch
dev_ver db 6 ;development system data version
;set in sysdat.dat
db 'COPYRIGHT (C) 1982,1983,1984'
db ' DIGITAL RESEARCH '
db 'XXXX-0000-'
serial db '654321'
;====
init:
;====
; system initialization
; DS set to Sysdat Segment by loader
;make INIT a process:
;set up init stack
cli ! cld ;Loader enters here
mov ax,ds ;with interrupts
mov ss,ax ! mov sp,offset (init_tos) ;possibly on
;initialize init uda
mov bx,offset initpd
mov ax,offset inituda
mov cl,4 ! shr ax,cl
add ax,sysdat ! mov p_uda[bx],ax
mov es,ax
mov u_wrkseg,ds
;we now look like we are in the O.S. as usual:
;DS=SYSDAT seg, ES=UDA, U_WRKSEG=PD's DS.
; set up mpm entry point
push ds
xor ax,ax ! mov ds,ax
mov i_os_ip,offset user_entry
mov i_os_cs,cs
pop ds
;initialize ndp owner to default
mov ax, 0ffffh ; ffff = no ndp chip present in system
mov owner_8087,ax
;initialize modules
mov bx,mod_init
push bx ! callf dword ptr rtmmod[bx] ! pop bx ; init RTM
push bx ! callf dword ptr memmod[bx] ! pop bx ; init MEM
test module_map,bdosmod_bit ! jz nbdo
push bx ! callf dword ptr bdosmod[bx] ! pop bx ; init BDOS
nbdo: test module_map,ciomod_bit ! jz ncio
push bx ! callf dword ptr ciomod[bx] ! pop bx ; init CIO
ncio: test module_map,xiosmod_bit ! jz nxio
push ds ! push es
callf dword ptr xiosmod[bx] ! pop es ! pop ds ; init XIOS
nxio:
; reset interrupt vectors after XIOS INIT
mov ax,ds ! sub bx,bx ! mov ds,bx
mov i_os_ip,offset user_entry
mov i_os_cs,cs
mov ds,ax
; get Character Dev Info from XIOS
;if mpm
; mov ax,io_maxconsole ! call xiosif
; mov ncondev,bl ! mov nciodev,bl
; mov ax,io_maxlist ! call xiosif
; mov nlstdev,bl ! add nciodev,bl
; mov bx,offset initpd
; mov al,ncondev
; mov p_lst[bx],al
;endif
; Init CCB and LCB adr in INIT UDA so
; child processes will inherit them
mov cl,f_conattach ! int osint
mov cl,f_lstattach ! int osint
; Start RSPs
nrsp: ;loop til done
mov ds,sysdat ;reset DS
mov cx,rspseg ! jcxz rsp_o ;?all done?
mov es,cx ;ES->RSP
mov ax,es:.rsp_link ;save next RSP
mov rspseg,ax
mov es:.rsp_link,ds ;give Sysdat to RSP
mov si,rsp_pd ;get PD
mov ds,cx ;DS = RSP Data Seg
mov p_mem[si],0
mov cl,f_createproc ;Create RSP Process(s)
mov dx,si ! int osint
jmps nrsp ;Do another...
rsp_o:
; terminate init process
mov cl,f_terminate
mov dl,0ffh ! int osint


View File

@@ -0,0 +1,978 @@
;*****************************************************
;*
;* Program Load
;*
;*****************************************************
;
; LDTAB Entry Format:
; 0 2 4 6 8
; +-----+-----+-----+-----+-----+-----+-----+-----+
; | START | MIN | MAX | PD |
; +-----+-----+-----+-----+-----+-----+-----+-----+
;
; 8 10(A) 12(C) 14(E) 16(10) 17(11)
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
; | ATR | FSTRT | FLEN | TYPE| ID |
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
;
;
; start Absolute Address requested
; min Min memory wanted
; max Max memory wanted
; pd PD to allocate to
; atr Attributes, Memory Flags
; fstrt Starting paragraph in File
; flen # of paragraphs in file
; type Group type
; id Segment Address of this group
;
; The Load Table contains 9 entries, One for each
; potential Group in Command File and One extra
; for Independent Memory Allocations.
ldt_start equ word ptr 0
ldt_min equ word ptr ldt_start + word
ldt_max equ word ptr ldt_min + word
ldt_pd equ word ptr ldt_max + word
ldt_atr equ word ptr ldt_pd + word
ldt_fstrt equ word ptr ldt_atr + word
ldt_flen equ word ptr ldt_fstrt + word
ldt_type equ byte ptr ldt_flen + word
ldt_id equ word ptr ldt_type + byte
ldtlen equ ldt_id + word
;=========
cload_ent: ; entry point to load for a chain command
;=========
; Assumes UDA is set in passed PD.
push bx ! mov bx,1
jmps load
;========
load_ent: ; User entry point to load .CMD file for execution
;========
; input: DX = address of open FCB in u_wrkseg
; output: BX = segment addr of Base Page
; = 0ffffh if error
; CX = Error Code
sub bx,bx
;jmp load
;====
load: ; Intermodule entry point to load .CMD file
;====
; input: DX = addr of open FCB in u_wrkseg
; BX = addr of unused PD to initialize
; 0 - do not init PD
; 1 - chain load (PD addr on stack)
; output: BX = seg addr of Base Page
; = 0ffffh if error
; CX = Error Code
; Get MXLoad Queue
push dx ! push bx
mov cx,f_qread ! mov dx,offset mxloadqpb
call osif
mov lod_chain,false
pop lod_pd ! pop si
cmp lod_pd,1 ! jne ld_cf
pop lod_pd ! mov lod_chain,true
; Copy FCB into lod_fcb
; SI-> user FCB in u_wrkseg
ld_cf: mov cx,fcblen/2 ! mov di,offset lod_fcb
push es ! push ds ! push ds
mov ds,u_wrkseg ! pop es
rep movsw
pop ds ! pop es
; Read the Header
mov bx,offset lod_fcb
mov byte ptr fcb_r0+2[bx],0
mov ax,0 ;record #
mov bx,1 ;# of sectors
mov dx,offset lod_dma ;DMA offset
mov cx,sysdat ;DMA segment
call drd ! cmp di,1 ;check for EOF in header read
je lod_eof
jcxz ndpchk
lod_eof:
mov cx, e_bad_load ; tried to load a 0 length cmd file
mov bx, 0ffffh ; or one whose header is incorrect
jmp lod_exit
ndpchk: ;see if 8087 required
mov lod_ndp,0 ;default = no
mov bx, offset lod_dma
test ch_lbyte[bx],need_8087
jz ndp_flg ;not required - but is it optional?
cmp owner_8087,0ffffh ;needs it,but is there one in system?
jnz ndp_yes ;yes- flag it
mov cx,e_nondp ;no - abandon load & return
mov bx, 0ffffh
jmp lod_exit
ndp_flg:
test ch_lbyte[bx],opt_8087 ;will use it if present?
jz h_hdr ;doesn't want it at all
cmp owner_8087,0ffffh ;will use it,but is there one ?
jnz ndp_yes ;if not, flag it as an emulator user
mov lod_ndp,1
jmp h_hdr
ndp_yes:
mov lod_ndp,0ffh ;flag it as an 8087 user
h_hdr:
mov lod_suspnd,0 ;default = no suspend needed
test ch_lbyte[bx],susp_mode ;require background suspension ?
jz h_hdr1 ;no...
mov lod_suspnd,0ffh ;yes, flag pd later
h_hdr1:
mov lod_indma,0
; initialize Load Disk and User
; from FCB
mov bx,rlr
mov al,p_user[bx]
mov lod_user,al
mov al,p_dsk[bx] ;default disk of calling PD
mov lod_disk,al ;1-15 -> A-P
mov bx,offset lod_fcb
mov al,fcb_dr[bx]
mov lod_fifty,al ;base page address 50H, 0=default
test al,al ! jz use_ddsk
dec al ;1-15 -> A-P
mov lod_disk,al
use_ddsk:
test byte ptr fcb_name+7[bx],080h ! jz use_dusr
mov lod_user,0
use_dusr:
; Initialize ldtab
; Zero ldtab
mov cx,ldtabsiz/2 ! sub ax,ax
mov di,offset ldtab
push es ! mov es,sysdat
rep stos ax ! pop es
; 1st ldtab entry is UDA and LSTK
; if a PD was specified...
mov lod_nldt,0
mov si,offset ldtab
cmp lod_pd,0 ! jne sel_uda
jmp gc_ifo
sel_uda: cmp lod_ndp,0 ;see if 8087 user and long
jz form_uda ;uda is needed
cmp lod_ndp,0ffh ;no...
jz form_87uda
form_emuda: mov ldt_min[si],(lstklen+em87len)/16 ;8087 emulator user
mov ldt_max[si],(lstklen+em87len)/16 ;64 byte extension
jmp cont_uda
form_87uda: mov ldt_min[si],(lstklen+u8087len)/16 ;8087 user
mov ldt_max[si],(lstklen+u8087len)/16 ;96 byte extension
jmp cont_uda
form_uda: mov ldt_min[si],(lstklen+ulen)/16 ;min=max=UDA+STK paragraphs
mov ldt_max[si],(lstklen+ulen)/16
cont_uda: mov ax,lod_pd ! mov ldt_pd[si],ax
mov ldt_atr[si],mf_load
add si,ldtlen
inc lod_nldt
cmp lod_chain,true ! jne gc_ifo
;We are CHAINING. Free all memory
; except UDA area and LDSTK. This will keep
; the first partition for the chain
; as well as not crash the system.
push si
mov cx,f_freeall ! call osif
;transfer memory to new pd
mov bx,rlr
mov ax,p_mem[bx] ! mov p_mem[bx],0
mov bx,lod_pd ! mov p_mem[bx],ax
pop si
gc_ifo:
;go through CMD header and init
;a ldtab entry per header entry.
;alloc abs mem
mov bx,offset lod_dma
mov al,ch_lbyte[bx] ; save fixup flag
mov lod_lbyte,al
mov ax,ch_fixrec[bx] ; save record # of fixups, if any
mov lod_fixrec,ax
mov lod_fixrec1,ax
mov cx,ch_entmax ; BX = offset LOD_DMA
mov dx,8 ; DX = position in file
ch_more:cmp ch_form[bx],0 ! jne ch_doit
jmp ch_next
ch_doit: mov al,ch_form[bx] ! mov ldt_type[si],al ;type of seg
mov ax,ch_length[bx] ! mov ldt_flen[si],ax ;length
mov ldt_fstrt[si],dx ! add dx,ax ;pos in file
mov ax,ch_base[bx] ! mov ldt_start[si],ax ;abs seg
mov ax,ch_min[bx] ! mov ldt_min[si],ax ;min needed
mov ax,ch_max[bx]
cmp ax,0 ! jne setmax
mov ax,ch_min[bx]
setmax: mov ldt_max[si],ax ;max wanted
mov ax,lod_pd ! mov ldt_pd[si],ax ;pd to alloc to
cmp ax,0 ! je not_load
mov ax,mf_load
jmps not_load
skipjmp:jmps ch_more
;if mpm
not_load: cmp ch_form[bx],1 ! jne try_sh
add ax,mf_code ! jmps s_atr
try_sh: cmp ch_form[bx],9 ! jne s_atr
add ax,mf_code+mf_share
s_atr: mov ldt_atr[si],ax ;memory flags
;if abs, allocate memory
cmp ldt_start[si],0 ! je ch_nabs ;see if abs mem
jmps ch_al
ch_nabs: cmp ldt_type[si],9
jne ch_nxt ;see if shared code
push cx
push bx ! push dx ;save load DMA and position in file
call get_sh
pop dx ! pop bx
cmp cx,0 ! pop cx
je ch_nxt
jmp ld_out
ch_al: push bx ! push dx ! push cx ! push si
mov cx,f_malloc ! mov dx,si
call osif ! pop si
mov ax,ldt_start[si] ! mov ldt_id[si],ax
cmp cx,0 ! pop cx ! pop dx ! pop bx
je ch_nxt
;couldn't find memory
mov bx,0ffffh ! mov cx,e_no_memory
jmp ld_out
;endif
;if ccpm
;not_load: cmp ch_form[bx],9 ! jne try_code
; mov ch_form[bx],1
; mov ldt_type[si],1
;try_code: cmp ch_form[bx],1 ! jne s_atr
; add ax,mf_code
;s_atr: mov ldt_atr[si],ax ;memory flags
;
; ;if abs, allocate memory
; cmp ldt_start[si],0 ! je ch_nxt ;see if abs mem
;ch_al: push bx ! push dx ! push cx ! push si
; mov cx,f_malloc ! mov dx,si
; call osif ! pop si
; mov ax,ldt_start[si] ! mov ldt_id[si],ax
; cmp cx,0 ! pop cx ! pop dx ! pop bx
; je ch_nxt
; ;couldn't find memory
; mov bx,0ffffh ! mov cx,e_no_memory
; jmp ld_out
;
;endif
ch_nxt: add si,ldtlen
inc lod_nldt
ch_next:add bx,chlen
loop skipjmp
; alloc all other memory
; SI -> mpb for non_abs mem req.
;add all parts together for a single malloc
mov bx,offset ldtab
mov cx,lod_nldt
mov lod_nrels,0
lt_more:cmp ldt_min[bx],0 ! je lt_next
cmp ldt_start[bx],0 ! jne lt_next
mov ax,ldt_min[bx]
mov dx,ax
add ldt_min[si],ax
cmp dx,ldt_min[si] ! jbe lt_m ; check for ovrflw
mov ldt_min[si],0ffffh
lt_m: mov ax,ldt_max[bx]
mov dx,ax
add ldt_max[si],ax
cmp dx,ldt_max[si] ! jbe lt_m1 ; check for ovrflw
mov ldt_max[si],0ffffh
lt_m1: inc lod_nrels
lt_next:add bx,ldtlen ! loop lt_more
;malloc
cmp lod_pd,0 ! je noloadf
mov ldt_atr[si],mf_load
noloadf:mov ax,lod_pd ! mov ldt_pd[si],ax
push si ! mov dx,si ! mov cx,f_malloc
call osif ! pop si
mov ax,ldt_start[si] ! mov ldt_id[si],ax
cmp bx,0ffffh ! jne lt_sprd
;Not Enough Memory - release any
; memory already allocated
ld_out: push cx
mov bx,offset ldtab
mov cx,lod_nldt ! inc cx
lg_more: cmp ldt_id[bx],0 ! je lg_next
push cx ! push bx ! push ds
;push MFPB on stack
push ldt_pd[bx]
push ldt_id[bx]
mov dx,sp ! push ss ! pop ds
mov cx,f_memfree
call osif
pop cx ! pop cx
pop ds ! pop bx ! pop cx
lg_next: add bx,ldtlen ! loop lg_more
mov bx,0ffffh ! pop cx ! jmp lod_exit
lt_sprd:
;spread the memory allocated
;amongst the nrels
;1st give everyone the minimum
mov bx,offset ldtab
mov cx,lod_nldt
ls_more:cmp ldt_start[bx],0 ! jne ls_next
mov ax,ldt_min[bx]
sub ldt_min[si],ax
cmp ax,ldt_max[bx] ! jne ls_next
mov dx,ldt_start[si] ! mov ldt_start[bx],dx
add ldt_start[si],ax
dec lod_nrels
ls_next:add bx,ldtlen ! loop ls_more
;spread whats left amongst those that need more
mov bx,offset ldtab
mov cx,lod_nldt
lsl_mre:cmp ldt_start[bx],0 ! jne lsl_nxt
mov ax,ldt_start[si] ! mov ldt_start[bx],ax
mov ax,ldt_min[si]
cmp ax,0 ! je adj_start
push cx ! sub cx,cx
mov dx,cx ! mov cl,lod_nrels
div cx ! pop cx
cmp dx,0 ! je evendiv
inc ax
evendiv: mov dx,ldt_max[bx] ! sub dx,ldt_min[bx]
cmp ax,dx ! jbe nottoomuch
mov ax,dx
nottoomuch: add ldt_min[bx],ax ! sub ldt_min[si],ax
adj_start: mov ax,ldt_min[bx] ! add ldt_start[si],ax
dec lod_nrels
lsl_nxt:add bx,ldtlen ! loop lsl_mre
; fill memory from file
mov si,offset ldtab
mov cx,lod_nldt
lf_mre: cmp ldt_flen[si],0 ! je lf_nxt
push cx ! push ldt_start[si] ! push si
call lod_group
pop si ! pop ldt_start[si]
cmp cx,0 ! pop cx
je lf_nxt
;if ccpm
;
; jmp ld_out
;endif
;if mpm
; error in lod_group
; if loading shared code we also
; have to release Shared Code from SCL.
; It will be the top item in the list.
cmp ldt_atr[si],mf_load+mf_code+mf_share
je rm_sh
jmp ld_out
rm_sh: push cx ; remember Err Code
; Remove PD from SCL
pushf ! cli
mov bx,scl
mov ax,p_thread[bx]
mov scl,ax
popf
; Release the memory
push ds ! push bx
mov bx,p_mem[bx] ! push ms_start[bx]
mov ax,ss ! mov ds,ax
mov dx,sp ! mov cx,f_memfree
call osif
pop ax ! pop bx ! pop ds
; Place PD on PUL
pushf ! cli
mov ax,pul
mov pul,bx
mov p_link[bx],ax
popf
pop cx
jmp ld_out
;endif
lf_nxt: add si,ldtlen ! loop lf_mre
; Check for fixup records and do fixups
test lod_lbyte,80h ; hi bit of last byte in cmd header
jz init_base ; is set if fixups
fx_read:
mov ax,lod_fixrec ; get record # of fixups in file
mov bx,1 ; read one record
mov cx,ds
mov dx, offset lod_dma
call drd ; do random read
jcxz fx_read_ok ; 0=ok,CL=0ff if EOF
inc cl ; EOF ?
jnz fx_err ; some read error, not EOF
mov ax,lod_fixrec1 ; make sure one fixup
cmp ax,lod_fixrec ; record was read since cmd header
je fx_err ; said we needed them
jmps init_base
fx_read_ok: ; go look for fixup records
mov bx,offset lod_dma ; BX-> at fixup records
fx_chk:
mov al,fix_grp[bx] ; any more fixups?
test al,al
jz init_base
and al,0fh ; low nibble is target group
call tblsrch ; find target group in load table
mov dx,ldt_start[di] ; DX = target segment, this is
; what we add to the load image
mov al,fix_grp[bx] ; location group is high nibble
mov cl,4 ; put in low nibble of AL
shr al,cl
call tblsrch ; DI = location load table entry
mov ax,ldt_start[di] ; AX = base segment of location
add ax,fix_para[bx] ; add paragraph offset
push es ; absolute paragraph in memory
mov es,ax
xor ax,ax
mov al,fix_offs[bx] ; get offset of fixup location
mov di,ax
add es:[di],dx ; make the fixup (finally)
pop es
add bx,fixlen ; do next fixup
cmp bx,offset lod_dma + dskrecl ; end of this record ?
jne fx_chk
inc lod_fixrec ; read another record
jmps fx_read ; of fixups
tblsrch:
;-------
; Search for group in load table
; entry: AL = group # to match on
; exit: DI = load group entry that matches or
; pop return and exit loader
; BX,DX preserved
mov cx,lod_nldt ; # entries in table
mov di,offset ldtab
srchloop:
cmp al,ldt_type[di]
je srchdn ; found group's entry
add di,ldtlen
loop srchloop
pop ax
jmps fx_err
srchdn:
ret
fx_err:
mov cx,e_fixuprec
jmp ld_out
; init Base Page
; 1st Data Group has Base Page
; if none then first nonshared
; Code Group (8080 model)
init_base:
mov lod_8080,0
mov si,offset ldtab
mov cx,lod_nldt
lb_more:cmp ldt_type[si],2 ! je lb_fnd
add si,ldtlen ! loop lb_more
mov si,offset ldtab
mov cx,lod_nldt
lbc_mre: cmp ldt_type[si],1 ! je lb_fnd80
add si,ldtlen ! loop lbc_mre
mov cx,e_no_cseg ! jmp ld_out
lb_fnd80: mov lod_8080,1
lb_fnd:
push es ! mov es,ldt_start[si]
mov lod_basep,es
sub ax,ax ! mov di,ax
mov cx,05bh/2 ! rep stos ax
mov al,lod_8080 ! mov es:.5,al
mov si,offset ldtab
mov cx,lod_nldt
lbb_mre:cmp ldt_type[si],0 ! je lbb_nxt
mov ax,6 ! mov bl,ldt_type[si]
cmp bl,9 ! jne lbb_nsh
mov bl,1
lbb_nsh: dec bl ! mul bl ! mov bx,ax
;calculate last byte (3 byte value)
; =(paragraphs*16)-1
push cx ! mov dx,ldt_min[si]
push dx ! mov cl,4 ! shl dx,cl
push dx ! dec dx ! mov es:[bx],dx
pop cx ! pop dx ! push cx
mov cl,12 ! shr dx,cl ! pop cx
cmp cx,0 ! jne lbb_nzer
cmp dx,0 ! je lbb_zer
dec dl ! jmps lbb_nzer
lbb_zer: mov es:word ptr [bx],0
lbb_nzer: mov es:2[bx],dl ! pop cx
;put starting paragraph in place
mov ax,ldt_start[si] ! mov es:3[bx],ax
lbb_nxt:add si,ldtlen ! loop lbb_mre
;if 8080 model, copy CS info into DS info
cmp lod_8080,1 ! jne lnot80
push ds ! push es ! pop ds ! mov si,0
mov di,6 ! mov cx,3
rep movsw ! pop ds
lnot80:
mov al,lod_fifty ;initialize base page load disk
mov es:.50H,al
pop es
; init PD ,UDA and LDSTK
mov bx,lod_basep
cmp lod_pd,0 ! jne lip_1
jmp lod_exit
lip_1: mov si,offset ldtab
mov bx,lod_pd
; if 8087 user, flag it
cmp lod_ndp, 0
jz lip_2
cmp lod_ndp, 1
jnz true_87
or p_sflag[bx],psf_em87
jmp lip_2
true_87:
or p_flag[bx],pf_8087
lip_2:
;if it requires suspend mode, flag it
cmp lod_suspnd,0ffh
jnz lip_3
or p_sflag[bx],psf_suspend
lip_3:
mov ax,ldt_start[si]
mov p_uda[bx],ax
; remember where lstk,uda are
mov lod_uda,ax
push es ! mov es,ax
; if 8087 user, use long uda
cmp lod_ndp,0
jz shrt_uda
cmp lod_ndp,1
jz med_uda
add ax,(u8087len/16) ! jmp inter_uda ; full 8087 user, long uda
med_uda: add ax,(em87len/16) ! jmp inter_uda ; uses 87 emulator,medium uda
shrt_uda: add ax,(ulen/16) ; no 8087 activity,short uda
inter_uda: mov lod_lstk,ax
; initialize UDA,LDSTK with zeros
xor di,di ! mov ax,di
; if 8087 user, use long uda
cmp lod_ndp,0
jz shrt_uda1
; if 8087 emulator user, use medium uda
cmp lod_ndp,1
jnz long_uda1
mov cx,(em87len + lstklen)/2 ! jmp inter_uda1
long_uda1:
mov cx,(u8087len + lstklen)/2 ! jmp inter_uda1
shrt_uda1: mov cx,(ulen + lstklen)/2
inter_uda1: rep stos ax ! pop es
; setup p_uda for creat_proc
mov ax,sysdat
sub p_uda[bx],ax
mov p_stat[bx],ps_run
mov p_prior[bx],200
; init load disk/user
mov al,lod_user ! mov p_luser[bx],al
mov al,lod_disk ! mov p_ldsk[bx],al
; init UDA
push es ! mov es,lod_uda
mov u_dma_ofst,(offset bpg_dma)
mov bx,lod_basep
mov u_dma_seg,bx
mov ax,lod_lstk
cmp lod_ndp,0ffh ; if 8087 user, init control word for
jnz not_8087 ; first dispatch's frstor
mov u_8087, controlw ; 03ffh = post-init 8087 state
push ax
mov ax,sysvec87_of
mov u_ivec87_of,ax
mov ax,sysvec87_sg
mov u_ivec87_sg,ax
pop ax
not_8087:
push ds ! mov ds,bx
mov u_initds,bx
mov u_inites,bx
mov u_initss,ax
mov ax,bpg_cseg
cmp ax,0 ! jne h_cs
pop ds ! pop es ! mov cx,e_no_cseg
jmp ld_out
h_cs: mov u_initcs,ax
mov ax,bpg_eseg
cmp ax,0 ! je noes
mov u_inites,ax
noes: mov u_stack_sp,(offset ls_sp)
sub dx,dx ! mov al,bpg_8080
cmp al,0 ! je n80m
mov dx,0100h
n80m:
mov ds,u_initss
mov ls_offset,dx ;set up initial stack
mov ls_flags,0200h ;for a RETF from user
mov ls_roffset,offset user_retf ;process, see SUPIF.SUP
mov ls_rcseg,cs ;module for USER_RETF:
pop ds ! pop es ;code
mov bx,lod_basep
sub cx,cx
lod_exit:
push cx ! push bx
mov cx,f_qwrite ! mov dx,offset mxloadqpb
call osif ! pop bx ! pop cx ! ret
lod_group: ;load a group described in ldtab
;----------
; input: SI = addr of ldtab entry
; output: CX = Error Code
; see if first part already in DMA
mov bx,si
mov ax,lod_indma ;starting paragraph in dma
mov cx,ldt_fstrt[bx]
;AX = starting paragraph in local DMA
;CX = starting paragraph to transfer
;BX -> ldtab entry
cmp cx,ax ! jb rd_first
;starts at or after the pp. in dma
sub cx,ax
cmp cx,8 ! jae rd_first
;starts in the dma
mov dx,8 ! sub dx,cx
;CX = # of pp. to skip
;DX = length of remaining buffer
cmp dx,ldt_flen[bx] ! jbe xfer
mov dx,ldt_flen[bx]
xfer: mov si,offset lod_dma
mov ax,cx ! mov cl,4 ! shl ax,cl
add si,ax
;SI -> beginning of transfer area
; in lod_dma
mov ax,dx ! mov cl,3 ! shl ax,cl
mov cx,ax
;CX = number of words to transfer
xor di,di
push es ! mov es,ldt_start[bx]
rep movsw ! pop es
add ldt_start[bx],dx
sub ldt_flen[bx],dx ! add ldt_fstrt[bx],dx
rd_first:
cmp ldt_flen[bx],0 ! jne rd_1st
sub cx,cx ! ret
rd_1st:
test ldt_fstrt[bx],07h ! jnz rd_indma
cmp ldt_flen[bx],8 ! jae xf_d
rd_indma:
push bx
mov ax,ldt_fstrt[bx]
shr ax,1 ! shr ax,1 ! shr ax,1 ; Record #
mov bx,1 ; read 1 record
mov dx,offset lod_dma ; DMA offset
mov cx,sysdat ; DMA segment
call drd
pop bx
jcxz rd_agn
cmp cx,0ffh ! jne rd_r3
mov cx,0
rd_r3: ret
rd_agn: mov ax,ldt_fstrt[bx]
and ax,0fff8h ; note starting paragraph
mov lod_indma,ax ; in DMA
mov si,bx ! jmp lod_group
; We are at a Sector Boundary with at least
; a sector to place into the user area
xf_d:
push bx
sub dx,dx ; DMA offset
mov cx,ldt_start[bx] ; DMA segment
mov ax,ldt_fstrt[bx]
shr ax,1 ! shr ax,1 ! shr ax,1 ; Record #
mov bx,ldt_flen[bx]
shr bx,1 ! shr bx,1 ! shr bx,1 ; # of records
push bx
call drd
pop ax ! pop bx
jcxz xfer_n
cmp cx,0ffh ! jne rd_r4
xor cx,cx
rd_r4: ret
xfer_n: shl ax,1 ! shl ax,1 ! shl ax,1
add ldt_start[bx],ax
add ldt_fstrt[bx],ax
sub ldt_flen[bx],ax
jmp rd_first
drd:
; input: AX = Record Number
; BX = Number of Sectors
; CX = dma segment
; DX = dma offset
; output: CX = 0 if okay
; CX = 0FFH if End of File
; else Error Code
mov u_dma_ofst,dx
mov u_dma_seg,cx
; read BX sectors starting at Record AX
drd_lp:
push bx ;old # sectors
push ax ;old record #
cmp bx,128 ! jbe drd_r
mov bx,128
; Max Mulit-sector count is 128
drd_r: mov cl,u_mult_cnt
push cx
mov u_mult_cnt,bl
push bx
mov si,offset lod_fcb
mov fcb_r0[si],ax
mov cx,f_freadrdm ! mov dx,si
push es ! call osif ! pop es
pop dx ;multi_cnt used
pop cx ! mov u_mult_cnt,cl
cmp bl,1 ! jbe dr_r2
mov cx,e_bad_read ! mov bx,0ffffh
pop ax ! pop ax ! ret
dr_r2: mov cl,bl
xor bh,bh ! mov di,bx ;save BL for header read check
pop ax ! add ax,dx ;adjust record #
pop bx ! sub bx,dx ;adjust # sectors
shl dx,1 ! shl dx,1 ! shl dx,1
add u_dma_seg,dx
; check for CTRL C. If hit while loading
; last set of characters, this is the place to
; clean things up...
push cx ! push ax ! push bx ! push di
mov cx,f_ciostat ! call osif
pop di ! pop bx ! pop ax ! pop cx
; Now see if CTRL C was hit during the
; the load.
mov si,rlr
test p_flag[si],pf_ctlc ! jz dr_r1
mov cx,e_abort ! mov bx,0ffffh
ret
dr_r1: cmp cl,0 ! je dr_r5
mov cx,0ffh ! ret
dr_r5: cmp bx,0 ! jne dr_r6
xor cx,cx
ret
dr_r6: jmp drd_lp
;if mpm
get_sh:
;------
; Allocate memory for shared code. If memory already
; exists then mark LDTAB entry with FLEN=0 for no load.
; START must be non-zero on success.
;
; input: SI = LDTAB Entry for shared code
; output: CX = 0 on success
; = 0ffffh on failure
; SI is unchanged
;
; 1. Look for PD Name on SCL, making sure
; LDSK and LUSER are the same.
mov bx,(offset scl)-p_thread
gs_nxt: push si
mov dx,offset lod_fcb ! add dx,fcb_name
mov cx,f_findpdname ! call osif
; BX=pd found or 0ffffh
pop si
cmp bx,0ffffh ! je no_sh
mov al,lod_disk
cmp p_ldsk[bx],al ! jne gs_nxt
mov al,lod_user
cmp p_luser[bx],al ! jne gs_nxt
; 2. if (1.) then Share the Memory.
; 2.1 Set FLEN=0
push bx ! push si
call shmem
pop si ! pop bx
cmp cx,0ffffh ! je no_sh
mov ldt_flen[si],0
; Put SHARE PD on end of SCL
; BX = SHARE PD
pushf ! cli
mov di,(offset SCL)-p_thread
sh_nin1: cmp p_thread[di],bx ! je sh_rm ;look for share PD
mov di,p_thread[di] ! jmps sh_nin1
sh_rm: mov ax,p_thread[bx] ;take it off the list
mov p_thread[di],ax
sh_in: cmp p_thread[di],0 ! je sh_end ;look for the end
mov di,p_thread[di] ! jmps sh_in
sh_end: mov p_thread[di],bx ;insert share PD on end
xor cx,cx
mov p_thread[bx],cx
popf ! ret ;success
; 3. if (NOT 1.) allocate memory to NEW PD
no_sh:
; get new PD
pushf ! cli
mov bx,pul
cmp bx,0 ! je sherr
mov ax,p_link[bx] ! mov pul,ax
popf
; alloc memory for code segment
push bx ! push si
mov cx,f_malloc
mov dx,si
call osif
pop si ! pop bx
cmp cx,0 ! jne merr
; initialize new PD name
; BX = New PD
push si
mov si,ldt_pd[si] ;SI=old pd
push si
mov di,bx
add si,p_name ! add di,p_name
mov cx,4
push es ! mov ax,ds ! mov es,ax
rep movsw
pop es ! pop di ! pop si
; DI = old PD, BX=New PD
mov al,lod_user ! mov p_luser[bx],al
mov al,lod_disk ! mov p_ldsk[bx],al
; share w/new PD
mov ax,ldt_start[si]
push bx ! push si ! push ds
push ax ! push bx ! push di
mov ax,ss ! mov ds,ax
mov dx,sp ! mov cx,f_share
call osif
add sp,6
pop ds ! pop si ! pop bx
; put new PD on SCL
pushf ! cli
mov di,(offset SCL)-p_thread
sh_nin: cmp p_thread[di],0 ! je sh_doit
mov di,p_thread[di] ! jmps sh_nin
sh_doit: mov p_thread[di],bx ;insert new share PD
xor cx,cx
mov p_thread[bx],cx
popf ! ret ;success
merr: pushf ! cli
mov ax,pul
mov p_link[bx],ax
mov pul,bx
sherr: popf
mov cx,0ffffh ! ret
shmem:
;-----
;input: SI = LDTAB
; BX = Owner PD
; Load_pd = Requestor
; Have to set LDT_START
;
lea di,(p_mem-ms_link)[bx]
sm_nxt:
mov di,ms_link[di]
cmp di,0 ! je sm_no
mov ax,ms_flags[di]
and ax,mf_share+mf_code+mf_load
cmp ax,mf_share+mf_code+mf_load ! jne sm_nxt
push si ! push ds
push ms_start[di]
push ms_start[di]
push lod_pd
push bx
mov ax,ss ! mov ds,ax
mov dx,sp ! mov cx,f_share
call osif
; This will always work.
pop ax ! pop ax ! pop ax
pop dx ! pop ds ! pop si
mov ldt_start[si],dx
ret
sm_no: mov cx,0ffffh ! ret


View File

@@ -0,0 +1,19 @@
;*****************************************************
;*
;* Load Stack Format
;*
;*****************************************************
lstklen equ 96 * byte
DSEG
org lstklen - 10
ls_sp rw 0
ls_offset rw 1
ls_cseg rw 1
ls_flags rw 1
ls_roffset rw 1
ls_rcseg rw 1


View File

@@ -0,0 +1,303 @@
;*****************************************************
;*
;* Memory Allocation Unit Routines
;*
;* Memory Allocation Unit
;* A Memory Allocation Unit is a contiguous
;* area of memory that is described by a MD.
;* At the beginning of this area is a Suballocation
;* table that describes areas within it that are
;* allocated or free
;*
;* +----+----+----+----+----+----+----+----+
;* MD | Link | Start | Length | Plist |
;* +----+----+----+----+----+----+----+----+
;*
;* Link - Link field for placing MAUs on Linked
;* lists
;* Start - Segment Address of the area covered
;* Length - Length of area
;* Plist - used for a linked list of partitions
;* that are included in this area.
;*
;* Suballocation Table
;* The m_start field is the segment
;* address of the suballocation table (offset 0).
;* The first entry of the table is special and
;* has the following format.
;*
;* +----+----+----+----+----+
;* SAT0 |ents| reserved |
;* +----+----+----+----+----+
;*
;* sat1_ents - number of SAT entries
;* not including SAT0
;* Subsequent entries have the following format
;*
;* +----+----+----+----+----+
;* SAT | Start | Length |nall|
;* +----+----+----+----+----+
;*
;* start - start address of this contiguous
;* piece of memory
;* length - of this piece of memory
;* nall - number of times allocated
;* 0 = free 2 = share
;*
;*****************************************************
sat_start equ word ptr 0
sat_length equ word ptr sat_start + word
sat_nall equ byte ptr sat_length + word
satlen equ sat_nall + byte
;==============
maualloc_entry: ; Alloc from MAU
;==============
; Allocate a piece of memory from an MAU
;
; input: BX = address of MAU
; DX = MPB in u_wrkseg
; mpb_start = abs addr (0 = any)
; mpb_min = minimum necessary
; mpb_max = maximum wanted
;
; output: BX = 0h if success
; 0ffffh if failure
; CX = Error Code
; mpb_start = start address
; mpb_min = mcb_max = length
push es ! mov es,u_wrkseg
; if absolute, see if within MAU
mov si,dx ! mov cx,es:mpb_start[si]
cmp cx,0 ! je maua_rel
mov ax,m_start[bx]
cmp cx,ax ! jb maua_err
add ax,m_length[bx]
cmp cx,ax ! jae maua_err
maua_rel:
mov ds,m_start[bx]
maua_start:
sub bx,bx ! mov dl,bl ;BX->SAT entry
;DL = SAT number
maua_nsat:
inc dl ! add bx,satlen
cmp dl,.0 ! ja maua_err ;?out of table entries?
cmp sat_start[bx],0 ! je maua_err ;?end of used table?
cmp sat_nall[bx],0 ! jne maua_nsat ;?already allocated?
mov cx,es:mpb_start[si]
cmp cx,0 ! je maua_nabs ;?abs req?
mov ax,sat_start[bx]
cmp cx,ax ! jb maua_nsat ;?in this area?
add ax,sat_length[bx]
cmp cx,ax ! jae maua_nsat
cmp cx,sat_start[bx] ! je maua_nabs ;?exact?
sub cx,sat_start[bx]
push si
call mau_split ;make exact
pop si
jmps maua_start
maua_err:
mov bx,0ffffh ! mov cx,e_no_memory
jmps maua_out
maua_nabs:
mov cx,es:mpb_min[si]
mov ax,sat_length[bx]
cmp cx,ax ! ja maua_nsat
mov cx,es:mpb_max[si]
cmp cx,ax ! jae maua_alloc
cmp sat_nall[bx],0 ! je maua_splitit
mov ax,es:mpb_flags[si]
and ax,mf_share ! jz maua_nsat
jmps maua_alloc
maua_splitit: push si ! call mau_split ! pop si
maua_alloc: mov ax,sat_length[bx]
mov es:mpb_min[si],ax
mov es:mpb_max[si],ax
mov ax,sat_start[bx]
mov es:mpb_start[si],ax
inc sat_nall[bx]
call mau_collapse
sub bx,bx ! mov cx,bx
jmps maua_out
maua_out:
mov ds,sysdat
pop es ! ret
;=============
maufree_entry: ; Free from MAU
;=============
; free SAT in given MAU
; input: DX = address of MAF in u_wrkseg
; output: CX = 0 if successful
; CX = 0ffffh on failure
; if CX = 0,
; BX = 0 if MAU still in use
; BX = 0ffffh if MAU is empty
; if CX = 0ffffh
; BX = 0ffffh
push es ! mov es,u_wrkseg
mov si,dx
mov bx,es:maf_mau[si]
mov ds,m_start[bx]
; ES:SI -> MAF
; DS: 0 -> SAT table
sub bx,bx ! mov cx,bx
mov dx,es:maf_sat[si]
; DS:BX -> current SAT
; CX = SAT entry number
; DX = MAF_SAT start
mauf_nsat:
add bx,satlen ! inc cx
cmp cx,.0 ! ja mauf_err
cmp dx,sat_start[bx] ; This SAT?
jne mauf_nsat
cmp dx,es:maf_start[si] ; Freeing all of it?
je mauf_free
cmp sat_nall[bx],1 ; Is it shared?
je mauf_nsha
jmps mauf_out ; Can't split it
; since its shared.
; But, no error
mauf_nsha: mov cx,es:maf_start[si] ; Not shared,
mov ax,sat_start[bx]
add ax,sat_length[bx]
cmp ax,cx ! jb mauf_err ; Within range?
; must split this SAT
; this can only be done if not shared
sub cx,dx ! call mau_split
sub cx,cx ! mov bx,cx ! jmps mauf_c
mauf_free: dec sat_nall[bx]
mauf_c: call mau_collapse ! jmps mauf_out
mauf_err:
mov bx,0ffffh ! mov cx,e_no_memory
mauf_out:
pop es ! mov ds,sysdat
ret
mau_split: ;split SAT into 2
;--------- -----------------
; new SAT element starting at split boundary
; with nall=0, old has same nall.
; input: BX = address of SAT element
; CX = length to split at
; output: BX = address of original SAT element
push bx ! push cx
add bx,satlen ! call mau_insert
cmp cx,0 ! pop cx
pop bx ! jne maus_err ;create hole if error
lea di,satlen[bx] ! mov dx,sat_length[bx]
sub dx,cx ! mov sat_length[di],dx
mov dx,cx ! add dx,sat_start[bx]
mov sat_start[di],dx ! mov sat_nall[di],0
maus_err:
mov sat_length[bx],cx
ret
mau_collapse: ;collapse adjacent unallocated SATs
;------------ -----------------------------------
; collapse adjacent unallocated SATs and holes in table
; if possible
; return: BX = 0 if not empty
; = 0ffffh if empty
; CX = 0
sub bx,bx ! mov cx,bx
mauc_nsat:
inc cx
cmp cx,.0 ! je mauc_mtchk
add bx,satlen ! lea di,satlen[bx]
cmp sat_start[bx],0 ! je mauc_mtchk
cmp sat_start[di],0 ! je mauc_mtchk
cmp sat_nall[bx],0 ! jne mauc_notfree
;this SAT is free
mov ax,sat_start[bx] ! add ax,sat_length[bx]
cmp ax,sat_start[di] ! je mauc_fnohole
;followed by a hole
mov ax,sat_start[di] ! sub ax,sat_start[bx]
mov sat_length[bx],ax
mauc_fnohole:
;free SAT., no hole
cmp sat_nall[di],0 ! jne mauc_nsat
;followed by free SAT
mov ax,sat_length[di]
add sat_length[bx],ax
push bx ! push cx
mov bx,di ! call mau_release
pop cx ! pop bx
sub bx,satlen ! dec cx
jmp mauc_nsat
mauc_notfree:
;allocated SAT
mov ax,sat_start[bx] ! add ax,sat_length[bx]
cmp ax,sat_start[di] ! je mauc_nsat
;followed by a hole
cmp sat_nall[di],0 ! je mauc_nfhole
;next SAT is allocated
push bx ! push cx
mov di,bx ! call mau_insert
pop cx ! pop bx
jmp mauc_nsat
mauc_nfhole: ;Alloc SAT, followed by hole
;next SAT is free
mov ax,sat_start[di] ! sub ax,sat_start[bx]
sub sat_start[di],ax ! add sat_length[di],ax
jmp mauc_nsat
mauc_mtchk:
mov bp,0ffffh
xor cx,cx ! xor bx,bx
mauc_mtn:
inc cx
cmp cx,.0 ! je mauc_out
add bx,satlen
cmp sat_start[bx],0 ! je mauc_out
cmp sat_nall[bx],0 ! je mauc_mtn
mov bp,0
mauc_out:
mov bx,bp ! xor cx,cx ! ret
mau_release:
;-----------
; input: BX = SAT to release
push es ! mov ax,ds ! mov es,ax
mov ax,satlen
mul byte ptr .0
push ax ! mov cx,ax ! sub cx,bx
mov di,bx ! add bx,satlen
mov si,bx ! rep movs al,al
pop bx ! mov sat_length[bx],0
mov sat_start[bx],0
mov sat_nall[bx],0
pop es ! ret
mau_insert:
;----------
; input: BX = SAT to place new SAT in front
; output: CX = 0 if successful
mov ax,satlen ! mul byte ptr .0
mov si,ax ! mov cx,0ffffh
cmp sat_start[si],0 ! jne maui_r
mov cx,si ! sub cx,bx
dec si ! lea di,satlen[si]
push es ! push ds ! pop es
std ! rep movsb ! cld
pop es ! sub cx,cx
mov sat_start[bx],cx
mov sat_length[bx],cx
mov sat_nall[bx],cl
maui_r: ret


View File

@@ -0,0 +1,30 @@
include cpyright.def
;*****************************************************
;*
;* MP/M-86 Memory Management Module
;*
;*****************************************************
eject ! include system.def
eject ! include modfunc.def
eject ! include pd.def
eject ! include qd.def
eject ! include err.def
eject ! include mem.def
eject ! include mpb.def
eject ! include uda.def
eject ! include memif.mem
eject ! include cpmmem.mem
eject ! include memory.mem
eject ! include share.mem
eject ! include mau.mem
eject ! include ml.mem
eject ! include util.mem
eject ! include patch.cod
eject ! include uda.fmt
eject ! include lstk.fmt
eject ! include sysdat.dat
eject ! include data.bdo
eject ! end


View File

@@ -0,0 +1,480 @@
;*****************************************************
;*
;* 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 | length | flags | mau |
;* +----+----+----+----+----+----+----+----+----+----+
;*
;* link link field for p_mem list
;* start starting paragraph of memory segment
;* length length in paragraphs 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.
;
; 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 ;save UDA
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 ;ES=UDA
cmp ax,rlr ! je mall_pdv1
push ax ! push bx
push dx ! push di
mov bx,offset thrd_spb ;ok to call sync on
mov cx,f_sync ;thread after sync-ing
call osif ;on memory
pop di ! pop dx
pop bx ! pop ax
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 cx,e_active_pd
push bx ; save MD addr
mov bx,offset thrd_spb
mov cx,f_unsync
call osif
pop bx ; restore MD addr
jmp mall_err
mall_pdver:
push ax ! push bx
push dx ! push di
mov bx,offset thrd_spb
mov cx,f_unsync
call osif
pop di ! pop dx
pop bx ! pop ax
; verify MIN <= MAX
mall_pdv1:
push es ! mov es,u_wrkseg
mov cx,es:mpb_min[di]
cmp cx,es:mpb_max[di]
jbe mpb_ok
mov es:mpb_max[di],cx
mpb_ok:
; Make sure total allocation <= MMP
mov si,ax ! add si,(p_mem - ms_link)
sub cx,cx ! push si
max_chk_nxt:
mov si,ms_link[si]
cmp si,0 ! je max_chk_done
add cx,ms_length[si]
jmps max_chk_nxt
max_chk_done:
pop si ! mov ax,mmp
sub ax,cx
cmp ax,0 ! jne not_zero
no_min: pop es
mall_nomem: mov cx,e_no_memory
mall_err: call freemd ; Free the Memory Descriptor
mov bx,0ffffh ! ret ; CX=Error Code set previously
not_zero:
cmp ax,es:mpb_min[di] ! jb no_min
cmp ax,es:mpb_max[di] ! jae max_ok
mov es:mpb_max[di],ax
max_ok:
; initialize local variables
push di ! mov di,offset beststart
mov cx,11 ! sub ax,ax
mov es,sysdat
rep stosw ! pop di
sub cx,cx
pop es
; try to allocate memory
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]
call mall_try_mau
pop si ! pop bx ! pop dx
; Plus DI=MAU address
cmp cx,0 ! pop cx ! jne mall_next
; exact allocation
; 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 osif
mov ds,sysdat
;BX=MAU, (New MD,MPB on stack)
jcxz mall_ml0
pop dx ! pop bx
jmp mall_linkit
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
sub si,si
call mall_try_mau
pop dx ! pop bx
;DI=MAU, BX=New MD, DX=MPB in u_wrkseg
mall_linkit:
;BX -> MD
;DX -> MPB in u_wrkseg
cmp beststart,0 ! jne yesmem
;if ccpm
; jmp mall_nomem
;endif
;if mpm
; We couldn't find any memory ...
; lets take something off the SCL
pushf ! cli
mov di,scl
cmp di,0 ! jne take_one_off
; No where else to try, giveup.
popf ! jmp mall_nomem
; take first SHARE PD off SCL
take_one_off:
mov ax,p_thread[di]
mov scl,ax
popf
; Free its memory
; We can assume only one memory segment
push bx ! push dx
mov bx,p_mem[di]
push di ! push ds
push di ! push ms_start[bx]
push ss ! pop ds
mov dx,sp ! mov cx,f_memfree
call osif
pop ax ! pop ax
pop ds ! pop di
; There should be no error.
; Put SHARE PD on PUL
pushf ! cli
mov ax,pul
mov p_link[di],ax
mov pul,di
popf
; Let's assume we just released a partition
; and try the ML Alloc again.
pop dx ! pop bx
jmp mall_ml
;endif
; We have memory ...
yesmem:
push es ! mov es,u_wrkseg
mov di,dx
mov ax,beststart
mov es:mpb_start[di],ax
mov ms_start[bx],ax
mov ax,bestlen
mov es:mpb_min[di],ax
mov es:mpb_max[di],ax
mov ms_length[bx],ax
mov ax,es:mpb_flags[di]
mov ms_flags[bx],ax
mov si,bestsi
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
mov di,bestmau
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
; SI = MS Root that MAU came from
; output: CX = 0, found exact allocation
; else, exact not found
; save root,mau
mov currsi,si
mov currmau,bx
; copy user's MPB into local MPB
push dx ! push ds ! push es
mov ds,u_wrkseg
mov es,sysdat
mov si,dx ! mov di,offset currmpb
mov cx,5 ! rep movsw
pop es ! pop ds
mov dx,offset currmpb
mov cx,f_maualloc ! call osif
pop di
jcxz chkbest
ret
chkbest:
push es ! mov es,u_wrkseg
mov si,offset currmpb
mov ax,mpb_max[si]
sub cx,cx
cmp ax,es:mpb_max[di]
pop es
jz replacebest
mov cx,3 ! mov bx,currmau
mov di,si
cmp ax,bestlen ! jbe freeworst
replacebest:
mov di,offset beststart
mov bx,bestmau
call freeworst
mov si,offset currmpb
mov ax,mpb_start[si] ! mov beststart,ax
mov ax,mpb_max[si] ! mov bestlen,ax
mov ax,currmau ! mov bestmau,ax
mov ax,currsi ! mov bestsi,ax
savret: ret
freeworst: ; DI->Start, CX=Return Code, BX=MAU
cmp word ptr [di],0 ! je savret
; free worst memory
push cx ! push ds
push word ptr [di] ! push word ptr [di]
push bx ! push ss ! pop ds
mov dx,sp ! mov cx,f_maufree
call osif
; if MAU empty, free MAU
cmp cx,0 ! jne mflret
cmp bx,0ffffh ! jne mflret
pop bx ! pop ax ! pop ax ! pop ds
; take off MAL
; BX = MAU address
mov ax,bx ! mov bx,(offset mal)-m_link
mfl1: mov si,bx ! mov bx,m_link[si]
cmp bx,ax ! jne mfl1
push ax
mov ax,m_link[bx] ! mov m_link[si],ax
pop bx
; Replace into MFL
mov cx,f_mlfree
mov dx,bx ! mov bx,offset mfl
call osif ! pop cx ! ret
mflret: pop bx ! pop ax ! pop ax
pop ds ! pop cx ! 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_g1
mfree_chkpd:
push bx ! push dx
mov bx,offset thrd_spb
mov cx,f_sync
call osif
pop dx ! pop bx
mov si,(offset thrdrt)-p_thread
mfree_nxtpd:
mov si,p_thread[si]
cmp si,0 ! je mfree_gotpd
cmp si,bx ! jne mfree_nxtpd
cmp si,rlr ! je mfree_gotpd
mov bx,offset thrd_spb
mov cx,f_unsync
call osif
mov bx,0ffffh
mov cx,e_active_pd
ret
mfree_gotpd:
push bx ! push dx
mov bx,offset thrd_spb
mov cx,f_unsync
call osif
pop dx ! pop bx
mfree_g1:
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 osif
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_err
cmp dx,ms_start[si] ! je mfree_off
;decrease length
sub dx,ms_start[si]
mov ms_length[si],dx
mfree_r:
jmps mfree_exit
;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,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 osif


View File

@@ -0,0 +1,223 @@
;*****************************************************
;*
;* Memory List Functions
;*
;*****************************************************
;=============
mlalloc_entry: ; Alloc from Mem List
;=============
; Create a MAU from a Memory List. Memory List is a
; linked list of MDs in memory order (low first). It
; is assumed that units in the Memory List are paragraphs
; input: DX = address of MPB in u_wrkseg
; BX = ML root in SYSDAT
; output: BX = address of MAU
; = 0ffffh if error
; CX = Error Code
mov si,dx
sub ax,ax ! mov cx,ax ! mov dx,0ffffh
; AX = MD w/best score
; DX = best score
; CX = # partitions used
; SI -> MPB in u_wrkseg
push ax ! push cx
mla_nmd:cmp m_link[bx],0 ! je mla_found
push bx ! push dx ! push si
call mla_value
pop si ! pop dx ! pop bx
cmp cx,dx ! jae mla_next
mov dx,cx ! pop cx ! mov cx,ax
pop ax ! mov ax,bx
push ax ! push cx
cmp dx,0 ! je mla_found
mla_next: mov bx,m_link[bx]
jmps mla_nmd
mla_found:
pop cx ! pop ax
cmp ax,0 ! je mla_err
mov bx,ax ! mov ax,cx
jmp mla_makemau
mla_err:
mov bx,0ffffh ! mov cx,e_no_memory
mla_out:ret
mla_value:
;---------
; input: BX = ML element Root
; SI = MPB in u_wrkseg
; output: CX = value (0=perfect,0ffffh=no fit)
; AX = # of elements
xor bp,bp ; Func 129 repair, FMB, 1/20/84
push es ! mov es,u_wrkseg
sub ax,ax ! mov dx,0
; AX = # of partitions
; DX = total length so far
mov di,m_link[bx]
cmp di,0 ! je mlav_err
; we have a list
cmp es:mpb_start[si],0 ! je mlav_next
;an absolute request
mov cx,m_start[di] ! add cx,(2*satlen)
cmp es:mpb_start[si],cx ! jb mlav_err
;it starts after our start
add cx,m_length[di] ! sub cx,(2*satlen)
cmp es:mpb_start[si],cx ! jae mlav_err
; Func 129 repair, FMB, 1/20/84
mov bp,1 ; On an absolute request, the
inc ax ; current available length within
mov dx,cx ; the partition was not calculated
sub dx, es:mpb_start[si] ; correctly.
mov bx,di ;
mov di, m_link[bx] ;
;this list satisfies ABS requirement
mlav_next: mov cx,es:mpb_max[si]
cmp cx,dx ! jb mlav_chk
mlav_add: cmp ax,0 ! je mlav_ad1
push ax
mov ax,m_start[bx]
add ax,m_length[bx]
cmp ax,m_start[di] ! pop ax ! je mlav_ad1
jmps mlav_chkmin
mlav_ad1: inc ax ! add dx,m_length[di]
mov bx,di ! mov di,m_link[bx]
cmp di,0 ! jne mlav_next
mlav_chkmin: mov cx,es:mpb_min[si]
add cx,(2*satlen)
cmp cx,dx ! jbe mlav_calc
mlav_err: mov cx,0ffffh ! sub ax,ax
pop es ! ret
mlav_chk:
cmp bp,1 ! je mlav_calc ; Func 129 repair, FMB, 1/20/84
add cx,(2*satlen)
cmp cx,dx ! ja mlav_add
mlav_calc: ; HERE IS WHERE WE GIVE THIS SET A VALUE.
; IT CAN SATIFY THE REQUEST.
; ALGORITHM:
; #partitions = #partitions + 1 if next
; to contiquous memory
; value = (abs(max-length) SHR 4) +
; ((#partitions-1) SHL 2)
; idea is that 1K = 1 paritition to avoid
; gobbling all of our small partitions.
; we deal with 256 byte memory units so we
; won't overflow a word.
; AX = # partitions
; DX = memory size
push ax ! dec ax
mov cl,2
shl ax,cl
mov cx,es:mpb_max[si]
add cx,(2*satlen)
; If MAX memory is FFFF, SAT adjustment
; wraps around so force FFFF.
cmp cx,(2*satlen) ! jae mlav_added
mov cx,0ffffH
mlav_added:
cmp cx,dx ! jbe mlav_ab
xchg dx,cx
mlav_ab: sub dx,cx ! mov cl,4 ! shr dx,cl
add dx,ax ! mov cx,dx
pop ax ! pop es ! ret
mla_makemau:
;-----------
; input: BX = address of ML element Root
; AX = number of elements
; output: BX = MAU address
cmp ax,1 ! jg mlam_getmd
mov si,m_link[bx] ! mov cx,m_link[si]
mov m_link[bx],cx ! mov bx,si
sub cx,cx ! mov m_plist[bx],cx
mov m_link[bx],cx
jmp mla_initmau
mlam_getmd:
push ax ! push bx
call getmd
mov di,bx ! pop bx ! pop ax
jcxz mlam_gotmd
sub bx,bx ! ret
mlam_gotmd:
mov m_link[di],0 ! mov m_length[di],0
mov si,m_link[bx] ! mov m_plist[di],si
mov cx,m_start[si] ! mov m_start[di],cx
mlam_next:
mov cx,m_length[si] ! add m_length[di],cx
dec ax ! cmp ax,0 ! je mlam_nomore
mov si,m_link[si] ! jmps mlam_next
mlam_nomore:
push bx
mov bx,m_link[si]
mov m_link[si],0
pop si ! mov m_link[si],bx
mov bx,di ! sub cx,cx ! ;jmp mla_initmau
mla_initmau:
;----------
; input: BX = address of MAU
; output: BX = address of MAU
; CX = 0
mov dx,m_start[bx] ! mov cx,m_length[bx]
push cx ! push es ! mov es,dx ! sub ax,ax
mov di,ax ! mov cx,((32*satlen)/2)
rep stos ax ! pop es
pop cx ! mov ds,dx
mov byte ptr .0,31
sub cx,(2*satlen) ! add dx,(2*satlen)
mov si,satlen ! mov sat_start[si],dx
mov sat_length[si],cx ! mov sat_nall[si],0
mov ds,sysdat
sub cx,cx ! ret
;============
mlfree_entry: ; Free from Mem List
;============
; input: DX = MAU address
; BX = ML Root
mov si,dx
cmp m_plist[si],0 ! je mlf_freeone
mov di,si
mov si,m_plist[si]
mlf_nmd: cmp si,0 ! je mlf_endfree
push m_link[si] ! push bx ! push di
call ml_insert
pop di ! pop bx ! pop si ! jmps mlf_nmd
mlf_endfree:
mov bx,di ! call freemd
jmps mlf_exit
mlf_freeone:
call ml_insert
mlf_exit:
sub bx,bx ! mov cx,bx ! ret
ml_insert:
;---------
; input: SI = address of MD to insert
; BX = ML Root
mov di,m_link[bx]
cmp di,0 ! je mli_ins
mov ax,m_start[di]
cmp ax,m_start[si] ! ja mli_ins
mov bx,di ! jmps ml_insert
mli_ins:mov ax,m_link[bx] ! mov m_link[bx],si
mov m_link[si],ax
ret


View File

@@ -0,0 +1,155 @@
;*****************************************************
;*
;* Parse Filename Function
;*
;*****************************************************
;========= =========================
parse_ent: ; Parse filename into FCB
;========= =========================
; input: DX -> PCB in u_wrkseg
; output: BX = 0ffffh on error
; = 0 on last name in string
; = offset of delimiter following name
; CX = Error Code
;
; PCB: +----+----+----+----+
; | NAMEADR | FCBADR |
; +----+----+----+----+
;
; NAMEADR = offset of String to parse
; FCBADR = offset of FCB in u_wrkseg
;
; Parsed FCB:
; 0 => drive, 0=default, 1=A, 2=B, ...
; 1- 8 => name, converted to upper case,
; padded w/blanks
; 9-11 => type, converted to upper case,
; padded w/blanks
; 12-15 => set to zero
; 16-23 => password, convered to upper case,
; padded w/blanks
; 24-25 => address of password field in 'filename',
; set to zero if password length=0
; 26 => length of password (0-8)
; 27-31 => left as is
mov ax,u_wrkseg
push ds ! mov ds,ax ;DS->u_wrkseg
push es ! mov es,ax ;ES->u_wrkseg for string ops
mov bx,dx ! mov si,pcb_flnmptr[bx] ;SI->nxt char in parse string
mov bx,pcb_fcbptr[bx] ;BX -> FCB
call fcbi ! call debl ;init FCB, deblank parse str
mov bp,e_badfname ;BAD FILENAME
;BP=error code if error
call delim ! jnz prs1 ;chk 1st char
jmp pfn_endp
prs1: mov ch,al ! inc si ! mov al,[si] ;see if Disk spec
cmp al,':' ! jne prs2
mov bp,e_illdisk ;drive specified
mov al,ch ! sub al,'A' ! jc pfn_err ;see if legal
cmp al,16 ! jge pfn_err
inc al ! mov fcb_dr[bx],al ;good drv, set fcb_dr field
mov bp,e_badfname
inc si ! call delim ! jnz prs3 ;check nxt char
cmp al,'.' ! je pfn_err ;hit delim
cmp al,':' ! je pfn_err ; see if legal
cmp al,';' ! je pfn_err
jmp prs3
prs2: dec si ;use default disk
prs3: ;parse filename
mov di,bx ! lea bx,fcb_name[di]
mov ch,8 ! call setfld ;fill in FCB
cmp ch,0 ! jne prs4
call delim ! jz prs4 ;see if more than 8 chars
pfn_err: mov cx,bp
mov bx,0ffffh ! pop es ! pop ds ! ret
prs4: cmp al,'.' ! jnz prs5 ;see if filetype
mov bp,e_badftype
mov ch,3 ! lea bx,fcb_type[di]
inc si ! call setfld ;fill in FCB
cmp ch,0 ! jne prs5
call delim ! jz prs5
jmp pfn_err
;parse passwd
prs5:
cmp al,';' ! jnz prs8 ;see if password delim
mov bp,e_ill_passwd
mov ch,8 ! lea bx,fcb_pwd[di]
inc si
mov fcb_pptr[di],si ;pointer to password if any
call setfld ;yes
mov cl,8 ! sub cl,ch
mov fcb_plen[di],cl
cmp cl,0 ! jne prs51
mov fcb_pptr[di],0 ;no password
prs51: cmp ch,0 ! jne prs8
call delim ! jz prs8
jmp pfn_err
prs8: mov bx,si ! call debl ;see if more to parse
call delim ! jnz pfn_out ;if yes,exit
mov bx,si
cmp al,0 ! je pfn_endp
cmp al,cr ! jne pfn_out
pfn_endp: mov bx,0 ;NOPE
pfn_out:sub cx,cx ! pop es ! pop ds ! ret ;exit
setfld: ; fill in a field until end of field or delim
;------
pop dx ! call delim ! push dx
jz setret
cmp al,'*' ! jnz setfld1
mov byte ptr [bx],'?'
inc bx ! dec ch ! jnz setfld
jmp setfld2
setfld1: mov [bx],al ! inc bx ! dec ch
setfld2: inc si ! cmp ch,0 ! jne setfld
setret: ret
delim: ; see if char is delim, if not UPPER it, err if illegal
;-----
; input: SI -> next char in parse string
; output: 'z' flag on if delimiter found
; character converted to UPPER if 'a'-'z'
; AL = converted char
mov cl,ndelims ! mov al,[si] ;See if Delimiter
push di ! mov di,offset delims ;look at delim string
delnxt: cmp cl,0 ! je no_del ;if end of delims,not delim
cmp cs:[di],al ! je delret ;if delim, ret w/ z set
dec cl ! inc di ! jmps delnxt ;try next delim
no_del: cmp al,' ' ! ja del_up ;not delim, check graphic
pop di ! pop bx ! mov cx,e_badfname ;not graphic, err
jmp pfn_err ;go directly out, bypass ret
del_up: cmp al,'a' ! jb delret ;if below 'a', no high bit,ret
cmp al,'z' ! ja del_noup ;if above 'z',
and al,05fh ;make 'a'-'z' UPPER CASE
del_noup: and al,07fh ;strip high bit
delret: pop di ! ret
delims db 0,tab,cr,'.:;=,/[]<> '
ndelims equ (offset $)-(offset delims)
debl: ;strip leading blanks
;-------
; input: SI -> parse string
; output: SI -> first non-blank or tab char
cmp byte ptr [si],' ' ! je blnk
cmp byte ptr [si],tab ! je blnk
ret
blnk: inc si ! jmps debl
fcbi: ; Initialize FCB
;-------
mov di,bx ! sub ax,ax
sub cx,cx ! stosb ; 0 =0
mov al,' ' ! mov cl,11 ! rep stosb ; 1-11=' '
mov al,0 ! mov cl,2 ! rep stosw ;12-15=0
mov al,' ' ! mov cl,8 ! rep stosb ;16-23=' '
mov al,0 ! mov cl,3 ! rep stosb ;24-26=0
ret


View File

@@ -0,0 +1,41 @@
;*****************************************************
;*
;* PATCH AREA -- 128 bytes long
;*
;*****************************************************
patch:
nop ! nop ! nop ! nop ! nop ! nop ;00-0f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;10-1f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;20-2f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;30-3f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;40-4f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;50-5f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;60-6f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop
nop ! nop ! nop ! nop ! nop ! nop ;70-7f
nop ! nop ! nop ! nop ! nop ! nop
nop ! nop ! nop ! nop


View File

@@ -0,0 +1,250 @@
;*****************************************************
;*
;* 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 ;removed for network, 1/5/84 FMB
; 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
;set up p_userdisp for callf in dispatcher
mov word ptr p_userdisp[si],offset def_emultr
mov word ptr p_userdisp+2[si],cs
;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


View File

@@ -0,0 +1,456 @@
;*****************************************************
;*
;* Queue Routines
;*
;*****************************************************
; Each queue system entry point is mutually exclusive
; of the other queue system entry points.
; All the routines called in QUE2.RTM are
; subroutines of the entry points in QUE1.RTM and
; thus are called only when the process has ownership
; of the q system.
; If a process is already in the queue system another process
; will wait until the first process calls Q_UNSYNC.
; This allows us to keep interrupts on while using shared variables.
; To protect against terminating and potentially losing a QD,
; a message or neglecting to wake up a DQing or NQing
; process; a "no abort region" is entered whenever
; we obtain the queue system. In addition if we assign
; the queue system to a DQing or NQing process, the new owner
; of the q system is forced into a "no abort region". This
; makes the environment of the waking NQing or DQing process appear
; as if it never went to sleep.
; A note for the uninitiated: DQing is short for "Decoding from a Queue"
; or reading from a queue. NQing is short for "eNcoding to a Queue"
; or writing to a queue.
;=========== =======================
makeq_entry: ; Create a System Queue
;=========== =======================
; input : U_WRKSEG:DX = address of QD to create
; output: BX = 0 if okay , 0ffffh if error
; CX = error Code
call q_sync ;obtain q system, BX,DX preserved
call getqdaddr ;get QD and q buffer
jcxz qm_gotqd
jmp qm_err
qm_gotqd: ;DI->QD in SYSDAT
;make sure this queue doesn't
;already exist
qm_chk:
push es ;save UDA
mov es,sysdat
mov si,(offset qlr)-q_link
qm_nxt:
mov si,q_link[si] ;go down QLR to see if QD already
test si,si ! jz qm_go ;exists
push di ! push si ;save new QD and QLR ptr
mov cx,qnamsiz/2
add di,q_name ;ES:DI->QPB.NAME
add si,q_name ;DS:SI->QPB.NAME
repe cmpsw
pop si ! pop di ;restore QLR ptr and new QD
jne qm_nxt ;no match try next QD
pop es ;names match, restore UDA
call remqd ;QD pointed to by DS:DI
mov cx,e_q_inuse
jmps qm_err
qm_go: ;no match - alright to make this q
pop es ;ES=UDA
xor dx,dx ;initialize the QD
mov q_dq[di],dx
mov q_nq[di],dx
mov q_msgcnt[di],dx
mov q_msgout[di],dx
mov ax,qlr ;put QD on QLR
mov q_link[di],ax
mov qlr,di
xor bx,bx ;return success
jmps qm_ret
qm_err:
mov bx,0ffffh
qm_ret:
jmp q_unsync ;release q system; BX,CX preserved
;=========== ======================
openq_entry: ; Find an active Queue
;=========== ======================
; input: U_WRKSEG:DX = address of QPB
;
; output: sets QPB.QADDR to QD offset in SYSDAT
; BX = 0 if okay, 0ffffh if not
; CX = error Code
call q_sync ;obtain q system; BX,DX preserved
push es ;save UDA
mov es,u_wrkseg
mov si,(offset qlr)-q_link
mov di,dx ;ES:DI->QPB
qo_nqd:
mov si,q_link[si] ;go down QLR until QD name
test si,si ! jnz qo_cmp ;matches QPB name or end of QLR
pop es ;ES=UDA
mov cx,e_no_queue ;found end of QLR - can't open
jmps qo_err
qo_cmp:
push di ! push si ;compare names
mov cx,qnamsiz/2
add si,q_name ;DS:SI->QD.NAME
add di,qpb_name ;ES:DI->QPB.NAME
repe cmpsw
pop si ! pop di ;restore QD,QPB
jne qo_nqd ;try next QD if no match
test q_flags[si],qf_hide ;names match
jz noprot ;check for protection:
mov bx,rlr ;must be system process to
test p_flag[bx],pf_sys ;open q with QF_HIDE set
jnz noprot
pop es ;ES=UDA
mov cx,e_q_protected ;QF_HIDE and not SYS PD
jmps qo_err
noprot:
mov es:qpb_qaddr[di],si ;write the QD offset into
pop es ;ES=UDA
xor bx,bx ;the QPB_QADDR field
jmps qo_ret ;to open the q
qo_err: ;CX=error code
mov bx,0ffffh
qo_ret:
call q_unsync ;release q system; BX,CX preserved
ret
;============= =======================
deleteq_entry: ; Delete a System Queue
;============= =======================
; Takes QD off the QLR and place it in the QUL
; input: U_WRKSEG:DX = offset of QPB
; output: BX = 0 if ok, 0ffffh if error
; CX = error code
mov ax,es ;save UDA
mov es,u_wrkseg ;get QD address from user's
mov di,dx ;QPB
mov di,es:qpb_qaddr[di] ;DS:DI->QD (unverified)
mov es,ax ;ES=UDA
;Check for KEEP, SYS Flags
;DS:DI->QD
test q_flags[di],qf_keep
jnz qd_err1
test q_flags[di],qf_hide
jz qd_ok1
mov bx,rlr ;if hide flag then
test p_flag[bx],pf_sys ;SYS flag must be on in PD
jnz qd_ok1
qd_err1: mov cx,e_q_protected
mov bx,0ffffh
ret
qd_ok1:
push di ;DI->QD
call q_sync ;obtain q system; BX,DX preserved
pop di
mov ax,q_dq[di] ;if any process is NQing or
mov dx,q_nq[di] ;DQing we can't delete
or dx,ax ! mov cx,e_q_inuse
jnz qd_err2
mov bx,(offset qlr)-q_link
qd_nqd: ;look for QD on QLR
mov si,q_link[bx] ;DI=QD to delete
test si,si ! jz qd_noq
cmp si,di ! je qd_found
mov bx,si ! jmps qd_nqd ;try next queue
qd_found:
mov ax,q_link[di] ;found the queue, remove
mov q_link[bx],ax ;it from QLR
call remqd
xor bx,bx ;return success
jmps qd_ret
qd_noq:
mov cx,e_no_queue
qd_err2:
mov bx,0ffffh
qd_ret:
jmp q_unsync ;release q system
;ret ;BX,CX preserved
;=========== ============
readq_entry: ; Read Queue
;=========== ============
xor al,al ! jmps readq
;============
creadq_entry: ; Conditional Read Queue
;============
mov al,0ffh
; jmps readq
readq: ; Read message from queue
;----- -------------------------
; If no buffer is available the process
; making an unconditional READQ is placed into the DQ list.
;
; input: U_WRKSEG:DX = QPB
; AL = 0 if unconditional
; <> 0 if not
; output: BX = 0 if okay
; 0ffffh if error
; CX = Error Code
push ax ;save cond code
call q_sync ;get q system; BX,DX preserved
call queverify ;is the QPB valid ?
pop ax ;AL=cond code
mov si,dx ;U_WRKSEG:SI->QPB
jcxz qr_ver ;CX=0 QPB is ok
jmp qr_err ;CX=error code from
qr_ver: ;queverify
push es ;save UDA
mov es,u_wrkseg ;ES:SI->QPB
mov bx,es:qpb_qaddr[si] ;BX->QD
cmp q_msgcnt[bx],0 ;is there a msg to read ?
jne qr_readit
qr_wait:
pop es ;ES=UDA
test al,al ! jz qr_wait1 ;conditional read if AL <> 0
mov cx,e_q_empty
jmps qr_err
qr_wait1: ;ES=UDA
push bx ! push si ;QD, QPB
lea dx,q_dq[bx] ;DX=addr of DQ List
mov bl,ps_dq ;sleep status=DQ
call q_wait ;wait for a DQ
;we now own the q system
;and cannot be aborted
pop si ! pop bx ;QPB, QD
push es ;save UDA
mov es,u_wrkseg
qr_readit:
mov di,es:qpb_buffptr[si] ;ES:[DI]->user's queue buffer
mov cx,q_msglen[bx] ;ES=U_WRKSEG
test cx,cx ! jnz qr_lmsg ;check message length
xor ax,ax
test q_flags[bx],qf_mx ;msglen=0, check for MX q
jz qr_end
mov ax,rlr ;its a MX queue
mov q_buf[bx],ax ;BUF = PD addr of owner
xor ax,ax
jmps qr_end
qr_lmsg: ;msglen > 0
mov ax,q_msgout[bx] ! push ax ;MSGOUT is # of message to read
mul cx ! add ax,q_buf[bx] ;compute its start in buffer
mov si,ax
rep movsb ;move to QPB buffer
pop ax ! inc ax ;set MSGOUT to next message
cmp ax,q_nmsgs[bx] ;circular buffers, so
jne qr_end ;check for wrap around
xor ax,ax
qr_end:
pop es ;ES=UDA
mov q_msgout[bx],ax
dec q_msgcnt[bx]
lea dx,q_nq[bx]
call q_assign_sync ;give the queue system to
;first NQing process if any,
call q_unsync ;release q system if we still
;own it, exit no abort region
xor bx,bx ;indicate success
ret
qr_err:
call q_unsync ;release q system, exit no abort
;region, BX,CX preserved
mov bx,0ffffh ;indicate error
ret
;============ =============
writeq_entry: ; Write Queue
;============ =============
xor al,al ! jmps writeq
;============= =========================
cwriteq_entry: ; conditional Write Queue
;============= =========================
mov al,0ffh
;jmps writeq
writeq: ; Write message to queue
;------ ------------------------
; If no buffer is available when making an unconditional
; WRITEQ call, the calling process is placed into the NQ list.
;
; input: U_WRKSEG:DX = QPB
; AL = 0 if unconditional
; <> 0 if not
; output: BX = 0 if okay
; 0ffffh if error
; CX = Error Code
push ax ;save cond code
call q_sync ;get queue system
;BX,DX preserved
call queverify ;is the QPB valid ?
pop ax ;AL = cond code
mov di,dx ;U_WRKSEG:DI->QPB
jcxz qw_ver ;CX=0 QPB is ok
jmp qw_err ;CX=error code from
qw_ver: ;queverify
push es ;save UDA
mov es,u_wrkseg ;ES:DI->QPB
mov bx,es:qpb_qaddr[di] ;BX->QD
mov cx,q_msgcnt[bx]
cmp cx,q_nmsgs[bx] ;is there a buffer to write ?
jne qw_writeit
qw_wait:
pop es ;ES=UDA
test al,al ! jz qw_wait1 ;conditional read if AL <> 0
mov cx,e_q_full
jmps qw_err
qw_wait1: ;ES=UDA
push bx ! push di ;save QD, QPB
lea dx,q_nq[bx] ;DX=addr of NQ List
mov bl,ps_nq ;sleep status=NQ
call q_wait ;sleep on NQ List
;q system is assigned to us,
;we are in no abort region
;by DQing process that woke us
pop di ! pop bx ;QPB,QD
push es ;save UDA
mov es,u_wrkseg
qw_writeit:
mov si,es:qpb_buffptr[di] ;U_WRKSEG:[SI]->user's queue buffer
mov cx,q_msglen[bx] ;ES=U_WRKSEG
test cx,cx ! jnz qw_lmsg ;check message length
test q_flags[bx],qf_mx ;msglen=0, check for MX q
jz qw_end
xor ax,ax
mov q_buf[bx],ax ;its a MX queue
jmps qw_end ;BUF = 0
qw_lmsg: ;msglen > 0
mov ax,q_msgout[bx]
add ax,q_msgcnt[bx] ;AX = # of message to write
cmp ax,q_nmsgs[bx] ;check for wrap around
jb qw_move
sub ax,q_nmsgs[bx]
qw_move:
mul cx ! add ax,q_buf[bx] ;compute its start in buffer
mov di,ax ;DI offset of new msg in buffer
mov ax,ds ! mov dx,es
mov es,ax ! mov ds,dx ;ES=SYSDAT, DS=U_WRKSEG
rep movsb ;move to QPB buffer
mov ax,es ! mov ds,ax ;DS=SYSDAT
qw_end:
pop es ;ES=UDA
inc q_msgcnt[bx] ;one more message in the queue
lea dx,q_dq[bx] ;wake DQing process if any
call q_assign_sync
call q_unsync ;release q system if we still
xor bx,bx ;own it, exit no abort region
ret ;BX=0: success
qw_err:
call q_unsync ;release q system; exit no abort
;region BX,CX preserved
mov bx,0ffffh ;indicate error
ret
q_wait: ;wait on DQ or NQ list
;------
; entry: DX = list to wait on
; BL = sleep status
; calling process owns queue system through
; a call to q_sync
; Queue message or buffer space is not available.
; Give up queue system and sleep on DQ or NQ list, but
; do not allow any other process to read or write to a queue
; until we get on the sleep list.
pushf ! cli ;keep abort spec from running ...
push bx ! push dx ;save sleep status, list address
call q_unsync ;does not go to dispatcher, we can be
pop dx ! pop bx ;aborted once on sleep list
call sleep_entry ;go to dispatcher
popf ;come back after q_assign call
ret ;Q_ASSIGN: wakes us up when resource
;is ready
q_sync: ;obtain ownership of q system
;------
; entry: interrupts should be on
; ES=UDA
; exit: we own the queue system for make,open,read,write,delete
; queue operations, interrupts unchanged
; BX,DX preserved - usually entry parameters
push bx ! push dx
call no_abort_entry ;we cannot abort while in the queue system
mov bx,offset q_spb
call sync_entry
pop dx ! pop bx
ret
q_unsync: ;release the queue system
;-------- ;to other processes
; entry: interrupts can be or off
; exit: interrupts unchanged,
; have not gone to dispatcher,
; BX,CX preserved - usually return codes
push bx ! push cx
mov bx,offset q_spb
call unsync_entry ;wait for queue system
call ok_abort_entry ;allow calling PD to be terminated
pop cx ! pop bx
ret
q_assign_sync:
;-------------
; entry: DX = address of DQ or NQ list to give the queue
; exit: none
; Assign is used so a process is forced to read or write
; after DQing or NQing. Otherwise an awakening DQing or NQing
; process could be deleted, leaving a message or buffer space
; available with other processes still DQing or NQing.
; This message or buffer space would never be reclaimed.
; To prevent this situation, the waking DQing or NQing process
; is kept from aborting and assigned the QSPB. Note
; it is ok for a process to be aborted while it is on the NQ or
; DQ list before this routine is called.
pushf ! cli ;keep abort spec from terminating
mov bx,dx ;waking process
mov dx,[bx] ;first process on list
test dx,dx ;is there a process to wake?
jz qa_ret
push bx ;save list root
call no_abort_spec_entry ;can not abort while in queue
pop dx ;system
popf ;interrupts are ok now -
mov bx,offset q_spb ;present owner and next owner
jmp assign_sync_entry ;have TEMPKEEP on
qa_ret:
popf
ret


View File

@@ -0,0 +1,225 @@
;****************************************************************
;* *
;* Queue system subroutines: Q System must be owned *
;* before calling any of the following routines *
;* *
;****************************************************************
queverify: ; check QLR for existence of QD address
;--------- ---------------------------------------
; entry: U_WRKSEG:DX = offset of QPB
; exit: CX = 0 if queue is found
; CX = E_NO_QUEUE error code, if not
; BX=SI=QD offset
; ES,DX preserved
push es ;save UDA
mov es,u_wrkseg
mov bx,dx ;ES:BX->QPB
mov bx,es:qpb_qaddr[bx] ;get QD from user's QPB
pop es ;restore UDA
lea si,qlr-q_link
qv_nxt:
mov si,q_link[si] ;SI addresses of valid QDs
test si,si ! jz qv_nqf
cmp bx,si ! jne qv_nxt
xor cx,cx ! ret ;BX=SI=QD offset, return success
qv_nqf:
mov cx,e_no_queue ;couldn't find the queue
ret
getqdaddr:
;----------
; entry: DX = offset of QD in U_WRKSEG
; exit: DI = offset of QD in SYSDAT
;
; If QD address is within SYSDAT use it.
; Else get a QD from QDUL and set QF_TABLE flag.
; If Q_NMSGS=0 in QD then return error.
; If 0 length buffer needed, zero the Q_BUF field.
; If buffer space is within SYSDAT use it. Else get buffer
; from QMAU. Return the QD address within SYSDAT.
push dx ;save QD offset
mov bx,qdlen
call sysdat_chk
jcxz g_qul ;CX=0 if not within SYSDAT
mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG
mov bx,ds
sub ax,bx ;from SYSDAT
mov cl,4 ! shl ax,cl ;make into # of bytes
pop di ;DI=QD in U_WRKSEG
add di,ax ;make QD relative to SYSDAT
jmps g_qd
g_qul:
mov di,qul ;get QD from QUL
test di,di ;DI=unused QD
jnz g_gotqd
pop dx
mov cx,e_no_qd ;no QD available
ret
g_gotqd:
mov ax,q_link[di]
mov qul,ax
pop si ;SI=QD in U_WRKSEG
push di ;save SYSDAT QD
mov cx,qdlen/2
; ES=UDA, DS=SYSDAT
mov ax,ds
mov ds,u_wrkseg ; DS:SI = QD in U_WRKSEG
push es ! mov es,ax ; ES:DI = QD in SYSDAT
rep movsw ; copy QD into QD in SYSDAT
mov ax,es ! mov ds,ax
pop es ; ES=UDA, DS=SYSDAT
pop di ; SYSDAT:DI -> New QD
or q_flags[di],qf_table ; Set "from table" flag
g_qd: ;DI=QD in SYSDAT
xor cx,cx ;CX=0
cmp q_nmsgs[di],cx ;must have one or more msgs
jne g_buflen ;or illegal queue
mov cx,e_no_qbuf
jmps g_qdfree
g_buflen: ;if MX or buffer length is zero
test q_flags[di],qf_mx ;0 Q_BUF field and return
jnz g_mx ;CX=0 to indicate success
cmp q_msglen[di],cx
jne g_getbuf
g_mx:
mov q_buf[di],cx
ret
g_getbuf: ;non 0 length buffer needed
cmp q_buf[di],0 ;is there a buffer specified?
je g_buf
mov ax,q_msglen[di] ;yes make sure it fits in SYSDAT
mul q_nmsgs[di] ;AX=needed buffer space
mov bx,ax
mov dx,q_buf[di]
call sysdat_chk
jcxz g_buf ;CX=0 not within SYSDAT
mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG
mov bx,ds
sub ax,bx ;from SYSDAT
mov cl,4 ! shl ax,cl ;make into # of bytes
add q_buf[di],ax ;make buffer relative to SYSDAT
xor cx,cx ;indicate success
ret
g_buf: ;allocate buffer space to queue
call qspace
jcxz g_ret
mov cx,e_no_qbuf ;no buffer space
g_qdfree:
mov ax,qul ;error return QD to QUL
mov q_link[di],ax
mov qul,di ;CX = error code
g_ret:
ret
sysdat_chk:
;----------
; entry: DX = offset of data structure to check
; relative to U_WRKSEG
; BX = length of data structure
; exit: CX <> 0 if within SYSDAT
; or wrap around
; CX = 0 if not within SYSDAT
; SI,DI preserved
; Check data structure for being within SYSDAT
; Also check that data structure doesn't wrap
; around at 64K, or 1 megabyte.
add dx,bx ;find end of data structure
jc sc_no ;check for 64K wrap around
add dx,0fh
mov cl,4 ;round up to next paragraph
shr dx,cl ;1st paragraph after struct relative
add dx,u_wrkseg ;to U_WRKSEG
jc sc_no ;next paragraph after struct
;check for 1 MB wrap around
mov ax,sysdat
cmp dx,ax ;check for below SYSDAT
jb sc_no
add ax,1000h ;check for above SYSDAT
cmp ax,endseg ;must be within 64k and ENDSEG
jb sc_end ;(use the smaller of the 2)
mov ax,endseg
sc_end:
cmp dx,ax ;DX=next paragraph,
ja sc_no
mov cl,1 ;indicate within SYSDAT
ret
sc_no:
xor cx,cx
ret
qspace:
;------
; entry: DI = QD address
; exit: CX = 0 if ok else error code
; DI preserved
; Allocate buffer space for QD
; The QMAU describes the Memory Allocation Unit
; for the queues. QMAU is set up by GENCCPM or GENSYS.
mov ax,q_msglen[di] ;compute size of buffer
mul q_nmsgs[di] ;AX=size of request
xor cx,cx
push cx ! push cx ! push ax ;call MALLOC
push ax ! push cx ;with MPB on stack
mov dx,sp ! mov ax,ss
mov ds,ax
mov bx,offset qmau
push di ;save QD
mov cx,f_maualloc ;go through OSIF to
call osif ;get U_WRKSEG=SS
pop di ;DI=QD
mov ds,sysdat
cmp cx,0 ! jne qspace_ret
mov bp,sp
mov ax,mpb_start[bp]
mov q_buf[di],ax ;address of buffer
qspace_ret:
add sp,10 ;pop MPB from stack
ret
remqd:
;-----
; Place QD on queue unused list
; entry: DS:DI = QD address
; exit: none
mov ax,q_flags[di]
and ax,qf_table ! jz rqd_exit
mov ax,qul ! mov q_link[di],ax
mov qul,di
jmps qrelease
rqd_exit:
ret
qrelease:
;--------
; entry: DI = QD address
; exit : none
;
; Release buffer space for QD.
; If the released space is ajacent to another
; free area, they are joined in the SAT table.
; The QMAU describes the Memory Allocation Unit
; for the queues. QMAU is set up by GENCCPM or GENSYS.
mov ax,q_buf[di]
mov cx,offset qmau
push ax ! push ax ! push cx ;MFPB on stack
mov cx,f_maufree
mov dx,sp ! mov ax,ss ! mov ds,ax
call osif
add sp,6 ;pop MFPB from stack
mov ds,cs:sysdat ;DS=SYSDAT
ret


View File

@@ -0,0 +1,80 @@
;**********************************************************
;*
;* Call Resident System Procedure
;*
;**********************************************************
cpb_name equ word ptr 0
cpb_param equ word ptr cpb_name + qnamsiz
;=======
rpl_ent: ; Call Resident Procedure Library
;=======
; input: DX = CPB address in u_wrkseg
; output: BX = return from RPL (also u_retseg)
; 1 if error
; CX = error code
;
; The stack is used like this:
;
; stack bottom ------------------------- higher memory
; 26 | starting DS (sysdat)|
; 24 | starting ES (uda) |
; 22 | seg of rpl_ret: |
; 20 | offset of rpl_ret: |
; 18 | seg of the RPL |
; 16 | offset or RPL |<-------
; 14 | Q /\ | |
; 12 | P || | |
; 10 | | || | |
; 8 | B qname | |
; 6 | L buffptr |------>|
; 4 | O nmsgs |
; 2 | C qaddr |
; 0 | K flgs & net |<------SP
; stack top ------------------------- lower memory
push ds ! push es
mov ds,u_wrkseg ; save ds
mov si,dx
push cs ; rpl_ret segment
mov ax,offset rpl_ret ! push ax ; rpl_ret offset
sub ax,ax ! push ax ! push ax ; QPB buffer
mov di,sp ; DI -> buffer
push (cpb_name+6)[si] ; qpb_name
push (cpb_name+4)[si]
push (cpb_name+2)[si]
push cpb_name[si]
mov si,cpb_param[si] ; SI=param
push di ; qpb_buffer address
inc ax ! push ax ; qpb_nmsgs
dec ax ! push ax ! push ax ; qpb_addr,flg,net
mov dx,sp ! mov di,dx
mov ax,ss ! mov ds,ax
mov cx,f_qopen
push si ! push di ! call osif
pop di ! pop si
cmp cx,0 ! jne rpl_err
mov bx,qpb_qaddr[di]
push ds ! mov ds,sysdat
test q_flags[bx],qf_rpl ! pop ds
jz rpl_err
mov cx,f_qread ! mov dx,di
push si ! call osif ! pop si
cmp cx,0 ! jne rpl_err
add sp,16
mov dx,si
mov ds,u_wrkseg
mov es,u_retseg
retf
rpl_ret: mov ax,es
pop es ! pop ds
mov u_retseg,ax
ret
rpl_err:
add sp,24
pop es ! pop ds
mov bx,1 ! mov cx,e_no_queue
ret


View File

@@ -0,0 +1,40 @@
include cpyright.def
;*****************************************************
;*
;* RTM - MP/M-86 or CCP/M Real Time Monitor
;*
;*****************************************************
eject ! include system.def
eject ! include modfunc.def
eject ! include modtab.def
eject ! include xioscb.def
eject ! include flg.def
eject ! include mem.def
eject ! include mpb.def
eject ! include pd.def
eject ! include err.def
eject ! include qd.def
eject ! include sync.def
eject ! include cmdh.def
eject ! include apb.def
eject ! include vccb.def
eject ! include uda.def
eject ! include s8087.lib
eject ! include rtmif.rtm
eject ! include sysent.rtm
eject ! include proc.rtm
eject ! include dsptch.rtm
eject ! include flag.rtm
eject ! include que1.rtm
eject ! include que2.rtm
eject ! include findpd.rtm
eject ! include abort.rtm
eject ! include patch.cod
eject ! include vec.fmt
eject ! include uda.fmt
eject ! include sysdat.dat
eject ! include data.bdo
eject ! include xiosdat.fmt ;SUP 5 - DH - 14APR82
eject ! end


View File

@@ -0,0 +1,96 @@
;*****************************************************
;*
;* Concurrent CP/M-86 RTM Interface Routines
;*
;*****************************************************
cseg
org 0
jmp init ;RTM initialization
jmp entry ;RTM entry point
sysdat dw 0 ;SYSDAT segment
supervisor equ offset $
rw 2 ;SUP entry point
org 0ch
dev_ver db 6 ;development system data version
;set in sysdat.fmt
db 'COPYRIGHT (C) 1982,1983,1984'
db ' DIGITAL RESEARCH '
db 'XXXX-0000-'
serial db '654321'
;==== ===========================
init: ; RTM module Initialization
;==== ===========================
mov bx,(offset dispatcher) ;init interrupt pdisp
mov word ptr [bx],offset fdisp
mov word ptr 2[bx],cs
mov bx,(offset rtm_pdisp) ;init intermodule pdisp
mov word ptr [bx],offset farpdisp
mov word ptr 2[bx],cs
mov bx,rlr ;init the init process's userdisp vec
mov word ptr p_userdisp[bx],offset def_emultr
mov word ptr p_userdisp + 2[bx],cs
retf
;*****************************************************
;*
;* RTM Function Table
;*
;*****************************************************
org ((offset $)+1) AND 0fffeh ;Word Boundary
function dw sysreset_entry ;0
dw poll_entry ;1
dw flag_wait_entry ;2
dw flag_set_entry ;3
dw makeq_entry ;4
dw openq_entry ;5
dw deleteq_entry ;6
dw readq_entry ;7
dw creadq_entry ;8-conditional readq
dw writeq_entry ;9
dw cwriteq_entry ;10-conditional writeq
dw delay_entry ;11
dw dispatch_entry ;12
dw terminate_entry ;13
dw creat_proc_entry;14
dw set_prior_entry ;15
dw pd_entry ;16-get PD address
dw abort_spec_entry;17-abort process
dw sleep_entry ;18
dw wakeup_entry ;19
dw findpdname_entry;20
dw sync_entry ;21
dw unsync_entry ;22
dw no_abort_entry ;23
dw ok_abort_entry ;24
dw no_abort_spec_entry ;25
; dw flagalloc ;26
;===== =================
entry: ; RTM Entry Point
;===== =================
xor ch,ch ! shl cx,1 ! mov si,cx
call cs:function[si]
rtm_ret:retf
;==== ================
osif: ; O.S. Interface
;==== ================
callf cs:dword ptr .supervisor ! ret
;====== ================
xiosif: ; XIOS Interface
;====== ================
mov si,mod_entry
callf dword ptr xiosmod[si] ! ret


View File

@@ -0,0 +1,94 @@
pagesize 45
; *****************************
; * Codemacros for 8087 *
; * numeric data processor: *
; ***************************
;
; stack references:
st equ 0 ; stack top (= register 0)
st0 equ 0 ; register 0
st1 equ 1 ; register 1
st2 equ 2 ; register 2
st3 equ 3 ; register 3
st4 equ 4 ; register 4
st5 equ 5 ; register 5
st6 equ 6 ; register 6
st7 equ 7 ; register 7
;
;
codemacro FRSTOR src:M
db 9bh
segfix src
db 0ddh
modrm 4,src
endm
codemacro FSTCW dst:Mw
db 9bh
segfix dst
db 0d9h
modrm 7,dst
endm
codemacro FDISI
db 9bh
dw 0e1dbh
endm
codemacro FSAVE dst:M
segfix dst
db 0ddh
modrm 6,dst
endm
codemacro FNINIT
dw 0e3dbh
endm
codemacro FNDISI
dw 0e1dbh
endm
codemacro FNSTCW dst:Mw
segfix dst
db 0d9h
modrm 7,dst
endm
codemacro FNSTSW dst:Mw
segfix dst
db 0ddh
modrm 7,dst
endm
codemacro FNCLEX
dw 0e2dbh
endm
codemacro FNSAVE dst:M
db 0ddh
modrm 6,dst
endm
codemacro FNSTENV dst:M
segfix dst
db 0d9h
modrm 6,dst
endm
codemacro FLDENV src:M
db 9bh
segfix src
db 0d9h
modrm 4,src
endm
codemacro FNOP
db 9bh
dw 0d0ddh
endm
FWAIT equ WAIT


View File

@@ -0,0 +1,71 @@
;*****************************************************
;*
;* Shared Memory Routines
;*
;*****************************************************
;===========
share_entry: ; share memory
;===========
; input: DX->SPB in u_wrkseg
;
; +-----+-----+-----+-----+-----+-----+
; SPB | OPD | RPD | START |
; +-----+-----+-----+-----+-----+-----+
;
; Obtain new MD
push dx ! call getmd ! pop dx
jcxz se_c
jmp se_err2
se_c: mov bp,bx ; BP = New MD
push ds ! mov ds,u_wrkseg
mov di,dx ! mov bx,spb_opd[di] ; BX = Owner PD
mov si,spb_rpd[di] ; SI = Requestor PD
mov dx,spb_start[di] ; DX = start paragraph
pop ds
cmp bx,0 ! jne se_r
mov bx,rlr
se_r: cmp si,0 ! jne se_s
mov si,rlr
se_s: cmp si,bx ! je se_ge
lea di,(p_mem-ms_link)[bx]
se_go: mov di,ms_link[di]
cmp di,0 ! je se_err
cmp ms_start[di],dx ! jne se_go
; DI = Owner MS to share
; SI = Requestor PD
; DX = Start
; BP = New MD
mov bx,bp
mov ms_start[bx],dx
mov ax,ms_length[di] ! mov ms_length[bx],ax
mov ax,ms_flags[di] ! mov ms_flags[bx],ax
mov ax,ms_mau[di] ! mov ms_mau[bx],ax
mov di,bx ! mov bx,ax
push ds ! mov ds,m_start[bx]
sub bx,bx ! mov cl,.0
se_n: cmp cl,0 ! je se_err1
add bx,satlen ! dec cl
cmp sat_start[bx],dx ! jne se_n
inc sat_nall[bx]
; place new MS on RPD p_mem
pop ds ! lea bx,p_mem[si]
mov dx,ms_mau[di]
se_m: mov si,ms_link[bx]
cmp si,0 ! je se_link
cmp dx,ms_mau[si] ! je se_link
mov bx,si ! jmps se_m
se_link: mov ms_link[di],si
mov ms_link[bx],di
jmps se_ge
se_err1: pop ds ! mov bx,bp ! call freemd
se_err: mov cx,e_no_memory
se_err2: mov bx,0ffffh ! ret
se_ge: sub bx,bx ! mov cx,bx ! ret


View File

@@ -0,0 +1,43 @@
include cpyright.def
;*****************************************************
;*
;* MP/M or CCP/M Supervisor Module
;*
;*****************************************************
eject ! include system.def
eject ! include modfunc.def
eject ! include modtab.def
eject ! include xioscb.def
eject ! include pd.def
eject ! include err.def
eject ! include qd.def
eject ! include fcb.def
eject ! include acb.def
eject ! include enttab.def
eject ! include mem.def
eject ! include mpb.def
eject ! include clicb.def
eject ! include rsp.def
eject ! include pcb.def
eject ! include cmdh.def
eject ! include char.def
eject ! include vccb.def
eject ! include uda.def
eject ! include init.sup
eject ! include supif.sup
eject ! include sysfunc.sup
eject ! include command.sup
eject ! include load.sup
eject ! include parse.sup
eject ! include rpl.sup
eject ! include patch.cod
eject ! include basep.fmt
eject ! include lstk.fmt
eject ! include vec.fmt
eject ! include uda.fmt
eject ! include sysdat.dat
eject ! include data.bdo
eject ! include xiosdat.fmt
eject ! end


View File

@@ -0,0 +1,361 @@
;*****************************************************
;*
;* SUPERVISOR INTERFACE ROUTINES
;*
;*****************************************************
;=========
user_entry:
;=========
; User Entry Point - enter here from a INT 224
;
; REGISTER USAGE
; ENTRY EXIT
; ----- ----
; CL - Function Code AX - Copy of BX
; DX - Param BX - Return
; DS - Seg Addr CX - Error Code
; ES - Segment Return
;
; DS,SI,DI,BP preserved through call
;
; SETUP FOR MPM ENVIRONMENT
; -------------------------
; contents of users stack
; Flags
; CS
; IP <- u_stack_ss,_sp
; DS = Sysdat Segment
; ES -> user_data_area (UDA)
; DX -> function parameter
; u_wrkseg == user's DS
; u_retseg == user's ES
;interrupts are off
;set up MPM,CCPM environment
cld ! mov ax,ds ;AX = user's DS
mov ds,sysdat
mov bx,rlr
mov ds,p_uda[bx] ;DS = UDA segment
mov ds:u_retseg,es ;save user's ES
;U_INSYS is count of times
;through this entry point
cmp ds:u_insys,0 ! jne noswt ;change stacks to UDA stack
;if U_INSYS = 0
;otherwise leave stack alone
;U_WRKSEG where is user's entry DS
;is saved
mov ds:u_wrkseg,ax ;wipe out earlier u_wrkseg
mov ds:u_stack_ss,ss
mov ds:u_stack_sp,sp
mov ax,ds
mov ss,ax ! mov sp,ulen ;stack starts at end of UDA
jmps uecont
noswt:
push ds:u_wrkseg ;save current u_wrkseg on UDA stack
mov ds:u_wrkseg,ax
uecont:
sti
inc ds:u_insys
mov ax,ds ! mov es,ax ;register moves are faster than
mov ds,sysdat ;push and pop, DS=SYSDAT,ES=UDA
push si ! push di ! push bp
mov u_func,cl ;record function number in UDA
xor ch,ch ;call function and do
call netchk ;netwrk chk, returns BX, ES, CX
coret:
pop bp ! pop di ! pop si
mov ax,es ;setup user's environment and return
mov ds,ax ;DS = UDA segment
mov es,ds:u_retseg ;restore ES from entry unless
;function returns a segment value
mov ax,ds:u_wrkseg ;AX = user's entry DS
cli
dec ds:u_insys ! jnz nstk ;switch back to user's stack
;if U_INSYS = 0
push bx ! push ds ! push cx ;See if process should be suspended.
mov ds,sysdat ;Since it's on its way out, it doesn't
mov bx,rlr ;own any critical regions and we can
;put it to sleep until its console is
;switched into the foreground.
mov ax,p_sflag[bx]
test ax,psf_suspend ;is this a suspendable process ?
jz coret1 ;no...
mov es,p_uda[bx] ;Set up ES = UDA
mov al,p_cns[bx]
xor ah,ah ! xor bh,bh ;get vccb's state
mov bx,ccblen ! mul bx
mov bx,ccb ! add bx,ax
mov ax, c_state[bx]
test ax,csm_suspend ;is it to be suspended now ?
jz coret1 ;no...
mov bx,rlr
push dx
mov dx, offset splr ;get suspend list for sleep_entry
mov ud_param,dx
mov cx, f_sleep ;call to RTM to place in list
xor bh,bh
mov bl,ps_ciowait ;user ciowait instead of suspend
call osif ;so the abort code will work
pop dx
coret1:
pop cx ! pop ds ! pop bx
mov ax,ds:u_wrkseg
mov es,ds:u_retseg
coret2:
mov ss,ds:u_stack_ss
mov sp,ds:u_stack_sp
jmps ueout
nstk:
sti
pop ds:u_wrkseg ;restore previous U_WRKSEG if not
;going back to user's stack
ueout: mov ds,ax ;DS = user's entry DS
mov ax,bx ;parameter return BX = AX
inc ax
jz u_err1 ;CX=error code if AX,BX=0FFFFH
xor cx,cx ;CX always 0 if no error
u_err1:
dec ax
iret ;back to user ...
;restore interrupts as they
;were on entry
sysfunc: ; call system function
;------- -----------------------
; entry: if CH <> 0 then CH is module number
; (usually 1:SUP, 2:RTM, 3:MEM, 4:CIO, 5:BDOS)
; network check is bypassed
; if CH = 0 then network check is done
; CL = function #
; DX = arg
; BX = arg
; exit: BX = return value
; ES = segment return value
; CX = error code if BX = 0FFFFH
test ch,ch ! jz netchk ;network or local
mov ax,cx ! jmps localfunc ;in local module
illfunc: ;illegal function number
jmp i_ent
netchk:
; enter here for network check
; check for function numbers represented in function table,
; ENTTAB_TABLE. Table space is saved by making the functions
; contiguous as we check the range.
; The table has entries for functions 0-80, 98-116, 128-164.
; Numbers 70-97, 117-127, 165-255 are not in the table.
; Illegal functions in this table return the error codes
; not implemented (1) or illegal function number (2).
; Function not in the table return the illegal function number
; code.
; To add a new user function modify the files SYSDAT.DAT and
; MODFUNC.DEF as well as the ranges immediately
; below. All of the modules SUP,RTM,MEM,CIO,BDOS,SYSDAT must
; then be reassembled.
if netversion
mov ax,cx
cmp al,80 ! jbe okfunc
sub al,17 ! cmp al,81 ! jb illfunc
cmp al,99 ! jbe okfunc
sub al,11
;
; 3.1M patch for illegal function numbers 117-127
;
cmp al,100 ! jb illfunc ;117 -127 are now 89 -99
cmp al,136 ! ja illfunc
;
; end of 3.1M patch
;
endif
if not netversion
cmp cl,80 ! jbe okfunc
sub cl,17 ! cmp cl,81 ! jb illfunc ;98-116 are now 81-99
cmp cl,99 ! jbe okfunc ;128-164 are now 100-136
sub cl,11
;
; 3.1M patch for illegal functions 117-127
;
cmp cl,100 ! jb illfunc ;117 -127 are now 89 - 99
cmp cl,136 ! ja illfunc
;
; end of 3.1M patch
;
endif
okfunc:
if netversion
shl ax,1
mov si,ax
mov ax,word ptr sysent[si]
test ah,net_bit
jz localfunc
and ah, not net_bit
mov bl,module_map
test bl,netmod_bit
je localfunc
push ax
callf dword ptr .netmod
cmp al,0ffh
pop ax
je localfunc
mov ax,bx
ret
endif
if not netversion
;CL is now 0 - num entries
;- 1 in entry table
mov si,cx ! shl si,1 ;times 2 for entry table
add si,offset sysent ;AH high nibble flags
mov ax,enttab_entry[si] ;AH low nibble module
;AL function number
;within module
test ah,net_bit ! jz localfunc ;not a network function
and ah,not net_bit ;turn off network bit
mov al,module_map
test al,netmod_bit ! je localfunc ;network module is not there
push ax
callf dword ptr .netmod ;call network CL = func
cmp al,true ;if AL=0FFH do func locally
pop ax ;in addition over network
jne localfunc
mov ax,bx ! ret
endif
localfunc: ;not over the network
cmp ah,sup ! je insup ;AH=module, AL=function
mov cl,ah
mov ch,module_map ! shr ch,cl ;does module exist ?
jnc badmod
xor ch,ch ! dec cx ;make module 0 relative
shl cx,1 ! shl cx,1 ! shl cx,1 ;* 8
mov si,cx ! mov cl,al ;func # in CL
callf dword ptr module_table[si]
ret
badmod:
jmp n_imp
insup:
xor ah,ah
shl ax,1 ! mov si,ax ; mov cx,ax
jmp cs:supfunc[si]
;=====
entry: ; Supervisor module entry point
;===== -------------------------------
;
; Arrive here usually on a CALLF using address
; at SYSDAT:4. Note: flag set is handled specially.
;
; entry: if CH <> 0 then CH is module number
; (usually 1:SUP, 2:RTM, 3:MEM, 4:CIO, 5:BDOS)
; network check is bypassed
; if CH = 0 then network check is done;
; CL = function #. If CH = 0 then CL is treated
; as a function number used with an INT 224:
; it is a USER function.
; If CH is not 0 then CL is the function number
; within the module specified by CH.
; The file MODFUNC.DEF contains the equates
; used for accessing functions from within the O.S.
; These functions are INTERNAL functions.
; Note the INTERNAL functions are a superset of
; the USER functions. The equates for USER
; functions in MODFUNC.DEF have a 0 for the high byte
; forcing network checking from this entry point.
; An example: if f_conin (from MODFUNC.DEF) is
; equal to 0001H. A Console output call to this
; entry point thus result in CH = 0, CL = 1.
; DX = arg
; BX = arg
;
; exit: BX = return value
; ES = segment return value
; CX = error code if BX = 0FFFFH
cmp cx,f_flagset ! jne notfs ;flag set is exception:
mov cx,f_inflagset ;do not go over network,
call sysfunc ;make path shorter,
mov ax,bx ;parameter return BX = AX
inc ax ;AX=0FFFFH if error
jz u_err2 ;CX= error code if AX,BX=0FFFFH
xor cx,cx ;CX=0 if no error
u_err2:
dec ax ;set AX back to 0 or 0FFFFH
retf ;DS must equal system
notfs: ;data segment
;mov u_unused,cx ;save 16 bit function number
call osif ! retf
osif: ;point SUP uses to get
;to other modules
push u_wrkseg ;save current u_wrkseg
mov ax,ds
mov u_wrkseg,ax
mov ax,sysdat
mov ds,ax
call sysfunc
mov ax,u_wrkseg
mov ds,ax
pop u_wrkseg
mov ax,bx ;BX,CX are return codes
inc ax ;AX=0FFFFH if error
jz u_err3 ;CX= error code if AX,BX=0FFFFH
xor cx,cx ;CX=0 if no error
u_err3:
dec ax ;set AX back to 0 or 0FFFFH
ret
;=========
user_retf:
;=========
; If a user process does a RETF to terminate,
; the process ends here. The Load function sets up
; the default stack to point here.
mov bx,rlr
and p_flag[bx],not pf_keep+pf_tempkeep+pf_ctlc+pf_sys
mov cx,f_terminate
xor dx,dx
int osint ;make sure the terminate
;succeed by reseting the
;the keep,tempkeep,ctlc,sys flags
;======
xiosif:
;======
callf dword ptr .xiosmod ! ret
;*****************************************************
;*
;* Supervisor function table
;*
;*****************************************************
org ((offset $)+1) AND 0fffeh ;Word Boundary
supfunc dw n_imp ; 0-not implemented
dw i_ent ; 1-illegal function number
dw bver_ent ; 2-(12)get BDOS version
dw cbios_ent ; 3-(50)call bios
dw load_ent ; 4-(59)user load function
dw cli_ent ; 5-(150)CLI
dw rpl_ent ; 6-(151)Call RPL
dw parse_ent ; 7-(152)parse filename
dw sdat_ent ; 8-(154)get sysdat addr
dw tod_ent ; 9-(155)get tod addr
dw load ; 10-load function
dw over_ent ; 11-O.S. version number
dw chain_ent ; 12-(47)Program Chain
dw ser_ent ; 13-(107)return serial
dw cload_ent ; 14-chain load function


View File

@@ -0,0 +1,15 @@
eject ! include cpyright.def
;*****************************************************
;*
;* System Data Area - Initialized Data
;*
;*****************************************************
eject ! include system.def
eject ! include pd.def
eject ! include uda.def
eject ! include qd.def
eject ! include modfunc.def
eject ! include sysdat.dat
eject ! include data.bdo


View File

@@ -0,0 +1,587 @@
;*****************************************************
;*
;* System Data Area
;*
;*****************************************************
CSEG
org 0ch
;dev_ver
db 6 ;development system data version
;SYSDAT.CON has 16 byte code segment
DSEG
org 0
;
;This data is initialized by GENCCPM
;
;Module Table - contains the FAR CALL addresses
; of each module for their initialization
; and entry routines.
;
; +---+---+---+---+---+---+---+---+
; | entry | initialize |
; +---+---+---+---+---+---+---+---+
;
; entry init
; ----- ----
module_table equ dword ptr (offset $)
supmod equ (offset $)
dw 3,0, 0,0 ;SUP
rtmmod equ (offset $)
dw 3,0, 0,0 ;RTM
memmod equ (offset $)
dw 3,0, 0,0 ;MEM
ciomod equ (offset $)
dw 3,0, 0,0 ;CIO
bdosmod equ (offset $)
dw 3,0, 0,0 ;BDOS
xiosmod equ (offset $)
dw 0C03H,0, 0C00H,0 ;XIOS
netmod equ (offset $)
dw 3,0, 0,0 ;NET
dispatcher equ (offset $)
dw 0,0 ;far dispatcher (does IRET)
rtm_pdisp equ (offset $)
dw 0,0 ;far dispatcher (does RETF)
; location in memory of MP/M-86 or CCP/M-86
osseg dw 1008h ;1st parag. of MP/M-86 or CCP/M
rspseg dw 0 ;segment of first RSP
endseg dw 0 ;1st parag. outside of MP/M or CCP/M
module_map db 03fh ;bit map of modules that exist
; in this system. low order bit
; corresponds to 1st module in
; module table. If bit is on,then
; module exists.
; some answers to GENCCPM questions
ncns db 4 ;# system console devices
nlst db 1 ;# system list devices
nccb db 5 ;# character control blocks
nflags db 20h ;# flags
srchdisk db 1 ;system disk
mmp dw 04000h ;Max Memory per process
nslaves db 0 ;Number of network requestors
dayfile db 0 ;if 0ffh,display command info
tempdisk db 1 ;Temporary disk
tickspersec db 60 ;Number of ticks per second
; data lists created by GENCCPM
free_root dw 0 ;locked unused list
ccb dw 0 ;addr. Console Ctrl Blk Table
flags dw 0 ;addr. Flag Table
mdul dw 020h ;Mem descr. Unused List
mfl dw 0 ;Memory Free List
pul dw 014h ;Proc. descr. Unused List
qul dw 020h ;QCB Unused List
;MAU for queue buffer info
qmau dw 0 ;link
dw 0 ;start segment
dw 400h ;length
dw 0 ;plist
;
;This data is initialized at Assembly time
;
rlr dw initpd ;Ready List Root
dlr dw 0 ;Delay List Root
drl dw 0 ;Dispatcher Ready List
plr dw 0 ;Poll List Root
scl dw 0 ;Shared Code List
thrdrt dw initpd ;Process Thread Root
qlr dw mxloadqd;Queue List Root
mal dw 0 ;Memory Alloc List
; Version Information
version dw unknown ;addr. version str in SUP code segment
;set by GENCCPM if CCP/M
if mpm
bvernum dw 01431h ;MPM-86 w/BDOS v3.1
osvernum dw 01431h ;MPM-86 V3.1
endif
if ccpm
bvernum dw 01431h ;CCP/M w/BDOS 3.1
osvernum dw 01421h ;CCP/M V2.1
endif
; Time of Day Structure
tod rw 0
tod_day dw 067EH ;day since 1/1/78 (09 Jul 82)
tod_hr db 12h ;hour of day
tod_min db 00h ;minute of hour
tod_sec db 00h ;second of minute
; info from XIOS
ncondev db 0 ;# console devs in XIOS
nlstdev db 0 ;# character devs in XIOS
nciodev db 0 ;# character i/o devices
; supported by XIOS.
lcb dw 0 ; list control block address
openvec dw 0 ; open file vector
lock_max db 20h ; Max Locked Records/process
open_max db 20h ; Max Open Files/process
owner8087 dw 0 ; no one owns it initially
rw 1 ; RESERVED
cmod db 0ffh ; BDOS Compatibility
ndp8087 rb 1 ; RESERVED
err_intercept dw 0,0 ; BDOS does a callf here
; to print error msgs,
; if second word is <> 0
slr dw offset mem_spb ; Sync List Root
dw 0,0,0 ; RESERVED
db 0 ; RESERVED
xpcns db 0 ; # physical consoles
iofs87 rw 1 ; address of NDP interrupt
iseg87 rw 1 ; vector.
sysvec87_of rw 1 ; system exception handler's
sysvec87_sg rw 1 ; segment and offset.
splr dw 0 ; suspend list root
; SYSENT Table - MP/M-86, CCP/M-86 system function information
; The supervisor calls the appropriate module
; through this table.
;
; Low Byte High Byte
; +----+----+--------+
; |function |flgs|mod|
; +----+----+--------+
;
; flgs - 001h - network intercept
; if on, the network module is called
; first, on return, either the function
; is called or it is considered complete
; depending on the return.
; mod - module number (0-15)
; function- function to call within module
; note: sup function 0 returns not the
; implemented error code to the caller,
; and sup function 1 returns the illegal
; function error code.
; standard CPM-2 functions
; func, module
org ((offset $) + 1) and 0fffeh
sysent db 0, rtm ; 0-system reset
db 0, cio ; 1-conin
db 1, cio ; 2-conout
db 0, sup ; 3-raw conin/aux in
db 0, sup ; 4-raw conout/aux out
db 4, cio or net_bit ; 5-list out
db 5, cio ; 6-raw conio
db 0, sup ; 7-getiobyte
db 0, sup ; 8-setiobyte
db 6, cio ; 9-conwrite
db 7, cio ; 10-conread
db 8, cio ; 11-constat
db 2, sup or net_bit ; 12-get version
db 0, bdos or net_bit ; 13-diskreset
db 1, bdos or net_bit ; 14-diskselect
db 2, bdos or net_bit ; 15-file open
db 3, bdos or net_bit ; 16-file close
db 4, bdos or net_bit ; 17-search first
db 5, bdos or net_bit ; 18-search next
db 6, bdos or net_bit ; 19-file delete
db 7, bdos or net_bit ; 20-file read seq
db 8, bdos or net_bit ; 21-file write seq
db 9, bdos or net_bit ; 22-file make
db 10, bdos or net_bit ; 23-file rename
db 11, bdos or net_bit ; 24-login vector
db 12, bdos ; 25-get def disk
db 13, bdos ; 26-set dma
db 14, bdos or net_bit ; 27-get alloc vector
db 15, bdos or net_bit ; 28-write protect
db 16, bdos or net_bit ; 29-get r/0 vector
db 17, bdos or net_bit ; 30-set file attr.
db 18, bdos or net_bit ; 31-get disk parm block
db 19, bdos ; 32-user code
db 20, bdos or net_bit ; 33-file read random
db 21, bdos or net_bit ; 34-file write random
db 22, bdos or net_bit ; 35-file size
db 23, bdos or net_bit ; 36-set random record
db 24, bdos or net_bit ; 37-reset drive
db 25, bdos or net_bit ; 38-access drive
db 26, bdos or net_bit ; 39-free drive
db 27, bdos or net_bit ; 40-file write random w/zero fill
;CPM-3 extensions
db 0, sup ; 41-Test and Write (NOT IMPLEMENTED)
; Would be BDOS func # 28
db 28, bdos or net_bit ; 42-Lock Record
db 29, bdos or net_bit ; 43-Unlock Record
db 30, bdos ; 44-Set Multi-sector
db 31, bdos or net_bit ; 45-Set Bdos Error Mode
db 32, bdos or net_bit ; 46-Get Disk Free Space
db 12, sup or net_bit ; 47-Chain to Program
; In CP/M-86 BDOS func # 34
db 33, bdos ; 48-Flush Buffers
db 1, sup ; 49-
;CPM-86 extensions
db 3, sup ; 50-call xios
db 34, bdos ; 51-set dma base
db 35, bdos ; 52-get dma
db 0, mem ; 53-get max mem
db 1, mem ; 54-get abs max mem
db 2, mem ; 55-alloc mem
db 3, mem ; 56-alloc abs mem
db 4, mem ; 57-free mem
db 5, mem ; 58-free all mem
db 4, sup or net_bit ; 59-load
db 1, sup ; 60-
db 1, sup ; 61-
db 1, sup ; 62-
db 1, sup ; 63-
;CP/NET functions
db 64, net or net_bit ; 64-network login
db 65, net or net_bit ; 65-network logoff
db 66, net or net_bit ; 66-network send msg
db 67, net or net_bit ; 67-network rcv msg
db 68, net or net_bit ; 68-network status
db 69, net or net_bit ; 69-get network config addr
db 70, net or net_bit ; 70-set Compatibility attributes
db 71, net or net_bit ; 71-get network server config table
db 72, net or net_bit ; 72-set network error mode
db 73, net or net_bit ; 73-attach network
db 74, net or net_bit ; 74-detach network
db 75, net or net_bit ; 75-set message buffer size
db 76, net or net_bit ; 76-get network time and date
db 77, net or net_bit ; 77-get network parameter table
db 1, sup ; 78-unused
db 1, sup ; 79-unused
db 1, sup ; 80-unused
;CP/M-3 extensions
db 36, bdos or net_bit ; 98-Reset Alloc Vector
db 37, bdos or net_bit ; 99-Truncate File
db 38, bdos or net_bit ;100-Set Dir Label
db 39, bdos or net_bit ;101-Return Dir Label
db 40, bdos or net_bit ;102-Read File XFCB
db 41, bdos or net_bit ;103-Write File XFCB
db 42, bdos ;104-Set Date and Time
db 43, bdos ;105-Get Date and Time
db 44, bdos or net_bit ;106-Set Default Password
db 13, sup ;107-Return Serial Number
db 0, sup ;108-(not implemented)
db 25, cio ;109-Get/Set Console Mode
db 26, cio ;110-Get/Set Output Delimiter
db 27, cio ;111-Print Block
db 28, cio or net_bit ;112-List Block
db 1, sup ;113-reserved
db 1, sup ;114-reserved
db 1, sup ;115-reserved
db 45, bdos ;116-Set File_Date_Time
; MP/M functions
db 6, mem ;128-mem req
db 6, mem ;129-(same function as 128)
db 7, mem ;130-mem free
db 1, rtm ;131-poll device
db 2, rtm ;132-flag wait
db 3, rtm ;133-flag set
db 4, rtm or net_bit ;134-queue make
db 5, rtm or net_bit ;135-queue open
db 6, rtm or net_bit ;136-queue delete
db 7, rtm or net_bit ;137-queue read
db 8, rtm or net_bit ;138-cond. queue read
db 9, rtm or net_bit ;139-queue write
db 10, rtm or net_bit ;140-cond. queue write
db 11, rtm ;141-delay
db 12, rtm ;142-dispatch
db 13, rtm ;143-terminate
db 14, rtm or net_bit ;144-create process
db 15, rtm ;145-set priority
db 9, cio ;146-console attach
db 10, cio ;147-console detach
db 11, cio ;148-set def console
db 12, cio ;149-console assign
db 5, sup ;150-CLI
db 6, sup ;151-call RPL
db 7, sup ;152-parse filename
db 13, cio ;153-get def console
db 8, sup ;154-sysdat addr
db 9, sup ;155-time of day
db 16, rtm ;156-get PD addr
db 17, rtm ;157-abort process
; MPM II extensions
db 15, cio or net_bit ;158-attach list
db 16, cio or net_bit ;159-detach list
db 17, cio or net_bit ;160-set list dev
db 18, cio or net_bit ;161-Cond. Attach list
db 19, cio ;162-Cond. Attach Console
db 11, sup or net_bit ;163-MP/M Version Number
db 20, cio or net_bit ;164-get list dev
; Initialized Queues
org ((offset $) + 1) and 0fffeh
mxloadqd dw mxdiskqd
db 0,0
dw qf_keep+qf_mx
db 'MXLoad '
dw 0,1,0,0,1,0,0
mxloadqpb db 0,0
dw mxloadqd,1,0
; db 'MXLoad '
; Data Used by Load Program
org ((offset $) + 1) and 0fffeh
lod_uda dw 0
lod_lstk dw 0
lod_basep dw 0
lod_nldt dw 0
lod_pd dw 0
lod_fcb rs 36
lod_indma dw 0
lod_nrels db 0
lod_chain db 0
lod_user db 0
lod_disk db 0
lod_fifty db 0
lod_8080 db 0
lod_lbyte db 0
lod_fixrec dw 0
lod_ndp db 0
lod_suspnd db 0
lod_fixrec1 dw 0
lod_dma rb dskrecl
ldtab rb ldtabsiz
cli_dma_ofst rw 1
cli_dma_seg rw 1
cli_pflag rw 1
cli_chain rb 1
cli_term rb 1
cli_dma rb dskrecl ;dma buffer
;copy of user's clicb
cli_net rb 1 ;net
cli_ppd rw 1 ;parent PD
cli_cmdtail rb 129 ;command sent
rb 1
cli_fcb rb fcblen+1 ;internal FCB
cli_cuspqpb db 0,0 ;QPB of command
dw 0,0
dw offset cli_ppd
db '$$$$$$$$'
cli_acb db 0,0 ;cns,match
dw 0 ;pd
db '$$$$$$$$' ;name
cli_pcb dw offset cli_cmdtail ;parse
dw offset cli_fcb ;ctl bk
cli_pd dw 0 ;pd of load prog
cli_err dw 0 ;error return
cli_bpage dw 0 ;base page
cli_lddsk db 1 ;load disk
;parent information
cli_cns db 0 ;pd.p_cns save
cli_user db 0 ;pd.p_dsk save
cli_dsk db 0 ;pd.p_user save
cli_err_mode db 0 ;u_error_mode save
cli_dfil db 0 ;dayfile flag
;
;System Initialization Variables
;
initpd dw 0 ;link
dw 0 ;thread
db ps_run ;stat
db 1 ;prior
dw pf_sys+pf_kernal;flag
db 'Init ' ;name
dw unknown ;uda segment
db 0 ;disk
db 0 ;user
db 0,0 ;ldsk,luser
dw 0 ;mem
dw 0 ;dvract
dw 0 ;wait
db 0,0 ;org,net
dw 0 ;parent
db 0 ;cns
db 0 ;abort
db 0,0 ;cin,cout
db 0 ;lst
db 0,0,0 ;sf3,4,5
rb 4 ;reserved
dw 0,0 ;pret,scratch
;User Data Area of Init process
;paragraph aligned
org ((offset $)+0fh) AND 0fff0h
inituda rb ulen
init_tos rw 0
org offset inituda + ud_insys
db 1 ;keep the SUP from doing stack
org offset init_tos ;switches
; RTM data
; is word aligned from init uda
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dsptchtos rw 0
indisp db false ;?currently in dispatch?
intflag db 0 ;if 0, interrupts not enabled -
;not implemented
es_sav dw 0 ;(staying word aligned)
bx_sav dw 0
ax_sav dw 0
; MEM Data
beststart dw 0
bestlen dw 0
bestsi dw 0
bestmau dw 0
currmau dw 0
currsi dw 0
currmpb dw 0,0,0,0,0
; **3.1M**
;
; save area and stack for memory manager local stack switch
;
mem_save_sp dw 0
mem_save_ss dw 0
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch,0cccch
mem_tos rw 0
;
; **3.1M**
;
; SYNC Parameter Blocks
; The MEM ENTRY: point uses the following for
; mutual exclusion and recursion.
mem_cnt db 0 ;how many times a process has recursivly
;called the memory manager
mem_spb dw q_spb ;link Mem Sync Parameter Block
dw 0 ;owner
dw 0 ;wait
dw 0 ;next
; The queue sub-system in the RTM uses the following
; structure for mutual exclusion
q_spb dw cli_spb ;link Queue Sync Parameter Block
dw 0 ;owner
dw 0 ;wait
dw 0 ;next
; The CLI uses the CLI_SPB for mutual exclusion
cli_spb dw thrd_spb;link CLI Sync Parameter Block
dw 0 ;owner
dw 0 ;wait
dw 0 ;next
; When the thread is accessed, the THRD_SPB must be owned
; first.
thrd_spb dw msg_spb ;link Thread Sync Parameter Block
dw 0 ;owner
dw 0 ;wait
dw 0 ;next
; Currently the order in which the SYNCs must be obtained if
; more than one is needed is:
; CLI
; QUEUE ;called by CLI for RSPs
; MEM ;called by make queue
; THREAD ;used from the MEM module
; The SYNCs must be released in reverse order
; MSG_SPB is used by the BDOS to protect the BDOS error message
; buffer. MSG_SPB is in DATA.BDO


View File

@@ -0,0 +1,309 @@
;********************************************************
;* *
;* SYSTEM ENTRY FUNCTIONS *
;* *
;********************************************************
;========== =========================
poll_entry: ; Poll device - DL=device
;========== =========================
mov ax,rlr
mov bx,ax
mov p_wait[bx],dx
mov dx,offset plr
mov bl,ps_poll
jmp sleep_entry
;=========== ===================
delay_entry: ;Delay - DX = ticks
;=========== ===================
mov bx,rlr
mov p_stat[bx],ps_delay
mov u_dparam,dx
xor bx,bx ;return success after coming back into
jmp dsptch ;context from the dispatcher
;=============== ==============
dispatch_entry: ;Call dispatch
;=============== ==============
xor bx,bx ;return success ala DELAY_ENTRY:
jmp pdisp
;=============== ===========================
set_prior_entry: ;Set Priority - DX=priority
;=============== ===========================
mov bx,rlr
mov p_prior[bx],dl
xor bx,bx ;return success ala DELAY_ENTRY:
jmp pdisp
;======== ==================
pd_entry: ;Return addr of PD
;======== ==================
mov u_retseg,ds
mov bx,rlr
ret
;================ ============================
creat_proc_entry: ;Create Process - DX->new PD
;================ ============================
call proc_creat ! jmp pdisp
;=========== ==============================
sleep_entry: ;Put Calling PD on System List
;=========== ==============================
; entry: DX = list root to sleep on
; BL = sleep status passed to the dispatcher in
; the PD.P_WAIT field and becomes the PD.STATUS
; when sleeping
; interrupts are typically off to ensure
; the PD sleeps on the specified list
; before another process runs.
; exit: BX = 0 to indicate success after return from dispatcher
; if entered with interrupts off the process will return
; from the dispatcher with them still off
mov ax,rlr ! mov si,ax
mov ax,dx ! mov u_dparam,ax
mov p_scratch[si],bl
mov p_stat[si],ps_sleep
xor bx,bx
jmp dsptch
;============ ==============================
wakeup_entry: ;wakeup top PD in System List
;============ ==============================
; entry: DX = List Root Address
; exit: first PD on list is the last entry on the DRL
; Puting the process on the end of the DRL allows the
; process to run before equal priority processes waking up
; from flag sets, i.e., interrupts.
; To work, the dispatcher must disable interrupts
; from when the last process on the DRL is placed on the
; RLR to when the process is back in context and
; turns on the interrupt flag.
pushf ! cli
mov bx,dx ! mov si,[bx] ;SI=PD to wake
test si,si ! jz wke_out ;check for a process to wake up
mov ax,p_link[si] ;take PD off list
mov [bx],ax ;set list root to next PD
mov di,offset drl - p_link ;go to the end of DRL
xor ax,ax ;AX=0
wu_drl:
cmp p_link[di],ax
je wu_drlend
mov di,p_link[di] ! jmps wu_drl
wu_drlend:
mov p_link[di],si ;make waking PD last on DRL
mov p_link[si],ax ;0 the end of the DRL
mov p_stat[si],ps_run ;new status
call pdisp
wke_out:
popf ! ret
;========== ========================
sync_entry: ;Obtain mutual exclusion
;========== ========================
; entry: interrupts on or off
; BX = Sync Parameter Block
; exit: ownership of Sync Parameter Block,
; interrupt state unchanged
; Obtain ownership of mutually exclusive section of code
; without using MXqueues. A process only sleeps temporarily
; on a SYNC structure. A process that obtains the
; SYNC must call UNSYNC when finished with the
; protected data structure and before sleeping or
; calling SYNC with on a different SYNC structure.
mov ax,rlr
mov si,ax ;AX=SI calling process
pushf ! cli
xchg ax,sy_owner[bx] ;AX=owner
test ax,ax ;0 nobody owns it
jz s_got_it
cmp ax,si ;do we already own it ?
je s_got_it
mov sy_owner[bx],ax ;restore owner
lea dx,sy_wait[bx] ;list to sleep on
mov bl,ps_sync ;sleep with sync status
call sleep_entry
;awaken with sync ownership
s_got_it:
popf ! ret ;we own the SPB
;============ ==========================
unsync_entry: ;release mutual exlclusion
;============ ==========================
;
; entry: BX = Sync Parameter Block
; exit: SYNC_OWNER changed to the PD in the SY_NEXT
; field if SY_NEXT is non 0. The PD in the SY_NEXT
; must have a 0 P_LINK. If SY_NEXT=0, the SY_OWNER
; field is changed to the first PD on the SY_WAIT
; list. If SY_WAIT is 0, SY_OWNER becomes 0.
mov ax,rlr
cmp ax,sy_owner[bx] ;do we own it ?
jne us_ret
xor ax,ax
pushf ! cli ;no other process can change SYNC or DRL
xchg ax,sy_next[bx] ;0 SY_NEXT field
test ax,ax ;assigned next process ?
jz us_wait
mov si,ax
jmps us_own
us_wait:
mov si,sy_wait[bx] ;give the sync to first waiting process
test si,si ;no waiting PD ?
jz us_zero
mov ax,p_link[si]
mov sy_wait[bx],ax
mov p_link[si],0
us_own:
mov p_stat[si],ps_run
mov ax,drl
mov p_link[si],ax ;put process on DRL
mov drl,si
us_zero:
mov sy_owner[bx],si ;SI=0 or process to now own sync
popf ;allow interrupts
us_ret: ;wait for next dispatch
ret
;================= ============================
assign_sync_entry: ;give away mutual exlclusion
;================= ============================
; interrupts on
; entry:
; BX = Sync Parameter Block
; DX = address of list root, assign
; SPB to first PD on list
; exit: none
;
mov ax,rlr
cmp sy_owner[bx],ax ;check that we own the resource
jne as_ret
mov si,dx ;SI=list root
pushf ! cli ;no other process can run
mov di,[si] ;get first PD from list
test di,di ;test for 0 list
jz as_done
mov ax,p_link[di] ;take PD off list
mov [si],ax
mov p_link[di],0 ;0 link of NEXT PD
;status is still PS_SLEEP.
;if TEMPKEEP is on ABORT_SPEC
;will just turn on CTLC flag.
;if no TEMPKEEP, ABORT_SPEC
;will not find PD on the U_DPARAM
;list and will fail.
mov sy_next[bx],di ;see UN_SYNC_ENTRY
;for use of SYNC_NEXT field
as_done:
popf
as_ret:
ret
;==============
no_abort_entry:
;==============
; Keep the calling process from being aborted by
; using the PF_TEMPKEEP flag.
; Turn on the PF_TEMPKEEP flag and
; increment the P_TKEEPCNT.
; entry: none
; exit: PD fields altered
; interrupt state unaltered
; This code must be exclusive of ABORT_SPEC's testing
; and acting on the PD flags.
mov ax,rlr
mov si,ax
na_spec:
cmp p_tkcnt[si],0
jne na_saved
test p_flag[si],pf_tempkeep
jz na_saved
or p_tkcnt[si],80h ;save orignal TEMPKEEP in MSB
na_saved: ;until rest of O.S. is fixed
or p_flag[si],pf_tempkeep
inc p_tkcnt[si]
ret
;===================
no_abort_spec_entry:
;===================
; Keep the specified process from being aborted by setting
; its TEMPKEEP flag.
; entry: DX=PD address, interrupts off
; exit: PD TEMPKEEP turned on, TKCNT incremented
mov si,dx
jmps na_spec
;==============
ok_abort_entry:
;==============
; Allow the calling process to be aborted if
; the PF_TEMPKEEP flag is keeping it from being aborted.
; P_TKCNT is decremented in the PD, if P_TKCNT
; is = 0 then PF_TEMPKEEP is turned off and PF_CTLC
; flag is tested.
; Interrupts should be turned off if an NO_ABORT_SPEC
; can be performed on a process running this code.
; entry: none
; exit: PD fields altered
mov ax,rlr
mov si,ax
mov al,p_tkcnt[si]
and al,07FH ;high bit is original TEMPKEEP
dec al
jz oa_restore ;assume
dec p_tkcnt[si] ;no borrow from MSB
ret
oa_restore:
if netversion
and p_tkcnt[si],80H ;was TEMPKEEP on originally ?
endif
if not netversion
test p_tkcnt[si],80h
endif
jnz oa_ret ;if it was don't chk CTLC here
;turn off TEMPKEEP
and p_flag[si],not pf_tempkeep
test p_flag[si],pf_ctlc
jz oa_ret
mov dx,0ffffh ;if PF_CTLC is set ok to
if netversion
push si
call terminate_entry ;terminate even if SYS PD,
pop si
endif ;see ABT_CHK in ABORT.RTM
;terminate may fail if
;KEEP was set while
if not netversion
call terminate_entry
endif
oa_ret: ;TEMPKEEP was also set.
mov p_tkcnt[si],0
ret


View File

@@ -0,0 +1,174 @@
;*****************************************************
;*
;* SYSTEM ENTRY FUNCTIONS
;*
;*****************************************************
;===== ==========================
n_imp: ; Function not implemented
;===== ==========================
mov cx,e_not_implemented
mov bx,0ffffh ! ret
;==== =========================
i_ent: ; Illegal System Function
;==== =========================
mov cx,e_bad_entry
mov bx,0ffffh ! ret
;======= ====================
bver_ent: ; Get BDOS Version #
;======= ====================
mov bx,bvernum ! xor cx,cx ! ret
;======= ====================
over_ent: ; Get O.S. Version #
;======= ====================
mov bx,osvernum ! xor cx,cx ! ret
;if mpm
;
;========= ================== ============
;cbios_ent: ; Direct BIOS call MPM 2.x ONLY
;========= ================== ============
;
; mov si,dx
; push ds ! mov ds,u_wrkseg
; mov al,[si] ! mov cx,1[si]
; mov dx,3[si] ! pop ds
; cmp al,1 ! ja goxios ;if BOOT,WBOOT; terminate
; mov cx,f_terminate
; mov dx,0 ! jmp osif
;goxios:
; cmp al,7 ! jbe gx1 ;7=reader input
; cmp al,15 ! je gx1 ;15=list status
; mov bx,0ffffh ! mov cx,e_bad_entry
; ret
;gx1: mov bx,rlr
; cmp al,4 ! ja xlst ;4=console output
; mov dl,p_cns[bx]
; cmp al,4 ! je jxio
; mov cl,dl ! jmps jxio
;
;xlst: cmp al,6 ! je jxio
; cmp al,7 ! je jxio
; mov dl,p_lst[bx]
; cmp al,15 ! jne jxio
; mov cl,dl
;jxio: sub al,2 ! mov ah,0
; jmp xiosif
;endif ;end of MP/M direct BIOS call
;if ccpm ;CCP/M direct BIOS call
;========= ================== =============
cbios_ent: ; Direct BIOS call CCPM 2.x ONLY
;========= ================== =============
; DI = 0 if last call was also func 50.
; DI = 0ffffh if it wasn't
; xor di,di
; cmp u_func,50
; je c_next50
; dec di
c_next50:
; mov u_func,50
mov si,dx
mov bp,ds ;user register for speed
mov ds,u_wrkseg
mov al,[si] ! mov cx,1[si]
mov dx,3[si]
mov ds,bp ;DS=SYSDAT
cmp al,2 ! jne not_consts ;optimize constat
; test di,di ;DI=0 if last call was func 50
; jnz go_cio
; mov si,rlr
; mov bl,ncns ;is it a virtual console ?
; cmp bl,p_cns[si]
; jae go_cio
;get_status:
; mov si,u_conccb ;if it was U_CCB is valid
; xor bx,bx
; cmp c_nchar[si],0
; jnz s_gotchar
; mov bl,c_numchars[si] ;number of chars in VINQ
; jmps s_quick
go_cio:
mov cx,f_ciostat ;doesn't change console mode
call osif
;s_quick:
test bl,bl ! jz x_cs ;returns 1 or 0 (or char count)
;s_gotchar:
mov bx,0ffh ;BIOS returns 0ffh or 0
x_cs:
ret
not_consts:
cmp al,4 ! jne not_conout ;console output
mov dl,cl ;character to send
mov cx,f_rconout
jmp osif
not_conout:
cmp al,1 ! ja goxios
mov cx,f_terminate ;cold or warm boot
mov dx,0 ! jmp osif
goxios:
cmp al,7 ! jbe gx1 ;BIOS 2-7 and 15 are ok
cmp al,15 ! je gx1
mov bx,0ffffh ! mov cx,e_bad_entry
ret
gx1:
cmp al,3 ! jne not_conin ;console input
mov cx,f_rconin
jmp osif ;BIOS return in AL and BL
not_conin:
cmp al,5 ! jne not_listout
mov dl,cl
mov cx,f_lstout
jmp osif
not_listout:
cmp al,6 ! jne not_auxout
mov ax,io_auxout
jmp xiosif
not_auxout:
cmp al,7 ! jne not_auxin
mov ax,io_auxin
jmp xiosif
not_auxin:
mov ax,io_listst ;when we move this to CIO
jmp xiosif ;check for ownership
;endif ;end of CCP/M direct BIOS
;======== ==============================
sdat_ent: ; Ret Addr of System Data Area
;======== ==============================
mov u_retseg,ds
xor bx,bx ! mov cx,bx ! ret
;======= ============================
tod_ent: ; Return current Time of Day
;======= ============================
; copy tod struct into user area
push es ! mov es,u_wrkseg
mov di,dx
mov si,offset tod ! mov cx,todlen
rep movsb
pop es ! xor cx,cx ! mov bx,cx ! ret
;======= ======================
ser_ent: ; Return Serial Number
;======= ======================
; copy serial field into user area
push es ! mov es,u_wrkseg
mov di,dx ! mov si,offset serial
push ds ! mov ax,cs ! mov ds,ax
mov cx,3 ! rep movsw
pop ds ! pop es
xor cx,cx ! mov bx,cx ! ret


View File

@@ -0,0 +1,25 @@
;*****************************************************
;*
;* SYSTEM DEFINITIONS
;*
;*****************************************************
true equ 0ffffh ; value of TRUE
false equ 0 ; value of FALSE
;unknown equ 0 ; value to be filled in
dskrecl equ 128 ; log. disk record len
pnamsiz equ 8 ; size of process name
qnamsiz equ pnamsiz ; size of queue name
;fnamsiz equ pnamsiz ; size of file name
;ftypsiz equ 3 ; size of file type
mpmint equ 224 ; int vec for mpm ent.
;debugint equ mpmint+1 ; int vec for debuggers
ulen equ 0100h ; size of uda
pdlen equ 030h ; size of Process Descriptor
;todlen equ 5 ; size of Time of Day struct
;flag_tick equ 1 ; flag 0 = tick flag
;flag_sec equ 2 ; flag 1 = second flag
;flag_min equ 3 ; flag 2 = minute flag
ldtabsiz equ 0aah ; ldtablen=11, 10 entries


View File

@@ -0,0 +1,48 @@
;*****************************************************
;*
;* TICK Process
;*
;*****************************************************
;======
notick: ;NO ONE ON DELAY LIST
;======
mov bx,rlr ! mov es,p_uda[bx]
mov u_wrkseg,ds
;if mpm ;FIX 6 - DH - 14APR82
; mov al,io_stopclk ! call xiosif
;endif ;FIX 6 - DH - 14APR82
;if ccpm ;FIX 6 - DH - 14APR82
mov tick,false ;FIX 6 - DH - 14APR82
;endif ;FIX 6 - DH - 14APR82
tick_l: ;SOMEONE MAY BE ON DELAY LIST
;------
; flag wait on the TICK flag
mov dx,flag_tick ! mov cx,f_flagwait
int osint
; see if anyone delaying
pushf ! cli
mov bx,dlr
cmp bx,0 ! jz drl_e
; decrement # of ticks to wait
; see if done waiting
dec p_wait[bx] ! jnz n_tck
; our process is done waiting
ede: mov si,p_link[bx] ! mov dlr,si
mov p_stat[bx],ps_run
mov ax,drl ! mov p_link[bx],ax
mov drl,bx
cmp si,0 ! je drl_e
cmp p_wait[si],0 ! jne n_tck
mov bx,si ! jmps ede
n_tck: popf ! jmps tick_l
drl_e:
popf ! jmps notick


View File

@@ -0,0 +1,67 @@
;*****************************************************
;*
;* User Data Area - The User Data Area is an
;* extension of the process descriptor but it
;* travels with the user. It contains info
;* that is needed only while in context.
;*
;* While in the operating system, The Extra
;* Segment register points to the beginning
;* of the User Data Area.
;*
;*****************************************************
;u_dparam equ es:word ptr .000h ; arg to dispatch
; this area overlays part of BDOS
u_dma_ofst equ es:word ptr .002h ; BDOS dma offset
u_dma_seg equ es:word ptr .004h ; BDOS dma segment
u_func equ es:byte ptr .006h ; actual function number
;u_searchl equ es:byte ptr .007h ; BDOS search length
;u_searcha equ es:word ptr .008h ; BDOS search FCB offset
;u_searchabase equ es:word ptr .00Ah ; BDOS search user's segment
;u_dcnt equ es:word ptr .00Ch ; BDOS directory count
;u_dblk equ es:word ptr .00Eh ; BDOS directory block #
u_error_mode equ es:byte ptr .010h ; BDOS error mode
u_mult_cnt equ es:byte ptr .011h ; BDOS multi-sector count
;u_df_password equ es:byte ptr .012h ; BDOS default password
u_pd_cnt equ es:byte ptr .01Ah ; BDOS process count
uda_ovl_len equ 19h
; end of overlay area
;u_in_int equ es:byte ptr .01Bh
;u_sp equ es:word ptr .01Ch ; save register area
;u_ss equ es:word ptr .01Eh
;u_ax equ es:word ptr .020h
;u_bx equ es:word ptr .022h
;u_cx equ es:word ptr .024h
;u_dx equ es:word ptr .026h
;u_di equ es:word ptr .028h
;u_si equ es:word ptr .02Ah
;u_bp equ es:word ptr .02Ch
u_wrkseg equ es:word ptr .02Eh ; curr seg addr of buf
u_retseg equ es:word ptr .030h ; usr ES return
;u_ds_sav equ es:word ptr .032h ;\
;u_stack_sp equ es:word ptr .034h ; usr stack segment
;u_stack_ss equ es:word ptr .036h ; usr stack pointer
;u_ivectors equ es:word ptr .038h ; save int 0-4
;u_es_sav equ es:word ptr .04Ch ; > Used during interrupts
;u_flag_sav equ es:word ptr .04Eh ;/
;u_initcs equ es:word ptr .050h
;u_initds equ es:word ptr .052h
;u_inites equ es:word ptr .054h
;u_initss equ es:word ptr .056h
;u_mpm_ip equ es:word ptr .058h ; MPM vec save
;u_mpm_cs equ es:word ptr .05Ah
;u_debug_ip equ es:word ptr .05Ch ; RTS,Debug Vector Save
;u_debug_cs equ es:word ptr .05Eh
;u_insys equ es:byte ptr .060h ; # times through user_entry
;u_stat_sav equ es:byte ptr .061h
u_conccb equ es:word ptr .062h
;u_lstccb equ es:word ptr .064h
;u_delim equ es:byte ptr .066h
u_ioexerr equ es:byte ptr .067h ;extended IOS error for PCMODE


View File

@@ -0,0 +1,77 @@
;*****************************************************
;*
;* User Data Area - The User Data Area is an
;* extension of the process descriptor but it
;* travels with the user. It contains info
;* that is needed only while in context.
;*
;* While in the operating system, The Extra
;* Segment register points to the beginning
;* of the User Data Area.
;*
;*****************************************************
eseg
org 0
u_dparam rw 1 ; arg to dispatch
; this area overlays part of BDOS
u_dma_ofst rw 1 ; BDOS dma offset
u_dma_seg rw 1 ; BDOS dma segment
u_func rb 1 ; actual function number
u_searchl rb 1 ; BDOS search length
u_searcha rw 1 ; BDOS search FCB offset
u_searchabase rw 1 ; BDOS search user's segment
u_dcnt rw 1 ; BDOS directory count
u_dblk rw 1 ; BDOS directory block #
u_error_mode rb 1 ; BDOS error mode
u_mult_cnt rb 1 ; BDOS multi-sector count
u_df_password rb 8 ; BDOS default password
u_pd_cnt rb 1 ; BDOS process count
uda_ovl_len equ (offset $)-(offset u_dma_ofst)
; end of overlay area
u_in_int rb 1
u_sp rw 1 ; save register area
u_ss rw 1
u_ax rw 1
u_bx rw 1
u_cx rw 1
u_dx rw 1
u_di rw 1
u_si rw 1
u_bp rw 1
u_wrkseg rw 1 ; curr seg addr of buf
u_retseg rw 1 ; usr ES return
u_ds_sav rw 1 ;\
u_stack_sp rw 1 ; usr stack segment
u_stack_ss rw 1 ; usr stack pointer
u_ivectors rw 4 ; save int 0,1
u_ivec87_of rw 1 ; NDP interrupt vector
u_ivec87_sg rw 1 ; for exception handling
u_ivectors2 rw 4 ; save int 3,4
u_es_sav rw 1 ; > Used during interrupts
u_flag_sav rw 1 ;/
u_initcs rw 1
u_initds rw 1
u_inites rw 1
u_initss rw 1
u_os_ip rw 1 ; O.S. vec save
u_os_cs rw 1
u_debug_ip rw 1 ; RTS,Debug Vector Save
u_debug_cs rw 1
u_insys rb 1 ; # times through user_entry
u_stat_sav rb 1 ; used during interrupts
u_conccb rw 1 ; default console's CCB addr
u_lstccb rw 1 ; default list devices CCB addr
u_delim rb 1 ; delimiter for user function 9
u_ioexerr rb 1 ; extended error ret codes for bdos
org ulen
u_8087 rw 47 ; 8087 save area
; see dispatcher, loader and terminate


View File

@@ -0,0 +1,31 @@
;*****************************************************
;*
;* MEM Common Functions
;*
;*****************************************************
getmd: ; get MD from MDUL
;----- ------------------
; output: BX = MD address
; 0 if none found
; CX = Error Code
pushf ! cli
mov cx,e_no_umd ! mov bx,mdul
cmp bx,0 ! je gmd_ret
xor cx,cx
mov si,m_link[bx] ! mov mdul,si
mov m_link[bx],cx ! mov m_start[bx],cx
mov m_length[bx],cx ! mov m_plist[bx],cx
gmd_ret:popf ! ret
freemd: ; put MD on MDUL
;------ ----------------
; input: BX = MD address
pushf ! cli
mov si,mdul ! mov mdul,bx
mov m_link[bx],si ! popf ! ret


View File

@@ -0,0 +1,26 @@
;*****************************************************
;*
;* Interrupt Vectors - to fiddle with the interrupt
;* vectors, set the Data Segment Register to 0
;* and use the following variables.
;*
;*****************************************************
DSEG
i_divide_ip rw 1 ; int 0
i_divide_cs rw 1
i_trace_ip rw 1 ; int 1
i_trace_cs rw 1
i_nomask_ip rw 1 ; int 2
i_nomask_cs rw 1
i_break_ip rw 1 ; int 3
i_break_cs rw 1
i_ovrflw_ip rw 1 ; int 4
i_ovrflw_cs rw 1
i_interrupts rw ((osint-5)*2)
i_os_ip rw 1
i_os_cs rw 1
i_debug_ip rw 1
i_debug_cs rw 1


View File

@@ -0,0 +1,16 @@
;*****************************************************
;*
;* Concurrent CP/M XIOS Data Area
;*
;*****************************************************
DSEG
org 0C0CH
tick rb 1
;see XIOS for format of the rest of the
;XIOS header, most of the variables
;are copied to the System Data Segment
;by GENSYS.