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,14 @@
Herein lie all sources to following CCP/M-86 2.0 modules:
SUP.CON
CIO.CON
MEM.CON
RTM.CON
SYSDAT.CON
WARNING! There are several .DEF files in this group with the same name
as the .DEF files compiled with the BDOS. THESE FILES ARE NOT NECESSARILY
THE SAME, AND SHOULD BE KEPT SEPARATE!!!!
These modules are assembled using ASM86 running under CP/M or CP/M-86.

View File

@@ -0,0 +1,521 @@
;*************************************************************
;*
;* 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
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
jmp terminate_entry
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
mov es:[si],offset terminate
; 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
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
mov di,u_dparam ; flag PD field asleep on
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 sniped 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,11 @@
;*****************************************************
;*
;* Assign Console Control Block
;*
;*****************************************************
acb_cns equ byte ptr 0
acb_match equ byte ptr acb_cns + byte
acb_pd equ word ptr acb_match + byte
acb_name equ byte ptr acb_pd + word
acblen equ acb_name + pnamsiz

View File

@@ -0,0 +1,16 @@
;*************************************************************
;*
;* Abort Parameter Block
;*
;*************************************************************
apb_pd equ word ptr 0
apb_term equ word ptr apb_pd + word
apb_cns equ byte ptr apb_term + word
apb_net equ byte ptr apb_cns + byte
apb_pdname equ byte ptr apb_net + byte
apb_len equ apb_pdname + pnamsiz
; Priority processes are set to when aborting
abt_prior equ 32

View File

@@ -0,0 +1,48 @@
;*****************************************************
;*
;* 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,24 @@
;
;
; GENERATE CONCURRENT CP/M-86 MODULES
;
;
vax $$a#home#
vax $$a#set def [.ccpm.micro.kern]#
;
ren system.def=system.ccc
ren cpyright.def=cpyright.ccc
;
; GENERATE BDOS.CON
;
;a86 bdos
;gencmd bdos
;era bdos.con
;ren bdos.con=bdos.cmd
;xref86 bdos
;ren cbdos.xrf=bdos.xrf
;vax cbdos.xrf $$satn
;era bdos.lst
;era cbdos.xrf
;era bdos.sym
;era bdos.h86

View File

@@ -0,0 +1,7 @@
;
; Character Block (CP/M 3.0 Character Control Block)
;
cb_off equ word ptr 0
cb_seg equ word ptr cb_off + word
cb_len equ word ptr cb_seg + word

View File

@@ -0,0 +1,46 @@
;*****************************************************
;*
;* Console Control Block Definition
;*
;* +---------+---------+---------+---------+
;* 00 | attach | queue |
;* +---------+---------+---------+---------+
;* 04 | flag | startcol| column | nchar |
;* +---------+---------+---------+---------+
;* 08 | mimic | msource | type | btmp |
;* +---------+---------+---------+---------+
;*
;* attach - current owner of device
;* if 0, no owner
;* if 0ffffh, a mimic device
;* queue - linked list of PDs waiting to attach
;* flag - run-time flags
;* startcol - used for line editing
;* column - used for line editing
;* nchar - 1 character read ahead for CTRL chars.
;* mimic - cio dev that mimics us.
;* 0ffh means no mimic device
;* msource - if attach = 0ffffh, we are a
;* mimic device and msource is the
;* device we are mimicing.
;* type - type of device
;* btmp - Temporary console variable
;*
;*****************************************************
c_attach equ word ptr 0
c_queue equ word ptr c_attach + word
c_flag equ byte ptr c_queue + word
c_strtcol equ byte ptr c_flag + byte
c_column equ byte ptr c_strtcol + byte
c_nchar equ byte ptr c_column + byte
c_mimic equ byte ptr c_nchar + byte
c_msource equ byte ptr c_mimic + byte
c_type equ byte ptr c_msource + byte
c_btmp equ byte ptr c_type + byte
ccblen equ byte ptr c_btmp + byte
; Flags for c_flag
cf_listcp equ 001h ;control P toggle
cf_compc equ 002h ;suppress output

View File

@@ -0,0 +1,114 @@
;
;
; GENERATE CONCURRENT CP/M-86 MODULES
;
; This .SUB file also transfers XRF files to vax.
; 'CVAX' is the 'VAX' program modified to use '#' as a command delimiter
; (rather than backslant).
;
;
; You MUST login to vax first!
;
cvax $$a#home#
cvax $$a#set def [.kern]#
;
ren system.def=system.ccc
ren cpyright.def=cpyright.ccc
;
; GENERATE BDOS.CON
;
; this is done elsewhere
;
; GENERATE SUP.CON
;
asm86 sup
gencmd sup
era sup.con
ren sup.con=sup.cmd
xref86 sup
era csup.xrf
ren csup.xrf=sup.xrf
cvax csup.xrf $$satn
era csup.sym
ren csup.sym=sup.sym
cvax csup.sym $$tans
era sup.lst
era sup.h86
era csup.xrf
;
; GENERATE RTM.CON
;
asm86 rtm
gencmd rtm
era rtm.con
ren rtm.con=rtm.cmd
xref86 rtm
era crtm.xrf
ren crtm.xrf=rtm.xrf
cvax crtm.xrf $$satn
era crtm.sym
ren crtm.sym=rtm.sym
cvax crtm.sym $$tans
era rtm.lst
era rtm.h86
era crtm.xrf
;
; GENERATE MEM.CON
;
asm86 mem
gencmd mem
era mem.con
ren mem.con=mem.cmd
xref86 mem
era cmem.xrf
ren cmem.xrf=mem.xrf
cvax cmem.xrf $$satn
era cmem.sym
ren cmem.sym=mem.sym
cvax cmem.sym $$tans
era mem.lst
era cmem.xrf
era mem.h86
;
; GENERATE CIO.CON
;
asm86 cio
gencmd cio
era cio.con
ren cio.con=cio.cmd
xref86 cio
era ccio.xrf
ren ccio.xrf=cio.xrf
cvax ccio.xrf $$satn
era ccio.sym
ren ccio.sym=cio.sym
cvax ccio.sym $$tans
era cio.lst
era ccio.xrf
era cio.h86
;
;
; GENERATE SYSDAT.CON
;
asm86 sysdat
gencmd sysdat
era sysdat.con
ren sysdat.con=sysdat.cmd
xref86 sysdat
era csysdat.xrf
ren csysdat.xrf=sysdat.xrf
cvax csysdat.xrf $$satn
era sysdat.lst
era sysdat.sym
era csysdat.xrf
era sysdat.h86
;
ren system.ccc=system.def
ren cpyright.ccc=cpyright.def
;
;
;
; KERNEL GENERATION COMPLETED!
;

View File

@@ -0,0 +1,24 @@
;*****************************************************
;*
;* Character Definitions
;*
;*****************************************************
ctlc equ 003h
ctld equ 004h
ctle equ 005h
bell equ 007h
ctlh equ 008h
tab equ 009h
lf equ 00ah
cr equ 00dh
ctlp equ 010h
ctlq equ 011h
ctlr equ 012h
ctls equ 013h
ctlu equ 015h
ctlx equ 018h
ctlz equ 01ah
ctl equ 05eh
rubout equ 07fh

View File

@@ -0,0 +1,773 @@
;*****************************************************
;*
;* Character I/0 Routines
;*
;*****************************************************
;===========
cmode_entry: ;Get/Set Console Mode
;===========
;
; entry: DX = 0FFFFH if returning current value
; else DX = new console mode word
; return: BX = console mode if DX = 0FFFFH on entry
;
mov bx,rlr
inc dx ! jz cm_get
dec dx
mov p_conmode[bx],dx
xor bx,bx
ret
cm_get:
mov bx,p_conmode[bx]
ret
;===========
conin_entry: ;Function 1:console input
;===========
call coninit
call coninf ;char in AL and BL
mov dl,al ;PIN handles control chars
co_notp:
call echoc ! jb ciexit ;check nonprint char
call tabout ;echo character - if printable
ciexit:
mov bl,dl ! ret
;============
conout_entry: ;Function 2:console output - DL = char
;============
call coninit
test p_conmode[bx],pcm_rout ;BX=RLR PD
jz co_tab
jmp conoutf
co_tab:
jmp tabout
;============ ;internal only under CCP/M
rconin_entry: ; raw console input
;============
call rawinit
jmp coninf ;returns char in AL and BL
;============= ;internal only under CCP/M
rconout_entry: ; raw console output - DL = char
;=============
call rawinit
rconout:
jmp conoutf
;=============
listout_entry: ; write to list device - DL = char
;=============
mov bx,rlr ! mov dh,p_lst[bx]
mov si,u_lstccb
push dx ! call lstattach_entry ! pop dx
jmp listf
;=============
constat_entry: ;check console status
;=============
call coninit ;console mode is made "cooked"
call cse_cl
test bl,bl ! jz co_r ;BL=1 if char ready
mov di,rlr
test p_conmode[di],pcm_11
jz co_r
call coninf ;read the char
cmp al,ctlc ! jne co_nc ;want only control C
mov c_nchar[si],ctlc
mov bl,1
co_r:
ret ;return BL=0 or 1
co_nc:
xor bl,bl ! ret ;char not a ^C
;=======
ciostat: ; check status w/out changing pf_raw
;=======
mov bx,rlr
mov dh,p_cns[bx]
mov si,u_conccb
test si,si ;U_CONCCB=0 if no attach yet
jz cse_no
cmp bx,c_attach[si]
je cse_cl
cse_no:
mov cl,f_dispatch ! call osif
mov bl,0 ! ret
cse_cl:
call constf
test bl,bl ! jz cse_c2
mov bl,1
cse_c2:
mov al,bl ! ret
;===========
dirio_entry: ;function 6
;===========
; direct console i/o - read if 0ffh
; entry: DL = 0ffh if readif (ret=0 on not ready, else char)
; = 0feh if status (ret=0 not read or 0ffh if ready)
; = 0fdh if input (wait there is a character)
; = char to output
; exit: BL = 0, 0ffh or character if status or input
call rawinit
cmp dl,0fdh
jb rconout ;output DL
ja diosts
jmp coninf ;DL=0FDh, get char
diosts: ;some type of status
call constf
cmp dl,0feh ! jne diocin ;DL=0FEh, return status
dio1:
ret ;BL=0FFh or 0h
diocin:
test bl,bl ! jz dio1 ;DL=0FFh, if char,conin
jmp coninf
;==============
conwrite_entry: ;write line until delimiter in UDA encountered
;============== ;user function 9, delimiter set by function 110
;
; input: DX = buffer addr in u_wrkseg
push dx
call coninit
pop bx
cwr1: push ds ! mov ds,u_wrkseg
mov dl,[bx] ! pop ds
cmp dl, u_delim ! je cwr_e
push bx
mov bx,rlr
test p_conmode[bx],pcm_rout ! jz cw_tab
call conoutf ! jmps cw_notab
cw_tab:
call tabout
cw_notab:
pop bx
inc bx ! jmps cwr1
cwr_e: ret
;===========
delim_entry: ;get/set output delimiter, user function 110
;===========
;
; entry: DX = 0FFFFH if returning current delimiter
; else DL = new delimiter
; return: BL = delimiter if DX = 0FFFFH on entry
cmp dx,0FFFFH ! jz d_get
mov u_delim,dl
ret
d_get:
mov bl,u_delim
ret
;=============
p_block_entry:
;=============
; entry: DX = CB addr where 1st word is offset,
; 2nd word is segment, 3rd word
; is length
; return: None
push dx
call coninit ;BX=PD address
pop di
xor ax,ax
mov bp,p_conmode[bx]
jmps block_out
;=============
l_block_entry:
;=============
; return: None
; entry: DX = CB addr where 1st word is offset,
; 2nd word is segment, 3rd word
; is length
push dx
call lstattach_entry
pop di
mov bx,rlr ! mov dh,p_lst[bx]
mov ax,0ffffh
;jmps block_out
;SI -> CCB or LCB (in XIOS)
block_out: ;u_wrkseg:DI -> user's parameter block
;DH=list or console device number
;AX = 0 if console, 0FFFFH if list
push ds ! mov ds,u_wrkseg
mov cx,cb_len[di] ;CX = string length
mov bx,cb_seg[di]
mov di,cb_off[di] ;BX:DI = string start
pop ds
test cx,cx ! jz b_ret ;test for zero length
b_loop: ;BX:DI -> string to print or list
;AX = 0 if to console = 0FFFFH if to list
;BP = p_conmode if going to console
push ds ! mov ds,bx
mov dl,[di]
pop ds
push bp ! push di ! push cx ! push bx ! push ax
test ax,ax ! jz b_con
call listf ! jmps nb_nxt
b_con:
test bp,pcm_rout ! jnz nb_nt ;raw output mode ?
call tabout ! jmps nb_nxt ;test for ctrlP ?
nb_nt:
call conoutf
nb_nxt:
pop ax ! pop bx ! pop cx ! pop di ! pop bp
inc di
loop b_loop
b_ret:
ret
;==============
conprint_entry: ;write line until delimiter or max
;============== ;mask parity, do not check for ctrl chars
;
; input: DX = address of buffer in u_wrkseg
; BH = max characters (0=no max)
; BL = delimiter character
push bx ! push dx
call coninit
pop bx ! pop ax
xor cx,cx
and al,07fh
; AH=max, AL=delimiter, BX->buffer
; CX = count = 0
cpr1: cmp ah,0 ! je cpr2
cmp ah,cl ! je cpr_e
cpr2: push ds ! mov ds,u_wrkseg
mov dl,[bx] ! pop ds
and dl,07fh
cpr3: cmp dl,al ! je cpr_e
push ax ! push cx ! push bx
call conoutf
call chk_ctrlP
pop bx ! pop cx ! pop ax
inc cl ! inc bx
jmps cpr1
cpr_e: ret
;=============
conread_entry: ;read a buffered console line
;=============
; buffer=(max length, current length, buffer)
push dx
call coninit
pop bx
read: push bx ;[SP] = buffer offset
mov al,c_column[si]
mov c_strtcol[si],al ;start column = current column
xor bx,bx ;BX = character count
;read next character, CX, BX active
readnx: push bx
readn0: call coninf ;AL, BL = char just read
mov dl,al
pop bx
; Carriage Return
cmp dl,cr ! jnz notcr
eofre: jmp readen
notcr:
; Line Feed
cmp dl,lf ! jz eofre
tryh: ; Backspace
cmp dl,ctlh ! jnz noth
or bl,bl ! jz readnx ;if not 1st char
dec bl ! mov al,c_column[si] ;decrement char count
mov c_btmp[si],al ;temporary hold
or c_flag[si],cf_compc ! jmp linelen
noth:
; Rubout
cmp dl,rubout ! jnz notrub
or bl,bl ! jz readnxx ;only if not 1st char
pop di ! push di
push ds ! mov ds,u_wrkseg
mov dl,1[di+bx] ! pop ds ;make char=last char
dec bx ;dec char count
jmp rdech1 ;echo, read next
readnxx: jmp readnx
notrub:
; Control E
cmp dl,ctle ! jnz note
push bx
mov dl,cr ! call conoutf
mov dl,lf ! call conoutf
mov c_column[si],0
mov c_strtcol[si],0
jmp readn0
note:
; Control X
cmp dl,ctlx ! jnz notx
backx: mov al,c_strtcol[si]
cmp al,c_column[si] ! jb backxxx
xor bx,bx ! jmps readnxx
backxxx: mov dl,ctlh ! call conoutf
mov dl,' ' ! call conoutf
mov dl,ctlh ! call conoutf
dec c_column[si]
jmps backx
notx:
; Control U
cmp dl,ctlu ! jnz notu
call crlfp
pop bx ! jmp read
notu:
; CONTROL R - redraw line
cmp dl,ctlr ! jnz notr
linelen: push bx ! call crlfp
;print buffer on screen
pop cx ! xor bx,bx
rep0: or cl,cl ! jz rep1
pop di ! push di
push ds ! mov ds,u_wrkseg
inc bx ! dec cl
mov dl,1[di+bx] ! pop ds ;DL = nxt char
mov ch,bl ! push cx
call ctlout
pop cx ! mov bh,0 ! mov bl,ch
jmps rep0
rep1: test c_flag[si],cf_compc
push bx ! jz l_22
and c_flag[si],not cf_compc
mov ah,c_btmp[si] ! mov al,ah
backsp: cmp al,c_column[si]
jb l_22
sub al,c_column[si]
or al,al ! jz l_22
push ax
mov dl,ctlh ! call conoutf
mov dl,' ' ! call conoutf
mov dl,ctlh ! call conoutf
pop ax ! dec ah ! mov al,ah
jmps backsp
l_22: jmp readn0
notr:
; All other characters
rdecho: inc bx
pop di ! push di
push ds ! mov ds,u_wrkseg
mov 1[di+bx],dl ! pop ds
rdech1: push bx ! call ctlout ! pop bx
pop di ! push di
push ds ! mov ds,u_wrkseg
cmp bl,[di] ! pop ds ! jae readen
push bx ! jmps l_22
; End of Console String
readen: pop di
push ds ! mov ds,u_wrkseg
mov 1[di],bl ! pop ds
mov dl,cr ! call conoutf
mov c_column[si],0
ret
rawinit:
;-------
mov bx,rlr ;turn on raw flag
or p_flag[bx],pf_raw
jmps ninit
coninit:
;-------
; entry: DL = char if called by output routine
; exit: DH = console device number
; BX = RLR PD - raw flag turned off
; SI = CCB owned by calling PD
mov bx,rlr ;turn off raw flag
and p_flag[bx],not pf_raw
ninit:
mov dh,p_cns[bx]
mov si,u_conccb
test si,si ! jz attach
cmp c_attach[si],bx
jne attach
ret
attach:
; exit: SI=CCB
; BX,DX preserved
push bx ! push dx
call conattach_entry
pop dx ! pop bx
ret
echoc:
;-----
; check if character is graphic
; input: DL = character
; DH = console #
; SI = CCB address
; output: carry set if not graphic
; DL,DH,SI pass through
cmp dl,cr ! je ret0
cmp dl,lf ! je ret0
cmp dl,tab ! je ret0
cmp dl,ctlh ! je ret0
cmp dl,' '
ret0: ret
prcsmsg:
;-------
; print string in Code Segment
; input: DX->null terminated string in CS
xor bx,bx ! mov ax,cs
prstr: push u_wrkseg
mov u_wrkseg,ax
call conprint_entry
pop u_wrkseg ! ret
prname:
;------
; print name
; input: DX->8 char name in DS
mov bh,8 ! mov bl,' '
mov ax,ds ! jmps prstr
conout:
;------
; compute character position/write console
; input: DL = character
; DH = console #
; SI = ccb address
; output: DL = character
; DH = console #
; SI = ccb address
;check if only calculating column position
test c_flag[si],cf_compc ! jnz compout
;write the character, then compute column.
call conoutf
mov bx,rlr
test p_conmode[bx],pcm_rout
jnz co_np
call chk_ctrlP ;printer echo handling
co_np:
;compute column position
compout:
mov al,c_column[si]
cmp dl,rubout ! je ccret
inc al
cmp dl,' ' ! jae ccret
dec al
or al,al ! jz ccret
cmp dl,ctlh ! jnz notbs
dec al ! jmps ccret
notbs: cmp dl,cr ! jne ccret
mov al,0
ccret: mov c_column[si],al
ret
chk_ctrlP:
;---------
; Entry: SI=CCB address
; DH=console device number
; DL=character just sent to console
; Exit: SI,DX preserved
; Echo the character to the printer if the ctrlP flag is set
; in the CCB, and the ctrlO flag is off, and the cf_bufp
; flag is off. Cf_bufp is set when we send a character
; to a VOUT process when we are a background buffered
; console. The VOUT process decides whether to send the
; character to the screen when it purges the buffered output.
mov ax,c_state[si]
test ax,csm_ctrlP
jz cp_ret
test ax,csm_ctrlO
jnz cp_ret
mov al,c_flag[si]
test al,cf_bufp
jz cp_listit
and c_flag[si],not cf_bufp ;turn off the flag
jmps cp_ret
cp_listit:
push dx ! push si
mov dh,c_mimic[si]
cmp dh,0ffh ;mimic = 0ffh if
je cp_no ;PIN turned off ^P
call listf
cp_no:
pop si ! pop dx
cp_ret:
ret
ctlout:
;------
; send CTRL character with possible preceding up-arrow
; input: DL = character
; DH = console #
; SI = ccb address
; output: DL,DH = character,console
; SI = ccb address
call echoc ! jae tabout
push dx ! mov dl,ctl ! call conout
pop dx ! or dl,40h
; jmp tabout
tabout:
;------
; expand tabs to console
; input: DL = character
; DH = console
; SI = ccb address
; output: DL,DH = char,console
; SI = ccb address
cmp dl,tab ! je tab1
jmp conout
tab1:
mov dl,' '
tab0: call conout
mov al,c_column[si]
and al,111b ! jnz tab0
mov dl,tab
ret2: ret
crlf:
;----
push dx ! mov dl,cr ! call conout
mov dl,lf ! call conout ! pop dx
ret
crlfp:
;-----
; print #, cr, lf for ctlx, ctlu, ctlr functions
; then print ' ' until we are at strtcol (starting column)
; input: DH = console
; SI = ccb address
; output: DH = console
; SI = ccb address
mov dl,'#' ! call conout
call crlf
mov dl,' '
crlfp0: mov al,c_column[si]
cmp al,c_strtcol[si] ! jae crlfp1
call conout ! jmps crlfp0
crlfp1: ret
;
; XIOS CHARACTER I/O INTERFACE
;
; XIOS CONSTAT CALL
;
; entry: DH = console #
; SI = ccb address
; returns:DH = console #
; SI = ccb address
; AX = BX = 0 if no char, = 0FFH if char ready
constf:
cmp dh,ncns ;if not VC goto XIOS
jb cst_vc
mov al,io_const
jmp goxios
cst_vc:
xor bx,bx
cmp c_nchar[si],bl
jne cst_true
mov di,c_vinq[si]
cmp q_msgcnt[di],bx ;number of chars in type ahead
je cst_ret ;queue
cst_true:
mov bl,0ffh ;char ready
cst_ret:
mov al,bl
ret
; XIOS CONIN CALL
;
; entry: DH = console #
; SI = ccb address
; returns:DH = console #
; AL = BL = character
; SI = ccb address
;
coninf:
cmp dh,ncns ;if not VC goto XIOS
jb ci_vc
mov al,io_conin
jmp goxios
ci_vc:
cmp c_nchar[si],0
jne ci_gotc
mov cx,f_qread
call csi_readq
ci_gotc:
mov bl,c_nchar[si]
mov al,bl
mov c_nchar[si],0
ret
csi_readq:
push dx ! push si
mov ax,c_vinq[si]
mov c_qpbqaddr[si],ax
lea ax,c_nchar[si]
mov c_qpbbuffptr[si],ax
lea dx,c_qpbflags[si]
call osif
pop si ! pop dx
ret
; XIOS CONOUT CALL
;
; entry: DH = console #
; DL = character
; SI = ccb address
; exit: DH = console #
; SI = ccb address
conoutf:
cmp dh,ncns ;if not VC goto XIOS
jb co_vc
mov al,io_conout ;console number
jmp goxios ;control C could hang up this
co_vc: ;hardware, should handle similar
pushf ! cli ;to virtual screens
mov ax,c_state[si]
mov bx,ax
and ax,not(csm_ctrlP + csm_ctrlO + csm_noswitch)
cmp ax,2 ;0=foreground&dynamic, 1=foreground&
jbe co_getconout ;buffered, 2=background&dynamic
cmp ax,csm_buffered + csm_background
je co_buffer
;sleep on all other states
push dx ! push si ;and wait for the PIN or
lea dx, c_usleep[si] ;VOUT to wake us up
mov bl, ps_ciowait
mov cx, f_sleep
call osif
pop si ! pop dx
popf
jmps co_vc ;start over, state could
;have changed
co_buffer: ;Virtual Console is in some type of buffered state
popf ;allow interrupts
or c_flag[si],cf_vout+cf_bufp ;VOUT we are writing a msg.
;If we switch screens, and VOUT
;just finishes purging, VOUT
;will wait for this message.
;Turn on cf_bufp so we don't
;echo to the printer if ctrlP is on
mov ax,c_voutq[si]
mov c_qpbqaddr[si],ax
lea ax,c_qbuff[si] ;points to 2-byte message
mov c_qpbbuffptr[si],ax
push dx ! push si
xor dh,dh ;DL = data, DH = data msg type (0)
mov c_qbuff[si],dx
lea dx,c_qpbflags[si]
mov cx, f_qwrite
call osif
pop si ! pop dx
and c_flag[si],not cf_vout ;tell VOUT we're done writing
ret ;message
co_getconout:
test bx,csm_ctrlO ;BX = ccb.state
jz co_cbitsget ;famous racehorse
popf ! ret ;ctrl O byte bucket
co_cbitsget: ;output is going to XIOS,
;ensure no other process
test c_flag[si],cf_conout ;is in XIOS console output code
jz co_gotconout ;for this screen
co_conoutsleep:
push dx ! push si
lea dx, c_cosleep[si]
mov bl, ps_ciowait
mov cx, f_sleep
call osif
pop si ! pop dx
popf
jmp co_vc ;start over, state
;could have changed
co_gotconout:
or c_flag[si], cf_conout ;set XIOS conout "ownership" flag
popf ;allow interrupts
mov bx,rlr
push p_flag[bx] ;save flags
or p_flag[bx],pf_tempkeep ;don't allow abort
push bx
mov ax,io_conout ;XIOS function number
call goxios
and c_flag[si], not cf_conout ;wake any process wanting XIOS
cmp c_cosleep[si],0 ;test here for faster output
je co_nowake
push dx ! push si
mov cx,f_wakeup
mov bl,ps_ciowait
lea dx,c_cosleep[si]
call osif
pop si ! pop dx
co_nowake:
pop bx ;process address
test p_flag[bx],pf_ctlc ;was ^C typed ?
pop p_flag[bx] ;restore PD flags
jz co_xret
or p_flag[bx],pf_ctlc
push dx ! push si
xor dx,dx
mov cx,f_terminate
call osif ;returns here if keep flg is on
pop si ! pop dx
co_xret:
ret
; XIOS LIST OUT CALL
;
; entry: DH = console #
; DL = character
; SI = ccb address
; exit: DH = console #
; SI = ccb address
listf:
mov ax,io_list
;jmps goxios
goxios:
push dx ! push si
mov cl,dl ! mov dl,dh ;CL = char, DL = device
call xiosif
pop si ! pop dx
ret

View File

@@ -0,0 +1,32 @@
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
if mpm
eject ! include ccb.def
endif
if ccpm
eject ! include vccb.def
endif
eject ! include char.def
eject ! include cmode.def
eject ! include cb.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,92 @@
;*****************************************************
;*
;* Character I/O Interface
;*
;*****************************************************
CSEG
org 0
jmp init
jmp entry
;3 variables set by GENSYS
sysdat dw 0
supervisor equ (offset $)
rw 2
org 0ch
dev_ver db 6 ;development system data version
;set in sysdat.fmt
db 'COPYRIGHT (C) 1982,'
db ' DIGITAL RESEARCH '
db 'XXXX-0000-'
serial db '654321'
;====
init:
;====
retf
;*****************************************************
;*
;* CIO function table
;*
;*****************************************************
functab dw conin_entry ; 0 - Console Input
dw conout_entry ; 1 - Console Output
dw rconin_entry ; 2 - raw console input
dw rconout_entry ; 3 - raw console output
dw listout_entry ; 4 - list output
dw dirio_entry ; 5 - direct console I/O
dw conwrite_entry ; 6 - print string
dw conread_entry ; 7 - read buffer
dw constat_entry ; 8 - console status
dw conattach_entry ; 9 - attach console
dw condetach_entry ; 10- detach console
dw setdefcon_entry ; 11- set default console
dw conassign_entry ; 12- assign console
dw getdefcon_entry ; 13- get default console
dw conprint_entry ; 14- print string (internal)
dw lstattach_entry ; 15- attach list
dw lstdetach_entry ; 16- detach list
dw setdeflst_entry ; 17- set default list
dw clstattch_entry ; 18- cond list attach
dw cconattch_entry ; 19- cond list detach
dw getdeflst_entry ; 20- get default list
dw notimp ; 21
dw notimp ; 22
dw cioterm ; 23- cleanup for term.
dw ciostat ; 24- check status w/out
; changing raw/cooked flag
dw cmode_entry ; 25- get/set console mode word -
; user func 109
dw delim_entry ; 26- get/set delimiter - user func 110
dw pblock_entry ; 27- print block - user func 111
dw lblock_entry ; 28- list block - user func 112
;===== =================
entry: ; CIO entry point
;===== =================
shl cx,1 ! mov si,cx
call cs:functab[si] ! retf
;==== ==============
osif: ; OS interface
;==== ==============
callf cs:dword ptr .supervisor ! ret
;====== ================
xiosif: ; XIOS interface
;====== ================
callf dword ptr .xiosmod ! ret
;======
notimp:
;======
mov bx,0ffffh
ret

View File

@@ -0,0 +1,12 @@
;*****************************************************
;*
;* Cli Command Control Block
;*
;*****************************************************
clicb_net equ byte ptr 0
clicb_cmd equ byte ptr clicb_net + byte
clicblen equ clicb_cmd + 129*byte

View File

@@ -0,0 +1,26 @@
;*****************************************************
;*
;* Command Header Format and Load Fixup Records
;*
;*****************************************************
;group descriptor format
ch_form equ byte ptr 0
ch_length equ word ptr (ch_form + byte)
ch_base equ word ptr (ch_length + word)
ch_min equ word ptr (ch_base + word)
ch_max equ word ptr (ch_min + word)
chlen equ ch_max + word
ch_entmax equ 8 ;max number of group
;descriptors
ch_lbyte equ byte ptr 07fh ;MSB bit in CH_LBYTE
ch_fixrec equ word ptr 07dh ;signals fixup records
;start at record number
;in CH_FIXREC
fix_grp equ byte ptr 0 ;format of fixup record
fix_para equ word ptr fix_grp + byte
fix_offs equ byte ptr fix_para + word
fixlen equ fix_offs + byte

View File

@@ -0,0 +1,9 @@
;
; Bit masks for the console mode word
;
cm_ctlc equ 0001H
cm_ctls equ 0002H
cm_rawo equ 0004H
cm_rsx1 equ 0100H
cm_rsx2 equ 0200H

View File

@@ -0,0 +1,717 @@
;*****************************************************
;*
;* 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
or ax,pf_tempkeep + pf_noctls
mov p_flag[bx],ax
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
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)
mov cx,f_terminate ;TERM_ACT in dispatcher
jmp osif ;releases CLI_SYNC
clirls:
push cli_pflag
push cli_err
call cli_unsync
pop dx
pop ax ! and ax,pf_tempkeep+pf_noctls
mov bx,rlr ! mov cx,p_flag[bx]
and cx,not pf_tempkeep+pf_noctls
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,428 @@
;*****************************************************
;*
;* Character I/O ownership routines
;*
;*****************************************************
;===============
lstattach_entry:
;===============
xor cx,cx ;unconditional attach code
jmps lcb_verify
;===============
clstattch_entry:
;===============
mov cx,0ffffh ;conditional attach code
lcb_verify:
;----------
push cx
mov si,u_lstccb ;U_LSTCCB=0 if not yet initialized
test si,si ! jnz lcb_ok
call getlcbadr
mov u_lstccb,si
lcb_ok:
pop cx ;restore attach code
jmps cioattach
;===============
conattach_entry:
;===============
xor cx,cx ;unconditional attach code
jmps ccb_verify
;===============
cconattch_entry:
;===============
mov cx,0ffffh ;conditional attach code
ccb_verify:
push cx
mov si,u_conccb
test si,si ! jnz ccb_ok
call getccbadr
mov u_conccb,si
ccb_ok:
pop cx ;conditional attach if 0ffffh
;jmps cioattach
;=========
cioattach: ;NOTE: PIN does attaches also for ^P
;=========
; Attach calling process to default ciodev.
; if ciodev is being used, sleep on c_queue
; until another process detaches from device
; and calling process is next in queue.
; input: SI = CCB address of device
; DI = offset of dev number in PD
; CX = 0ffffh if conditional
mov ax,rlr ! mov bx,ax
; BX = PD addr
; SI = CCB addr
; CX = Condition Flag
pushf ! cli
cmp bx,c_attach[si] ! je ca_ret ;we already own it
cmp c_attach[si],0 ! je ca_atch ;nobody owns it, we'll take it
jcxz ca_sleep ;somebody else owns it
popf ! mov bx,0ffffh ;or it is a mimic list (0ffffh)
mov cx,e_no_attach ! ret ;- no attach in either case
ca_sleep:
push dx ;save DH=cons #
lea dx,c_queue[si] ;unconditional if CX=0
mov bl,ps_ciowait
push si
mov cx,f_sleep ! call osif
pop si ! pop dx ! popf ! xor cx,cx
jmps cioattach
ca_atch: mov c_attach[si],bx
ca_ret: popf ! xor bx,bx ! ret
;===============
lstdetach_entry:
;===============
call lcb_verify ;ensure U_LSTCCB is non zero
jmps ciodetach
;===============
condetach_entry:
;===============
call ccb_verify ;ensure U_CONCCB is non zero
;jmps ciodetach
;=========
ciodetach: ;NOTE PIN also does detaching for ^P
;=========
; Detach Calling process from default ciodev.
; If current owner of ciodev then zero c_attach
; and wakeup the c_queue list to give another
; process the ciodev.
; input: SI = CCB addr of device
mov bx,rlr
; SI = CCB address
; BX = PD address
pushf ! cli
cmp c_attach[si],0 ! je cd_ret
cmp c_attach[si],bx ! je cd_detach
popf ! mov bx,0ffffh
mov cx,e_not_owner ! ret
cd_detach:
mov ax,c_queue[si]
mov c_attach[si],ax
mov cx,f_wakeup
lea dx,c_queue[si]
call osif
cd_ret:
popf
xor bx,bx ! ret
;===============
conassign_entry:
;===============
; Attach specified console to specified process
;
; entry: U_WRKSEG:DX -> ACB
;
; +-----+-----+-----+-----+
; | CNS |Match| PD Addr |
; +-----+-----+-----+-----+-----+-----+-----+-----+
; | Name |
; +-----+-----+-----+-----+-----+-----+-----+-----+
;
; CNS - console to assign
; Match - if not 0,
; PD's default console must match acb_cns
; PD Addr - PD address to assign to
; Name - use PD name to assign, if PD addr=0
; Name - use PD name to assign, if PD addr=1,
; but also ensure DSKLD flag is off
; (DiSK LoaD is set when PD was created
; from disk transient, RSPs have DSKLD=0)
; Should check for DSKLD=1 if PD addr = 0
; but we may have compatibility issues
;
; exit: BX = 0 if success, 0ffffh if failure
; CX = Error Code
push dx ;save ACB
mov bx,offset thrd_spb ;get ownership of thread
mov cx,f_sync
call osif
pop di ;U_WRKSEG:DI->ACB
mov indisp,true ;stop dispatching
push ds ;save SYSDAT
mov ds,u_wrkseg
cmp acb_pd[di],1 ;name or address match ?
jbe as_name
mov bx,acb_pd[di] ;find by PD address
pop ds ;DS=SYSDAT
mov si,(offset thrdrt)-p_thread
as_next1: ;verify PD is on thread
mov si,p_thread[si]
test si,si ! jz as_nom ;no match if end of thread
cmp bx,si ! je as_found_id
jmps as_next1
as_found_id:
call as_chk ;check console match
jcxz as_mok ;match ok
jmps as_nom ;no match
as_name: ;look for PD by name on thread
pop ds ;DS=SYSDAT
mov bx,(offset thrdrt)-p_thread
as_next2: ;look for PD by name on thread
push di ;save ACB
lea dx,acb_name[di] ;U_WRKSEG:DI->ACB
mov ds,u_wrkseg ;DS:DX->ASCII name
mov cx,f_findpdname
call osif
mov ds,sysdat
pop di ;ACB
jcxz as_okname ;CX<>0 if no match
as_nom:
mov cx,e_no_pdname ;couldn't find PD specified
jmps as_err ;by ACB on thread list
as_okname:
;matched PD by name check by ACB
call as_chk ;BX->PD matched by name
jcxz as_mok
;console or DSKLD didn't match
jmps as_next2 ;search for another PD
as_mok: ;match OK, found the PD
push bx ! push di ;BX=matched PD, DI=ACB
mov bx,offset thrd_spb
mov cx,f_unsync
call osif
pop di ! pop ax ;DI=ACB, AX=matched PD
mov ds,u_wrkseg
push ax ;save matched PD
mov al,acb_cns[di]
mov ds,sysdat
call getccbadr_spec ;SI=CCB on return
mov bx,rlr ;BX=running process
pop ax ;AX=matched PD
cmp c_attach[si],0 ;and change CCB
je as_ok ;CCB must be unused (0) or
cmp c_attach[si],bx ;running process must own it
je as_ok
mov cx,e_not_owner
as_err:
push cx ;save error code
call as_ok_disp
mov bx,offset thrd_spb
mov cx,f_unsync
call osif
pop cx
mov bx,0ffffh
ret
as_ok:
mov c_attach[si],ax ;new owner
push ax ! push si ;save owner and CCB
call as_ok_disp ;allow dispatches
pop si ! pop ax
mov bx,ax ;AX=BX=new owner
add si,c_queue-p_link ;go down CCB queue for PD
mov di,si ;DI=SI=address of CCB.QUEUE
as_nqpd:
cmp p_link[si],0 ;look on C_QUEUE for PD being
jz as_gexit ;assigned the console
cmp p_link[si],bx
je as_qfix
mov si,p_link[si]
jmps as_nqpd ;next PD
as_qfix:
mov ax,p_link[bx] ;take PD out of C_QUEUE
mov p_link[si],ax
mov si,p_link[di] ;SI = first PD on C_QUEUE
mov p_link[di],bx ;put PD in front of C_QUEUE
mov p_link[bx],si ;attach rest of list
mov dx,di ;pass C_QUEUE address to wakeup
mov cx,f_wakeup
call osif
as_gexit:
xor bx,bx
ret
as_ok_disp:
;----------
; entry: none
; exit: none
; Allow dispatching
mov indisp,false
pushf ! cli
cmp drl,0 ! je as_nwake
mov cx,f_dispatch
call osif
as_nwake:
popf ! ret
as_chk:
;------
; check PD against Assign Control Block parameters
; entry: BX = PD to check
; U_WRKSEG:DI = ACB
; exit: CX = 0 if assign match
; CX <> 0 if no match
; CX,AX used
xor cx,cx
push es ;save UDA
mov es,u_wrkseg
mov ax,es:acb_pd[di]
cmp ax,1 ;if >1 then matching on PD address
ja asc_cns
dec ax
jnz asc_cns
test p_flag[bx],pf_dskld ;RSP, DSKLD must be off
jnz asc_no
asc_cns:
cmp es:acb_match[di],0 ;console match requested ?
je asc_ok
mov al,es:acb_cns[di] ;must match on console
cmp al,p_cns[bx]
je asc_ok
asc_no:
inc cx
asc_ok:
pop es ;ES=UDA
ret
;=============== =====================
getdefcon_entry: ; Get Default Console
;=============== =====================
mov si,rlr
xor bh,bh ! mov bl,p_cns[si]
ret
;=============== ==================
getdeflst_entry: ; Get Default List
;=============== ==================
mov si,rlr
xor bh,bh ! mov bl,p_lst[si]
ret
;=============== =====================
setdefcon_entry: ; Set Default Console
;=============== =====================
cmp dl,ncondev
jb sd_good
mov cx,e_ill_cns
mov bx,0ffffh ! ret
sd_good:
mov si,rlr
mov p_cns[si],dl
call getccbadr
mov u_conccb,si
xor bx,bx
ret
;=============== ==================
setdeflst_entry: ; Set Default List
;=============== ==================
cmp dl,nlstdev
jb sdl_good
mov cx,e_ill_lst
mov bx,0ffffh ! ret
sdl_good:
mov si,rlr
mov p_lst[si],dl
call getlcbadr
mov u_lstccb,si
xor bx,bx
ret
getccbadr:
;---------
; get CCB for calling process' console device
; input: None
; output: SI = address of CCB
; BX = running PD address
mov bx,rlr
mov al,p_cns[bx]
getccbadr_spec: ;AL is console number
xor ah,ah ;when called from ASSIGN
mov si,ccb
mov cl,2
shl ax,cl
add si,ax ;+4
add si,ax ;+4 = 8
add si,ax ;+4 =12
mov cl,3
shl ax,cl
add si,ax ;+32 =44
ret
getlcbadr:
;---------
; Get LCB for calling process list device
; entry: None
; output: SI = address of LCB
; BX = PD address
mov bx,rlr
xor ah,ah
mov al,p_lst[bx]
mov si,lcb
push ax ;lcb#
shl ax,1 ;2*lcb#
add si,ax ;lcbadr + 2*lcb#
pop ax ;lcb#
mov cl,3
shl ax,cl ;8*lcb#
add si,ax ;lcbadr + 2*lcb# + 8*lcb#
ret
;=======
cioterm:
;=======
; Detach Calling process from all character devices.
; Called only from the dispatcher
mov al,ncondev
mov si,ccb
nxtccb: cmp al,0 ! je ct_dlcb
cmp si,u_conccb ! jne ct_dccb
and c_flag[si],not (cf_conout + cf_vout + cf_bufp)
mov cx,f_wakeup ;release proc waiting for XIOS conout
lea dx,c_cosleep[si]
push ax ! push si
call osif
pop si ! pop ax
ct_dccb:
push ax ! push si
call ciodetach
pop si ! pop ax
dec al
add si,ccblen
jmps nxtccb
ct_dlcb:
mov al,nlstdev
mov si,lcb
ct_nlcb:
cmp al,0 ! je ct_ret
push ax ! push si
call ciodetach
pop si ! pop ax
dec al
add si,lcblen
jmps ct_nlcb
ct_ret: xor bx,bx ! ret

View File

@@ -0,0 +1,237 @@
;*****************************************************
;*
;* 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
add ax,(lstklen+ulen)/16 ;CX=# paragraphs
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,28 @@
;*****************************************************
;*
;* Concurrent CP/M-86 V2.1
;* =======================
;*
;* Copyright (c) 1982
;*
;* Digital Research
;* P.O.Box 579
;* Pacific Grove, California 93950
;*
;* (408) 649-3896
;* TWX 9103605001
;*
;* All Information contained in this source listing is
;*
;* PROPRIETORY
;* ===========
;*
;* All rights reserved. No part of this document
;* may be reproduced, transmitted, stored in a
;* retrieval system, or translated into any language
;* or computer language, in any form or by any means
;* without the prior written permission of Digital
;* Research, P.O Box 579, Pacific Grove, California.
;*
;*****************************************************

View File

@@ -0,0 +1,474 @@
;*****************************************************
;*
;* bdos data area
;*
;*****************************************************
CCPMOFF equ true
if BCPM
;
; 8086 variables that must reside in code segment
;
cseg $
;
axsave dw 0 ; register saves
ss_save dw 0
sp_save dw 0
stack_begin dw endstack
;
; variables in data segment:
;
dseg cpmsegment
org bdosoffset+bdoscodesize
header rs 128
rs 72
pag0 dw 0 ;address of user's page zero
ip0 db 0 ;initial page value for ip register
;
; memory control block
;
umembase dw 0 ;user'sbase for memory request
umemlg dw 0 ;length of memory req
contf db 0 ;flag indicates added memory is avail
;
;
hold_info dw 0 ;save info
hold_spsave dw 0 ;save user sp during program load
hold_sssave dw 0 ;save user ss during program load
mod8080 db 0
;
; byte i/o variables:
;
compcol db 0 ;true if computing column position
strtcol db 0 ;starting column position after read
column db 0 ;column position
listcp db 0 ;listing toggle
kbchar db 0 ;initial key char = 00
endif
dseg
if BMPM
org 0c00h ;org for MP/M system
endif
if BMPM and CCPMOFF
org 0800h ;org for CCP/M system
endif
if BMPM
rlog dw 0 ;removeable logged-in disks
tlog dw 0 ;removeable disk test login vector
ntlog dw 0 ;new tlog vector
endif
rodsk dw 0 ;read only disk vector
dlog dw 0 ;logged-in disks
open_fnd db 0 ;open file found in srch_olist
;the following variables are set to zero upon entry to file system
fcbdsk db 0 ;disk named in fcb
parlg db 0 ;length of parameter block copied
aret dw 0 ;adr value to return
lret equ byte ptr aret ;low(aret)
resel db 0 ;reselection flag
rd_dir_flag db 0 ;must read/locate directory record
comp_fcb_cks db 0 ;compute fcb checksum flag
search_user0 db 0 ;search user 0 for file (open)
make_xfcb db 0 ;make & search xfcb flag
find_xfcb db 0 ;search find xfcb flag
xdcnt dw 0 ;empty directory dcnt
DIR_CNT DB 0 ;DIRECT I/O COUNT
MULT_NUM DB 0 ;MULTI-SECTOR COUNT used in bdos
olap_type db 0 ;record lock overlap type
ff_flag db 0 ;0ffh xios error return flag
err_type db 0 ;type of error to print if not zero
rb 4 ;reserved bytes
zerolength equ (offset $)-(offset fcbdsk)
mult_sec db 1 ;multi sector count passed to xios
RELOG DB 0 ;AUTOMATIC RELOG SWITCH
BLK_OFF DB 0 ;RECORD OFFSET WITHIN BLOCK
blk_num dw 0 ;block number
;
ua_lroot dw offset ua0 ;unallocated block list root
;
ua0 dw offset ua1,0
db 0ffh,0
ua1 dw offset ua2,0
db 0ffh,0
ua2 dw offset ua3,0
db 0ffh,0
ua3 dw offset ua4,0
db 0ffh,0
ua4 dw offset ua5,0
db 0ffh,0
ua5 dw 0,0
db 0ffh,0
HASH RB 4 ;HASH CODE WORK AREA
HASHL DB 0 ;HASH SEARCH LENGTH
LOG_FXS db 11 ;number of log_fxs entrys
; fxi15,fxi17,fxi19,fxi22,fxi23
db 02h ,04h ,06h ,09h ,0ah
; fxi30,fxi35,fxi99,fxi100,fxi102,fxi103
db 11h ,16h ,25h ,26h ,28h ,29h
db 0,0,0,0 ;reserved
rw_fxs db 7 ;number of rw_fxs entrys
; fxi20,fxi21,fxi33,fxi34,fxi40,fxi42,fxi43
db 07h ,08h ,14h ,15h ,1bh ,1ch ,1dh
db 0,0 ;reserved
sc_fxs db 2 ;number of sc_fxs entrys
; fxi16,fxi18
db 03h ,05h
db 0,0 ;reserved
DEBLOCK_FX DB 0 ;DEBLOCK FUNCTION #
PHY_OFF DB 0 ;RECORD OFFSET WITHIN PHYSICAL RECORD
CUR_BCBA DW 0 ;CURRENT BCB OFFSET
ROOT_BCBA DW 0 ;ROOT BCB OFFSET
EMPTY_BCBA DW 0 ;EMPTY BCB OFFSET
if BMPM
P_LAST_BCBA DW 0 ;PROCESS'S LAST BCB OFFSET
P_BCB_CNT DB 0 ;PROCESS BCB COUNT IN BCB LIST
endif
fx_intrn db 0 ;internal BDOS function number
TRACK DW 0 ;BCB RECORD'S TRACK
SECTOR DW 0 ;BCB RECORD'S SECTOR
; seldsk,usrcode are initialized as a pair
seldsk db 0 ;selected disk num
usrcode db 0 ;curr user num
info dw 0 ;info adr
searcha dw 0 ;search adr
;the following variable order is critical
;variables copied from uda for mp/m x
;variables included in fcb checksum for mp/m and cp/m x
;variables used to access system lock list for mp/m x
dma_ofst dw 0 ;dma offset 1
dma_seg dw 0 ;dma segment 2
func db 0 ;bdos function # 3
searchl db 0 ;search len 4
if BMPM
searchaofst dw 0 ;search adr ofst 5
searchabase dw 0 ;search adr base 6
endif
dcnt dw 0 ;directory counter 7
dblk dw 0 ;directory block 8 ?? - not used - ??
error_mode db 0 ;bdos error mode 9
mult_cnt db 0 ;bdos multi-sector cnt 10
df_password rb 8 ;process default pw 11
if BMPM
pd_cnt db 0 ;bdos process cnt 12 1
endif
high_ext db 0 ;fcb high extent bits 2
xfcb_read_only db 0 ;xfcb read only flag 3
curdsk db 0ffh ;current disk 4 1
if BMPM
packed_dcnt db 0 ;packed dblk+dcnt 2
db 0
db 0
pdaddr dw 0 ;process descriptor addr 3
endif
org ((offset $) + 1) and 0fffeh
; curtrka - alloca are set upon disk select
; (data must be adjacent)
cdrmaxa dw 0 ;ptr to cur dir max val
drvlbla dw 0 ;drive label data byte addr
buffa dw 0 ;ptr to dir dma addr
dpbaddr dw 0 ;curr disk param block addr
checka dw 0 ;curr checksum vector addr
alloca dw 0 ;curr alloc vector addr
DIR_BCBA DW 0 ;DIRECTORY BUFFER CONTROL BLOCK ADDR
DAT_BCBA dw 0 ;DATA BUFFER CONTROL BLOCK ADDR
HASH_SEG dw 0 ;HASH TABLE SEGMENT
addlist equ 12 ;"$-buffa" = addr list size
; sectpt - offset obtained from disk parm block at dpbaddr
; (data must be adjacent)
sectpt dw 0 ;sectors per track
blkshf db 0 ;block shift factor
blkmsk db 0 ;block mask
extmsk db 0 ;extent mask
maxall dw 0 ;max alloc num
dirmax dw 0 ;max dir num
dirblk dw 0 ;reserved alloc bits for dir
chksiz dw 0 ;size of checksum vector
offsetv dw 0 ;offset tracks at beginning
PHYSHF DB 0 ;PHYSICAL RECORD SHIFT FACTOR
PHYMSK DB 0 ;PHYSICAL RECORD MASK
endlist rs 0 ;end of list
dpblist equ (offset endlist)-(offset sectpt)
;size
; local variables
common_dma rb 16 ;copy of user's dma 1st 16 bytes
make_flag db 0 ;make function flag
actual_rc db 0 ;directory ext record count
save_xfcb db 0 ;search xfcb save flag
save_mod db 0 ;open_reel module save field
pw_mode db 0 ;password mode
attributes db 0 ;fcb interface attributes hold byte
if BMPM
; number of lock list items required for lock operation
required_table db 1,0,2,2,1,1,2,2,1,1,2,2,1,1,2,2
chk_olist_flag db 0 ;check | test olist flag
lock_sp dw 0 ;lock stack ptr
lock_shell db 0 ;lock shell flag
check_fcb_ret db 0 ;check_fcb return switch
lock_unlock db 0 ;lock | unlock function flag
incr_pdcnt db 0 ;increment process_cnt flag ??
free_mode db 0 ;free lock list entries flag ??
;1=free entries for curdsk
;0=free all entries
cur_pos dw 0 ;current position in lock list
prv_pos dw 0 ;previous position in lock list
dont_close db 0 ;inhibit actual close flag
open_cnt db 0 ;process open file count
lock_cnt db 0 ;process locked record count
file_id dw 0 ;address of file' lock list entry
set_ro_flag db 0 ;set drive r/o flag
check_disk db 0 ;disk reset open file check flag
flushed db 0 ;lock list open file flush flag
;free_root, lock_max, open_max initialized by sysgen
dw offset free_root
open_root dw 0 ;lock list open file list root
lock_root dw 0 ;lock list locked record list root
endif
sdcnt dw 0 ;saved dcnt of file's 1st fcb
sdcnt0 dw 0 ;saved dcnt (user 0 pass)
if BCPM
chain_flag db 0 ;chain flag ??
tod db 0ffh,0ffh,0ffh,0ffh ??
endif
rmf db 0 ;read mode flag for open$reel
wflag db 0 ;xios/bios write flag
dirloc db 0 ;directory flag in rename, etc.
linfo db 0 ;low(info)
dminx db 0 ;local for diskwrite
single db 0 ;set true if single byte
;alloc map
rcount db 0 ;record count in curr fcb
extval db 0 ;extent num and extmsk
vrecord db 0 ;curr virtual record
ADRIVE DB 0 ;CURRENT DISK - must preceed arecord
arecord dw 0 ;curr actual record
db 0 ;curr actual record high byte
ARECORD1 dw 0 ;curr actual block# * blkmsk
drec dw 0 ;curr actual directory record
CUR_dma_seg DW 0
CUR_DMA DW 0
; local variables for directory access
dptr db 0 ;directory pointer 0,1,2,3
ldcnt equ byte ptr dcnt ;low(dcnt)
user_zero_pass db 0 ;search user zero flag
; shell variables
shell_si dw 0 ;bdos command offset
shell_rr db 0,0,0 ;r0,r1,r2 save area
; special 8086 variables:
uda_save dw 0 ;user data area saved value
parametersegment dw 0 ;user parameter segment
returnseg dw 0 ;user return segment
; error messages
err_drv db 0
err_pd_addr dw 0
dskmsg db 13,10,'CP/M Error On '
dskerr db ' : ',0
xerr_list dw 0,permsg,rodmsg,rofmsg,selmsg
dw xe5,xe6,xe7,xe8,xe9,xe10,xe11,xe3
permsg db 'Disk I/O',0
rodmsg db 'Read/Only Disk',0
rofmsg db 'Read/Only File',0
selmsg db 'Invalid Drive',0
xe3 db 'File Opened in Read/Only Mode',0
xe5 db 'File Currently Open',0
xe6 db 'Close Checksum Error',0
xe7 db 'Password Error',0
xe8 db 'File Already Exists',0
xe9 db 'Illegal ? in FCB',0
xe10 db 'Open File Limit Exceeded',0
xe11 db 'No Room in System Lock List',0
crlf_str db 13,10,0
pr_fx db 13,10,'Bdos Function = '
pr_fx1 db ' '
pr_fcb db ' File = '
pr_fcb1 rs 12
db 0
deniedmsg db 13,10,'Disk reset denied, Drive '
denieddrv db 0,':'
db ' Console '
deniedcns db 0
db ' Program '
deniedprc db '12345678',0
if BMPM
; bdos stack switch variables and stack
; used for all bdos disk functions
org ((offset $) + 1) and 0fffeh
; 69 word bdos stack
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
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
dw 0cccch,0cccch,0cccch
bdosstack rw 0
save_sp rw 1
ss_save rw 1
sp_save rw 1
; local buffer area:
info_fcb rb 40 ;local user FCB
save_fcb rb 16 ;fcb save area for xfcb search
mxdiskqd dw 0 ;link
db 0,0 ;net,org
dw qf_keep+qf_mx ;flags (MX queue)
db 'MXdisk '
dw 0,1 ;msglen,nmsgs
dw 0,0 ;nq,dq
dw 1,0 ;msgcnt,out
dw 0 ;buffer ptr
mxdiskqpb db 0 ;flgs
db 0 ;net
dw mxdiskqd ;qaddr
dw 1 ;nmsgs
dw 0 ;buffer
db 'MXdisk '
; Error Message sync param block for mutual exclusion
msg_spb dw 0 ;link Error Message sync parameter block
dw 0 ;owner
dw 0 ;wait
dw 0 ;next
endif
if BCPM
;
; special 8086 variables:
;
ioloc db 0 ;iobyte
user_parm_seg dw 0 ;holds user parameter seg during load
nallocmem db 0 ;no. of allocated memory segments
ncrmem db 0 ;no. of available memory segments
crmem dw 0,0 ;memory table (16 elements)
dw 0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
;
mem_stack_length equ 40
memstack rs mem_stack_length
;8 possible allocations
stbase equ word ptr 0
stlen equ word ptr 2
ccpflag equ byte ptr 4
nccpalloc db 0 ;number of current ccp allocations
mem_stk_ptr dw 0 ;current memory stack location
stackarea rw ssize ;stack size
endstack rb 0 ;top of stack
;
endif
org 0fffh
if CCPMOFF
org 0bffh
endif
db 0

View File

@@ -0,0 +1,604 @@
;*****************************************************
;*
;* 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
; take current process off RLR.
mov ds,sysdat
; ;disable memory for the process
; ;we are taking out of context
;turn off interrupts ?
; mov bx,rlr !; lea si,p_mem-ms_link[bx]
;dsp_dnxt:
; mov si,ms_link[si]
; test si,si !; jz dsp_disabled
; mov cx,ms_start[si] !; mov dx,ms_length[si]
; push si
; mov ax,io_disable !; call xiosif
; pop si
; jmps dsp_dnxt
;
;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 ;
test bx,bx ! jnz switch1 ;
jmp schedule ;
switch1: ;
; ;enable memory for this process
; ;turn on interrupts ?
; mov bx,rlr !; lea si,p_mem-ms_link[bx]
;dsp_enxt:
; mov si,ms_link[si]
; test si,si !; jz dsp_enabled
; mov cx,ms_start[si] !; mov dx,ms_length[si]
; push si
; mov ax,io_enable !; call xiosif
; pop si
; jmps dsp_enxt
;
;dsp_enabled:
;
; ;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.
; ;BX=PD to run next
; test p_flag[bx],pf_8087 ;does this process use the NPX ?
; jz done8087
; cmp bx,owner_8087 ;do we already own it
; je done8087
; xchg bx,owner_8087 ;new owner, also set by terminate
; test bx,bx ! jz get8087 ;no one owns it if BX=0
; mov dx,ds ;save sysdat in DX
; mov ds,p_uda[bx] ;old owner's UDA
; fnstcw ds:u_8087 ;save IEM bit status
; nop ;delay while 8087 busy saves control reg
; fndisi ;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
;get8087:
; mov ds,dx ;DS=sysdat
; mov bx,rlr
; mov ds,p_uda[bx] ;PD to run next
; frstor ds:u_8087 ;get its 8087 environment
; push ds ;DS=UDA
; jmps restore ;UDA on stack
;
;done8087: ;BX=PD to run next
mov dx,p_uda[bx] ! mov ds,dx ;DS=UDA
push dx ;UDA on stack
;Restore interrupt vectors
restore:
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,15 @@
;*****************************************************
;*
;* System Entry Table entry format
;*
;*****************************************************
enttab_entry equ word ptr 0
entlen equ enttab_entry + word
; Flags Values in ent_flag
ef_network equ 0f0h ; network intercept
; see SYSTEM.DEF for ent_tab definition

View File

@@ -0,0 +1,47 @@
;*****************************************************
;*
;* Error definitions
;*
;*****************************************************
e_not_implemented equ 1 ; not implemented
e_bad_entry equ 2 ; illegal func. #
e_no_memory equ 3 ; cant find memory
e_ill_flag equ 4 ; illegal flag #
e_flag_ovrrun equ 5 ; flag over run in
e_flag_underrun equ 6 ; flag underrun in
e_no_qd equ 7 ; no unused qd's
e_no_qbuf equ 8 ; no free qbuffer
e_no_queue equ 9 ; cant find que on qlr
e_q_inuse equ 10 ; queue in use
; equ 11 ;
e_no_pd equ 12 ; no free pd's
e_q_protected equ 13 ; no que access
e_q_empty equ 14 ; empty queue
e_q_full equ 15 ; full queue
e_ncliq equ 16 ; Cli queue missing
; equ 17 ;
e_no_umd equ 18 ; no unused MD's
e_ill_cns equ 19 ; illegal cns num.
e_no_pdname equ 20 ; no PD match
e_no_cnsmatch equ 21 ; no cns match
e_nclip equ 22 ; no cli process
e_illdisk equ 23 ; illegal disk #
e_badfname equ 24 ; illegal filename
e_badftype equ 25 ; illegal filetype
e_nochar equ 26 ; char not ready
e_ill_md equ 27 ; illegal mem descriptor
e_bad_load equ 28 ; bad ret. from BDOS load
e_bad_read equ 29 ; bad ret. from BDOS read
e_bad_open equ 30 ; bad ret. from BDOS open
e_nullcmd equ 31 ; null command
e_not_owner equ 32 ; not owner of resource
e_no_cseg equ 33 ; no CSEG in load file
e_active_pd equ 34 ; PD exists on Thread Root
e_pd_noterm equ 35 ; could not terminate process
e_no_attach equ 36 ; could not attach to ciodev
e_ill_lst equ 37 ; illegal list device
e_ill_passwd equ 38 ; illegal password specified
e_no_mimic equ 39 ; can't mimic or unmimic
e_abort equ 40 ; external termination occured
e_fixuprec equ 41 ; fixup error

View File

@@ -0,0 +1,16 @@
;*****************************************************
;*
;* File Control Block Format
;*
;*****************************************************
fcb_dr equ byte ptr 00h
fcb_name equ byte ptr 01h
fcb_type equ byte ptr 09h
fcb_pwd equ byte ptr 010h
fcb_pptr equ word ptr 018h
fcb_plen equ byte ptr 01ah
fcb_cr equ byte ptr 020h
fcb_r0 equ word ptr 021h

View File

@@ -0,0 +1,39 @@
;*****************************************************
;*
;* 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] ! jmp flag_exit
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,14 @@
;*****************************************************
;*
;* Format of Flag Table Entry
;*
;*****************************************************
flg_pd equ word ptr 0
flg_ignore equ byte ptr (flg_pd + word)
flglen equ flg_ignore + byte
flag_off equ 0ffffh ;flag not set
flag_on equ 0fffeh ;flag set
flag_zig equ 0ffh ;normal value

View File

@@ -0,0 +1,28 @@
;*****************************************************
;*
;* 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,118 @@
;*****************************************************
;*
;* MP/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,'
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 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,17 @@
;*****************************************************
;*
;* Format of Load Table Used by Load Program
;*
;*****************************************************
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

View File

@@ -0,0 +1,902 @@
;*****************************************************
;*
;* 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 ! jcxz h_hdr
jmp lod_exit
h_hdr:
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 form_uda
jmp gc_ifo
form_uda: mov ldt_min[si],(lstklen+ulen)/16 ;min=max=UDA+STK paragraphs
mov ldt_max[si],(lstklen+ulen)/16
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
mov ax,ldt_start[si]
mov p_uda[bx],ax
; remember where lstk,uda are
mov lod_uda,ax
push es ! mov es,ax
add ax,(ulen/16) ! mov lod_lstk,ax
; initialize UDA,LDSTK with zeros
xor di,di ! mov ax,di
mov cx,(ulen + lstklen)/2
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
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
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
mov cx,f_ciostat ! call osif
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 drd_lp
xor cx,cx
ret
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
endif

View File

@@ -0,0 +1,30 @@
;*****************************************************
;*
;* Memory Partition Block
;*
;*****************************************************
mpb_segadr equ word ptr 0
mpb_min equ word ptr mp_segadr + word
mpb_max equ word ptr mp_min + word
mpb_pdadr equ word ptr mp_max + word
mpb_attrib equ word ptr mp_pdadr + word
mpblen equ mp_attrib + word
;*****************************************************
;*
;* Load Memory Segment Format
;*
;*****************************************************
mp_stacksize equ 96*byte
mp_uda equ 0
mp_stack equ mp_uda+ulen
mp_segstart equ mp_stack+mp_stacksize
mp_udapar equ mp_uda/16
mp_stkpar equ mp_stack/16
mp_nparag equ mp_segstart/16

View File

@@ -0,0 +1,18 @@
;*****************************************************
;*
;* 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,306 @@
;*****************************************************
;*
;* 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,28 @@
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 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,30 @@
;*****************************************************
;*
;* Memory Descriptor Formats
;*
;*****************************************************
; format while on MFL or MAL
m_link equ word ptr 0
m_start equ word ptr m_link+word
m_length equ word ptr m_start+word
m_plist equ word ptr m_length+word
m_unused equ word ptr m_plist+word
mdlen equ m_unused+word
; format while on PD as memory segment
; ms_flags uses same definitions as
; mpb_flags
ms_link equ word ptr m_link
ms_start equ word ptr m_start
ms_length equ word ptr m_length
ms_flags equ word ptr m_plist
ms_mau equ word ptr m_unused
; format of spb (share parameter block)
spb_opd equ word ptr 0
spb_rpd equ word ptr spb_opd + word
spb_start equ word ptr spb_rpd + word

View File

@@ -0,0 +1,117 @@
;*****************************************************
;*
;* Memory Management Module Interface
;*
;*****************************************************
CSEG
org 0
jmp init
jmp entry
;3 variables set by GENSYS
sysdat dw 0
supervisor equ (offset $)
rw 2
org 0ch
dev_ver db 6 ;development system data version
;set in sysdat.fmt
db 'COPYRIGHT (C) 1983,'
db ' DIGITAL RESEARCH '
db 'XXXX-0000-'
serial db '654321'
;====
init:
;====
retf
;*****************************************************
;*
;* MEM function table
;*
;*****************************************************
functab dw maxmem_entry ; 53 - Get Max Memory
dw absmax_entry ; 54 - Get Abs Max Mem
dw cpmalloc_entry ; 55 - Alloc Mem
dw cpmabsa_entry ; 56 - Alloc Abs Mem
dw cpmfree_entry ; 57 - Free Mem
dw freeall_entry ; 58 - Free All Mem
dw malloc_entry ; 129 - Rel Mem Rqst
dw mfree_entry ; 130 - Memory Free
dw share_entry ; share memory
dw maualloc_entry ; Alloc from MAU
dw maufree_entry ; Free from MAU
dw mlalloc_entry ; Alloc from Mem List
dw mlfree_entry ; Free from Mem List
;===== =================
entry: ; MEM entry point
;===== =================
; entry: CX = memory function number
; DX,BX parameters
; exit: AX=BX=return code
; CX=error code if BX=0ffffh
; The memory manager is a mutually exclusive code
; section, only one process may be in the memory code
; at one time. However, a process already in the memory manager
; can call the memory manager ENTRY: point again.
; Once a process gets into the memory code it cannot
; be terminated.
call m_sync ;obtain memory system
mov ch,0 ! shl cx,1 ;and make sure TEMPKEEP is on
mov si,cx
call cs:functab[si]
call m_unsync
mov ax,bx ;last time out, BX,CX preserved
retf
m_sync:
;------
push bx ! push cx ! push dx ;save entry parameters
mov bx,offset mem_spb
mov cx,f_sync ;obtain memory system
call osif ;reetrancy stops here ...
inc mem_cnt ;keep track how many
;times through memory entry
cmp mem_cnt,1 ! jne ms1
mov cx,f_no_abort ;cannot abort while in
call osif ;MEM, call NO_ABORT_ENTRY
ms1: ;on 1st time through only
pop dx ! pop cx ! pop bx
ret
; Note: the MEM_CNT variable is set to 1 by TERMINATE in the RTM
; and back to 0 by the TERM_ACT in the dispatcher.
m_unsync:
;--------
dec mem_cnt ;only release when last time
jnz mu_ret ;out of memory system
push bx ! push cx
mov bx,offset mem_spb
mov cx,f_unsync
call osif ;reentrancy starts here ...
mov cx,f_ok_abort
call osif ;exit no_abort region
pop cx ! pop bx
mu_ret:
ret
;==== ================
osif: ; O.S. interface
;==== ================
callf cs:dword ptr .supervisor ! ret
;====== ================
xiosif: ; XIOS interface
;====== ================
callf dword ptr .xiosmod ! ret

View File

@@ -0,0 +1,484 @@
;*****************************************************
;*
;* 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,212 @@
;*****************************************************
;*
;* 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
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
;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: 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,159 @@
;*****************************************************
;*
;* CCP/M-86, MP/M-86 Inter-Module Function Definitions
;*
;* Same calling conventions as User programs
;* except CX = function instead of CL
;* BX = 2nd parameter on entry
;* (CH=module, CL=function # in module)
;*
;*****************************************************
; Module definitions
user equ 0
sup equ 1
rtm equ 2
mem equ 3
cio equ 4
bdos equ 5
xios equ 6
net equ 7
; Bits that represent present modules
; in module_map
supmod_bit equ 001h
rtmmod_bit equ 002h
memmod_bit equ 004h
bdosmod_bit equ 008h
ciomod_bit equ 010h
xiosmod_bit equ 020h
netmod_bit equ 040h
; Supervisor Functions
;f_sysreset equ (user * 0100h) + 0
;f_conin equ (user * 0100h) + 1
f_conout equ (user * 0100h) + 2
;f_rconin equ (user * 0100h) + 3 ;supported internally
;f_rconout equ (user * 0100h) + 4 ;under CCP/M
f_lstout equ (user * 0100h) + 5
;f_rawconio equ (user * 0100h) + 6
;f_getiobyte equ (user * 0100h) + 7
;f_setiobyte equ (user * 0100h) + 8
f_conwrite equ (user * 0100h) + 9
f_conread equ (user * 0100h) + 10
;f_constat equ (user * 0100h) + 11
;f_bdosversion equ (user * 0100h) + 12
;f_diskreset equ (user * 0100h) + 13
;f_diskselect equ (user * 0100h) + 14
f_fopen equ (user * 0100h) + 15
f_fclose equ (user * 0100h) + 16
;f_searchfirst equ (user * 0100h) + 17
;f_searchnext equ (user * 0100h) + 18
;f_fdelete equ (user * 0100h) + 19
f_freadseq equ (user * 0100h) + 20
;f_fwriteseq equ (user * 0100h) + 21
;f_fmake equ (user * 0100h) + 22
;f_frename equ (user * 0100h) + 23
;f_loginvector equ (user * 0100h) + 24
f_getdefdisk equ (user * 0100h) + 25
f_setdma equ (user * 0100h) + 26
;f_getallocvec equ (user * 0100h) + 27
;f_writeprotect equ (user * 0100h) + 28
;f_getrovector equ (user * 0100h) + 29
;f_setfileattr equ (user * 0100h) + 30
;f_getdpb equ (user * 0100h) + 31
f_usercode equ (user * 0100h) + 32
f_freadrdm equ (user * 0100h) + 33
;f_fwriterdm equ (user * 0100h) + 34
;f_filesize equ (user * 0100h) + 35
f_setrndrec equ (user * 0100h) + 36
;f_resetdrive equ (user * 0100h) + 37
;f_accessdrive equ (user * 0100h) + 38
;f_freedrive equ (user * 0100h) + 39
;f_writerndzero equ (user * 0100h) + 40
;f_chain equ (user * 0100h) + 47
f_callbios equ (user * 0100h) + 50
f_setdmab equ (user * 0100h) + 51
;f_getdma equ (user * 0100h) + 52
;f_getmaxmem equ (user * 0100h) + 53
;f_getabsmaxmem equ (user * 0100h) + 54
;f_allocmem equ (user * 0100h) + 55
;f_allocabsmem equ (user * 0100h) + 56
f_freemem equ (user * 0100h) + 57
f_freeall equ (user * 0100h) + 58
;f_userload equ (user * 0100h) + 59
f_delim equ (user * 0100h) + 110
f_malloc equ (user * 0100h) + 128
f_memfree equ (user * 0100h) + 130
;f_polldev equ (user * 0100h) + 131
f_flagwait equ (user * 0100h) + 132
f_flagset equ (user * 0100h) + 133
f_qmake equ (user * 0100h) + 134
f_qopen equ (user * 0100h) + 135
;f_qdelete equ (user * 0100h) + 136
f_qread equ (user * 0100h) + 137
f_cqread equ (user * 0100h) + 138
f_qwrite equ (user * 0100h) + 139
f_cqwrite equ (user * 0100h) + 140
;f_delay equ (user * 0100h) + 141
f_dispatch equ (user * 0100h) + 142
f_terminate equ (user * 0100h) + 143
f_createproc equ (user * 0100h) + 144
f_setprior equ (user * 0100h) + 145
f_conattach equ (user * 0100h) + 146
f_condetach equ (user * 0100h) + 147
;f_setdefcon equ (user * 0100h) + 148
f_conassign equ (user * 0100h) + 149
;f_clicmd equ (user * 0100h) + 150
;f_callrsp equ (user * 0100h) + 151
f_parsefilename equ (user * 0100h) + 152
;f_getdefcon equ (user * 0100h) + 153
;f_sdataddr equ (user * 0100h) + 154
;f_timeofday equ (user * 0100h) + 155
;f_pdaddress equ (user * 0100h) + 156
;f_abortprocess equ (user * 0100h) + 157
f_lstattach equ (user * 0100h) + 158
f_lstdetach equ (user * 0100h) + 159
;f_setdeflst equ (user * 0100h) + 160
;f_clstattch equ (user * 0100h) + 161
f_cconattch equ (user * 0100h) + 162
;f_osvernum equ (user * 0100h) + 163
;f_getdeflst equ (user * 0100h) + 164
; Internal SUP functions
f_load equ (sup * 0100h) + 10
f_cload equ (sup * 0100h) + 14
; Internal RTM functions
f_inflagset equ (rtm * 0100h) + 3
f_sleep equ (rtm * 0100h) + 18
f_wakeup equ (rtm * 0100h) + 19
f_findpdname equ (rtm * 0100h) + 20
f_sync equ (rtm * 0100h) + 21
f_unsync equ (rtm * 0100h) + 22
f_no_abort equ (rtm * 0100h) + 23
f_ok_abort equ (rtm * 0100h) + 24
f_no_abort_spec equ (rtm * 0100h) + 25
; Internal MEM functions
f_share equ (mem * 0100h) + 8
f_maualloc equ (mem * 0100h) + 9
f_maufree equ (mem * 0100h) + 10
f_mlalloc equ (mem * 0100h) + 11
f_mlfree equ (mem * 0100h) + 12
; Internal CIO functions
f_conprint equ (cio * 0100h) + 14
f_cioterm equ (cio * 0100h) + 23
f_ciostat equ (cio * 0100h) + 24
f_rconin equ (cio * 0100h) + 2
f_rconout equ (cio * 0100h) + 3
; Internal BDOS functions
f_bdosterm equ (bdos * 0100h) + 45

View File

@@ -0,0 +1,10 @@
;*****************************************************
;*
;* Definition of Module Table Entry
;*
;*****************************************************
mod_entry equ 0
mod_init equ mod_entry + dword
modlen equ mod_init + dword

View File

@@ -0,0 +1,49 @@
;*****************************************************
;*
;* Memory Parameter Block
;*
;*****************************************************
mpb_start equ word ptr 0
mpb_min equ word ptr mpb_start + word
mpb_max equ word ptr mpb_min + word
mpb_pdadr equ word ptr mpb_max + word
mpb_flags equ word ptr mpb_pdadr + word
mpblen equ mpb_flags + word
; mpb_flags definition (also ms_flags)
mf_load equ 00001h
mf_share equ 00002h
mf_code equ 00004h
; mf_data equ 00008h
; mf_extra equ 00010h
; mf_stack equ 00020h
mf_udaonly equ 00040h
;*****************************************************
;*
;* Memory Free Parameter Block
;*
;*****************************************************
mfpb_start equ word ptr 0
mfpb_pd equ word ptr mfpb_start + word
mfpblen equ mfpb_pd + word
;*****************************************************
;*
;* MAU Free Request
;*
;* +----+----+----+----+----+----+
;* | mau | sat | start |
;* +----+----+----+----+----+----+
;*
;*****************************************************
maf_mau equ word ptr 0
maf_sat equ word ptr maf_mau + word
maf_start equ word ptr maf_sat + word
maflen equ maf_start + word

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,40 @@
;*****************************************************
;*
;* 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,10 @@
;*****************************************************
;*
;* Parse Control Block
;*
;*****************************************************
pcb_flnmptr equ word ptr 0 ; name ptr
pcb_fcbptr equ word ptr pcb_flnmptr + word ; fcb ptr
pcblen equ pcb_fcbptr + word

View File

@@ -0,0 +1,123 @@
;*****************************************************
;*
;* Process Descriptor - with the UDA associated
;* with the PD, describes the current
;* state of a Process under MP/M-CCP/M
;*
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;* 00| link | thread |stat |prior| flag |
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;* 08| Name |
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;* 10| uda | dsk | user| ldsk|luser| mem |
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;* 18| cmod|tkcnt| wait | reserved | parent |
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;* 20| cns |abort| conmode | lst | reserved |
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;* 28| reserved | pret | scratch |
;* +-----+-----+-----+-----+-----+-----+-----+-----+
;*
;* link - Used for placement into System Lists
;* thread - link field for Thread List
;* stat - Current Process activity
;* prior - priority
;* flag - process state flags
;* name - name of process
;* uda - Segment Adress of User Data Area
;* dsk - Current default disk
;* user - Current default user number
;* ldsk - Disk program loaded from
;* luser - User number loaded from
;* mem - pointer to MD list of memory owned
;* by this process
;* cmod - compatibility mode bits.
;* 80 -> F1 bit
;* 40 -> F2 bit
;* 20 -> F3 bit
;* 10 -> F4 bit
;* tkcnt - temp keep count, # times tempkeep has been
;* turned on
;* wait - parameter field while on System Lists
;* org - Network node that originated this process
;* net - Network node running this process
;* parent - process that created this process
;* cns - default console #
;* abort - abort code
;* lst - default list #
;* conmode - console mode for function 109
;* reserved- not currently used
;* pret - return code at termination
;* scratch - scratch word
;*
;*****************************************************
p_link equ word ptr 0
p_thread equ word ptr p_link + word
p_stat equ byte ptr p_thread + word
p_prior equ byte ptr p_stat + byte
p_flag equ word ptr p_prior + byte
p_name equ byte ptr p_flag + word
p_uda equ word ptr p_name + pnamsiz
p_dsk equ byte ptr p_uda + word
p_user equ byte ptr p_dsk + byte
p_ldsk equ byte ptr p_user + byte
p_luser equ byte ptr p_ldsk + byte
p_mem equ word ptr p_luser + byte
p_cmod equ byte ptr p_mem + word
p_tkcnt equ byte ptr p_cmod + byte
p_wait equ word ptr p_tkcnt + byte
p_parent equ word ptr p_wait + 4
p_cns equ byte ptr p_parent + word
p_abort equ byte ptr p_cns + byte
p_conmode equ word ptr p_abort + byte
p_lst equ byte ptr p_conmode + word
p_pret equ word ptr p_lst + 8
p_scratch equ byte ptr p_pret + word
p_wscrtch equ word ptr p_scratch
;
; Process descriptor pd_status values
;
ps_run equ 0 ; in ready list root
ps_poll equ 1 ; in poll list
ps_delay equ 2 ; in delay list
ps_swap equ 3 ; in swap list
ps_term equ 4 ; terminating
ps_sleep equ 5 ; sleep processing
ps_dq equ 6 ; in dq list
ps_nq equ 7 ; in nq list
ps_flagwait equ 8 ; in flag table
ps_ciowait equ 9 ; waiting for character
ps_sync equ 10 ; waiting for sync structure
;
; Process descriptor pd_flag bit values
;
pf_sys equ 00001h ; system process
pf_keep equ 00002h ; do not terminate
pf_kernal equ 00004h ; resident in kernal
pf_pure equ 00008h ; pure memory descibed
pf_table equ 00010h ; from pd table
pf_resource equ 00020h ; waiting for resource
pf_raw equ 00040h ; raw console i/o
pf_ctlc equ 00080h ; abort pending
pf_active equ 00100h ; active tty
pf_tempkeep equ 00200h ; don't terminate yet...
pf_ctld equ 00400h ; explicit detach occured
pf_childabort equ 00800h ; child terminated abnormally
pf_noctls equ 01000h ; control S not allowed
pf_dskld equ 02000h ; process was loaded from disk
pf_nokbd equ 04000h ; ignore keyboard
pf_8087 equ 08000h ; process uses 8087
;
; Process descriptor pcm_flag bit values
; (console mode set by function 109)
;
pcm_11 equ 00001h ; control C status for function 11
pcm_ctls equ 00002h ; disable control S-Q
pcm_rout equ 00004h ; raw output, no tabs or control P
pcm_ctlc equ 00008h ; disable control C
;pcm_rsrv equ 00040h ; used by CP/M 3.0
pcm_ctlo equ 00080h ; disable control O
pcm_rsx equ 00300h ; 2 bits used by RSX for status

View File

@@ -0,0 +1,245 @@
;*****************************************************
;*
;* Process Routines
;*
;*****************************************************
;====== =========================
freepd: ; Free Process Descriptor
;====== =========================
; entry: SI = PD address
; Assumes no memory and on no list except thread.
; Called only from TERM_ACT in the dispatcher
mov di,(offset thrdrt)-p_thread
freepd_npd:
mov bx,p_thread[di] ;find pd on thread
cmp bx,si ! je freepd_trd
mov di,bx ! jmps freepd_npd
freepd_trd:
mov ax,p_thread[si] ! mov p_thread[di],ax
mov ax,p_flag[si] ! and ax,pf_table
cmp ax,0 ! jz freepd_exit
mov bx,pul ! mov p_link[si],bx
mov pul,si
freepd_exit:
ret
;========== ================
proc_creat: ; Create Process
;========== ================
; DX = pd address in u_wrkseg
cmp dx,0 ! jne cp_doit
sub bx,bx ! ret
cp_doit:
call getpdadr ;si->pdaddr in rtm
jcxz cp_gpd
mov bx,0ffffh ! ret
cp_gpd:
mov dx,p_link[si]
push dx ! push si
; init uda fields
cp_uda:
;set Parent
mov bx,rlr
mov p_parent[si],bx
mov p_conmode[si],0 ;console mode - not inherited
;unless RSX which aren't yet
;implemented
mov p_tkcnt[si],0 ;temp keep count
and p_flag[bx],not (pf_childabort + pf_resource)
mov al,p_lst[si]
cmp al,nlstdev ! jb cp_slst
mov al,0 ;make sure its a legal list device
cp_slst:
if mpm
add al,ncondev
endif
mov p_lst[si],al ;list device is relative to 0 in
;CCP/M
;share memory
cmp p_mem[bx],0 ! je cp_nm
cmp p_mem[si],0 ! jne cp_nm
lea di,p_mem[bx]
cp_mnxt: mov di,ms_link[di]
cmp di,0 ! je cp_nm
push di
push ms_start[di] ! push si ! push bx
mov cx,f_share ! mov dx,sp
push ds ! mov ax,ss ! mov ds,ax
call osif ! pop ds
pop bx ! pop si ! pop ax ! pop di
jmps cp_mnxt
cp_nm:
;set physical UDA segment
mov ax,u_wrkseg
mov dx,p_uda[si] ! add dx,ax
mov p_uda[si],dx
;inherit password
push es ! push ds
mov cx,es ! mov es,dx ! mov ds,cx
mov si,offset u_df_password ! mov di,si
mov cx,4 ! rep movsw
;set initial segment values
mov ds,dx ! xor dx,dx
cmp ds:u_initcs,dx ! jne cp_uda1
mov ds:u_initcs,ax
cp_uda1:cmp ds:u_initds,dx ! jne cp_uda2 ;DX=0
mov ds:u_initds,ax
cp_uda2:cmp ds:u_initss,dx ! jne cp_uda3 ;DX=0
mov ds:u_initss,ax
cp_uda3:cmp ds:u_inites,dx ! jne cp_uda4 ;DX=0
mov ds:u_inites,ax
cp_uda4:
;Interrupt vector save areas:
;Get parent's interrupt vectors 0,1,3,4,224,225
;into child's UDA, if the
;interrupt vector is not initialized in the
;child's UDA.
mov ds,dx ;DX,DS=0,ES=child's UDA
mov si,dx ;divide error vector, #0
mov di,offset u_ivectors
call cp_icopy
call cp_icopy ;single step, #1
add si,4 ! add di,4 ;skip NMI, #2
call cp_icopy ;1-byte, #3
call cp_icopy ;overflow, #4
mov si,offset i_os_ip
mov di,offset u_os_ip
call cp_icopy ;O.S. entry, #224
call cp_icopy ;debugger entry, #225
; set user's stack
push es ! pop ds
mov ax,ds:u_initss
mov ds:u_ss,ax
mov ax,ds:u_stack_sp
mov ds:u_sp,ax
; set other uda values
xor dx,dx
mov ds:u_delim,'$' ;console mode init
mov ds:u_error_mode,dl
mov ds:u_pd_cnt,dl
mov ds:u_mult_cnt,1
mov ds:u_in_int,true
;mov ds:u_insys,dl ;don't set insys
mov bx,ds:u_initds
mov ds:u_ds_sav,bx
mov ds:u_dma_seg,bx
mov ax,ds:u_inites
mov ds:u_es_sav,ax
mov ds:u_dparam,dx
mov ds:u_flag_sav,dx
mov ds:u_conccb,dx
mov ds:u_lstccb,dx
; setup user stack for iret
mov ds,ds:u_ss
mov di,u_sp ;sp->offset
mov ax,u_initcs
mov 2[di],ax ; ->segment
mov word ptr 4[di],0200h ; ->flags, interrupts on
pop ds ! pop es ; DS=SYSDAT, ES=UDA
; put on thread list
pop si ! pushf ! cli ; don't need SYNC here
mov dx,thrdrt ; but this code cannot
mov p_thread[si],dx ; be reentrant
mov thrdrt,si
; put on dispatcher ready list
mov dx,drl ! mov p_link[si],dx
mov drl,si ! popf
; do the next process
pop dx ! jmp proc_creat
cp_icopy:
;--------
; Entry: ES:DI = UDA ivector location to store
; DS:SI = ivector to copy
; DX = 0
; Exit:
; DI,SI = incremented by 4
cmp es:word ptr 0[di],dx ;DX=0, DI=UDA ivector to copy
jne cp_nocopy ;don't copy interrupt vector
cmp es:word ptr 2[di],dx ;if it is <> 0 in the UDA
jne cp_nocopy
mov cx,2 ;move two words
rep movsw ;copy to UDA
ret
cp_nocopy:
add si,4 ! add di,4
ret
getpdadr:
;--------
; entry: DX = PD address in U_WRKSEG
; exit: CX = 0 successful
; SI = PD address in SYSDAT if success
; CX =
; Make sure PD address is in SYSDAT. If not, copy into
; one in PD table. Make address relative to SYSDAT
push dx ;save PD in U_WRKSEG
mov bx,pdlen
call sysdat_chk
jcxz gpd_bad
mov ax,u_wrkseg ;PD is within SYSDAT
mov bx,ds
sub ax,bx ;U_WRKSEG-SYSDAT
mov cl,4 ! shl ax,cl ;make into bytes
pop si ;SI relative to U_WRKSEG
add si,ax ;SI->PD relative to SYSDAT
jmps gpd_done
gpd_bad:
pop si ;U_WRKSEG:SI->PD to copy
pushf ! cli ;turn off interrupts while
mov di,pul ;changing the PUL
test di,di
jnz gpd_have
mov cx,e_no_pd ;no free PDs left
popf ! ret
gpd_have: ;DI->PD in SYSDAT
mov ax,p_link[di]
mov pul,ax ;update PUL
popf ;allow interrupts
push di ;save address of PD in SYSDAT
push es ;save UDA
push ds ;SYSDAT
mov ds,u_wrkseg ;DS=U_WRKSEG
pop es ;ES=SYSDAT
mov cx,pdlen/2
rep movsw ;copy PD into SYSDAT PD
push es ! pop ds ;DS=SYSDAT
pop es ;ES=UDA
pop si ;SI=PD in SYSDAT
or p_flag[si],pf_table ;got it from PD table
gpd_done:
xor cx,cx
ret

View File

@@ -0,0 +1,82 @@
;*****************************************************
;*
;* Queue Descriptor - This is structure is used
;* to create a queue. One is maintained
;* in the system data area for each queue
;*
;* +----+----+----+----+----+----+----+----+
;* 00 | link |net |org | flags | name...
;* +----+----+----+----+----+----+----+----+
;* 08 ...name | msglen |
;* +----+----+----+----+----+----+----+----+
;* 10 | nmsgs | dq | nq | msgcnt |
;* +----+----+----+----+----+----+----+----+
;* 18 | msgout | buffer |
;* +----+----+----+----+
;*
;* link - used to link QDs is system lists
;* net - which machine in the network
;* org - origin machine in the network
;* flags - Queue Flags
;* name - Name of Queue
;* msglen - # of bytes in one message
;* nmsgs - maximum # of messages in queue
;* dq - Root of PDs waiting to read
;* nq - Root of PDs list waiting to write
;* msgcnt - # of messages currently in queue
;* msgout - next message # to read
;* buf - pointer to queue message buffer
;* (for MX queues, owner of queue)
;*
;*****************************************************
q_link equ word ptr 0
q_net equ byte ptr q_link + word
q_org equ byte ptr q_net + byte
q_flags equ word ptr q_org + byte
q_name equ byte ptr q_flags + word
q_msglen equ word ptr q_name + qnamsiz
q_nmsgs equ word ptr q_msglen + word
q_dq equ word ptr q_nmsgs + word
q_nq equ word ptr q_dq + word
q_msgcnt equ word ptr q_nq + word
q_msgout equ word ptr q_msgcnt + word
q_buf equ word ptr q_msgout + word
qdlen equ q_buf + word
;
; Q_FLAGS values
;
qf_mx equ 001h ; Mutual Exclusion
qf_keep equ 002h ; NO DELETE
qf_hide equ 004h ; Not User writable
qf_rsp equ 008h ; rsp queue
qf_table equ 010h ; from qd table
qf_rpl equ 020h ; rpl queue
qf_dev equ 040h ; device queue
;*****************************************************
;*
;* QPB - Queue Parameter Block
;*
;* +----+----+----+----+----+----+----+----+
;* 00 |flgs|net | qaddr | nmsgs | buffptr |
;* +----+----+----+----+----+----+----+----+
;* 08 | name |
;* +----+----+----+----+----+----+----+----+
;*
;* flgs - unused
;* net - unused (which machine to use)
;* qaddr - Queue ID, address of QD
;* nmsgs - number of messages to read/write
;* buffptr - address to read/write into/from
;* name - name of queue (for open only)
;*
;*****************************************************
qpb_flgs equ byte ptr 0
qpb_net equ byte ptr qpb_flgs + byte
qpb_qaddr equ word ptr qpb_net + byte
qpb_nmsgs equ word ptr qpb_qaddr + word
qpb_buffptr equ word ptr qpb_nmsgs + word
qpb_name equ byte ptr qpb_buffptr + word
qpblen equ qpb_name + qnamsiz

View File

@@ -0,0 +1,458 @@
;*****************************************************
;*
;* 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,224 @@
;****************************************************************
;* *
;* 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,79 @@
;**********************************************************
;*
;* 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,49 @@
;*****************************************************
;*
;* RSP.DEF - Describes the relative offsets of
;* data items in the Data Segment of a
;* Resident System Process. GENSYS
;* links all RSP's together through the
;* rsp_link field (segment address ptrs).
;* Each RSP is started up as System
;* Initialization.
;*
;* Format: +---+---+---+---+---+---+---+---+
;* 00 | link |sdatvar|ncp| reserved |
;* +---+---+---+---+---+---+---+---+
;* 08 | reserved | CS |reserve|
;* +---+---+---+---+---+---+---+---+
;* 10 | Process Descriptor |
;* +---+---+---+---+---+---+---+---+
;* 40 | User Data Area |
;* +---+---+---+---+---+---+---+---+
;* E0 | RSP data area |
;* +---+---+---+---+---+---+---+---+
;*
;* link - GENSYS links all RSP's through this.
;* At system init, this value is filled
;* with the SYSDAT segment address
;* sdatvar - if non-zero, this is a variable address
;* in the SYSDAT area which indicates the
;* a value to put into ncopies (ncp).
;* ncp - Number of copies - Used by GENSYS to determine
;* how many copies of this RSP to generate.
;* This number is modified to be the specific
;* copy that was generated.
;* CS - Used by GENSYS to determine where a shared
;* code segment may exist in multiple copy
;* RSPs.
;*
;*****************************************************
rsp_top equ 0
rsp_link equ word ptr rsp_top
rsp_sysdat equ rsp_link
rsp_sdatvar equ word ptr rsp_link + word
rsp_ncopies equ byte ptr rsp_sdatvar + word
rsp_reserved equ rsp_ncopies + byte
rsp_md equ 08h
rsp_pd equ 10h
rsp_uda equ ((rsp_pd+pdlen+0fh)/10h)*10h
rsp_bottom equ rsp_uda + ulen

View File

@@ -0,0 +1,43 @@
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
if mpm
eject ! include ccb.def
endif
if ccpm
eject ! include vccb.def
endif
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,90 @@
;*****************************************************
;*
;* 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,'
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
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,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,47 @@
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
if ccpm
eject ! include vccb.def
endif
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
if ccpm
eject ! include xiosdat.fmt
endif
eject ! end

View File

@@ -0,0 +1,292 @@
;*****************************************************
;*
;* 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
dec ds:u_insys ! jnz nstk ;switch back to user's stack
;if U_INSYS = 0
cli
mov ss,ds:u_stack_ss
mov sp,ds:u_stack_sp
jmps ueout
nstk:
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-69, 98-112, 128-164.
; Numbers 70-97, 112-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.
cmp cl,69 ! jbe okfunc
sub cl,28 ! cmp cl,70 ! jb illfunc ;98-112 are now 70-84
cmp cl,84 ! jbe okfunc ;128-164 are now 100-136
sub cl,15 ;128-164 are now 85-121
cmp cl,121 ! ja illfunc
okfunc: ;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,ef_network ! jz localfunc ;not a network function
and ah,not ef_network ;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
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,11 @@
;********************************************************
; *
; Sync Parameter Block *
; *
;********************************************************
sy_link equ word ptr 0
sy_owner equ word ptr sy_link + 2
sy_wait equ word ptr sy_owner + 2
sy_next equ word ptr sy_wait + 2
synclen equ sy_next + 2

View File

@@ -0,0 +1,14 @@
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,540 @@
;*****************************************************
;*
;* 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 01130h ;MPM-86 w/BDOS v3.0
osvernum dw 01121h ;MPM-86 V2.1
endif
if ccpm
bvernum dw 01431h ;CCP/M w/BDOS 3.1
osvernum dw 01420h ;CCP/M V2.0
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 db false ; true 8087 exits
; (Numeric Data Processor)
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,0 ; RESERVED
; 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 ; 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 ; 12-get version
db 0, bdos ; 13-diskreset
db 1, bdos ; 14-diskselect
db 2, bdos ; 15-file open
db 3, bdos ; 16-file close
db 4, bdos ; 17-search first
db 5, bdos ; 18-search next
db 6, bdos ; 19-file delete
db 7, bdos ; 20-file read seq
db 8, bdos ; 21-file write seq
db 9, bdos ; 22-file make
db 10, bdos ; 23-file rename
db 11, bdos ; 24-login vector
db 12, bdos ; 25-get def disk
db 13, bdos ; 26-set dma
db 14, bdos ; 27-get alloc vector
db 15, bdos ; 28-write protect
db 16, bdos ; 29-get r/0 vector
db 17, bdos ; 30-set file attr.
db 18, bdos ; 31-get disk parm block
db 19, bdos ; 32-user code
db 20, bdos ; 33-file read random
db 21, bdos ; 34-file write random
db 22, bdos ; 35-file size
db 23, bdos ; 36-set random record
db 24, bdos ; 37-reset drive
db 25, bdos ; 38-access drive
db 26, bdos ; 39-free drive
db 27, bdos ; 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 ; 42-Lock Record
db 29, bdos ; 43-Unlock Record
db 30, bdos ; 44-Set Multi-sector
db 31, bdos ; 45-Set Bdos Error Mode
db 32, bdos ; 46-Get Disk Free Space
db 12, sup ; 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 ; 59-load
db 1, sup ; 60-
db 1, sup ; 61-
db 1, sup ; 62-
db 1, sup ; 63-
;CP/NET functions
db 64, net ; 64-network login
db 65, net ; 65-network logoff
db 66, net ; 66-network send msg
db 67, net ; 67-network rcv msg
db 68, net ; 68-network status
db 69, net ; 69-get network config addr
;CP/M-3 extensions
db 36, bdos ; 98-Reset Alloc Vector
db 37, bdos ; 99-Truncate File
db 38, bdos ;100-Set Dir Label
db 39, bdos ;101-Return Dir Label
db 40, bdos ;102-Read File XFCB
db 41, bdos ;103-Write File XFCB
db 42, bdos ;104-Set Date and Time
db 43, bdos ;105-Get Date and Time
db 44, bdos ;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 ;112-List Block
; 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 ;134-queue make
db 5, rtm ;135-queue open
db 6, rtm ;136-queue delete
db 7, rtm ;137-queue read
db 8, rtm ;138-cond. queue read
db 9, rtm ;139-queue write
db 10, rtm ;140-cond. queue write
db 11, rtm ;141-delay
db 12, rtm ;142-dispatch
db 13, rtm ;143-terminate
db 14, rtm ;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 ;158-attach list
db 16, cio ;159-detach list
db 17, cio ;160-set list dev
db 18, cio ;161-Cond. Attach list
db 19, cio ;162-Cond. Attach Console
db 11, sup ;163-MP/M Version Number
db 20, cio ;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_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
; 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,297 @@
;********************************************************
;* *
;* 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:
test p_tkcnt[si],80H ;was TEMPKEEP on originally ?
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
call terminate_entry ;terminate even if SYS PD,
;see ABT_CHK in ABORT.RTM
;terminate may fail if
;KEEP was set while
oa_ret: ;TEMPKEEP was also set.
mov p_tkcnt[si],0
ret

View File

@@ -0,0 +1,176 @@
;*****************************************************
;*
;* 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,31 @@
;*****************************************************
;*
;* 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
fcblen equ 32 ; size of file control block
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
osint equ 224 ; int vec for O.S. entry
debugint equ osint+1 ; int vec for debuggers
ulen equ 0100h ; size of uda
u8087len equ ulen + 94 ; size of uda when process uses 8087
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
mpm equ false ; MP/M-86 or
ccpm equ not mpm ; CCP/M-86
BCPM equ false ; CP/M-86 BDOS
BMPM equ not BCPM ; multi-process BDOS

View File

@@ -0,0 +1,49 @@
;*****************************************************
;*
;* 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,4 @@
;
; UDA offsets
;
ud_insys equ 60H

View File

@@ -0,0 +1,76 @@
;*****************************************************
;*
;* 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.
;*
;*****************************************************
ud_insys equ 60h
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_unused rw 2 ;
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
; 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,116 @@
;************************************************
;*
;* Virtual Console Control Block Definition
;*
;* +---------+---------+---------+---------+
;* 00 | attach | queue |
;* +---------+---------+---------+---------+
;* 04 | flag | startcol| column | nchar |
;* +---------+---------+---------+---------+
;* 08 | mimic | msource | pc | vc |
;* +---------+---------+---------+---------+
;* 0C | btmp | rsvd | state |
;* +---------+---------+---------+---------+
;* 10 | maxbufsiz | vinq |
;* +---------+---------+---------+---------+
;* 14 | voutq | vcmxq |
;* +---------+---------+---------+---------+
;* 18 | qpbflags| qpbfill | qpbqaddr |
;* +---------+---------+---------+---------+
;* 1C | qpbnmsgs | qpbbuffptr |
;* +---------+---------+---------+---------+
;* 20 | qbuff | cosleep |
;* +---------+---------+---------+---------+
;* 24 | usleep | vsleep |
;* +---------+---------+---------+---------+
;* 28 | Reserved |
;* +---------+---------+---------+---------+
;*
;*
;*
;* attach - current owner of device
;* if 0, no owner
;* if 0ffffh, a mimic device
;* queue - linked list of PDs waiting to attach
;* flag - run-time flags
;* startcol- used for line editing
;* column - used for line editing
;* nchar - 1 character read ahead for CTRL chars.
;* mimic - cio dev that mimics us.
;* 0ffh means no mimic device
;* msource - if attach = 0ffffh, we are a
;* mimic device and msource is the
;* device we are mimicing.
;* pc - physical console number
;* vc - virtual console number
;* btmp - temporary line editing variable
;* rsvd - unused
;* state - current state of virtual console
;* maxbufsiz - maximum file size for buffered mode
;* vinq - address of QPB for this virtual console's
;* input. written by PIN, created by the VOUT
;* process associated with this virtual console
;* voutq - address of QPB for this virtual console's
;* output. written and created by the assoc. VOUT
;* vcmxq - MX queue for changing of virtual console state
;* qpbflags- the 1st 8 bytes of a Queue Parameter Block, for
;* queue reads and writes, used only by reentrant
;* intercept code
;* qbuff - buffer for queue writes
;* cosleep - temporary list for processes waiting for XIOS console output
;* usleep - user process sleeps here
;* vsleep - vout process sleeps here
;*
c_attach equ word ptr 0
c_queue equ word ptr c_attach + word
c_flag equ byte ptr c_queue + word
c_strtcol equ byte ptr c_flag + byte
c_column equ byte ptr c_strtcol + byte
c_nchar equ byte ptr c_column + byte
c_mimic equ byte ptr c_nchar + byte
c_msource equ byte ptr c_mimic + byte
c_pc equ byte ptr c_msource + byte
c_vc equ byte ptr c_pc + byte
c_btmp equ byte ptr c_vc + byte
c_rsvd equ byte ptr c_btmp + byte
c_state equ word ptr c_rsvd + byte
c_maxbufsiz equ word ptr c_state + word
c_vinq equ word ptr c_maxbufsiz + word
c_voutq equ word ptr c_vinq + word
c_vcmxq equ word ptr c_voutq + word
c_qpbflags equ byte ptr c_vcmxq + word
c_qpbfill equ byte ptr c_qpbflags + byte
c_qpbqaddr equ word ptr c_qpbfill + byte
c_qpbnmsgs equ word ptr c_qpbqaddr + word
c_qpbbuffptr equ word ptr c_qpbnmsgs + word
c_qbuff equ word ptr c_qpbbuffptr + word
c_cosleep equ word ptr c_qbuff + word
c_usleep equ word ptr c_cosleep + word
c_vsleep equ word ptr c_usleep + word
ccblen equ c_vsleep + word + 4
; Flags for c_flag
cf_listcp equ 001h ;control P toggle
cf_compc equ 002h ;suppress output
cf_switchs equ 004h ;XIOS supports switch screening
cf_conout equ 008h ;ownership flag of console output
cf_vout equ 010h ;process writing to VOUTQ
cf_bufp equ 020h ;just sent a char to a VOUTQ, don't
;echo to list if csm_ctrlP is set.
;CCB state flags
csm_buffered equ 00001h
csm_background equ 00002h
csm_purging equ 00004h
csm_noswitch equ 00008h
csm_suspend equ 00010h
csm_abort equ 00020h
csm_filefull equ 00040h
csm_ctrlS equ 00080h
csm_ctrlO equ 00100h
csm_ctrlP equ 00200h
;LCB - list control block is first ten bytes of VCCB
lcblen equ 10

View File

@@ -0,0 +1,25 @@
;*****************************************************
;*
;* 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,66 @@
;*****************************************************
;*
;* XIOS function jump table offsets
;*
;*****************************************************
if ccpm
io_const equ 0 ;func 50, direct BIOS
io_conin equ 1 ;can access io_funcs 0-6
io_conout equ 2
io_listst equ 3
io_list equ 4
io_auxin equ 5
io_auxout equ 6
io_switch equ 7
io_statline equ 8
io_seldsk equ 9
io_read equ 10
io_write equ 11
io_flush equ 12
io_polldev equ 13
nxiosfuncs equ io_flush
endif
if mpm
io_const equ 0
io_conin equ 1
io_conout equ 2
io_list equ 3
;io_punch equ 4 ;not used
;io_reader equ 5 ;not used
io_home equ 6
io_seldsk equ 7
io_settrk equ 8
io_setsec equ 9
io_setdma equ 10
io_read equ 11
io_write equ 12
;io_listst equ 13 ;not used
io_sectran equ 14
io_setdmab equ 15
;io_getsegt equ 16 ;not used
io_polldev equ 17
io_strtclk equ 18
io_stopclk equ 19
io_maxconsole equ 20
io_maxlist equ 21
io_selmemory equ 22
io_idle equ 23
io_flush equ 24
nxiosfuncs equ io_flush
endif
;*****************************************************
;*
;* XIOS Parameter Block for CALL XIOS functions
;*
;*****************************************************
xcb_func equ 0
xcb_cx equ word ptr xcb_func + byte
xcb_dx equ word ptr xcb_cx + word
xcblen equ xcb_dx + word

View File

@@ -0,0 +1,15 @@
;*****************************************************
;*
;* 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.