mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-26 01:44:21 +00:00
Upload
Digital Research
This commit is contained in:
@@ -0,0 +1,538 @@
|
||||
;*************************************************************
|
||||
;*
|
||||
;* Terminate and Abort Specify Process Entry Points
|
||||
;*
|
||||
;*************************************************************
|
||||
|
||||
;============== ==============
|
||||
sysreset_entry: ; System Reset
|
||||
;============== ==============
|
||||
xor dx,dx
|
||||
mov cx,f_terminate
|
||||
jmp osif
|
||||
|
||||
;=============== ===============================
|
||||
terminate_entry: ; Terminate - DX=terminate code
|
||||
;=============== ===============================
|
||||
; This entry point is used for a process to terminate itself. The
|
||||
; code from the label 'TERMINATE:' on, is also used by a process to be
|
||||
; terminated when it comes back into context, as set up by
|
||||
; abort specified process.
|
||||
|
||||
mov bx,rlr
|
||||
call abt_chk
|
||||
jcxz terminate
|
||||
jmp term_err
|
||||
|
||||
terminate: ;process terminated by abort
|
||||
mov bx,rlr ;spec resumes execution here
|
||||
cli ;interrupts off during stack switch
|
||||
mov ss,p_uda[bx] ;reset the stack to top of UDA
|
||||
mov sp,ulen
|
||||
sti
|
||||
|
||||
mov p_prior[bx],abt_prior ;finish termination quickly
|
||||
;abort spec can't force us
|
||||
;to reenter terminate when
|
||||
;we have best priority
|
||||
|
||||
mov bx,offset thrd_spb ;get ownership of thread
|
||||
call sync_entry ;list before searching
|
||||
|
||||
xor dx,dx
|
||||
mov bx,(offset thrdrt)-p_thread
|
||||
mov ax,rlr
|
||||
nxtchld:
|
||||
mov bx,p_thread[bx] ;set all child process's p_parent
|
||||
test bx,bx ! jz nochld ;field to 0
|
||||
cmp p_parent[bx],ax
|
||||
jne nxtchld
|
||||
mov p_parent[bx],dx ;found a child, 0 its parent field
|
||||
jmps nxtchld
|
||||
nochld:
|
||||
mov bx,offset thrd_spb
|
||||
call unsync_entry
|
||||
;set parent's child abort flag
|
||||
mov bx,rlr ;if terminating process's
|
||||
test p_flag[bx],pf_ctlc ;CTL_C flag is on, ie, we are
|
||||
jz term_r1 ;terminating from an abort spec
|
||||
and p_flag[bx],not pf_ctlc ;or control C
|
||||
mov bx,p_parent[bx]
|
||||
test bx,bx ! jz term_r1
|
||||
or p_flag[bx],pf_childabort
|
||||
term_r1:
|
||||
mov u_error_mode,0feh ;call BDOS termination
|
||||
if netversion
|
||||
mov cx, f_netterm
|
||||
call osif
|
||||
endif
|
||||
mov cx,f_bdosterm
|
||||
call osif
|
||||
|
||||
mov bx,offset q_spb
|
||||
call sync_entry
|
||||
call rlsmx ;release all MXqueues
|
||||
mov bx,offset q_spb
|
||||
call unsync_entry
|
||||
|
||||
mov bx,offset mem_spb ;get ownership of MEM
|
||||
call sync_entry
|
||||
mov mem_cnt,1 ;keep MEM from freeing
|
||||
;the MEM_SPB
|
||||
|
||||
mov bx,offset thrd_spb ;get the MEM sync BEFORE
|
||||
call sync_entry ;the THRD sync to avoid
|
||||
;deadlock
|
||||
|
||||
mov cx,f_freeall ;free all memory except
|
||||
call osif ;load stack and UDA
|
||||
mov bx,rlr ;dispatcher does rest of
|
||||
mov p_stat[bx],ps_term ;termination
|
||||
jmp dsptch
|
||||
|
||||
term_err:
|
||||
;--------
|
||||
; entry: CX=1 then can't terminate because KEEP or SYS flag
|
||||
; CX=0ffffh TEMPKEEP on, CTLC turned on
|
||||
|
||||
; called from TERMINATE_ENTRY and ABORT_SPEC_ENTRY
|
||||
; after call to ABT_CHK:
|
||||
|
||||
dec cx ! jz term_err1
|
||||
;TEMPKEEP and CTLC flag on
|
||||
xor bx,bx ! mov cx,bx ;and process will terminate
|
||||
ret ;itself, or needs CTLC information
|
||||
|
||||
term_err1:
|
||||
mov cx,e_pd_noterm ;couldn't term because of
|
||||
mov bx,0ffffh ! ret ;SYS or KEEP flags,
|
||||
;CTLC is off
|
||||
|
||||
;================
|
||||
abort_spec_entry: ;Abort the specified process
|
||||
;================
|
||||
; entry: DX = address of APB in the caller's U_WRKSEG
|
||||
; exit: BX = 0 if success, 0FFFFH if failure
|
||||
; CX = 0 " " , error code if failure
|
||||
|
||||
; Set up the specified PD for termination when it is next in context.
|
||||
; If the running PD is the same as the PD to abort, we can just use
|
||||
; the terminate entry point. Otherwise we use the Abort Parameter Block
|
||||
; to find it. If it cannot be found, name and console must both match,
|
||||
; the abort fails. If the TEMPKEEP flag is on, set the CTLC flag
|
||||
; and return. If the KEEP flag is on and not the TEMPKEEP flag,
|
||||
; then fail.
|
||||
; If the terminate code in DL on entry, is not 0ffh
|
||||
; and the SYS flag is on in the PD to be aborted, then fail.
|
||||
; The PD is taken off the list it is attached to via its link field.
|
||||
; The terminating PD's priority is set to ABT_PRIOR,
|
||||
; and the address of TERMINATE: is put on top of its UDA stack.
|
||||
; This forces the terminating process to run next (it has the
|
||||
; best priority in the system) and for it to resume execution
|
||||
; at TERMINATE: on returning from the dispatcher.
|
||||
|
||||
push dx
|
||||
mov bx,offset thrd_spb ; get ownership of thread
|
||||
call sync_entry ; while searching
|
||||
pop si ; U_WRKSEG:SI->APB
|
||||
|
||||
push ds ! mov ds,u_wrkseg
|
||||
mov bx,apb_pd[si] ; get PD adr to abort
|
||||
mov cx,apb_term[si] ; get termination/memfree code
|
||||
mov ah,apb_cns[si] ; console from APB
|
||||
pop ds
|
||||
push cx ; save termination code
|
||||
test bx,bx ! jz abt_findit ; got a PD ID, but not verified
|
||||
call find_pdthrd ; find it on thread
|
||||
push cx ; save return code
|
||||
jmps abt_unsync
|
||||
|
||||
abt_findit:
|
||||
add dx,offset apb_pdname ; get adr of named PD
|
||||
mov bx,offset thrdrt - p_thread ; find it on thread
|
||||
call findpdnc ; look for PD name and console match
|
||||
push cx ; save return code
|
||||
abt_unsync:
|
||||
push bx ; BX=PD if found
|
||||
mov bx,offset thrd_spb
|
||||
call unsync_entry
|
||||
pop bx
|
||||
pop cx ; CX=0 if no PD found
|
||||
jcxz abt_err1
|
||||
; successfully found PD
|
||||
pop dx ; DX = terminate code
|
||||
mov ax,rlr ; we are aborting ourselves
|
||||
cmp ax,bx ; jump to TERMINATE_ENTRY
|
||||
jne abt_notus
|
||||
;if netversion
|
||||
; jmp sysreset_entry
|
||||
;endif
|
||||
;if not netversion
|
||||
jmp terminate_entry
|
||||
;endif
|
||||
abt_notus:
|
||||
mov indisp,true ; stop dispatching
|
||||
;pushf ! cli ; do not let process or another
|
||||
; process (NO_ABORT_SPEC) change the
|
||||
or p_flag[bx],pf_ctlc ; flags while testing and acting on them.
|
||||
call abt_chk ; ok to abort this PD ?
|
||||
jcxz abt_ok
|
||||
;popf ; can't abort it - return
|
||||
call ok_disp
|
||||
jmps term_err
|
||||
|
||||
; The interrupt window above may be lessened if the TERMINATE_ENTRY
|
||||
; code is moved to the dispatcher and the status is set to PS_TERM.
|
||||
; Turning interrupts back on, the aborting process could come
|
||||
; back into context. Before turning on TEMPKEEP it would check
|
||||
; its status, if it is PS_TERM, then it goes to the dispatcher
|
||||
; to terminate.
|
||||
|
||||
abt_ok: ; this process will be aborted
|
||||
mov dl,p_stat[bx] ; call abort function based on status
|
||||
mov dh,0 ! mov di,dx
|
||||
|
||||
add di,di
|
||||
call cs:abort_tab[di] ; find via p_link and take PD off its list
|
||||
;popf
|
||||
call ok_disp ; process can't come back into context
|
||||
; so interrupts are ok
|
||||
jcxz abt_err2 ; couldn't find PD on list by indicated
|
||||
mov indisp,false ; by P_STAT
|
||||
mov p_prior[bx],abt_prior
|
||||
; set to low priority
|
||||
push es ; save calling process' UDA
|
||||
mov es,p_uda[bx] ; UDA of PD being aborted
|
||||
mov si,(ulen-2) ; reset stack to top of UDA
|
||||
mov u_sp,si
|
||||
mov u_ss,es
|
||||
;if netversion
|
||||
; mov es:[si],offset sysreset_entry
|
||||
;endif
|
||||
;if not netversion
|
||||
mov es:[si],offset terminate
|
||||
;endif
|
||||
; TERMINATE: will be executed when
|
||||
; terminating process comes back into
|
||||
; context
|
||||
xor ax,ax ; on exit from dispatcher interrupts
|
||||
mov u_flag_sav,ax ; will be off
|
||||
mov u_inint,false ; return into context with a RET and
|
||||
; not an IRET
|
||||
if netversion
|
||||
inc es:byte ptr u_insys
|
||||
endif
|
||||
pop es ; ES=calling PD's UDA
|
||||
call abt_putdrl
|
||||
xor bx,bx ; indicate sucess
|
||||
jmp pdisp ; force abort to happen before we return
|
||||
; since terminating process has better
|
||||
; priority
|
||||
|
||||
abt_err1:
|
||||
pop dx ; throw out termination code
|
||||
abt_err2:
|
||||
mov cx,e_no_pdname ; set TERM_ERR for other returns
|
||||
mov bx,0ffffh
|
||||
ret
|
||||
|
||||
; The folowing are the abort handlers for a specific PD status.
|
||||
; These labels are entered in the abort_tab(le) in the RTM data area.
|
||||
; Interrupts assumed off.
|
||||
; For all of the following:
|
||||
; entry: BX = PD addr to be aborted
|
||||
; AH = cons
|
||||
; exit: CX=0 if error
|
||||
; BX preserved
|
||||
;
|
||||
; abort_specified process jump table
|
||||
;
|
||||
; Status
|
||||
abort_tab dw abtrun ; 0 = ready list root
|
||||
dw abtslp ; 1 = poll
|
||||
dw abtdly ; 2 = delay
|
||||
dw abtslp ; 3 = swap
|
||||
dw abttrm ; 4 = term
|
||||
dw abtrun ; 5 = sleep
|
||||
dw abtslp ; 6 = dq
|
||||
dw abtslp ; 7 = nq
|
||||
dw abtflg ; 8 = flagwait
|
||||
dw abtslp ; 9 = ciowait
|
||||
dw abtslp ; 10 = sync
|
||||
abt_tablen equ offset $ - offset abort_tab
|
||||
|
||||
abtrun:
|
||||
;-------
|
||||
; On ready list root or dispatcher ready list
|
||||
|
||||
mov di,(offset rlr) - p_link
|
||||
call find_pd
|
||||
jcxz abtr_drl
|
||||
jmps snip_it
|
||||
abtr_drl: ; wasn't on rlr, try drl
|
||||
mov di,(offset drl) - plink
|
||||
jmps abt_common
|
||||
|
||||
abtslp:
|
||||
;------
|
||||
; On list indicated by u_dparam
|
||||
; Note: a PD in the SY_NEXT field will not be found
|
||||
; and cannot be terminated. Usually the PD has TEMPKEEP on
|
||||
; so it never gets this far.
|
||||
|
||||
push es ! mov es,p_uda[bx]
|
||||
mov di,u_dparam
|
||||
pop es ! jmps abt_common
|
||||
|
||||
abtdly:
|
||||
;------
|
||||
mov di,offset dlr - p_link
|
||||
call find_pd
|
||||
jcxz abt_tab_err
|
||||
mov si,p_link[si] ; Fix wait field in next PD on dlr
|
||||
test si,si
|
||||
jz ad_nofix ; Are there more PDs after the one
|
||||
mov dx,p_wait[si] ; being aborted on the DLR ?
|
||||
add dx,p_wait[bx] ; Add wait of aborting PD
|
||||
mov p_wait[si],dx ; New value in next PD on dlr
|
||||
ad_nofix:
|
||||
jmps snip_it
|
||||
|
||||
abttrm:
|
||||
;------
|
||||
mov indisp,false
|
||||
call pdisp ; we are terminating already
|
||||
xor cx,cx ; make sure termination completes
|
||||
jmps abt_tab_err ; before returning error
|
||||
|
||||
abtflg:
|
||||
;------
|
||||
xor cx,cx
|
||||
push es ! mov es, p_uda[bx]
|
||||
mov di,u_dparam ; flag PD field asleep on
|
||||
pop es
|
||||
cmp bx,[di] ; if interrupts are allowed
|
||||
jne aflg_err ; in this code, check DRL
|
||||
inc flg_ignore[di] ; and RLR if not in flags
|
||||
mov flg_pd[di],flag_off
|
||||
inc cx
|
||||
aflg_err:
|
||||
ret
|
||||
|
||||
abt_common:
|
||||
;----------
|
||||
call find_pd ! jcxz abt_tab_err
|
||||
;jmps snip_it
|
||||
|
||||
snip_it:
|
||||
;-------
|
||||
; Take PD out of linked list of PDs
|
||||
; entry: BX = PD being snipped out
|
||||
; DI = offset of previous PD or offset of root - p_link.
|
||||
|
||||
mov dx,p_link[bx] ; DX = next link
|
||||
mov p_link[di],dx
|
||||
ret ; CX<>0
|
||||
|
||||
abt_tab_err:
|
||||
;-----------
|
||||
ret ; CX = 0
|
||||
|
||||
;
|
||||
; End of abort_tab(le) functions
|
||||
;
|
||||
|
||||
|
||||
abt_putdrl:
|
||||
;-------
|
||||
; Puts PD on DRL
|
||||
; entry: BX = PD to insert
|
||||
; exit: BX preserved
|
||||
|
||||
pushf ! cli
|
||||
mov dx,drl
|
||||
mov p_link[bx],dx
|
||||
mov drl,bx
|
||||
popf ! ret
|
||||
|
||||
; Utility routines for abort entry point
|
||||
|
||||
findpdnc:
|
||||
;--------
|
||||
; Find PD by name and console, via thread list.
|
||||
; entry: BX = offset of thread list root - p_thread
|
||||
; DX = adr of name in u_wrkseg
|
||||
; AH = console number
|
||||
; ownership of thread sync
|
||||
; exit: BX = PD
|
||||
; CX = 0 failure
|
||||
|
||||
xor cx,cx
|
||||
nxt_pdname:
|
||||
push ax ; save console number
|
||||
call findpdname_entry
|
||||
pop ax
|
||||
jcxz fnc_found_one ; CX = 0 is success from findpdname
|
||||
xor cx,cx
|
||||
ret ; CX = 0 is failure from this routine
|
||||
fnc_found_one: ; found PD w/ same name
|
||||
cmp p_cns[bx],ah ; chk for same console #
|
||||
jnz nxt_pdname
|
||||
inc cx ! ret ; success
|
||||
|
||||
find_pdthrd:
|
||||
;-----------
|
||||
; Find PD on thread list
|
||||
; entry: BX = PD address we want
|
||||
; ownership of thread sync
|
||||
; exit: CX = 0 if not found
|
||||
; BX prserved
|
||||
|
||||
xor cx,cx
|
||||
mov di,offset thrdrt - p_thread
|
||||
fp_next:
|
||||
mov di,p_thread[di]
|
||||
test di,di
|
||||
jz fp_err
|
||||
cmp bx,di
|
||||
jne fp_next
|
||||
inc cx
|
||||
fp_err:
|
||||
ret
|
||||
|
||||
|
||||
find_pd:
|
||||
;-------
|
||||
; Find PD through link field, interrupts assumed off
|
||||
; entry: BX = PD address
|
||||
; DI = offset of list root - p_link
|
||||
; exit: BX = SI = PD address
|
||||
; DI = Previous PD
|
||||
; CX = 0 if failure
|
||||
|
||||
mov si,p_link[di]
|
||||
xor cx,cx
|
||||
fpd_nxt_pd:
|
||||
test si,si ; SI could be zero to start
|
||||
jz fpd_not_found
|
||||
cmp si,bx ; Are addresses the same ?
|
||||
jz fpd_found
|
||||
fpd_nxt_lnk:
|
||||
mov di,si ; Save previous link
|
||||
mov si,p_link[si]
|
||||
jmps fpd_nxt_pd
|
||||
fpd_found:
|
||||
inc cx
|
||||
fpd_not_found:
|
||||
ret
|
||||
|
||||
fflgpd:
|
||||
;-----
|
||||
; Find offset into flag table of flag waiting PD
|
||||
; entry: BX = PD
|
||||
; exit: DI = offset in RTM data of flag
|
||||
; CX = 0 if failure
|
||||
; BX preserved
|
||||
|
||||
mov cl,nflags
|
||||
xor ch,ch
|
||||
mov di,flags
|
||||
ffp_nxt_flg:
|
||||
cmp bx,flg_pd[di] ; assume legal flag
|
||||
jz ffp_pdfound
|
||||
add di,flglen
|
||||
loop ffp_nxt_flg
|
||||
ffp_pdfound:
|
||||
ret ; CX is 0 at end of loop instr
|
||||
; CX <> 0 if found
|
||||
|
||||
|
||||
ok_disp:
|
||||
;-------
|
||||
mov indisp,false
|
||||
cmp drl,0
|
||||
jz od_ret
|
||||
call pdisp
|
||||
od_ret:
|
||||
ret
|
||||
|
||||
|
||||
abt_chk:
|
||||
;-------
|
||||
; Check different PD flags for terminate or abort
|
||||
; CTLC flag is on if called from ABORT_SPEC
|
||||
; entry: BX = PD to possibly abort
|
||||
; DL = termination code
|
||||
; interrupts off if called from ABORT_SPEC
|
||||
; exit: CX = 00000H if ok to abort
|
||||
; 00001H IF NOT OK TO ABORT
|
||||
; 0FFFFH IF TEMPKEEP
|
||||
; BX = PD as on entry
|
||||
; interrupts unchanged
|
||||
|
||||
xor cx,cx
|
||||
mov ax,p_flag[bx] ;AX = PD flags
|
||||
|
||||
;test TEMPKEEP first
|
||||
;for signaling KEEP process
|
||||
;to terminate i.e., the TMP
|
||||
;while in the CLI
|
||||
test ax,pf_tempkeep ! jz ac_keep
|
||||
or ax,pf_ctlc ;signal control C
|
||||
dec cx ;temp keep return
|
||||
jmps ac_ret
|
||||
ac_keep:
|
||||
test ax,pf_keep ! jnz ac_no
|
||||
;not KEEP, test SYS
|
||||
inc dl ! jz ac_ok ;if DL = 0ffh -> ok to terminate
|
||||
test ax,pf_sys ! jz ac_ok ;DL<>0ffh & not sys-> ok to terminate
|
||||
ac_no:
|
||||
and ax,not pf_ctlc ;turn off ctlc
|
||||
inc cx ;CX=1, can't terminate
|
||||
|
||||
ac_ret:
|
||||
mov p_flag[bx],ax ;new flags if no termination
|
||||
ac_ok:
|
||||
ret
|
||||
|
||||
rlsmx:
|
||||
;-----
|
||||
; Release all MX queues owned by the terminating process
|
||||
; called only from TERMINATE_ENTRY
|
||||
; entry: we own the Queue SYNC
|
||||
; exit: none
|
||||
|
||||
; To guard against queue deletes, and to make interrupt
|
||||
; windows are smaller, we start over from the beginning of
|
||||
; QLR after we write to an MXqueue that we own.
|
||||
|
||||
mov bx,rlr ;BX=running process
|
||||
; pushf ! cli
|
||||
mov si,(offset qlr)-q_link
|
||||
rm_nxt:
|
||||
mov si,q_link[si] ;SI=QD currently checking
|
||||
test si,si ;end of list ?
|
||||
jz rm_done
|
||||
test q_flags[si],qf_mx ;is it an MX queue ?
|
||||
jz rm_nxt
|
||||
cmp bx,q_buf[si] ;do we own it ?
|
||||
jne rm_nxt
|
||||
; popf ;allow interrupts
|
||||
push si ;put 2-word QPB on stack
|
||||
xor ax,ax
|
||||
push ax
|
||||
mov dx,sp
|
||||
mov cx,f_qwrite
|
||||
push ds ;save DS
|
||||
push ss ! pop ds ;DS=SS
|
||||
call osif
|
||||
pop ds ;restore DS
|
||||
pop ax ! pop ax ;throw out 2-word QPB
|
||||
jmps rlsmx ;start over from
|
||||
;top of queue list
|
||||
;a queue could have been
|
||||
;deleted while we were writing
|
||||
rm_done:
|
||||
; popf
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Base Page Format
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
DSEG
|
||||
org 0
|
||||
|
||||
bpg_clen rb 3
|
||||
bpg_cseg rw 1
|
||||
bpg_8080 rb 1
|
||||
|
||||
bpg_dlen rb 3
|
||||
bpg_dseg rw 1
|
||||
bpg_dxxx rb 1
|
||||
|
||||
bpg_elen rb 3
|
||||
bpg_eseg rw 1
|
||||
bpg_exxx rb 1
|
||||
|
||||
bpg_slen rb 3
|
||||
bpg_sseg rw 1
|
||||
bpg_sxxx rb 1
|
||||
|
||||
org 050h
|
||||
|
||||
bpg_lddsk rb 1
|
||||
bpg_pw1ptr rw 1
|
||||
bpg_pw1len rb 1
|
||||
bpg_pw2ptr rw 1
|
||||
bpg_pw2len rb 1
|
||||
|
||||
org 05ch
|
||||
|
||||
bpg_fcb0 rb 0
|
||||
|
||||
org 06ch
|
||||
|
||||
bpg_fcb1 rb 0
|
||||
|
||||
org 80h
|
||||
|
||||
bpg_dma rb 0
|
||||
|
||||
org 100h
|
||||
|
||||
bpg_udata rb 0
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
|
||||
|
||||
include cpyright.def
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* BDOS - Basic Disk Operating System
|
||||
;*
|
||||
;*****************************************************
|
||||
;
|
||||
; generation of BDOS.CON file
|
||||
;
|
||||
; RASM86 bdos
|
||||
; LINK86 bdos.con = bdos [data[origin[0]]]
|
||||
;
|
||||
;*****************************************************
|
||||
|
||||
eject ! include equ.bdo ; symbol definitions
|
||||
eject ! include system.dat
|
||||
eject ! include pd.def
|
||||
eject ! include qd.def
|
||||
eject ! include modfunc.def
|
||||
eject ! include xioscb.def
|
||||
eject
|
||||
|
||||
PCMODE equ false
|
||||
|
||||
include bdosif.bdo ; system initialization
|
||||
eject ! include file1.bdo ; file system part 1
|
||||
eject ! include file2.bdo ; file system part 2
|
||||
eject ! include file3.bdo ; file system part 3
|
||||
eject ! include file4.bdo ; file system part 4
|
||||
eject ! include file5.bdo ; file system part 5
|
||||
eject ! include const.bdo
|
||||
eject ! include patch.cod
|
||||
eject ! include uda.cic ; User Data area
|
||||
eject ! include sysdat.bdo
|
||||
eject ! include data.bdo
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
include cpyright.def
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* MP/M-86 and Concurrent CP/M-86
|
||||
;* Character I/O Module
|
||||
;*
|
||||
;*****************************************************
|
||||
eject ! include system.def
|
||||
eject ! include modfunc.def
|
||||
eject ! include xioscb.def
|
||||
eject ! include pd.def
|
||||
eject ! include err.def
|
||||
eject ! include qd.def
|
||||
eject ! include acb.def
|
||||
eject ! include vccb.def
|
||||
eject ! include char.def
|
||||
eject ! include cmode.def
|
||||
eject ! include cb.def
|
||||
eject ! include uda.def
|
||||
eject ! include cioif.cio
|
||||
eject ! include console.cio
|
||||
eject ! include chario.cio
|
||||
eject ! include patch.cod
|
||||
eject ! include uda.fmt
|
||||
eject ! include sysdat.dat
|
||||
eject ! include data.bdo
|
||||
eject ! end
|
||||
|
||||
@@ -0,0 +1,736 @@
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Command Line Interpreter, Program Chain
|
||||
;*
|
||||
;*****************************************************
|
||||
;=========
|
||||
chain_ent:
|
||||
;=========
|
||||
|
||||
xor dx,dx
|
||||
|
||||
;=======
|
||||
cli_ent:
|
||||
;=======
|
||||
; Create a process based on an Ascii Command Line.
|
||||
; The command Line is first parsed and an FCB is
|
||||
; initialized as a result.
|
||||
; An attempt is made to open a queue with the filename
|
||||
; of the FCB, and with the RSP flag on.
|
||||
; The command tail is written to the queue if it is found.
|
||||
; If the queue cannot be opened or is not and RSP type then
|
||||
; we try and load the command from disk.
|
||||
; If the write queue fails we return e_q_full error code and
|
||||
; do not look on the disk.
|
||||
; After the queue write, an console assign call attempted to
|
||||
; a process with the same name and the PF_DSKLD flag off.
|
||||
; Irregardless of the success of the assign we then return.
|
||||
;
|
||||
; If the RSP queue cannot be opened, or is not an RSP type queue then
|
||||
; we make the name type in the
|
||||
; FCB to be 'CMD' and attempt to open the file. If this fails,
|
||||
; so do we.
|
||||
; We then obtain a Process Descriptor from the
|
||||
; PD table. Again we fail if it does.
|
||||
; On a successful open, we call the BDOS load function.
|
||||
; If the load fails, so do we. The PD is
|
||||
; initialized, the default console is assigned to the
|
||||
; PD, the PF_DSKLD flag turned on,
|
||||
; and a create process call is made.
|
||||
;
|
||||
; input: DX -> command buffer in u_wrkseg
|
||||
; It is assumed that the calling process
|
||||
; is attached to its default console
|
||||
; and is willing to lose it since it
|
||||
; will be handed to the newly created
|
||||
; process.
|
||||
; if DX = 0, assume chain w/command in DMA
|
||||
;
|
||||
; output: BX = 0 if successful
|
||||
; = 0ffffh if failure has occured
|
||||
; CX = error code
|
||||
|
||||
mov bx,rlr ! mov ax,p_flag[bx]
|
||||
push ax ;save flags on stack
|
||||
if netversion
|
||||
or ax,pf_noctls
|
||||
endif
|
||||
if not netversion
|
||||
or ax,pf_tempkeep + pf_noctls
|
||||
endif
|
||||
mov p_flag[bx],ax
|
||||
if netversion
|
||||
mov cx,f_no_abort
|
||||
call osif
|
||||
endif
|
||||
push dx ;save parameter
|
||||
call cli_sync ;rentrancy stops with sync call
|
||||
pop dx ;we can save the flags
|
||||
pop cli_pflag ;and other variables in the CLI
|
||||
;data area
|
||||
; we have CLI SYNC
|
||||
; Check for Chain
|
||||
|
||||
mov cli_chain,false
|
||||
cmp dx,0 ! jne cli_cli
|
||||
mov cli_chain,true
|
||||
mov cli_term,false
|
||||
cli_cli:
|
||||
; initialize defaults from parent PD
|
||||
|
||||
mov cli_dfil,false
|
||||
cmp dayfile,0ffh ! jne nodf
|
||||
push dx ! mov cx,f_cconattch
|
||||
call osif ! pop dx
|
||||
cmp cx,0 ! jne nodf
|
||||
mov cli_dfil,true
|
||||
push dx
|
||||
call prtime
|
||||
pop dx
|
||||
nodf: mov bx,rlr
|
||||
mov cli_ppd,bx
|
||||
mov cl,p_dsk[bx]
|
||||
mov cli_dsk,cl
|
||||
mov cl,p_user[bx]
|
||||
mov cli_user,cl
|
||||
mov cl,p_cns[bx]
|
||||
mov cli_cns,cl
|
||||
mov cl,u_error_mode
|
||||
mov cli_err_mode,cl
|
||||
mov cx,u_dma_ofst
|
||||
mov cli_dma_ofst,cx
|
||||
mov cx,u_dma_seg
|
||||
mov cli_dma_seg,cx
|
||||
mov clierr,0
|
||||
|
||||
; copy command into local area
|
||||
|
||||
cmp cli_chain,true ! jne cli_cpy
|
||||
push es ! push ds
|
||||
mov es,sysdat
|
||||
mov si,cli_dma_ofst
|
||||
mov di,offset cli_cmdtail
|
||||
mov ds,cli_dma_seg
|
||||
mov cx,040H
|
||||
rep movsw
|
||||
pop ds ! pop es
|
||||
jmp cli_parse
|
||||
|
||||
cli_cpy:
|
||||
push es ! push ds
|
||||
mov ds,u_wrkseg ! pop es
|
||||
; DS=Wrkseg, ES=Sysdat, SP->UDA
|
||||
; copy clicb_net
|
||||
mov si,dx ! mov di,offset cli_net
|
||||
movsb
|
||||
; copy command
|
||||
mov si,dx ! add si,clicb_cmd
|
||||
mov di,offset cli_cmdtail
|
||||
mov cx,clicblen-clicb_cmd
|
||||
rep movsb
|
||||
push es ! pop ds ! pop es
|
||||
|
||||
;parse the command
|
||||
cli_parse:
|
||||
call pfn ! jcxz cli_gprs
|
||||
mov clierr,cx
|
||||
jmp cli_exit
|
||||
cli_gprs:
|
||||
|
||||
call shtal
|
||||
|
||||
;fcb has parsed filename
|
||||
;if not explicit disk then
|
||||
; if not RSP try CMD
|
||||
;else try CMD
|
||||
|
||||
cmp cli_fcb,0 ! jne cli_ffload
|
||||
mov bx,(offset cli_fcb)
|
||||
cmp fcb_plen[bx],0 ! jne cli_ffload
|
||||
call cli_checkque ! jnz cli_ffload
|
||||
;successful RSP access
|
||||
cli_qful:
|
||||
cmp cli_chain,true ! jne cli_exit2
|
||||
mov cli_term,true
|
||||
cli_exit2: jmp cli_exit
|
||||
cli_ffload:
|
||||
cmp cx,e_q_full ! jne cli_fload
|
||||
mov clierr,cx ! jmps cli_qful
|
||||
|
||||
cli_checkque:
|
||||
;------------
|
||||
; output: z flag on if successful
|
||||
|
||||
;copy fcb.name to qpb.name
|
||||
|
||||
mov si,(offset cli_fcb)+fcb_name
|
||||
mov di,(offset cli_cuspqpb)+qpb_name
|
||||
mov cx,qnamsiz/2 ! push es ! push ds ! pop es
|
||||
push si ! rep movsw
|
||||
|
||||
;copy fcb.name to acb.name
|
||||
|
||||
pop si ! mov cx,qnamsiz/2
|
||||
mov di,(offset cli_acb)+acb_name
|
||||
rep movsw ! pop es
|
||||
|
||||
;open queue
|
||||
|
||||
mov cx,f_qopen ! mov dx,(offset cli_cuspqpb)
|
||||
call osif ! jcxz cli_goodq
|
||||
retcli1: cmp cx,0 ! ret ;CX = 0ffffh on error
|
||||
|
||||
;we successfully opened the queue
|
||||
;now check RSP flag
|
||||
cli_goodq:
|
||||
mov bx,offset cli_cuspqpb
|
||||
mov bx,qpb_qaddr[bx]
|
||||
test q_flags[bx],qf_rsp ! jnz cli_gq
|
||||
mov cx,e_no_queue ! jmps retcli1
|
||||
|
||||
;write command tail to queue
|
||||
|
||||
cli_gq: mov cx,f_cqwrite ! mov dx,offset cli_cuspqpb
|
||||
call osif ! jcxz cli_qw
|
||||
mov cx,e_q_full ! jmps retcli1
|
||||
|
||||
;successful queue write, assign console
|
||||
|
||||
cli_qw: cmp cli_dfil,true ! jne noqm
|
||||
call prcusp
|
||||
noqm: mov bx,offset cli_acb
|
||||
mov al,cli_cns ! mov acb_cns[bx],al
|
||||
mov acb_match[bx],false
|
||||
mov acb_pd[bx],1 ;match on PD with DSKLD flag off
|
||||
call conasn ! xor cx,cx ! ret
|
||||
|
||||
cli_fload:
|
||||
;---------
|
||||
; Try to Load a file for execution
|
||||
; The Command Line Parsed correctly and we have an FCB
|
||||
; set up. We already know there isn't a queue and a
|
||||
; process by the same name as the command.
|
||||
|
||||
; Obtain a Process Descriptor
|
||||
|
||||
pushf ! cli ! mov bx,pul
|
||||
cmp bx,0 ! jne cli_gpd
|
||||
popf ! mov clierr,e_no_pd
|
||||
jmp cli_exit
|
||||
cli_gpd:
|
||||
mov si,p_link[bx] ! mov pul,si
|
||||
popf ! mov cli_pd,bx
|
||||
; zero PD
|
||||
push es ! push ds ! pop es
|
||||
mov di,bx ! mov cx,pdlen/2
|
||||
xor ax,ax ! rep stosw
|
||||
pop es
|
||||
|
||||
; Initialize the PD for Load
|
||||
|
||||
mov bx,cli_pd
|
||||
mov p_flag[bx],pf_table
|
||||
mov di,bx ! add di,p_name
|
||||
mov si,offset cli_fcb ! add si,fcb_name
|
||||
push es ! mov ax,ds ! mov es,ax
|
||||
mov cx,pnamsiz/2 ! rep movsw
|
||||
pop es
|
||||
mov si,rlr
|
||||
mov al,cli_dsk ! mov p_dsk[bx],al ;inherit parents drive/user
|
||||
mov al,cli_user ! mov p_user[bx],al ;even if we load off another
|
||||
;drive or user
|
||||
|
||||
;this should be in
|
||||
;process create ?
|
||||
|
||||
mov al,cli_cns ! mov p_cns[bx],al
|
||||
mov al,p_lst[si]
|
||||
;if mpm
|
||||
; sub al,ncondev
|
||||
;endif
|
||||
mov p_lst[bx],al
|
||||
|
||||
; 3. Open the file
|
||||
|
||||
mov si,(offset cli_fcb)+fcb_pwd
|
||||
mov di,offset cli_dma
|
||||
push es ! mov es,sysdat
|
||||
mov cx,4 ! rep movsw
|
||||
pop es
|
||||
mov u_dma_ofst,offset cli_dma
|
||||
mov u_dma_seg,ds
|
||||
|
||||
mov si,offset cli_fcb
|
||||
mov byte ptr fcb_type[si],'C'
|
||||
mov byte ptr fcb_type+1[si],'M'
|
||||
mov byte ptr fcb_type+2[si],'D'
|
||||
|
||||
; Open the CMD file
|
||||
|
||||
mov u_error_mode,0feh
|
||||
call flopn
|
||||
cmp bl,0ffh ! jne cli_gopen
|
||||
|
||||
; on failure,
|
||||
; if default is not system disk
|
||||
; and not an explicit disk then
|
||||
; try CMD file on System disk
|
||||
|
||||
cmp bh,0 ! jne cli_bo ;extended error
|
||||
mov cl,srchdisk
|
||||
cmp cl,cli_dsk ! je cli_bo ;already on system disk
|
||||
cmp cli_fcb,0 ! jne cli_bo ;check for explicit
|
||||
;select
|
||||
; try system disk
|
||||
|
||||
; mov bx,rlr
|
||||
; mov p_dsk[bx],cl
|
||||
inc cl
|
||||
mov cli_fcb,cl ;set drive byte to
|
||||
call flopn ;system disk
|
||||
cmp bl,0ffh ! je cli_bo
|
||||
|
||||
;make sure SYS attribute is on...
|
||||
|
||||
mov bx,offset cli_fcb
|
||||
test byte ptr fcb_type+1[bx],080h ! jnz cli_gopen
|
||||
|
||||
;We opened a NON-SYS file. Do explicit open
|
||||
;on user zero if not already
|
||||
|
||||
call flclse
|
||||
mov bx,rlr
|
||||
cmp p_user[bx],0 ! je cli_boe
|
||||
mov p_user[bx],0
|
||||
call flopn
|
||||
cmp bl,0ffh ! je cli_bo
|
||||
mov bx,offset cli_fcb
|
||||
test byte ptr fcb_type+1[bx],080h
|
||||
jnz cli_gopen
|
||||
call flclse
|
||||
jmps cli_boe
|
||||
|
||||
;could not find CMD file
|
||||
|
||||
cli_bo: cmp bh,0 ! jne cli_rmpd2
|
||||
cli_boe: mov clierr,e_bad_open
|
||||
cli_rmpd2: jmp cli_rmpd
|
||||
cli_gopen:
|
||||
|
||||
; 8. Call the load function
|
||||
|
||||
mov bx,rlr
|
||||
test p_flag[bx],pf_ctlc ! jz cli_ld1
|
||||
mov bx,0ffffh ! mov cx,e_abort
|
||||
jmp cli_cl
|
||||
cli_ld1:
|
||||
cmp cmod,true ! jne not_cmod
|
||||
mov bx,cli_pd
|
||||
mov si,offset cli_fcb
|
||||
|
||||
;test F1 bit
|
||||
mov p_cmod[bx],0
|
||||
test byte ptr fcb_name[si],080h ! jz not_f1
|
||||
or p_cmod[bx],080h
|
||||
|
||||
;test F2 bit
|
||||
not_f1: test byte ptr fcb_name+1[si],080h ! jz not_f2
|
||||
or p_cmod[bx],040h
|
||||
|
||||
;test F3 bit
|
||||
not_f2:
|
||||
|
||||
;if mpm dave brown test
|
||||
test byte ptr fcb_name+2[si],080h
|
||||
jz not_f3
|
||||
;endif
|
||||
|
||||
or p_cmod[bx],020h
|
||||
|
||||
;test F4 bit
|
||||
not_f3: test byte ptr fcb_name+3[si],80h ! jz not_cmod
|
||||
or p_cmod[bx],070h
|
||||
not_cmod:
|
||||
|
||||
cmp cli_chain,true ! jne cli_kuda
|
||||
mov bx,cli_pd
|
||||
mov p_uda[bx],es
|
||||
mov ax,offset inituda
|
||||
mov cl,4 ! shr ax,cl
|
||||
add ax,sysdat
|
||||
mov bx,es ! mov es,ax ! mov di,0
|
||||
mov ds,bx ! mov si,di
|
||||
mov cx,ulen/2
|
||||
rep movsw
|
||||
pushf ! cli ! pop dx
|
||||
mov ax,es
|
||||
mov ds,sysdat
|
||||
mov ss,ax
|
||||
mov bx,rlr
|
||||
mov p_uda[bx],ax
|
||||
push dx ! popf
|
||||
cli_kuda:
|
||||
cmp cli_dfil,true ! jne noprfil
|
||||
call prfilnam
|
||||
call crlf
|
||||
|
||||
noprfil:mov bx,cli_pd
|
||||
mov dx,offset cli_fcb
|
||||
mov cx,f_load
|
||||
cmp cli_chain,true ! jne cli_ld
|
||||
mov cli_term,true
|
||||
mov cx,f_cload
|
||||
call osif
|
||||
jcxz cli_cl
|
||||
mov cli_term,false
|
||||
jmp cli_cl
|
||||
cli_ld: call osif
|
||||
cli_cl: push bx ! push cx
|
||||
mov u_error_mode,0
|
||||
call flclse
|
||||
pop cx ! pop bx
|
||||
jcxz cli_gload
|
||||
cmp cx,e_abort ! jne cli_lnab
|
||||
jmp cli_rmpd
|
||||
cli_lnab: mov clierr,cx
|
||||
jmp cli_rmpd
|
||||
cli_gload:
|
||||
mov cli_bpage,bx
|
||||
|
||||
; 9a. Parse Command Tail
|
||||
|
||||
; copy cmdtail to user DMA buffer
|
||||
|
||||
push es ! mov es,cli_bpage
|
||||
mov di,offset bpg_dma+1
|
||||
mov si,offset cli_cmdtail
|
||||
mov cx,127
|
||||
rep movsb ! pop es
|
||||
|
||||
; count cmd length and convert
|
||||
; to upper case
|
||||
|
||||
push ds ! mov ds,cli_bpage
|
||||
mov cl,0 ! mov di,offset bpg_dma+1
|
||||
ncmdchar:
|
||||
cmp byte ptr [di],0 ! je endtail
|
||||
|
||||
; convert CMD tail to UPPER CASE
|
||||
|
||||
cmp byte ptr [di],'a' ! jb nlow
|
||||
cmp byte ptr [di],'z' ! ja nlow
|
||||
and byte ptr [di],05fh
|
||||
nlow:
|
||||
|
||||
|
||||
inc di ! inc cl ! jmps ncmdchar
|
||||
endtail:
|
||||
mov bpg_dma,cl ! pop ds
|
||||
|
||||
; load disk init, location 50H
|
||||
; of base page is done in LOAD
|
||||
|
||||
push es ! mov es,cli_bpage
|
||||
|
||||
; init default fcb
|
||||
|
||||
mov di,offset bpg_fcb0
|
||||
xor ax,ax ! stosb ;default disk
|
||||
mov al,' '
|
||||
mov cx,11 ! rep stosb ;name,type
|
||||
xor ax,ax
|
||||
mov cx,2 ! rep stosw ;other
|
||||
push ds ! push es ! pop ds
|
||||
mov si,offset bpg_fcb0
|
||||
mov cx,8 ! rep movsw
|
||||
pop ds ! pop es
|
||||
|
||||
; if cmdtail, parse
|
||||
|
||||
cmp cli_cmdtail,0 ! je ctdone
|
||||
call pfn
|
||||
cmp bx,0ffffh ! je ctdone
|
||||
|
||||
; copy fcb to user fcb front
|
||||
|
||||
push es ! mov es,cli_bpage
|
||||
mov di,offset bpg_fcb0
|
||||
mov si,offset cli_fcb
|
||||
mov ax,fcb_pptr[si]
|
||||
; AX->password in CLI_CMDTAIL
|
||||
sub ax,offset cli_cmdtail
|
||||
add ax,offset bpg_dma + 1
|
||||
; AX->password in Base Page
|
||||
mov es:bpg_pw1ptr,ax
|
||||
mov al,fcb_plen[si]
|
||||
mov es:bpg_pw1len,al
|
||||
mov cx,8 ! rep movsw ! pop es
|
||||
|
||||
; if more cmdtail, parse
|
||||
|
||||
cmp bx,0 ! je ctdone
|
||||
push cli_pcb ! inc bx
|
||||
mov cli_pcb,bx
|
||||
call pfn
|
||||
pop cli_pcb
|
||||
cmp bx,0ffffh ! je ctdone
|
||||
|
||||
; copy 2nd fcb front
|
||||
|
||||
push es ! mov es,cli_bpage
|
||||
mov di,offset bpg_fcb1
|
||||
mov si,offset cli_fcb
|
||||
mov ax,fcb_pptr[si]
|
||||
; AX->password in CLI_CMDTAIL
|
||||
sub ax,offset cli_cmdtail
|
||||
add ax,offset bpg_dma + 1
|
||||
; AX->password in Base Page
|
||||
mov es:bpg_pw2ptr,ax
|
||||
mov al,fcb_plen[si]
|
||||
mov es:bpg_pw2len,al
|
||||
mov cx,8
|
||||
rep movsw
|
||||
pop es
|
||||
ctdone:
|
||||
|
||||
; 10. Create the process
|
||||
|
||||
cmp cli_chain,true ! jne nprior
|
||||
mov cx,f_setprior
|
||||
mov dx,1 ! call osif
|
||||
nprior:
|
||||
mov si,cli_pd ! or p_flag[si],pf_dskld ;from disk, to differ
|
||||
mov dx,si ! mov cx,f_createproc ;from RSP with same name
|
||||
call osif
|
||||
|
||||
; 11. Assign Console to new process
|
||||
|
||||
mov bx,rlr
|
||||
and p_flag[bx],not pf_ctlc
|
||||
|
||||
; Check to see if user hit CTRL D
|
||||
test p_flag[bx],pf_ctld ! jz asgn
|
||||
and p_flag[bx],not pf_ctld
|
||||
mov bx,cli_pd
|
||||
or p_flag[bx],pf_ctld
|
||||
jmp cli_exit
|
||||
asgn: mov bx,offset cli_acb
|
||||
mov al,cli_cns ! mov acb_cns[bx],al
|
||||
mov ax,cli_pd ! mov acb_pd[bx],ax
|
||||
mov acb_match[bx],true
|
||||
call conasn
|
||||
mov clierr,cx
|
||||
|
||||
jmps cli_exit
|
||||
|
||||
; 12. All Done
|
||||
|
||||
cli_rmpd: ; release PD
|
||||
|
||||
mov si,cli_pd
|
||||
|
||||
; Release any memory that might still be
|
||||
; associated with the PD. This could
|
||||
; happen from a CTRL C.
|
||||
|
||||
cmp p_mem[si],0 ! je rmpd1
|
||||
push ds ! push es
|
||||
push si
|
||||
mov si,p_mem[si]
|
||||
push ms_start[si]
|
||||
mov cx,f_memfree
|
||||
mov dx,sp
|
||||
mov ax,ss ! mov ds,ax
|
||||
call osif
|
||||
pop ax ! pop si
|
||||
pop es ! pop ds
|
||||
jmps cli_rmpd
|
||||
|
||||
; Place empty PD on PUL.
|
||||
|
||||
rmpd1: pushf ! cli
|
||||
mov bx,pul
|
||||
mov p_link[si],bx ! mov pul,si
|
||||
popf
|
||||
|
||||
; Normal EXIT
|
||||
|
||||
cli_exit: ; close file and release CLI SYNC
|
||||
mov bx,rlr
|
||||
mov cl,cli_dsk ! mov p_dsk[bx],cl
|
||||
mov cl,cli_user ! mov p_user[bx],cl
|
||||
mov cl,cli_err_mode ! mov u_error_mode,cl
|
||||
mov cx,cli_dma_ofst ! mov u_dma_ofst,cx
|
||||
mov cx,cli_dma_seg ! mov u_dma_seg,cx
|
||||
cmp cli_chain,true ! jne clirls
|
||||
mov bx,rlr ! mov si,cli_pd ;inherit calling PD's
|
||||
mov ax,p_parent[bx] ;parent if chaining
|
||||
mov p_parent[si],ax
|
||||
cmp cli_term,true ! jne clirls
|
||||
and p_flag[bx],not (pf_keep+pf_sys+pf_tempkeep+pf_ctlc)
|
||||
if netversion
|
||||
mov p_tkcnt[bx],0
|
||||
endif
|
||||
mov cx,f_terminate ;TERM_ACT in dispatcher
|
||||
jmp osif ;releases CLI_SYNC
|
||||
clirls:
|
||||
push cli_pflag
|
||||
push cli_err
|
||||
call cli_unsync
|
||||
if netversion
|
||||
mov cx,f_ok_abort
|
||||
call osif
|
||||
endif
|
||||
pop dx
|
||||
if netversion
|
||||
pop ax ! and ax,pf_noctls
|
||||
endif
|
||||
if not netversion
|
||||
pop ax ! and ax,pf_tempkeep+pf_noctls
|
||||
endif
|
||||
mov bx,rlr ! mov cx,p_flag[bx]
|
||||
if netversion
|
||||
and cx,not pf_noctls
|
||||
endif
|
||||
if not netversion
|
||||
and cx,not pf_tempkeep+pf_noctls
|
||||
endif
|
||||
or cx,ax ! mov p_flag[bx],cx
|
||||
test p_flag[bx],pf_ctlc ! jz cli_nctl
|
||||
mov cx,f_terminate ! xor dx,dx
|
||||
call osif
|
||||
and p_flag[bx],not pf_ctlc
|
||||
mov dx,e_abort
|
||||
|
||||
; setup error return if needed
|
||||
cli_nctl:
|
||||
|
||||
mov cx,dx
|
||||
xor bx,bx
|
||||
jcxz cli_gexit
|
||||
mov bx,0ffffh
|
||||
|
||||
cli_gexit:
|
||||
ret
|
||||
|
||||
shtal:
|
||||
;---------
|
||||
; setup command tail to be parsed
|
||||
; input: AX = output of previous parsefilename
|
||||
|
||||
cmp ax,0 ! je ntail
|
||||
|
||||
;shift command tail to beginning
|
||||
;of command buffer
|
||||
|
||||
push ax ! sub ax,offset cli_cmdtail
|
||||
mov cx,128 ! sub cx,ax ! shr cx,1
|
||||
pop si ! mov di,offset cli_cmdtail
|
||||
push es ! push ds ! pop es
|
||||
rep movsw ! pop es
|
||||
ret
|
||||
ntail:
|
||||
mov cli_cmdtail,0
|
||||
ret
|
||||
|
||||
;============================
|
||||
; Various string subroutines
|
||||
|
||||
crlf: mov dl,13 ! call prchar
|
||||
mov dl,10
|
||||
;jmps prchar
|
||||
|
||||
prchar:
|
||||
mov si,u_conccb
|
||||
mov di,rlr
|
||||
cmp [si],di ! jne prr
|
||||
mov cx,f_conout ! jmp osif
|
||||
prr: ret
|
||||
|
||||
prtime: mov dl,tod_hr ! call prnum
|
||||
mov dl,':' ! call prchar
|
||||
mov dl,tod_min ! call prnum
|
||||
mov dl,':' ! call prchar
|
||||
mov dl,tod_sec ! call prnum
|
||||
mov dl,' ' ! jmps prchar
|
||||
|
||||
prnum: push dx ! mov cl,4
|
||||
shr dl,cl ! add dl,'0'
|
||||
call prchar
|
||||
pop dx ! and dl,0fh
|
||||
add dl,'0' ! jmps prchar
|
||||
|
||||
prfilnam:
|
||||
call prdisk
|
||||
mov dx,(offset cli_fcb)+fcb_name
|
||||
call prnam
|
||||
mov dl,'.' ! call prchar
|
||||
mov dx,(offset cli_fcb) + fcb_type
|
||||
call prtyp
|
||||
mov dl,' ' ! call prchar
|
||||
mov bx,offset cli_fcb
|
||||
test byte ptr fcb_name+7[bx],080h ! jnz pruser
|
||||
cmp cli_user,0 ! je pret
|
||||
mov bx,rlr
|
||||
cmp p_user[bx],0 ! je pruser
|
||||
pret: ret
|
||||
|
||||
pruser: mov dx,offset userstr
|
||||
jmps prcsm
|
||||
|
||||
prdisk: mov dl,cli_fcb
|
||||
cmp dl,0 ! je prpddsk
|
||||
dec dl ! jmps prdsk1
|
||||
prpddsk:
|
||||
mov bx,rlr
|
||||
mov dl,p_dsk[bx]
|
||||
prdsk1: add dl,'A' ! call prchar
|
||||
mov dl,':' ! jmp prchar
|
||||
|
||||
prcusp: mov dx,(offset cli_cuspqpb) + qpb_name
|
||||
call prnam ! mov dx,offset questr
|
||||
call prcsm ! jmp crlf
|
||||
|
||||
prcsm: mov si,u_conccb
|
||||
mov di,rlr
|
||||
cmp [si],di ! jne prr1
|
||||
xor bx,bx ! push ds
|
||||
mov ax,cs ! mov ds,ax
|
||||
call cprnt1 ! pop ds
|
||||
prr1: ret
|
||||
|
||||
prtyp: mov bh,3 ! jmps prn1
|
||||
prnam: mov bh,8
|
||||
prn1: mov bl,' '
|
||||
mov si,u_conccb
|
||||
mov di,rlr
|
||||
cmp [si],di ! jne prr1
|
||||
cprnt1: mov cx,f_conprint ! jmps jos
|
||||
|
||||
flclse:
|
||||
mov cx,f_fclose ! mov dx,offset cli_fcb
|
||||
jmps fo1
|
||||
flopn:
|
||||
mov cx,f_fopen
|
||||
mov si,offset cli_fcb
|
||||
or byte ptr fcb_name+5[si],080h ;f6`=open read-only
|
||||
mov dx,si
|
||||
fo1: push es ! call osif ! pop es ! ret
|
||||
|
||||
cli_sync:mov cx,f_sync
|
||||
jmps mx1
|
||||
|
||||
cli_unsync: mov cx,f_unsync
|
||||
mx1: mov bx,offset cli_spb
|
||||
jos: jmp osif
|
||||
|
||||
pfn: mov dx,offset cli_pcb ! mov cx,f_parsefilename
|
||||
jmps jos
|
||||
|
||||
conasn: mov cx,f_conassign ! mov dx,offset cli_acb
|
||||
jmps jos
|
||||
|
||||
questr db ' Msg Qued',0
|
||||
userstr db '(User 0)',0
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* MEM Entry Points
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
; Format of Memory Control Block used
|
||||
; in CP/M-86 Memory Calls (53 - 58)
|
||||
;
|
||||
; +-----------+-----------+-----+
|
||||
; MCB | Base | Length | ext |
|
||||
; +-----------+-----------+-----+
|
||||
;
|
||||
|
||||
mcb_base equ word ptr 0
|
||||
mcb_length equ word ptr mcb_base + word
|
||||
mcb_ext equ byte ptr mcb_length + word
|
||||
mcblen equ mcb_ext + byte
|
||||
|
||||
|
||||
;============ =====================
|
||||
maxmem_entry: ; 53 - Get Max Memory
|
||||
;============ =====================
|
||||
; input: DX = address of MCB in u_wrkseg
|
||||
; output: BX = 0ffffh if failure
|
||||
; 0h if success
|
||||
; CX = Error Code
|
||||
; mcb_ext = 0 if no additional mem
|
||||
; 1 if more available
|
||||
|
||||
mov si,dx
|
||||
push ds ! mov ds,u_wrkseg
|
||||
mov dx,mcb_length[si] ! pop ds
|
||||
sub ax,ax ! mov bx,ax
|
||||
call getmemory ! jcxz mm_gm
|
||||
mov bx,0ffffh ! ret
|
||||
mm_gm: push ds ! mov ds,u_wrkseg
|
||||
mov mcb_length[si],dx
|
||||
mov mcb_base[si],ax
|
||||
mov mcb_ext[si],1
|
||||
pop ds ! sub bx,bx ! ret
|
||||
|
||||
;============
|
||||
absmax_entry: ; 54 - Get Abs Max Mem
|
||||
;============
|
||||
; Allocate the largest absolute memory region which
|
||||
; is less than or equal mcb_length
|
||||
; input: DX = address of MCB in u_wrkseg
|
||||
; output: BX = 0ffffh if failure
|
||||
; 0h if success
|
||||
; CX = Error Code
|
||||
|
||||
mov si,dx
|
||||
push ds ! mov ds,u_wrkseg
|
||||
mov ax,mcb_base[si]
|
||||
mov dx,mcb_length[si] ! pop ds
|
||||
sub bx,bx
|
||||
call getmemory ! jcxz am_gm
|
||||
mov bx,0ffffh ! ret
|
||||
am_gm: push ds ! mov ds,u_wrkseg
|
||||
mov mcb_length[si],dx
|
||||
mov mcb_base[si],ax
|
||||
pop ds ! sub bx,bx ! ret
|
||||
|
||||
;==============
|
||||
cpmalloc_entry: ; 55 - Alloc Mem
|
||||
;==============
|
||||
; Allocate a memory region which is equal to mcb_length
|
||||
;
|
||||
; input: DX = address of MCB in u_wrkseg
|
||||
; output: BX = 0ffffh if failure
|
||||
; 0h if success
|
||||
; CX = Error Code
|
||||
|
||||
mov si,dx
|
||||
push ds ! mov ds,u_wrkseg
|
||||
sub ax,ax ! mov bx,mcb_length[si]
|
||||
mov dx,bx ! pop ds
|
||||
call getmemory ! jcxz ca_gm
|
||||
mov bx,0ffffh ! ret
|
||||
ca_gm: push ds ! mov ds,u_wrkseg
|
||||
mov mcb_length[si],dx
|
||||
mov mcb_base[si],ax
|
||||
pop ds ! sub bx,bx ! ret
|
||||
|
||||
|
||||
;=============
|
||||
cpmabsa_entry: ; 56 - Alloc Abs Mem
|
||||
;=============
|
||||
; Allocate an absolut memory region which is
|
||||
; equal to mcb_length. Note: For CP/M-86
|
||||
; compatibility, this function must return success
|
||||
; if the memory is already allocated because
|
||||
; the GET MAX functions allocate memory in MP/M, CCP/M
|
||||
; and not in CP/M.
|
||||
;
|
||||
; input: DX = address of MCB in u_wrkseg
|
||||
; output: BX = 0ffffh if failure
|
||||
; 0h if success
|
||||
; CX = Error Code
|
||||
|
||||
mov si,dx
|
||||
push ds ! mov ds,u_wrkseg
|
||||
mov ax,mcb_base[si]
|
||||
mov bx,mcb_length[si]
|
||||
mov dx,bx ! pop ds
|
||||
|
||||
; See if We already own this memory
|
||||
; SI -> MCB in U_WRKSEG
|
||||
; AX=Base, BX=Length, DX=Length
|
||||
|
||||
xor cx,cx
|
||||
mov di,rlr
|
||||
add di,p_mem-ms_link
|
||||
caa_n: mov di,ms_link[di]
|
||||
cmp di,0 ! je caa_g
|
||||
cmp ms_start[di],ax ! jne caa_n
|
||||
cmp ms_length[di],bx ! jbe caa_gm
|
||||
mov cx,e_no_memory
|
||||
mov bx,0ffffh ! ret
|
||||
|
||||
; SI -> MCB in U_WRKSEG
|
||||
; AX=Base, BX=Length, DX=Length
|
||||
caa_g: call getmemory ! jcxz caa_gm
|
||||
mov bx,0ffffh ! ret
|
||||
|
||||
; Successful allocation
|
||||
caa_gm: push ds ! mov ds,u_wrkseg
|
||||
mov mcb_length[si],dx
|
||||
mov mcb_base[si],ax
|
||||
pop ds ! sub bx,bx ! ret
|
||||
|
||||
getmemory:
|
||||
;---------
|
||||
; input: AX = start
|
||||
; BX = min
|
||||
; DX = max
|
||||
; output: AX = start
|
||||
; DX = length
|
||||
; CX = error code
|
||||
; preserve SI
|
||||
|
||||
push si
|
||||
sub cx,cx ! push cx ! push cx ! push dx ! push bx
|
||||
push ax ! mov dx,sp
|
||||
push ds ! mov cx,ss ! mov ds,cx
|
||||
mov cx,f_malloc ! call osif
|
||||
pop ds ! pop ax ! pop dx ! pop bx ! pop bx ! pop bx
|
||||
pop si ! ret
|
||||
|
||||
;=============
|
||||
cpmfree_entry: ; 57 - Free Mem
|
||||
;=============
|
||||
; Free memory as specified in MCB
|
||||
; input: DX = offset of MCB in u_wrkseg
|
||||
; mcb_ext = 0ffh = free all but load mem
|
||||
; else as specified by mcb_base.
|
||||
; mcb_base = seg addr of memory segment
|
||||
; to free. IF in middle of
|
||||
; existing segment then just free
|
||||
; the end of the segment.
|
||||
|
||||
push ds ! mov ds,u_wrkseg
|
||||
mov si,dx
|
||||
mov al,mcb_ext[si]
|
||||
mov dx,mcb_base[si] ! pop ds
|
||||
cmp al,0ffh ! jne free_memory
|
||||
cpmf_root: mov bx,rlr
|
||||
add bx,p_mem-ms_link
|
||||
cpmf_next: mov si,ms_link[bx]
|
||||
cmp si,0 ! jne try_seg
|
||||
sub bx,bx ! mov cx,bx ! ret
|
||||
try_seg: test ms_flags[si],mf_load ! jz free_seg
|
||||
mov bx,si ! jmps cpmf_next
|
||||
free_seg: mov dx,ms_start[si]
|
||||
push si ! call free_memory ! pop si
|
||||
jcxz cpmf_root
|
||||
jmps cpmf_next
|
||||
|
||||
free_memory:
|
||||
;-----------
|
||||
; input: DX = start
|
||||
; output: BX = 0,0ffffh (success,fail)
|
||||
; CX = Error Code
|
||||
|
||||
push ds ! push ss ! pop ds
|
||||
sub cx,cx ! push cx ! push dx
|
||||
mov dx,sp
|
||||
mov cx,f_memfree ! call osif
|
||||
pop dx ! pop dx ! pop ds
|
||||
ret
|
||||
|
||||
;=============
|
||||
freeall_entry: ; 58 - Free All Mem
|
||||
;=============
|
||||
; Free all memory except LOAD UDA and LDSTK
|
||||
; If a transient program calls this, it must free up the
|
||||
; all of the perceived memory. The UDA and LDSTK is not
|
||||
; perceived by CPM compatible programs. The UDA cannot be
|
||||
; freed, since it is part of the process descriptor, until
|
||||
; termination in the dispatcher.
|
||||
|
||||
mov si,rlr
|
||||
mov ax,p_uda[si]
|
||||
add si,p_mem-ms_link
|
||||
fam_n: mov si,ms_link[si]
|
||||
|
||||
; See if anymore memory to free
|
||||
cmp si,0 ! je fam_e
|
||||
mov bx,ms_start[si]
|
||||
|
||||
; See if UDA above start
|
||||
cmp bx,ax ! ja fam_a ;AX=UDA Segment
|
||||
mov cx,bx
|
||||
add cx,ms_length[si]
|
||||
|
||||
; See if below start+len
|
||||
cmp cx,ax ! jb fam_a
|
||||
|
||||
; WE HAVE A UDA !!!
|
||||
; see if we already trimmed it
|
||||
|
||||
test ms_flags[si],mf_udaonly
|
||||
jnz fam_n
|
||||
or ms_flags[si],mf_udaonly
|
||||
|
||||
; trim the memory above the UDA
|
||||
; check if it's an 8087 user
|
||||
mov bx,rlr ;get process
|
||||
test p_flag[bx],pf_8087 ;if not an 8087 user
|
||||
jz med_uda ;try medium uda len
|
||||
add ax,(lstklen+u8087len)/16 ;else use long uda
|
||||
jmp done_uda
|
||||
med_uda: test p_sflag[bx],psf_em87 ;if not 87 emulator
|
||||
jz norm_uda ;do normal uda len
|
||||
add ax,(lstklen+em87len)/16 ;else do medium len
|
||||
jmp done_uda
|
||||
norm_uda: add ax,(lstklen+ulen)/16 ;CX=# paragraphs
|
||||
done_uda: mov bx,ax
|
||||
|
||||
; Free the segment or after the UDA+LDSTK
|
||||
fam_a: mov dx,bx
|
||||
call free_memory
|
||||
jmps freeall_entry
|
||||
fam_e: xor bx,bx ! mov cx,bx ! ret
|
||||
|
||||
@@ -0,0 +1,689 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Dispatch Routines
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;=====
|
||||
fdisp:
|
||||
;=====
|
||||
; This entry point used by interrupt routines in XIOS
|
||||
; Note: if the XIOS is performing memory protection interrupt
|
||||
; handlers must enable O.S. memory before calling the O.S.
|
||||
|
||||
cli
|
||||
push ds ! mov ds,sysdat
|
||||
cmp indisp,true ! je nodisp ;if indisp=true then we are
|
||||
mov ax_sav,ax ;in the dispatcher and
|
||||
mov al,true ! mov indisp,al ;this code is skipped
|
||||
mov ax,es ! mov es_sav,ax
|
||||
mov ax,rlr ! xchg ax,bx ! mov bx_sav,ax
|
||||
mov es,p_uda[bx]
|
||||
mov al,true ! mov u_in_int,al
|
||||
pop ax ! mov u_ds_sav,ax
|
||||
mov al,p_stat[bx]
|
||||
mov u_stat_sav,al
|
||||
mov p_stat[bx],ps_run
|
||||
mov ax,es_sav
|
||||
mov u_es_sav,ax
|
||||
|
||||
; AX in AX_SAV
|
||||
; BX in BX_SAV
|
||||
; ES in U_ES_SAV
|
||||
; DS in U_DS_SAV
|
||||
; p_stat in U_STAT_SAV
|
||||
jmp intdisp
|
||||
;dispatcher will jump to here if
|
||||
; u_in_int = true.
|
||||
|
||||
int_disp_exit: ;interrupts are off
|
||||
|
||||
; AX in AX
|
||||
; BX in BX
|
||||
; ES in U_ES_SAV
|
||||
; DS in U_DS_SAV
|
||||
; p_stat in U_STAT_SAV
|
||||
|
||||
mov ax_sav,ax
|
||||
mov ax,bx ! mov bx_sav,ax
|
||||
;check for
|
||||
cmp drl,0 ! jnz intdisp ;interrupt occurence
|
||||
;on dispatcher exit
|
||||
|
||||
mov al,false ! mov u_in_int,al
|
||||
mov ax,rlr ! mov bx,ax
|
||||
mov al,u_stat_sav
|
||||
mov p_stat[bx],al
|
||||
mov ax,bx_sav ! mov bx,ax
|
||||
mov ax,ax_sav
|
||||
mov indisp,false
|
||||
mov ds,u_ds_sav
|
||||
mov es,u_es_sav
|
||||
iret
|
||||
|
||||
nodisp: pop ds
|
||||
iret
|
||||
|
||||
|
||||
;========
|
||||
farpdisp:
|
||||
;========
|
||||
; Intermodule pdisp (non-interrupt)
|
||||
|
||||
call pdisp ! retf
|
||||
|
||||
;=====
|
||||
pdisp:
|
||||
;=====
|
||||
; Call dispatcher with no special action
|
||||
|
||||
push bx ! mov bx,rlr
|
||||
mov p_stat[bx],ps_run ! pop bx
|
||||
;jmp dsptch
|
||||
|
||||
;======
|
||||
dsptch:
|
||||
;======
|
||||
; The dispatch function looks like a noop to the
|
||||
; caller. All flags and registers are maintained.
|
||||
; No levels of user stack is used.
|
||||
; (jmp dispatch = ret)
|
||||
; Interrupt routines enter through fdisp.
|
||||
;
|
||||
; Dispatch has two (2) arguments:
|
||||
; 1. the p_stat field of the process descriptor
|
||||
; determines the type of action to perform
|
||||
; for this process.
|
||||
; 2. the dparam field of the uda is an argument
|
||||
; to the action.
|
||||
; The main part of the dispatch routine takes the
|
||||
; currently running process off the Ready list
|
||||
; and jmps to a routine which will put it on some
|
||||
; other list depending on the p_stat argument.
|
||||
; The subsequent routine will then jump to the
|
||||
; scheduler which will do polling of devices and
|
||||
; move processes off the dispatch ready list onto
|
||||
; the Ready list. The Ready List is maintained
|
||||
; in priority order with round-robin scheduling
|
||||
; of processes with equivalent priorities. The
|
||||
; first process on the ready list will then be
|
||||
; switched in.
|
||||
|
||||
; set indisp flag
|
||||
pushf ! cli
|
||||
cmp indisp,true ! jne dispin
|
||||
popf ! ret
|
||||
dispin: mov indisp,true
|
||||
pop u_flag_sav
|
||||
|
||||
; assumming bx=RLR:
|
||||
; if PLR=0 and DRL=0 then
|
||||
; if p_stat[bx]=PS_RUN then
|
||||
; if p_link[bx]=0 or
|
||||
; p_prior[p_link[bx]]<>p_prior[bx] then
|
||||
; don't do dispatch
|
||||
|
||||
mov ax_sav,ax
|
||||
mov ax,bx ! mov bx_sav,bx
|
||||
intdisp:
|
||||
cmp plr,0 ! jne dcont ;if Poll list = 0 and
|
||||
cmp drl,0 ! jne dcont ;Dsptch Ready list = 0 and
|
||||
mov ax,rlr ! mov bx,ax ;(RLR can never be 0 here)
|
||||
cmp p_stat[bx],ps_run ! jne dcont ;our status is run and
|
||||
cmp p_link[bx],0 ! je no_disp2 ;other PD to ready to run
|
||||
mov al,p_prior[bx] ;with an equal priority
|
||||
mov bx,p_link[bx] ;THEN skip the dispatch
|
||||
cmp al,p_prior[bx] ! je dcont
|
||||
no_disp2:
|
||||
mov ax,bx_sav ! mov bx,ax
|
||||
mov ax,ax_sav
|
||||
jmp dext
|
||||
|
||||
dcont:
|
||||
mov u_ss,ss ! mov u_sp,sp
|
||||
mov ss,sysdat ! mov sp,offset dsptchtos
|
||||
mov ax,bx_sav ! mov bx,ax
|
||||
mov ax,ax_sav
|
||||
sti
|
||||
cld
|
||||
; save registers
|
||||
; NOTE: We will use DS instead of ES
|
||||
; No segment overrides...
|
||||
|
||||
push es ! pop ds
|
||||
mov ds:u_ax,ax
|
||||
mov ax,bx ! mov ds:u_bx,ax
|
||||
mov ax,cx ! mov ds:u_cx,ax
|
||||
mov ax,dx ! mov ds:u_dx,ax
|
||||
mov ax,di ! mov ds:u_di,ax
|
||||
mov ax,si ! mov ds:u_si,ax
|
||||
mov ax,bp ! mov ds:u_bp,ax
|
||||
|
||||
; Save interrupt vectors 0,1,3,4 not INT 2 which is NMI
|
||||
; MP/M-86, CCP/M-86 1.0 on the IBM PC saved NMI
|
||||
; Block move first 2
|
||||
|
||||
xor bx,bx ! mov ds,bx
|
||||
mov si,bx ! mov di,offset u_ivectors
|
||||
mov dx,4
|
||||
mov cx,dx ! rep movsw
|
||||
mov cx,dx ! add si,dx ;get next 2
|
||||
add di,dx ;skip INT 2 location documented
|
||||
rep movsw ;now as reserved word in UDA
|
||||
; block move osint,debugint
|
||||
|
||||
mov si,offset i_os_ip ! mov di,offset u_os_ip
|
||||
mov cx,dx ! rep movsw
|
||||
mov ds, sysdat
|
||||
|
||||
; if 8087 emulator user,swap extra vectors
|
||||
mov bx,rlr
|
||||
test p_sflag[bx],psf_em87
|
||||
jz u_disp ; not an emulator user
|
||||
push es ! mov ax,ds ; save segment registers
|
||||
push cx! push di
|
||||
mov cx, em_seg ; move 14 vectors from
|
||||
mov si, em_offs ; low memory to uda extension
|
||||
mov di, offset u_8087
|
||||
mov es, p_uda[bx]
|
||||
mov ds,cx
|
||||
mov cx, tot_emvecs/2
|
||||
rep movsw
|
||||
pop di ! pop cx
|
||||
pop es ! mov ds,ax ; restore segment registers
|
||||
|
||||
; swap out userdisp vectors.
|
||||
; acts like a nop to non-userdisp processes
|
||||
u_disp:
|
||||
mov si,rlr
|
||||
mov ax,user_save
|
||||
callf p_userdisp[si]
|
||||
jmps dcont1
|
||||
def_emultr: ; this is the default routine for non-userdisp proc's
|
||||
retf
|
||||
|
||||
dcont1: ; take current process off RLR.
|
||||
;disable memory for the process
|
||||
;we are taking out of context
|
||||
;turn off interrupts ?
|
||||
;dsp_disabled:
|
||||
nop
|
||||
mov ax,rlr ! mov si,ax
|
||||
mov ax,p_link[si] ! mov rlr,ax
|
||||
mov p_link[si],0
|
||||
; We are now in NO-MAN's land
|
||||
; From now until the end of the
|
||||
; switch routine, There is no
|
||||
; process in context.
|
||||
; SI -> PD just taken out of context.
|
||||
; jump to routine for given status
|
||||
xor bh,bh ! mov bl,p_stat[si] ! shl bx,1
|
||||
jmp cs:dsp_table[bx]
|
||||
|
||||
org ((offset $)+1) AND 0fffeh
|
||||
|
||||
dsp_table dw disp_act ;00 - run
|
||||
dw disp_act ;01 - (nop)-poll device
|
||||
dw delay_act ;02 - delay
|
||||
dw disp_act ;03 - (nop)-swap
|
||||
dw term_act ;04 - terminate
|
||||
dw sleep_act ;05 - sleep
|
||||
dw disp_act ;06 - (nop)-dq
|
||||
dw disp_act ;07 - (nop)-nq
|
||||
dw flag_act ;08 - flag wait
|
||||
dw disp_act ;09 - (nop)-ciowait
|
||||
dw disp_act ;10 - (nop)-sync
|
||||
|
||||
sleep_act:
|
||||
;---------
|
||||
; insert running process into list specified by
|
||||
; u_dparam and set p_stat from p_scratch
|
||||
; Note: we cannot sleep on the DLR since interrupts are on
|
||||
; here, and flag_set can change the DLR
|
||||
|
||||
mov ax,u_dparam
|
||||
mov bx,ax
|
||||
push si ! call insert_process
|
||||
pop si ! or p_flag[si],pf_resource
|
||||
mov al,p_scratch[si] ! mov p_stat[si],al
|
||||
jmp schedule
|
||||
|
||||
delay_act:
|
||||
;---------
|
||||
; Put the running process on the Delay List. The
|
||||
; delay list is built such that any process's
|
||||
; remaining delay time is the additive of the delay
|
||||
; times of all processes ahead of it plus the # of
|
||||
; ticks in it's own p_wait field. At each clock tick
|
||||
; the p_wait field of the top process in the list
|
||||
; is decremented. If it reaches zero (0), all
|
||||
; processes with a zero in the p_wait field are
|
||||
; placed on the dispatch ready list.
|
||||
; input: SI=pd address
|
||||
|
||||
cli ;keep flag set from changing
|
||||
;if mpm ;TICK, and changing DLR
|
||||
; push si ! mov al,io_strtclk
|
||||
; call xiosif ! pop si
|
||||
;endif
|
||||
|
||||
;if ccpm
|
||||
mov tick,true
|
||||
;endif
|
||||
|
||||
mov bx,(offset dlr)-p_link
|
||||
mov cx,u_dparam ! inc cx
|
||||
cmp cx,0 ! jne del_lp
|
||||
dec cx
|
||||
del_lp: mov di,p_link[bx]
|
||||
cmp di,0 ! je del_o
|
||||
mov ax,p_wait[di]
|
||||
cmp ax,cx ! ja del_o
|
||||
sub cx,ax ! mov bx,di ! jmps del_lp
|
||||
del_o: mov p_link[si],di ! mov p_link[bx],si
|
||||
mov p_wait[si],cx
|
||||
cmp di,0 ! je del_e
|
||||
sub p_wait[di],cx
|
||||
del_e: jmp schedule
|
||||
|
||||
flag_act:
|
||||
;--------
|
||||
; place running process in flag table to wait
|
||||
; for next flag. Note, flag may have been set...
|
||||
; input: SI=pd address
|
||||
; U_DPARAM=address of Flag entry
|
||||
|
||||
mov ax,u_dparam ! mov bx,ax
|
||||
cli ;protect from flag set
|
||||
cmp flg_pd[bx],flag_on ! je gflagon
|
||||
mov flg_pd[bx],si ! mov p_link[si],0
|
||||
jmp schedule
|
||||
gflagon: ; Flag set since wait check
|
||||
mov flg_pd[bx],flag_off
|
||||
sti
|
||||
jmps disp_act
|
||||
|
||||
term_act:
|
||||
;--------
|
||||
; Terminate the running process, free memory, free pd, free sync
|
||||
; structures. Can only be called by TERMINATE_ENTRY.
|
||||
|
||||
; input: SI=pd address
|
||||
; MEM_SYNC owned by calling process
|
||||
|
||||
; place PD on rlr for now.
|
||||
mov ax,rlr
|
||||
mov p_link[si],ax
|
||||
mov rlr,si
|
||||
|
||||
; clean up consoles
|
||||
mov cx,f_cioterm ! call osif
|
||||
|
||||
; clean up memory
|
||||
; (we own the MXmemory queue)
|
||||
free_nxt:
|
||||
mov ax,rlr ! mov si,ax
|
||||
mov si,p_mem[si]
|
||||
test si,si ! jz end_free
|
||||
push ds ! xor cx,cx ! push cx
|
||||
push ms_start[si]
|
||||
mov ax,ss ! mov ds,ax ! mov dx,sp
|
||||
mov cx,f_memfree ! call osif
|
||||
pop bx ! pop cx ! pop ds
|
||||
jmps free_nxt
|
||||
end_free:
|
||||
|
||||
;release any sync structures
|
||||
;after releasing memory
|
||||
mov mem_cnt,0 ;and MEM_CNT=1
|
||||
;on entry, also own THRD_SYNC
|
||||
;so it is safe to call
|
||||
;FREEPD below,
|
||||
;ASSIGN_SYNC cannot be called
|
||||
;with the THRD_SPB
|
||||
;SI=terminating process
|
||||
mov bx,offset slr - sy_link ;release any sync structures
|
||||
t_nsync: ;owned by terminating PD
|
||||
mov bx,sy_link[bx]
|
||||
test bx,bx ;end of syncs?
|
||||
jz t_sync_done
|
||||
push bx ;PD cannot be allowed to
|
||||
call unsync_entry ;abort if in SY.NEXT
|
||||
pop bx
|
||||
jmps t_nsync
|
||||
|
||||
t_sync_done:
|
||||
|
||||
; take off RLR
|
||||
mov si,rlr
|
||||
mov ax,p_link[si]
|
||||
mov rlr,ax
|
||||
mov p_link[si],0
|
||||
|
||||
cmp si,owner_8087 ;release 8087 if we owned it
|
||||
jne t_end ! mov owner_8087,0
|
||||
t_end:
|
||||
; free up PD
|
||||
call freepd ! jmp schedule
|
||||
|
||||
disp_act:
|
||||
;--------
|
||||
; place process on RLR
|
||||
; input: SI=pd address
|
||||
|
||||
mov p_stat[si],ps_run
|
||||
mov bx,(offset rlr)-p_link
|
||||
call insert_process ! jmp schedule
|
||||
|
||||
;==============
|
||||
insert_process:
|
||||
;==============
|
||||
;
|
||||
; put PD# in list ordered by priority
|
||||
;
|
||||
; entry: BX = list root
|
||||
; SI = pd number
|
||||
; exit: SI is preserved
|
||||
; interrupt state as on entry
|
||||
|
||||
mov cx,pflag[si] ! and cx,pf_resource
|
||||
;if a process was waiting
|
||||
ins_npd: mov di,p_link[bx] ;on a resource, insert
|
||||
test di,di ! jz ins_out ;it ahead of equal priority
|
||||
mov al,p_prior[di] ;process
|
||||
cmp al,p_prior[si]
|
||||
ja ins_out ;lowest priority first
|
||||
jb ins_nxt ;higher - keep going down list
|
||||
jcxz ins_nxt ;equal and not resource
|
||||
jmps ins_out ;equal & resource
|
||||
ins_nxt: mov bx,di ! jmp ins_npd
|
||||
ins_out: jcxz ins_exit
|
||||
and p_flag[si],not pf_resource
|
||||
ins_exit:
|
||||
mov p_link[si],di ! mov p_link[bx],si ! ret
|
||||
|
||||
;========
|
||||
schedule:
|
||||
;========
|
||||
; poll all required devices and place any ready
|
||||
; processes on the Ready List
|
||||
|
||||
;we can enable interrupts now.
|
||||
;there MUST be a process on the RLR
|
||||
;at this point, ie. IDLE...
|
||||
sti
|
||||
;go through the Poll List
|
||||
mov di,(offset plr)-p_link
|
||||
;get the next PD on list.
|
||||
;DI is the last one which
|
||||
;has already been checked.
|
||||
polld_another:
|
||||
mov si,p_link[di]
|
||||
;SI is the next PD to check
|
||||
test si,si ! jz drltorlr
|
||||
;SI is valid PD, poll it.
|
||||
|
||||
;If top PD on the PLR has a worse
|
||||
;priority compared to top PD on the RLR,
|
||||
;there is no reason to call the XIOS
|
||||
;and poll the device, this time through
|
||||
;the dispatcher. We must poll on equal
|
||||
;priority to keep a compute bound
|
||||
;process and the CLOCK from locking
|
||||
;out a polling process.
|
||||
;Note, we stop polling after
|
||||
;the first process that has polled
|
||||
;successfully, or we get to the end of
|
||||
;the PLR. The process is placed on
|
||||
;the RLR.
|
||||
|
||||
mov bx,rlr ! test bx,bx ;if RLR=0: poll
|
||||
jz poll_it
|
||||
mov al,p_prior[si] ;priority of 1st poll PD
|
||||
cmp al,p_prior[bx] ! jbe poll_it ;poll if equal or better
|
||||
jmps drltorlr ;priority than head of RLR
|
||||
poll_it:
|
||||
push di
|
||||
;if mpm
|
||||
; mov cx,p_wait[si]
|
||||
;endif
|
||||
;if ccpm
|
||||
mov dx,p_wait[si]
|
||||
;endif
|
||||
mov al,io_polldev ! call xiosif
|
||||
pop di ! mov si,p_link[di]
|
||||
;if AL=0, device not ready.
|
||||
cmp al,0 ! je polld_next
|
||||
;device ready,
|
||||
;move SI from PLR to RLR
|
||||
mov ax,p_link[si] ! mov p_link[di],ax
|
||||
mov bx,(offset rlr)-p_link
|
||||
mov p_stat[si],ps_run
|
||||
call insert_process ;got one ready to run:
|
||||
jmps drltorlr ;stop polling
|
||||
;p_link[SI]=next PD to check
|
||||
polld_next: ;SI has been checked
|
||||
mov di,si ! jmps polld_another
|
||||
|
||||
drltorlr:
|
||||
;--------
|
||||
; Pull all processes on the dispatch ready list and
|
||||
; place them on the Ready List.
|
||||
|
||||
;We must disable interrupts while
|
||||
;playing with DRL since interrupts
|
||||
;doing a Flag_set may also.
|
||||
;We must competely drain the DRL since
|
||||
;it is in no particular order.
|
||||
|
||||
cli ! mov si,drl ;protect DRL from flag set
|
||||
test si,si ! jz switch
|
||||
mov ax,p_link[si] ! mov drl,ax
|
||||
; test ax,ax ;is this the last PD on DRL?
|
||||
; jnz drl_noi ;yes - don't turn on interrupts
|
||||
sti ;interrupts off guarentees
|
||||
;drl_noi: ;the last DRL PD with the
|
||||
mov p_stat[si],ps_run ;best priority will run
|
||||
mov bx,(offset rlr)-p_link ;next and at least until
|
||||
call insert_process ;it turns on interrupts
|
||||
jmps drltorlr
|
||||
|
||||
switch:
|
||||
;------
|
||||
; switch to the first process on the Ready List
|
||||
|
||||
sti
|
||||
mov bx,rlr
|
||||
; if no next process, go back ;
|
||||
; to schedule. Gives more immediate ;
|
||||
; response to polled and interrupt ;
|
||||
; driven devices ;
|
||||
switch0:
|
||||
test bx,bx ! jnz switch1 ;
|
||||
jmp schedule ;
|
||||
|
||||
; Suspendable processes: in order to be suspended, a process
|
||||
; must be flagged as suspendable, it must be in the background,
|
||||
; and it must not be in the system (e.g.,owning a system queue).
|
||||
; It must also not be coming into context to terminate.
|
||||
switch1:
|
||||
|
||||
cli ;check if process should suspend
|
||||
mov ax,p_sflag[bx]
|
||||
test ax,psf_suspend
|
||||
jz switch2 ;no, not at all
|
||||
|
||||
mov al,p_cns[bx] ;Check vccb's state word
|
||||
xor ah,ah ! xor di,di
|
||||
mov di,ccblen ! mul di
|
||||
mov di,ccb ! add di,ax
|
||||
mov ax,c_state[di]
|
||||
|
||||
test ax,csm_background ;Has it gone into background ?
|
||||
jz switch2 ;no, don't need to suspend
|
||||
|
||||
push es
|
||||
mov es,p_uda[bx]
|
||||
mov al,u_insys ;Is it in the system? If so, don't
|
||||
test al,al ;suspend.
|
||||
pop es
|
||||
jne switch2
|
||||
|
||||
test p_flag[bx],pf_ctlc ;Is it terminating ?
|
||||
jnz switch2 ;Yes, don't put it back on list.
|
||||
|
||||
mov ax,p_link[bx] ;All conditions apply; take it off
|
||||
mov rlr,ax ;the RLR.
|
||||
mov ax,splr ;Get the suspend list
|
||||
mov p_link[bx],ax ;link up and
|
||||
mov splr,bx ;place on top of suspend list.
|
||||
mov p_stat[bx],ps_ciowait ;change its status
|
||||
|
||||
mov ax,c_state[di] ;Turn on suspend if process was
|
||||
test ax,csm_suspend ;created in the background.
|
||||
jnz do_dparam
|
||||
or c_state[di],csm_suspend
|
||||
do_dparam:
|
||||
push es ;Put list root into u_dparam
|
||||
mov es,p_uda[bx] ;for terminate's pd search.
|
||||
mov u_dparam, offset splr
|
||||
pop es
|
||||
|
||||
mov bx,rlr ;BX = RLR
|
||||
sti
|
||||
|
||||
jmp switch0 ;make sure next process isn't suspendable
|
||||
|
||||
;enable memory for this process
|
||||
;turn on interrupts ?
|
||||
;
|
||||
; ;Save and restore the 8087 environment if process to run
|
||||
; ;uses the 8087 and is not the owner. Interrupts
|
||||
; ;must be on. Code from Intel Ap. Note. 113 page 29
|
||||
;
|
||||
; ;This code shouldn't be added unless interrupt windows in
|
||||
; ;switch are allowed or the 8087 restore is separated
|
||||
; ;from the 8086/8088 restore. The switch code without this
|
||||
; ;commented out 8087 code,
|
||||
; ;creates an interrupt window approx. 100 to 200 micro
|
||||
; ;secs on 5 to 4 meg CPU.
|
||||
|
||||
; ;Allowing interrupt windows in switch
|
||||
; ;means we must check on leaving the dispatcher
|
||||
; ;for an interrupt awakened process (DRL again <> 0)
|
||||
; ;and call the
|
||||
; ;dispatcher again to prevent a 16 milli second wakeup time
|
||||
; ;for a PD doing a flagwait after the interrupt service routine.
|
||||
; ;Calling the dispatcher at the end of the dispatch
|
||||
; ;(see commented out code at end of dispatcher and at
|
||||
; ;INT_DISP_EXIT:)
|
||||
; ;creates contention problems between PDs waiting for a resource
|
||||
; ;and PDs waking up from interrupts. It cannot be guarenteed
|
||||
; ;who will run next. An interrupt awakened process can
|
||||
; ;get a just freed resource is should have waited for.
|
||||
; ;The RTM ASSIGN_SYNC_ENTRY is an untested solution
|
||||
; ;for allowing interrupts in the dispatcher switch code.
|
||||
|
||||
switch2:
|
||||
sti ;BX=PD to run next
|
||||
test p_flag[bx],pf_8087 ;does this process use the NDP?
|
||||
jz try_em87 ;if not, see if it emulates 8087
|
||||
cmp bx,owner_8087 ;do we already own it
|
||||
je done8087
|
||||
mov dx,ds ;DX = DS = SYSDAT
|
||||
fwait ;wait until other process is done
|
||||
xchg bx,owner_8087 ;new owner, also set by terminate
|
||||
test bx,bx ! jz get8087 ;no one owns it if BX=0
|
||||
mov ds,p_uda[bx] ;old owner's UDA
|
||||
fstcw ds:u_8087 ;save IEM bit status
|
||||
nop ;delay while 8087 busy saves control reg
|
||||
fdisi ;disable 8087 busy signal
|
||||
mov ax,ds:u_8087 ;get original control word
|
||||
fsave ds:u_8087 ;save NPX context
|
||||
fwait ;IEM=1.wait for save to finish
|
||||
mov ds:u_8087,ax ;save original control word
|
||||
mov ds,dx ;DS = SYSDAT
|
||||
mov es,p_uda[bx] ;swap out and save this user's
|
||||
mov di,offset u_ivec87_of ;ndp interrupt vector
|
||||
mov si,iofs_87 ;DS:SI = system's vector address
|
||||
mov ds,iseg_87 ;ES:DI = user's UDA save area
|
||||
mov cx,2! rep movsw
|
||||
mov ds,dx ;restore DS to SYSDAT
|
||||
get8087:
|
||||
mov bx,rlr
|
||||
mov ds,p_uda[bx] ;PD to run next
|
||||
|
||||
frstor ds:u_8087 ;copy in its 8087 environment frsure
|
||||
push ds ;DS=UDA . UDA on stack.
|
||||
|
||||
restore87_int:
|
||||
mov ds,dx
|
||||
les di,dword ptr iofs_87 ;restore interrupt vectors
|
||||
mov ds, p_uda[bx] ;for 8087 user
|
||||
mov si, offset u_ivec87_of
|
||||
mov cx, 2 ! rep movsw
|
||||
jmps restore
|
||||
|
||||
try_em87: ;8087 emulator has special vector
|
||||
test p_sflag[bx],psf_em87 ;set that must be swapped
|
||||
jz done8087
|
||||
mov ax,ds ;save DS
|
||||
mov cx,em_seg ;move 14 vectors from uda extension
|
||||
mov di,em_offs ;to low memory
|
||||
mov si,offset u_8087 ;u_8087 -> user save area in uda
|
||||
mov ds,p_uda[bx]
|
||||
mov es,cx
|
||||
mov cx,tot_emvecs/2
|
||||
rep movsw
|
||||
mov ds,ax ;restore DS
|
||||
|
||||
done8087: ;no more 8087 or emulator business...
|
||||
;BX=PD to run next
|
||||
mov dx,p_uda[bx] ! mov ds,dx ;DS=UDA
|
||||
push dx ;UDA on stack
|
||||
|
||||
restore:
|
||||
mov es, sysdat ;Restore userdisp vectors.
|
||||
mov ax, es:user_restore ;Acts like a nop to non-userdisp
|
||||
mov si, es:rlr ;processes.
|
||||
callf es:p_userdisp[si] ;Default routine does a retf.
|
||||
|
||||
xor ax,ax ! mov es,ax ! mov di,ax
|
||||
mov si,offset u_ivectors
|
||||
mov dx,4
|
||||
mov cx,dx ! rep movsw ;restore interrupt vectors 0,1
|
||||
mov cx,dx ! add di,dx ;don't touch NMI
|
||||
add si,dx ;skip what was NMI
|
||||
rep movsw ;restore interupt vectors 3,4
|
||||
|
||||
mov si,offset u_os_ip ;DS=UDA
|
||||
mov di,offset i_os_ip
|
||||
mov cx,dx ! rep movsw
|
||||
|
||||
; restore registers
|
||||
mov ax,ds:u_bx ! mov bx,ax
|
||||
mov ax,ds:u_cx ! mov cx,ax
|
||||
mov ax,ds:u_dx ! mov dx,ax
|
||||
mov ax,ds:u_si ! mov si,ax
|
||||
mov ax,ds:u_di ! mov di,ax
|
||||
mov ax,ds:u_bp ! mov bp,ax
|
||||
mov ax,ds:u_ax
|
||||
; restore DS and ES and stack
|
||||
pop es ;ES=UDA
|
||||
cli ;turn interrupts off for rest
|
||||
mov ss,u_ss ;of exit
|
||||
mov sp,u_sp
|
||||
mov ds,sysdat
|
||||
dext:
|
||||
cmp u_in_int,true ! jne dret
|
||||
jmp int_disp_exit
|
||||
dret:
|
||||
push u_flag_sav
|
||||
mov indisp,false
|
||||
cmp drl,0 ! je dd_ret
|
||||
popf ; someone is on DRL from interrupt during
|
||||
jmp pdisp ; switch, dispatch now, no 16ms wait
|
||||
dd_ret:
|
||||
popf
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Find Process Descriptor
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;================ =================================
|
||||
findpdname_entry: ; Find Process Descriptor by Name
|
||||
;================ =================================
|
||||
; Find process by name in thread list
|
||||
; Before calling this routine, calling process must
|
||||
; own the THRD_SPB (Thread Sync Parameter Block) as
|
||||
; interrupts are not turned off.
|
||||
;
|
||||
; input: DX->name in u_wrkseg
|
||||
; BX->thread list root - p_thread
|
||||
; output: BX=pd if found
|
||||
; =0ffffh if not found
|
||||
; CX=0 if found
|
||||
; =e_no_pdname if not found
|
||||
|
||||
push es ! mov es,u_wrkseg
|
||||
fpn_cmpname:
|
||||
mov si,dx
|
||||
mov bx,p_thread[bx]
|
||||
cmp bx,0 ! je fpn_nomatch
|
||||
mov cl,0
|
||||
lea di,p_name[bx]
|
||||
fpn_cmplet:
|
||||
cmp cl,8 ! je fpn_found
|
||||
mov al,es:[si] ! sub al,[di]
|
||||
shl al,1 ! jnz fpn_cmpname
|
||||
inc cl ! inc si ! inc di
|
||||
jmps fpn_cmplet
|
||||
fpn_found: mov cx,0 ! jmps fpn_exit
|
||||
fpn_nomatch:
|
||||
mov cx,e_no_pdname ! mov bx,0ffffh
|
||||
fpn_exit:
|
||||
pop es ! ret
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Flag Management
|
||||
;*
|
||||
;* FLAGS-flag table offset NFLAGS-number of flags
|
||||
;*
|
||||
;* Format of Flag Table Entry:
|
||||
;* +-------------+------+
|
||||
;* | flag |ignore|
|
||||
;* +-------------+------+
|
||||
;* flag - 00000h, flag can be allocated
|
||||
;* flag - 0ffffh, flag is off but is allocated to some
|
||||
;* function.
|
||||
;* 0fffeh, flag is set
|
||||
;* 0xxxxh, PD that is waiting
|
||||
;* ignore- 0ffh, normal case
|
||||
;* 0xxh, number of flags to ignore-1
|
||||
;*
|
||||
;* GENSYS initializes the flags reserved by the system
|
||||
;* and the XIOS header to 0ffh's. The rest of the
|
||||
;* flags are initialized to 0 by GENSYS.
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;============
|
||||
;getfree_flag:
|
||||
;============
|
||||
|
||||
; input: DX = 0 then allocate a flag
|
||||
; else
|
||||
; if DH = 0FFH then release flag number
|
||||
; DL (0 relative)
|
||||
; output:
|
||||
; BX = flag allocated if getting a flag
|
||||
; or 0FFFFH if no flag is available
|
||||
; BX = 0FFFFH if attempting to release a
|
||||
; no existent flag
|
||||
; CX = 0 no error
|
||||
; CX = 4 if illegal flag number
|
||||
; CX = 27H if no more flags to allocate
|
||||
;
|
||||
; Flags reserved by CCP/M or MP/M and the XIOS
|
||||
; header, cannot be released.
|
||||
;
|
||||
;turn off interrupts
|
||||
;
|
||||
; test dx,dx ! jz rf_alloc
|
||||
; inc dh ! jnz rf_enum
|
||||
; cmp dl,nrsv_flags ! jbe rf_enum
|
||||
; cmp dl,nflags ! jae rf_enum
|
||||
; xor ax,ax ! mov bx,ax ! mov cx,ax
|
||||
; mov al,dl
|
||||
; add al,dl ! add al,dl
|
||||
; mov si,ax ! mov word ptr flags[si],0
|
||||
; mov byte ptr flags 2[si],0
|
||||
; ret
|
||||
|
||||
;rf_alloc:
|
||||
; mov si,flags ! xor ax,ax
|
||||
; mov bx,ax ! mov cx,nflags
|
||||
;rf_nxt:
|
||||
; cmp ax,[si] ! je rf_foundone ;got one
|
||||
; add si,3 ! inc bx
|
||||
; loop rf_nxt
|
||||
; mov cx,e_noflags ! jmps rf_err
|
||||
;rf_foundone:
|
||||
; mov cx,ax ;0 CX
|
||||
; dec ax
|
||||
; mov [si],ax ;set the 3 bytes to 0ffh
|
||||
; mov 2[si],al
|
||||
; ret
|
||||
;rf_enum:
|
||||
; mov cx,e_illflag
|
||||
;rf_err:
|
||||
; mov bx,0ffffh
|
||||
; ret
|
||||
|
||||
;============== ==========================
|
||||
flag_set_entry: ; Set Logical Interrupt Flag
|
||||
;============== ==========================
|
||||
; NOTE: the flagset routine can (must?) be called from outside
|
||||
; the operating system through an interrupt
|
||||
; routine. UDA variables cannot be used. This
|
||||
; is the only function an interrupt routine can
|
||||
; call.
|
||||
;
|
||||
; input: DL = flag number
|
||||
; output: BX = 0 if okay,0ffffh if error
|
||||
; CX = if error: e_flag_ovrrun
|
||||
|
||||
call flag_valid
|
||||
cmp cl,flag_tick ! jne notick
|
||||
mov bx,dlr
|
||||
test bx,bx ! jz dlr_null ;no process waiting
|
||||
dec p_wait[bx] ! jnz nxt_tick
|
||||
nxt_tpd:
|
||||
mov si,p_link[bx] ! mov dlr,si ;SI,DLR=next waiting PD
|
||||
mov p_stat[bx],ps_run ;put PD done waiting
|
||||
mov ax,drl ! mov p_link[bx],ax ;on DRL
|
||||
mov drl,bx
|
||||
test si,si ! jz dlr_null ;SI=next waiting PD
|
||||
cmp p_wait[si],0 ! jnz nxt_tick
|
||||
mov bx,si ! jmps nxt_tpd;another process was waiting
|
||||
;the same number of ticks
|
||||
nxt_tick: jmp flag_exit ;wait for next tick
|
||||
|
||||
dlr_null: ;DLR is empty turn off
|
||||
mov tick,false ! jmp flag_exit ;XIOS tick flag
|
||||
|
||||
no_tick:
|
||||
cmp flg_ignore[si],flag_zig ! je fs_set
|
||||
dec flg_ignore[si] !
|
||||
mov cx,e_flag_ignr ! jmp flag_bexit
|
||||
|
||||
fs_set: cmp bx,flag_on ! jne fs_non
|
||||
mov cx,e_flag_ovrrun ! jmp flag_bexit
|
||||
|
||||
fs_non: cmp bx,flag_off ! jne fs_noff
|
||||
mov flg_pd[si],flag_on
|
||||
jmp flag_exit
|
||||
|
||||
fs_noff:mov ax,drl ! mov p_link[bx],ax
|
||||
mov drl,bx ! mov p_stat[bx],ps_run
|
||||
or p_flag[bx],pf_resource ;12/4/83
|
||||
mov flg_pd[si],flag_off
|
||||
jmp flag_exit
|
||||
|
||||
;=============== ===============================
|
||||
flag_wait_entry: ; Wait for Logical Interrupt Flag
|
||||
;=============== ===============================
|
||||
; input: DL = flag number
|
||||
; output: BX = 0 if everything okay
|
||||
; BX = 0ffffh if Error
|
||||
; CX = Error Code:0,e_flag_underrun
|
||||
|
||||
call flag_valid
|
||||
cmp bx,flag_on ! jne fw_non
|
||||
mov flg_pd[si],flag_off
|
||||
jmp flag_exit
|
||||
fw_non: cmp bx,flag_off ! jne fw_noff
|
||||
mov bx,rlr
|
||||
mov p_stat[bx],ps_flagwait
|
||||
mov u_dparam,si
|
||||
call dsptch ! jmp flag_exit
|
||||
fw_noff:mov cx,e_flag_underrun ! jmp flag_bexit
|
||||
|
||||
flag_valid: ; Check validity of flag number
|
||||
;---------- -----------------------------
|
||||
; entry: DL = flag number
|
||||
; output: SI = ptr to flag entry
|
||||
; BX = contents of flag entry
|
||||
; CL = flag number
|
||||
; clear interrupt flag - Flags on stack
|
||||
|
||||
pop ax ! pushf ;AX=return address
|
||||
cmp dl,nflags ! jb flag_good
|
||||
flag_bad:
|
||||
mov cx,e_ill_flag ! jmp flag_bexit ;flags and next return
|
||||
flag_good: ;address on stack
|
||||
mov cl,dl ;save flag number
|
||||
xor dh,dh ! push ax ! cli ;return to fset/fwait on stack
|
||||
mov ax,dx ;multiply flag number
|
||||
mov bx,ax ;times 3
|
||||
add ax,ax ;*2
|
||||
add ax,bx ;*3
|
||||
mov si,flags ! add si,ax
|
||||
mov bx,[si]
|
||||
;test bx,bx ;FLAG field cannot be 0
|
||||
;jz flag_bad
|
||||
ret
|
||||
|
||||
flag_exit: ; Successful Exit
|
||||
;--------- ---------------
|
||||
; entry: flags and return from flagset or flagwait on stack
|
||||
|
||||
xor bx,bx ! popf ! ret
|
||||
|
||||
|
||||
flag_bexit: ; Exit with Error
|
||||
;---------- ---------------
|
||||
; entry: flags and return from flagset or flagwait on stack
|
||||
|
||||
xor bx,bx ! dec bx
|
||||
popf ! ret
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Idle Process
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;====
|
||||
idle: ;Idle Process
|
||||
;====
|
||||
; Jump to the XIOS idle routine
|
||||
|
||||
;if mpm
|
||||
; mov ds,sysdat
|
||||
; mov bx,rlr
|
||||
; mov es,p_uda[bx]
|
||||
; mov ax,io_idle
|
||||
; jmp xiosif
|
||||
;endif
|
||||
|
||||
;if ccpm ;we could move idle to the RTM
|
||||
mov ds,sysdat ;and initialize its IP:CS to
|
||||
mov bx,rlr
|
||||
mov ax,p_uda[bx] ;point to the dispatcher
|
||||
mov es,ax ;and get rid of this
|
||||
mov cx,f_dispatch ;code since idle will never
|
||||
call osif ;come out of the dispatcher
|
||||
jmps idle
|
||||
;endif
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Concurrent CP/M-86 Supervisor Initialization
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
cseg
|
||||
org 0
|
||||
|
||||
jmp init ;system initialization
|
||||
jmp entry ;intermodule entry pt.
|
||||
|
||||
;next 3 words are set by GENSYS
|
||||
sysdat dw 0 ;segment
|
||||
supervisor dw entry ;offset
|
||||
dw 0 ;segment
|
||||
|
||||
org 0ch
|
||||
dev_ver db 6 ;development system data version
|
||||
;set in sysdat.dat
|
||||
|
||||
db 'COPYRIGHT (C) 1982,1983,1984'
|
||||
db ' DIGITAL RESEARCH '
|
||||
db 'XXXX-0000-'
|
||||
serial db '654321'
|
||||
|
||||
;====
|
||||
init:
|
||||
;====
|
||||
; system initialization
|
||||
; DS set to Sysdat Segment by loader
|
||||
|
||||
;make INIT a process:
|
||||
;set up init stack
|
||||
|
||||
cli ! cld ;Loader enters here
|
||||
mov ax,ds ;with interrupts
|
||||
mov ss,ax ! mov sp,offset (init_tos) ;possibly on
|
||||
|
||||
;initialize init uda
|
||||
|
||||
mov bx,offset initpd
|
||||
mov ax,offset inituda
|
||||
mov cl,4 ! shr ax,cl
|
||||
add ax,sysdat ! mov p_uda[bx],ax
|
||||
mov es,ax
|
||||
mov u_wrkseg,ds
|
||||
|
||||
;we now look like we are in the O.S. as usual:
|
||||
;DS=SYSDAT seg, ES=UDA, U_WRKSEG=PD's DS.
|
||||
|
||||
; set up mpm entry point
|
||||
|
||||
push ds
|
||||
xor ax,ax ! mov ds,ax
|
||||
mov i_os_ip,offset user_entry
|
||||
mov i_os_cs,cs
|
||||
pop ds
|
||||
|
||||
;initialize ndp owner to default
|
||||
|
||||
mov ax, 0ffffh ; ffff = no ndp chip present in system
|
||||
mov owner_8087,ax
|
||||
|
||||
;initialize modules
|
||||
|
||||
mov bx,mod_init
|
||||
push bx ! callf dword ptr rtmmod[bx] ! pop bx ; init RTM
|
||||
push bx ! callf dword ptr memmod[bx] ! pop bx ; init MEM
|
||||
test module_map,bdosmod_bit ! jz nbdo
|
||||
push bx ! callf dword ptr bdosmod[bx] ! pop bx ; init BDOS
|
||||
|
||||
nbdo: test module_map,ciomod_bit ! jz ncio
|
||||
push bx ! callf dword ptr ciomod[bx] ! pop bx ; init CIO
|
||||
|
||||
ncio: test module_map,xiosmod_bit ! jz nxio
|
||||
push ds ! push es
|
||||
callf dword ptr xiosmod[bx] ! pop es ! pop ds ; init XIOS
|
||||
|
||||
nxio:
|
||||
; reset interrupt vectors after XIOS INIT
|
||||
|
||||
mov ax,ds ! sub bx,bx ! mov ds,bx
|
||||
mov i_os_ip,offset user_entry
|
||||
mov i_os_cs,cs
|
||||
mov ds,ax
|
||||
|
||||
; get Character Dev Info from XIOS
|
||||
|
||||
;if mpm
|
||||
; mov ax,io_maxconsole ! call xiosif
|
||||
; mov ncondev,bl ! mov nciodev,bl
|
||||
; mov ax,io_maxlist ! call xiosif
|
||||
; mov nlstdev,bl ! add nciodev,bl
|
||||
; mov bx,offset initpd
|
||||
; mov al,ncondev
|
||||
; mov p_lst[bx],al
|
||||
;endif
|
||||
; Init CCB and LCB adr in INIT UDA so
|
||||
; child processes will inherit them
|
||||
|
||||
mov cl,f_conattach ! int osint
|
||||
mov cl,f_lstattach ! int osint
|
||||
|
||||
; Start RSPs
|
||||
nrsp: ;loop til done
|
||||
mov ds,sysdat ;reset DS
|
||||
mov cx,rspseg ! jcxz rsp_o ;?all done?
|
||||
mov es,cx ;ES->RSP
|
||||
mov ax,es:.rsp_link ;save next RSP
|
||||
mov rspseg,ax
|
||||
mov es:.rsp_link,ds ;give Sysdat to RSP
|
||||
mov si,rsp_pd ;get PD
|
||||
mov ds,cx ;DS = RSP Data Seg
|
||||
mov p_mem[si],0
|
||||
mov cl,f_createproc ;Create RSP Process(s)
|
||||
mov dx,si ! int osint
|
||||
jmps nrsp ;Do another...
|
||||
rsp_o:
|
||||
; terminate init process
|
||||
mov cl,f_terminate
|
||||
mov dl,0ffh ! int osint
|
||||
|
||||
@@ -0,0 +1,978 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Program Load
|
||||
;*
|
||||
;*****************************************************
|
||||
;
|
||||
; LDTAB Entry Format:
|
||||
; 0 2 4 6 8
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; | START | MIN | MAX | PD |
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
;
|
||||
; 8 10(A) 12(C) 14(E) 16(10) 17(11)
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; | ATR | FSTRT | FLEN | TYPE| ID |
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
;
|
||||
;
|
||||
; start Absolute Address requested
|
||||
; min Min memory wanted
|
||||
; max Max memory wanted
|
||||
; pd PD to allocate to
|
||||
; atr Attributes, Memory Flags
|
||||
; fstrt Starting paragraph in File
|
||||
; flen # of paragraphs in file
|
||||
; type Group type
|
||||
; id Segment Address of this group
|
||||
;
|
||||
; The Load Table contains 9 entries, One for each
|
||||
; potential Group in Command File and One extra
|
||||
; for Independent Memory Allocations.
|
||||
|
||||
ldt_start equ word ptr 0
|
||||
ldt_min equ word ptr ldt_start + word
|
||||
ldt_max equ word ptr ldt_min + word
|
||||
ldt_pd equ word ptr ldt_max + word
|
||||
ldt_atr equ word ptr ldt_pd + word
|
||||
ldt_fstrt equ word ptr ldt_atr + word
|
||||
ldt_flen equ word ptr ldt_fstrt + word
|
||||
ldt_type equ byte ptr ldt_flen + word
|
||||
ldt_id equ word ptr ldt_type + byte
|
||||
ldtlen equ ldt_id + word
|
||||
|
||||
|
||||
;=========
|
||||
cload_ent: ; entry point to load for a chain command
|
||||
;=========
|
||||
; Assumes UDA is set in passed PD.
|
||||
|
||||
push bx ! mov bx,1
|
||||
jmps load
|
||||
|
||||
;========
|
||||
load_ent: ; User entry point to load .CMD file for execution
|
||||
;========
|
||||
; input: DX = address of open FCB in u_wrkseg
|
||||
; output: BX = segment addr of Base Page
|
||||
; = 0ffffh if error
|
||||
; CX = Error Code
|
||||
|
||||
sub bx,bx
|
||||
;jmp load
|
||||
;====
|
||||
load: ; Intermodule entry point to load .CMD file
|
||||
;====
|
||||
; input: DX = addr of open FCB in u_wrkseg
|
||||
; BX = addr of unused PD to initialize
|
||||
; 0 - do not init PD
|
||||
; 1 - chain load (PD addr on stack)
|
||||
; output: BX = seg addr of Base Page
|
||||
; = 0ffffh if error
|
||||
; CX = Error Code
|
||||
|
||||
; Get MXLoad Queue
|
||||
|
||||
push dx ! push bx
|
||||
mov cx,f_qread ! mov dx,offset mxloadqpb
|
||||
call osif
|
||||
mov lod_chain,false
|
||||
pop lod_pd ! pop si
|
||||
cmp lod_pd,1 ! jne ld_cf
|
||||
pop lod_pd ! mov lod_chain,true
|
||||
|
||||
; Copy FCB into lod_fcb
|
||||
; SI-> user FCB in u_wrkseg
|
||||
|
||||
ld_cf: mov cx,fcblen/2 ! mov di,offset lod_fcb
|
||||
push es ! push ds ! push ds
|
||||
mov ds,u_wrkseg ! pop es
|
||||
rep movsw
|
||||
pop ds ! pop es
|
||||
|
||||
|
||||
; Read the Header
|
||||
|
||||
mov bx,offset lod_fcb
|
||||
mov byte ptr fcb_r0+2[bx],0
|
||||
mov ax,0 ;record #
|
||||
mov bx,1 ;# of sectors
|
||||
mov dx,offset lod_dma ;DMA offset
|
||||
mov cx,sysdat ;DMA segment
|
||||
call drd ! cmp di,1 ;check for EOF in header read
|
||||
je lod_eof
|
||||
jcxz ndpchk
|
||||
lod_eof:
|
||||
mov cx, e_bad_load ; tried to load a 0 length cmd file
|
||||
mov bx, 0ffffh ; or one whose header is incorrect
|
||||
jmp lod_exit
|
||||
ndpchk: ;see if 8087 required
|
||||
mov lod_ndp,0 ;default = no
|
||||
mov bx, offset lod_dma
|
||||
test ch_lbyte[bx],need_8087
|
||||
jz ndp_flg ;not required - but is it optional?
|
||||
cmp owner_8087,0ffffh ;needs it,but is there one in system?
|
||||
jnz ndp_yes ;yes- flag it
|
||||
mov cx,e_nondp ;no - abandon load & return
|
||||
mov bx, 0ffffh
|
||||
jmp lod_exit
|
||||
ndp_flg:
|
||||
test ch_lbyte[bx],opt_8087 ;will use it if present?
|
||||
jz h_hdr ;doesn't want it at all
|
||||
cmp owner_8087,0ffffh ;will use it,but is there one ?
|
||||
jnz ndp_yes ;if not, flag it as an emulator user
|
||||
mov lod_ndp,1
|
||||
jmp h_hdr
|
||||
ndp_yes:
|
||||
mov lod_ndp,0ffh ;flag it as an 8087 user
|
||||
h_hdr:
|
||||
mov lod_suspnd,0 ;default = no suspend needed
|
||||
test ch_lbyte[bx],susp_mode ;require background suspension ?
|
||||
jz h_hdr1 ;no...
|
||||
mov lod_suspnd,0ffh ;yes, flag pd later
|
||||
|
||||
h_hdr1:
|
||||
mov lod_indma,0
|
||||
|
||||
; initialize Load Disk and User
|
||||
; from FCB
|
||||
|
||||
mov bx,rlr
|
||||
mov al,p_user[bx]
|
||||
mov lod_user,al
|
||||
mov al,p_dsk[bx] ;default disk of calling PD
|
||||
mov lod_disk,al ;1-15 -> A-P
|
||||
mov bx,offset lod_fcb
|
||||
mov al,fcb_dr[bx]
|
||||
mov lod_fifty,al ;base page address 50H, 0=default
|
||||
test al,al ! jz use_ddsk
|
||||
dec al ;1-15 -> A-P
|
||||
mov lod_disk,al
|
||||
use_ddsk:
|
||||
test byte ptr fcb_name+7[bx],080h ! jz use_dusr
|
||||
mov lod_user,0
|
||||
use_dusr:
|
||||
|
||||
; Initialize ldtab
|
||||
|
||||
; Zero ldtab
|
||||
mov cx,ldtabsiz/2 ! sub ax,ax
|
||||
mov di,offset ldtab
|
||||
push es ! mov es,sysdat
|
||||
rep stos ax ! pop es
|
||||
|
||||
; 1st ldtab entry is UDA and LSTK
|
||||
; if a PD was specified...
|
||||
|
||||
mov lod_nldt,0
|
||||
mov si,offset ldtab
|
||||
cmp lod_pd,0 ! jne sel_uda
|
||||
jmp gc_ifo
|
||||
sel_uda: cmp lod_ndp,0 ;see if 8087 user and long
|
||||
jz form_uda ;uda is needed
|
||||
cmp lod_ndp,0ffh ;no...
|
||||
jz form_87uda
|
||||
form_emuda: mov ldt_min[si],(lstklen+em87len)/16 ;8087 emulator user
|
||||
mov ldt_max[si],(lstklen+em87len)/16 ;64 byte extension
|
||||
jmp cont_uda
|
||||
form_87uda: mov ldt_min[si],(lstklen+u8087len)/16 ;8087 user
|
||||
mov ldt_max[si],(lstklen+u8087len)/16 ;96 byte extension
|
||||
jmp cont_uda
|
||||
form_uda: mov ldt_min[si],(lstklen+ulen)/16 ;min=max=UDA+STK paragraphs
|
||||
mov ldt_max[si],(lstklen+ulen)/16
|
||||
cont_uda: mov ax,lod_pd ! mov ldt_pd[si],ax
|
||||
mov ldt_atr[si],mf_load
|
||||
add si,ldtlen
|
||||
inc lod_nldt
|
||||
cmp lod_chain,true ! jne gc_ifo
|
||||
|
||||
;We are CHAINING. Free all memory
|
||||
; except UDA area and LDSTK. This will keep
|
||||
; the first partition for the chain
|
||||
; as well as not crash the system.
|
||||
|
||||
push si
|
||||
mov cx,f_freeall ! call osif
|
||||
|
||||
;transfer memory to new pd
|
||||
|
||||
mov bx,rlr
|
||||
mov ax,p_mem[bx] ! mov p_mem[bx],0
|
||||
mov bx,lod_pd ! mov p_mem[bx],ax
|
||||
pop si
|
||||
|
||||
gc_ifo:
|
||||
;go through CMD header and init
|
||||
;a ldtab entry per header entry.
|
||||
;alloc abs mem
|
||||
|
||||
mov bx,offset lod_dma
|
||||
mov al,ch_lbyte[bx] ; save fixup flag
|
||||
mov lod_lbyte,al
|
||||
mov ax,ch_fixrec[bx] ; save record # of fixups, if any
|
||||
mov lod_fixrec,ax
|
||||
mov lod_fixrec1,ax
|
||||
|
||||
mov cx,ch_entmax ; BX = offset LOD_DMA
|
||||
mov dx,8 ; DX = position in file
|
||||
ch_more:cmp ch_form[bx],0 ! jne ch_doit
|
||||
jmp ch_next
|
||||
ch_doit: mov al,ch_form[bx] ! mov ldt_type[si],al ;type of seg
|
||||
mov ax,ch_length[bx] ! mov ldt_flen[si],ax ;length
|
||||
mov ldt_fstrt[si],dx ! add dx,ax ;pos in file
|
||||
mov ax,ch_base[bx] ! mov ldt_start[si],ax ;abs seg
|
||||
mov ax,ch_min[bx] ! mov ldt_min[si],ax ;min needed
|
||||
mov ax,ch_max[bx]
|
||||
cmp ax,0 ! jne setmax
|
||||
mov ax,ch_min[bx]
|
||||
setmax: mov ldt_max[si],ax ;max wanted
|
||||
mov ax,lod_pd ! mov ldt_pd[si],ax ;pd to alloc to
|
||||
cmp ax,0 ! je not_load
|
||||
mov ax,mf_load
|
||||
jmps not_load
|
||||
skipjmp:jmps ch_more
|
||||
|
||||
;if mpm
|
||||
|
||||
not_load: cmp ch_form[bx],1 ! jne try_sh
|
||||
add ax,mf_code ! jmps s_atr
|
||||
try_sh: cmp ch_form[bx],9 ! jne s_atr
|
||||
add ax,mf_code+mf_share
|
||||
s_atr: mov ldt_atr[si],ax ;memory flags
|
||||
|
||||
;if abs, allocate memory
|
||||
cmp ldt_start[si],0 ! je ch_nabs ;see if abs mem
|
||||
jmps ch_al
|
||||
ch_nabs: cmp ldt_type[si],9
|
||||
jne ch_nxt ;see if shared code
|
||||
push cx
|
||||
push bx ! push dx ;save load DMA and position in file
|
||||
call get_sh
|
||||
pop dx ! pop bx
|
||||
cmp cx,0 ! pop cx
|
||||
je ch_nxt
|
||||
jmp ld_out
|
||||
ch_al: push bx ! push dx ! push cx ! push si
|
||||
mov cx,f_malloc ! mov dx,si
|
||||
call osif ! pop si
|
||||
mov ax,ldt_start[si] ! mov ldt_id[si],ax
|
||||
cmp cx,0 ! pop cx ! pop dx ! pop bx
|
||||
je ch_nxt
|
||||
;couldn't find memory
|
||||
mov bx,0ffffh ! mov cx,e_no_memory
|
||||
jmp ld_out
|
||||
|
||||
;endif
|
||||
|
||||
;if ccpm
|
||||
|
||||
;not_load: cmp ch_form[bx],9 ! jne try_code
|
||||
; mov ch_form[bx],1
|
||||
; mov ldt_type[si],1
|
||||
;try_code: cmp ch_form[bx],1 ! jne s_atr
|
||||
; add ax,mf_code
|
||||
;s_atr: mov ldt_atr[si],ax ;memory flags
|
||||
;
|
||||
; ;if abs, allocate memory
|
||||
; cmp ldt_start[si],0 ! je ch_nxt ;see if abs mem
|
||||
;ch_al: push bx ! push dx ! push cx ! push si
|
||||
; mov cx,f_malloc ! mov dx,si
|
||||
; call osif ! pop si
|
||||
; mov ax,ldt_start[si] ! mov ldt_id[si],ax
|
||||
; cmp cx,0 ! pop cx ! pop dx ! pop bx
|
||||
; je ch_nxt
|
||||
; ;couldn't find memory
|
||||
; mov bx,0ffffh ! mov cx,e_no_memory
|
||||
; jmp ld_out
|
||||
;
|
||||
;endif
|
||||
|
||||
ch_nxt: add si,ldtlen
|
||||
inc lod_nldt
|
||||
ch_next:add bx,chlen
|
||||
loop skipjmp
|
||||
|
||||
; alloc all other memory
|
||||
; SI -> mpb for non_abs mem req.
|
||||
;add all parts together for a single malloc
|
||||
mov bx,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
mov lod_nrels,0
|
||||
lt_more:cmp ldt_min[bx],0 ! je lt_next
|
||||
cmp ldt_start[bx],0 ! jne lt_next
|
||||
mov ax,ldt_min[bx]
|
||||
mov dx,ax
|
||||
add ldt_min[si],ax
|
||||
cmp dx,ldt_min[si] ! jbe lt_m ; check for ovrflw
|
||||
mov ldt_min[si],0ffffh
|
||||
lt_m: mov ax,ldt_max[bx]
|
||||
mov dx,ax
|
||||
add ldt_max[si],ax
|
||||
cmp dx,ldt_max[si] ! jbe lt_m1 ; check for ovrflw
|
||||
mov ldt_max[si],0ffffh
|
||||
lt_m1: inc lod_nrels
|
||||
lt_next:add bx,ldtlen ! loop lt_more
|
||||
|
||||
;malloc
|
||||
cmp lod_pd,0 ! je noloadf
|
||||
mov ldt_atr[si],mf_load
|
||||
noloadf:mov ax,lod_pd ! mov ldt_pd[si],ax
|
||||
push si ! mov dx,si ! mov cx,f_malloc
|
||||
call osif ! pop si
|
||||
mov ax,ldt_start[si] ! mov ldt_id[si],ax
|
||||
cmp bx,0ffffh ! jne lt_sprd
|
||||
|
||||
;Not Enough Memory - release any
|
||||
; memory already allocated
|
||||
ld_out: push cx
|
||||
mov bx,offset ldtab
|
||||
mov cx,lod_nldt ! inc cx
|
||||
lg_more: cmp ldt_id[bx],0 ! je lg_next
|
||||
push cx ! push bx ! push ds
|
||||
;push MFPB on stack
|
||||
push ldt_pd[bx]
|
||||
push ldt_id[bx]
|
||||
mov dx,sp ! push ss ! pop ds
|
||||
mov cx,f_memfree
|
||||
call osif
|
||||
pop cx ! pop cx
|
||||
|
||||
pop ds ! pop bx ! pop cx
|
||||
lg_next: add bx,ldtlen ! loop lg_more
|
||||
mov bx,0ffffh ! pop cx ! jmp lod_exit
|
||||
|
||||
lt_sprd:
|
||||
;spread the memory allocated
|
||||
;amongst the nrels
|
||||
;1st give everyone the minimum
|
||||
mov bx,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
ls_more:cmp ldt_start[bx],0 ! jne ls_next
|
||||
mov ax,ldt_min[bx]
|
||||
sub ldt_min[si],ax
|
||||
cmp ax,ldt_max[bx] ! jne ls_next
|
||||
mov dx,ldt_start[si] ! mov ldt_start[bx],dx
|
||||
add ldt_start[si],ax
|
||||
dec lod_nrels
|
||||
ls_next:add bx,ldtlen ! loop ls_more
|
||||
|
||||
;spread whats left amongst those that need more
|
||||
mov bx,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
lsl_mre:cmp ldt_start[bx],0 ! jne lsl_nxt
|
||||
mov ax,ldt_start[si] ! mov ldt_start[bx],ax
|
||||
mov ax,ldt_min[si]
|
||||
cmp ax,0 ! je adj_start
|
||||
push cx ! sub cx,cx
|
||||
mov dx,cx ! mov cl,lod_nrels
|
||||
div cx ! pop cx
|
||||
cmp dx,0 ! je evendiv
|
||||
inc ax
|
||||
evendiv: mov dx,ldt_max[bx] ! sub dx,ldt_min[bx]
|
||||
cmp ax,dx ! jbe nottoomuch
|
||||
mov ax,dx
|
||||
nottoomuch: add ldt_min[bx],ax ! sub ldt_min[si],ax
|
||||
adj_start: mov ax,ldt_min[bx] ! add ldt_start[si],ax
|
||||
dec lod_nrels
|
||||
lsl_nxt:add bx,ldtlen ! loop lsl_mre
|
||||
|
||||
; fill memory from file
|
||||
|
||||
mov si,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
lf_mre: cmp ldt_flen[si],0 ! je lf_nxt
|
||||
push cx ! push ldt_start[si] ! push si
|
||||
call lod_group
|
||||
pop si ! pop ldt_start[si]
|
||||
cmp cx,0 ! pop cx
|
||||
je lf_nxt
|
||||
|
||||
;if ccpm
|
||||
;
|
||||
; jmp ld_out
|
||||
;endif
|
||||
|
||||
;if mpm
|
||||
|
||||
; error in lod_group
|
||||
; if loading shared code we also
|
||||
; have to release Shared Code from SCL.
|
||||
; It will be the top item in the list.
|
||||
|
||||
cmp ldt_atr[si],mf_load+mf_code+mf_share
|
||||
je rm_sh
|
||||
jmp ld_out
|
||||
rm_sh: push cx ; remember Err Code
|
||||
|
||||
; Remove PD from SCL
|
||||
pushf ! cli
|
||||
mov bx,scl
|
||||
mov ax,p_thread[bx]
|
||||
mov scl,ax
|
||||
popf
|
||||
|
||||
; Release the memory
|
||||
|
||||
push ds ! push bx
|
||||
mov bx,p_mem[bx] ! push ms_start[bx]
|
||||
mov ax,ss ! mov ds,ax
|
||||
mov dx,sp ! mov cx,f_memfree
|
||||
call osif
|
||||
pop ax ! pop bx ! pop ds
|
||||
|
||||
; Place PD on PUL
|
||||
|
||||
pushf ! cli
|
||||
mov ax,pul
|
||||
mov pul,bx
|
||||
mov p_link[bx],ax
|
||||
popf
|
||||
|
||||
pop cx
|
||||
jmp ld_out
|
||||
;endif
|
||||
|
||||
lf_nxt: add si,ldtlen ! loop lf_mre
|
||||
|
||||
|
||||
; Check for fixup records and do fixups
|
||||
|
||||
test lod_lbyte,80h ; hi bit of last byte in cmd header
|
||||
jz init_base ; is set if fixups
|
||||
fx_read:
|
||||
mov ax,lod_fixrec ; get record # of fixups in file
|
||||
mov bx,1 ; read one record
|
||||
mov cx,ds
|
||||
mov dx, offset lod_dma
|
||||
call drd ; do random read
|
||||
jcxz fx_read_ok ; 0=ok,CL=0ff if EOF
|
||||
inc cl ; EOF ?
|
||||
jnz fx_err ; some read error, not EOF
|
||||
mov ax,lod_fixrec1 ; make sure one fixup
|
||||
cmp ax,lod_fixrec ; record was read since cmd header
|
||||
je fx_err ; said we needed them
|
||||
jmps init_base
|
||||
|
||||
fx_read_ok: ; go look for fixup records
|
||||
mov bx,offset lod_dma ; BX-> at fixup records
|
||||
fx_chk:
|
||||
mov al,fix_grp[bx] ; any more fixups?
|
||||
test al,al
|
||||
jz init_base
|
||||
and al,0fh ; low nibble is target group
|
||||
call tblsrch ; find target group in load table
|
||||
mov dx,ldt_start[di] ; DX = target segment, this is
|
||||
; what we add to the load image
|
||||
mov al,fix_grp[bx] ; location group is high nibble
|
||||
mov cl,4 ; put in low nibble of AL
|
||||
shr al,cl
|
||||
call tblsrch ; DI = location load table entry
|
||||
mov ax,ldt_start[di] ; AX = base segment of location
|
||||
add ax,fix_para[bx] ; add paragraph offset
|
||||
|
||||
push es ; absolute paragraph in memory
|
||||
mov es,ax
|
||||
xor ax,ax
|
||||
mov al,fix_offs[bx] ; get offset of fixup location
|
||||
mov di,ax
|
||||
add es:[di],dx ; make the fixup (finally)
|
||||
pop es
|
||||
|
||||
add bx,fixlen ; do next fixup
|
||||
cmp bx,offset lod_dma + dskrecl ; end of this record ?
|
||||
jne fx_chk
|
||||
inc lod_fixrec ; read another record
|
||||
jmps fx_read ; of fixups
|
||||
|
||||
tblsrch:
|
||||
;-------
|
||||
; Search for group in load table
|
||||
; entry: AL = group # to match on
|
||||
; exit: DI = load group entry that matches or
|
||||
; pop return and exit loader
|
||||
; BX,DX preserved
|
||||
|
||||
mov cx,lod_nldt ; # entries in table
|
||||
mov di,offset ldtab
|
||||
srchloop:
|
||||
cmp al,ldt_type[di]
|
||||
je srchdn ; found group's entry
|
||||
add di,ldtlen
|
||||
loop srchloop
|
||||
pop ax
|
||||
jmps fx_err
|
||||
srchdn:
|
||||
ret
|
||||
|
||||
fx_err:
|
||||
mov cx,e_fixuprec
|
||||
jmp ld_out
|
||||
|
||||
|
||||
; init Base Page
|
||||
; 1st Data Group has Base Page
|
||||
; if none then first nonshared
|
||||
; Code Group (8080 model)
|
||||
init_base:
|
||||
mov lod_8080,0
|
||||
mov si,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
lb_more:cmp ldt_type[si],2 ! je lb_fnd
|
||||
add si,ldtlen ! loop lb_more
|
||||
mov si,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
lbc_mre: cmp ldt_type[si],1 ! je lb_fnd80
|
||||
add si,ldtlen ! loop lbc_mre
|
||||
mov cx,e_no_cseg ! jmp ld_out
|
||||
lb_fnd80: mov lod_8080,1
|
||||
lb_fnd:
|
||||
push es ! mov es,ldt_start[si]
|
||||
mov lod_basep,es
|
||||
sub ax,ax ! mov di,ax
|
||||
mov cx,05bh/2 ! rep stos ax
|
||||
mov al,lod_8080 ! mov es:.5,al
|
||||
mov si,offset ldtab
|
||||
mov cx,lod_nldt
|
||||
lbb_mre:cmp ldt_type[si],0 ! je lbb_nxt
|
||||
mov ax,6 ! mov bl,ldt_type[si]
|
||||
cmp bl,9 ! jne lbb_nsh
|
||||
mov bl,1
|
||||
lbb_nsh: dec bl ! mul bl ! mov bx,ax
|
||||
|
||||
;calculate last byte (3 byte value)
|
||||
; =(paragraphs*16)-1
|
||||
push cx ! mov dx,ldt_min[si]
|
||||
push dx ! mov cl,4 ! shl dx,cl
|
||||
push dx ! dec dx ! mov es:[bx],dx
|
||||
pop cx ! pop dx ! push cx
|
||||
mov cl,12 ! shr dx,cl ! pop cx
|
||||
cmp cx,0 ! jne lbb_nzer
|
||||
cmp dx,0 ! je lbb_zer
|
||||
dec dl ! jmps lbb_nzer
|
||||
lbb_zer: mov es:word ptr [bx],0
|
||||
lbb_nzer: mov es:2[bx],dl ! pop cx
|
||||
|
||||
;put starting paragraph in place
|
||||
mov ax,ldt_start[si] ! mov es:3[bx],ax
|
||||
lbb_nxt:add si,ldtlen ! loop lbb_mre
|
||||
|
||||
;if 8080 model, copy CS info into DS info
|
||||
|
||||
cmp lod_8080,1 ! jne lnot80
|
||||
push ds ! push es ! pop ds ! mov si,0
|
||||
mov di,6 ! mov cx,3
|
||||
rep movsw ! pop ds
|
||||
lnot80:
|
||||
mov al,lod_fifty ;initialize base page load disk
|
||||
mov es:.50H,al
|
||||
pop es
|
||||
|
||||
; init PD ,UDA and LDSTK
|
||||
|
||||
mov bx,lod_basep
|
||||
cmp lod_pd,0 ! jne lip_1
|
||||
jmp lod_exit
|
||||
lip_1: mov si,offset ldtab
|
||||
mov bx,lod_pd
|
||||
; if 8087 user, flag it
|
||||
cmp lod_ndp, 0
|
||||
jz lip_2
|
||||
cmp lod_ndp, 1
|
||||
jnz true_87
|
||||
or p_sflag[bx],psf_em87
|
||||
jmp lip_2
|
||||
true_87:
|
||||
or p_flag[bx],pf_8087
|
||||
lip_2:
|
||||
;if it requires suspend mode, flag it
|
||||
cmp lod_suspnd,0ffh
|
||||
jnz lip_3
|
||||
or p_sflag[bx],psf_suspend
|
||||
lip_3:
|
||||
mov ax,ldt_start[si]
|
||||
mov p_uda[bx],ax
|
||||
; remember where lstk,uda are
|
||||
mov lod_uda,ax
|
||||
push es ! mov es,ax
|
||||
; if 8087 user, use long uda
|
||||
cmp lod_ndp,0
|
||||
jz shrt_uda
|
||||
cmp lod_ndp,1
|
||||
jz med_uda
|
||||
add ax,(u8087len/16) ! jmp inter_uda ; full 8087 user, long uda
|
||||
med_uda: add ax,(em87len/16) ! jmp inter_uda ; uses 87 emulator,medium uda
|
||||
shrt_uda: add ax,(ulen/16) ; no 8087 activity,short uda
|
||||
inter_uda: mov lod_lstk,ax
|
||||
|
||||
; initialize UDA,LDSTK with zeros
|
||||
xor di,di ! mov ax,di
|
||||
|
||||
; if 8087 user, use long uda
|
||||
cmp lod_ndp,0
|
||||
jz shrt_uda1
|
||||
; if 8087 emulator user, use medium uda
|
||||
cmp lod_ndp,1
|
||||
jnz long_uda1
|
||||
mov cx,(em87len + lstklen)/2 ! jmp inter_uda1
|
||||
long_uda1:
|
||||
mov cx,(u8087len + lstklen)/2 ! jmp inter_uda1
|
||||
shrt_uda1: mov cx,(ulen + lstklen)/2
|
||||
inter_uda1: rep stos ax ! pop es
|
||||
|
||||
; setup p_uda for creat_proc
|
||||
|
||||
mov ax,sysdat
|
||||
sub p_uda[bx],ax
|
||||
mov p_stat[bx],ps_run
|
||||
mov p_prior[bx],200
|
||||
|
||||
; init load disk/user
|
||||
|
||||
mov al,lod_user ! mov p_luser[bx],al
|
||||
mov al,lod_disk ! mov p_ldsk[bx],al
|
||||
|
||||
; init UDA
|
||||
|
||||
push es ! mov es,lod_uda
|
||||
mov u_dma_ofst,(offset bpg_dma)
|
||||
mov bx,lod_basep
|
||||
mov u_dma_seg,bx
|
||||
mov ax,lod_lstk
|
||||
cmp lod_ndp,0ffh ; if 8087 user, init control word for
|
||||
jnz not_8087 ; first dispatch's frstor
|
||||
mov u_8087, controlw ; 03ffh = post-init 8087 state
|
||||
push ax
|
||||
mov ax,sysvec87_of
|
||||
mov u_ivec87_of,ax
|
||||
mov ax,sysvec87_sg
|
||||
mov u_ivec87_sg,ax
|
||||
pop ax
|
||||
not_8087:
|
||||
push ds ! mov ds,bx
|
||||
mov u_initds,bx
|
||||
mov u_inites,bx
|
||||
mov u_initss,ax
|
||||
mov ax,bpg_cseg
|
||||
cmp ax,0 ! jne h_cs
|
||||
pop ds ! pop es ! mov cx,e_no_cseg
|
||||
jmp ld_out
|
||||
h_cs: mov u_initcs,ax
|
||||
mov ax,bpg_eseg
|
||||
cmp ax,0 ! je noes
|
||||
mov u_inites,ax
|
||||
noes: mov u_stack_sp,(offset ls_sp)
|
||||
sub dx,dx ! mov al,bpg_8080
|
||||
cmp al,0 ! je n80m
|
||||
mov dx,0100h
|
||||
n80m:
|
||||
mov ds,u_initss
|
||||
mov ls_offset,dx ;set up initial stack
|
||||
mov ls_flags,0200h ;for a RETF from user
|
||||
mov ls_roffset,offset user_retf ;process, see SUPIF.SUP
|
||||
mov ls_rcseg,cs ;module for USER_RETF:
|
||||
pop ds ! pop es ;code
|
||||
mov bx,lod_basep
|
||||
sub cx,cx
|
||||
lod_exit:
|
||||
push cx ! push bx
|
||||
mov cx,f_qwrite ! mov dx,offset mxloadqpb
|
||||
call osif ! pop bx ! pop cx ! ret
|
||||
|
||||
|
||||
lod_group: ;load a group described in ldtab
|
||||
;----------
|
||||
; input: SI = addr of ldtab entry
|
||||
; output: CX = Error Code
|
||||
|
||||
; see if first part already in DMA
|
||||
mov bx,si
|
||||
mov ax,lod_indma ;starting paragraph in dma
|
||||
mov cx,ldt_fstrt[bx]
|
||||
;AX = starting paragraph in local DMA
|
||||
;CX = starting paragraph to transfer
|
||||
;BX -> ldtab entry
|
||||
cmp cx,ax ! jb rd_first
|
||||
;starts at or after the pp. in dma
|
||||
sub cx,ax
|
||||
cmp cx,8 ! jae rd_first
|
||||
;starts in the dma
|
||||
mov dx,8 ! sub dx,cx
|
||||
;CX = # of pp. to skip
|
||||
;DX = length of remaining buffer
|
||||
cmp dx,ldt_flen[bx] ! jbe xfer
|
||||
mov dx,ldt_flen[bx]
|
||||
xfer: mov si,offset lod_dma
|
||||
mov ax,cx ! mov cl,4 ! shl ax,cl
|
||||
add si,ax
|
||||
;SI -> beginning of transfer area
|
||||
; in lod_dma
|
||||
mov ax,dx ! mov cl,3 ! shl ax,cl
|
||||
mov cx,ax
|
||||
;CX = number of words to transfer
|
||||
xor di,di
|
||||
push es ! mov es,ldt_start[bx]
|
||||
rep movsw ! pop es
|
||||
add ldt_start[bx],dx
|
||||
sub ldt_flen[bx],dx ! add ldt_fstrt[bx],dx
|
||||
rd_first:
|
||||
cmp ldt_flen[bx],0 ! jne rd_1st
|
||||
sub cx,cx ! ret
|
||||
rd_1st:
|
||||
test ldt_fstrt[bx],07h ! jnz rd_indma
|
||||
cmp ldt_flen[bx],8 ! jae xf_d
|
||||
rd_indma:
|
||||
push bx
|
||||
mov ax,ldt_fstrt[bx]
|
||||
shr ax,1 ! shr ax,1 ! shr ax,1 ; Record #
|
||||
mov bx,1 ; read 1 record
|
||||
mov dx,offset lod_dma ; DMA offset
|
||||
mov cx,sysdat ; DMA segment
|
||||
call drd
|
||||
pop bx
|
||||
jcxz rd_agn
|
||||
cmp cx,0ffh ! jne rd_r3
|
||||
mov cx,0
|
||||
rd_r3: ret
|
||||
rd_agn: mov ax,ldt_fstrt[bx]
|
||||
and ax,0fff8h ; note starting paragraph
|
||||
mov lod_indma,ax ; in DMA
|
||||
mov si,bx ! jmp lod_group
|
||||
|
||||
; We are at a Sector Boundary with at least
|
||||
; a sector to place into the user area
|
||||
xf_d:
|
||||
push bx
|
||||
sub dx,dx ; DMA offset
|
||||
mov cx,ldt_start[bx] ; DMA segment
|
||||
mov ax,ldt_fstrt[bx]
|
||||
shr ax,1 ! shr ax,1 ! shr ax,1 ; Record #
|
||||
mov bx,ldt_flen[bx]
|
||||
shr bx,1 ! shr bx,1 ! shr bx,1 ; # of records
|
||||
push bx
|
||||
call drd
|
||||
pop ax ! pop bx
|
||||
jcxz xfer_n
|
||||
cmp cx,0ffh ! jne rd_r4
|
||||
xor cx,cx
|
||||
rd_r4: ret
|
||||
xfer_n: shl ax,1 ! shl ax,1 ! shl ax,1
|
||||
add ldt_start[bx],ax
|
||||
add ldt_fstrt[bx],ax
|
||||
sub ldt_flen[bx],ax
|
||||
jmp rd_first
|
||||
|
||||
drd:
|
||||
; input: AX = Record Number
|
||||
; BX = Number of Sectors
|
||||
; CX = dma segment
|
||||
; DX = dma offset
|
||||
; output: CX = 0 if okay
|
||||
; CX = 0FFH if End of File
|
||||
; else Error Code
|
||||
|
||||
mov u_dma_ofst,dx
|
||||
mov u_dma_seg,cx
|
||||
|
||||
; read BX sectors starting at Record AX
|
||||
drd_lp:
|
||||
push bx ;old # sectors
|
||||
push ax ;old record #
|
||||
cmp bx,128 ! jbe drd_r
|
||||
mov bx,128
|
||||
|
||||
; Max Mulit-sector count is 128
|
||||
|
||||
drd_r: mov cl,u_mult_cnt
|
||||
push cx
|
||||
mov u_mult_cnt,bl
|
||||
push bx
|
||||
mov si,offset lod_fcb
|
||||
mov fcb_r0[si],ax
|
||||
mov cx,f_freadrdm ! mov dx,si
|
||||
push es ! call osif ! pop es
|
||||
pop dx ;multi_cnt used
|
||||
pop cx ! mov u_mult_cnt,cl
|
||||
cmp bl,1 ! jbe dr_r2
|
||||
mov cx,e_bad_read ! mov bx,0ffffh
|
||||
pop ax ! pop ax ! ret
|
||||
dr_r2: mov cl,bl
|
||||
xor bh,bh ! mov di,bx ;save BL for header read check
|
||||
pop ax ! add ax,dx ;adjust record #
|
||||
pop bx ! sub bx,dx ;adjust # sectors
|
||||
shl dx,1 ! shl dx,1 ! shl dx,1
|
||||
add u_dma_seg,dx
|
||||
|
||||
; check for CTRL C. If hit while loading
|
||||
; last set of characters, this is the place to
|
||||
; clean things up...
|
||||
|
||||
push cx ! push ax ! push bx ! push di
|
||||
mov cx,f_ciostat ! call osif
|
||||
pop di ! pop bx ! pop ax ! pop cx
|
||||
|
||||
; Now see if CTRL C was hit during the
|
||||
; the load.
|
||||
|
||||
mov si,rlr
|
||||
test p_flag[si],pf_ctlc ! jz dr_r1
|
||||
mov cx,e_abort ! mov bx,0ffffh
|
||||
ret
|
||||
dr_r1: cmp cl,0 ! je dr_r5
|
||||
mov cx,0ffh ! ret
|
||||
dr_r5: cmp bx,0 ! jne dr_r6
|
||||
xor cx,cx
|
||||
ret
|
||||
dr_r6: jmp drd_lp
|
||||
|
||||
;if mpm
|
||||
|
||||
get_sh:
|
||||
;------
|
||||
; Allocate memory for shared code. If memory already
|
||||
; exists then mark LDTAB entry with FLEN=0 for no load.
|
||||
; START must be non-zero on success.
|
||||
;
|
||||
; input: SI = LDTAB Entry for shared code
|
||||
; output: CX = 0 on success
|
||||
; = 0ffffh on failure
|
||||
; SI is unchanged
|
||||
;
|
||||
|
||||
; 1. Look for PD Name on SCL, making sure
|
||||
; LDSK and LUSER are the same.
|
||||
|
||||
mov bx,(offset scl)-p_thread
|
||||
gs_nxt: push si
|
||||
mov dx,offset lod_fcb ! add dx,fcb_name
|
||||
mov cx,f_findpdname ! call osif
|
||||
; BX=pd found or 0ffffh
|
||||
pop si
|
||||
cmp bx,0ffffh ! je no_sh
|
||||
mov al,lod_disk
|
||||
cmp p_ldsk[bx],al ! jne gs_nxt
|
||||
mov al,lod_user
|
||||
cmp p_luser[bx],al ! jne gs_nxt
|
||||
|
||||
; 2. if (1.) then Share the Memory.
|
||||
; 2.1 Set FLEN=0
|
||||
|
||||
push bx ! push si
|
||||
call shmem
|
||||
pop si ! pop bx
|
||||
cmp cx,0ffffh ! je no_sh
|
||||
mov ldt_flen[si],0
|
||||
|
||||
; Put SHARE PD on end of SCL
|
||||
; BX = SHARE PD
|
||||
|
||||
pushf ! cli
|
||||
mov di,(offset SCL)-p_thread
|
||||
sh_nin1: cmp p_thread[di],bx ! je sh_rm ;look for share PD
|
||||
mov di,p_thread[di] ! jmps sh_nin1
|
||||
sh_rm: mov ax,p_thread[bx] ;take it off the list
|
||||
mov p_thread[di],ax
|
||||
sh_in: cmp p_thread[di],0 ! je sh_end ;look for the end
|
||||
mov di,p_thread[di] ! jmps sh_in
|
||||
sh_end: mov p_thread[di],bx ;insert share PD on end
|
||||
xor cx,cx
|
||||
mov p_thread[bx],cx
|
||||
popf ! ret ;success
|
||||
|
||||
; 3. if (NOT 1.) allocate memory to NEW PD
|
||||
no_sh:
|
||||
|
||||
; get new PD
|
||||
|
||||
pushf ! cli
|
||||
mov bx,pul
|
||||
cmp bx,0 ! je sherr
|
||||
mov ax,p_link[bx] ! mov pul,ax
|
||||
popf
|
||||
|
||||
; alloc memory for code segment
|
||||
|
||||
push bx ! push si
|
||||
mov cx,f_malloc
|
||||
mov dx,si
|
||||
call osif
|
||||
pop si ! pop bx
|
||||
cmp cx,0 ! jne merr
|
||||
|
||||
; initialize new PD name
|
||||
; BX = New PD
|
||||
push si
|
||||
mov si,ldt_pd[si] ;SI=old pd
|
||||
push si
|
||||
mov di,bx
|
||||
add si,p_name ! add di,p_name
|
||||
mov cx,4
|
||||
push es ! mov ax,ds ! mov es,ax
|
||||
rep movsw
|
||||
pop es ! pop di ! pop si
|
||||
|
||||
; DI = old PD, BX=New PD
|
||||
|
||||
mov al,lod_user ! mov p_luser[bx],al
|
||||
mov al,lod_disk ! mov p_ldsk[bx],al
|
||||
|
||||
; share w/new PD
|
||||
|
||||
mov ax,ldt_start[si]
|
||||
push bx ! push si ! push ds
|
||||
push ax ! push bx ! push di
|
||||
mov ax,ss ! mov ds,ax
|
||||
mov dx,sp ! mov cx,f_share
|
||||
call osif
|
||||
add sp,6
|
||||
pop ds ! pop si ! pop bx
|
||||
|
||||
; put new PD on SCL
|
||||
|
||||
pushf ! cli
|
||||
mov di,(offset SCL)-p_thread
|
||||
sh_nin: cmp p_thread[di],0 ! je sh_doit
|
||||
mov di,p_thread[di] ! jmps sh_nin
|
||||
sh_doit: mov p_thread[di],bx ;insert new share PD
|
||||
xor cx,cx
|
||||
mov p_thread[bx],cx
|
||||
popf ! ret ;success
|
||||
merr: pushf ! cli
|
||||
mov ax,pul
|
||||
mov p_link[bx],ax
|
||||
mov pul,bx
|
||||
sherr: popf
|
||||
mov cx,0ffffh ! ret
|
||||
|
||||
shmem:
|
||||
;-----
|
||||
;input: SI = LDTAB
|
||||
; BX = Owner PD
|
||||
; Load_pd = Requestor
|
||||
; Have to set LDT_START
|
||||
;
|
||||
|
||||
lea di,(p_mem-ms_link)[bx]
|
||||
sm_nxt:
|
||||
mov di,ms_link[di]
|
||||
cmp di,0 ! je sm_no
|
||||
mov ax,ms_flags[di]
|
||||
and ax,mf_share+mf_code+mf_load
|
||||
cmp ax,mf_share+mf_code+mf_load ! jne sm_nxt
|
||||
push si ! push ds
|
||||
push ms_start[di]
|
||||
push ms_start[di]
|
||||
push lod_pd
|
||||
push bx
|
||||
mov ax,ss ! mov ds,ax
|
||||
mov dx,sp ! mov cx,f_share
|
||||
call osif
|
||||
|
||||
; This will always work.
|
||||
|
||||
pop ax ! pop ax ! pop ax
|
||||
pop dx ! pop ds ! pop si
|
||||
mov ldt_start[si],dx
|
||||
ret
|
||||
sm_no: mov cx,0ffffh ! ret
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Load Stack Format
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
lstklen equ 96 * byte
|
||||
|
||||
DSEG
|
||||
org lstklen - 10
|
||||
|
||||
ls_sp rw 0
|
||||
ls_offset rw 1
|
||||
ls_cseg rw 1
|
||||
ls_flags rw 1
|
||||
ls_roffset rw 1
|
||||
ls_rcseg rw 1
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Memory Allocation Unit Routines
|
||||
;*
|
||||
;* Memory Allocation Unit
|
||||
;* A Memory Allocation Unit is a contiguous
|
||||
;* area of memory that is described by a MD.
|
||||
;* At the beginning of this area is a Suballocation
|
||||
;* table that describes areas within it that are
|
||||
;* allocated or free
|
||||
;*
|
||||
;* +----+----+----+----+----+----+----+----+
|
||||
;* MD | Link | Start | Length | Plist |
|
||||
;* +----+----+----+----+----+----+----+----+
|
||||
;*
|
||||
;* Link - Link field for placing MAUs on Linked
|
||||
;* lists
|
||||
;* Start - Segment Address of the area covered
|
||||
;* Length - Length of area
|
||||
;* Plist - used for a linked list of partitions
|
||||
;* that are included in this area.
|
||||
;*
|
||||
;* Suballocation Table
|
||||
;* The m_start field is the segment
|
||||
;* address of the suballocation table (offset 0).
|
||||
;* The first entry of the table is special and
|
||||
;* has the following format.
|
||||
;*
|
||||
;* +----+----+----+----+----+
|
||||
;* SAT0 |ents| reserved |
|
||||
;* +----+----+----+----+----+
|
||||
;*
|
||||
;* sat1_ents - number of SAT entries
|
||||
;* not including SAT0
|
||||
;* Subsequent entries have the following format
|
||||
;*
|
||||
;* +----+----+----+----+----+
|
||||
;* SAT | Start | Length |nall|
|
||||
;* +----+----+----+----+----+
|
||||
;*
|
||||
;* start - start address of this contiguous
|
||||
;* piece of memory
|
||||
;* length - of this piece of memory
|
||||
;* nall - number of times allocated
|
||||
;* 0 = free 2 = share
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
sat_start equ word ptr 0
|
||||
sat_length equ word ptr sat_start + word
|
||||
sat_nall equ byte ptr sat_length + word
|
||||
satlen equ sat_nall + byte
|
||||
|
||||
;==============
|
||||
maualloc_entry: ; Alloc from MAU
|
||||
;==============
|
||||
; Allocate a piece of memory from an MAU
|
||||
;
|
||||
; input: BX = address of MAU
|
||||
; DX = MPB in u_wrkseg
|
||||
; mpb_start = abs addr (0 = any)
|
||||
; mpb_min = minimum necessary
|
||||
; mpb_max = maximum wanted
|
||||
;
|
||||
; output: BX = 0h if success
|
||||
; 0ffffh if failure
|
||||
; CX = Error Code
|
||||
; mpb_start = start address
|
||||
; mpb_min = mcb_max = length
|
||||
|
||||
push es ! mov es,u_wrkseg
|
||||
|
||||
; if absolute, see if within MAU
|
||||
mov si,dx ! mov cx,es:mpb_start[si]
|
||||
cmp cx,0 ! je maua_rel
|
||||
mov ax,m_start[bx]
|
||||
cmp cx,ax ! jb maua_err
|
||||
add ax,m_length[bx]
|
||||
cmp cx,ax ! jae maua_err
|
||||
maua_rel:
|
||||
mov ds,m_start[bx]
|
||||
maua_start:
|
||||
sub bx,bx ! mov dl,bl ;BX->SAT entry
|
||||
;DL = SAT number
|
||||
maua_nsat:
|
||||
inc dl ! add bx,satlen
|
||||
cmp dl,.0 ! ja maua_err ;?out of table entries?
|
||||
cmp sat_start[bx],0 ! je maua_err ;?end of used table?
|
||||
cmp sat_nall[bx],0 ! jne maua_nsat ;?already allocated?
|
||||
mov cx,es:mpb_start[si]
|
||||
cmp cx,0 ! je maua_nabs ;?abs req?
|
||||
mov ax,sat_start[bx]
|
||||
cmp cx,ax ! jb maua_nsat ;?in this area?
|
||||
add ax,sat_length[bx]
|
||||
cmp cx,ax ! jae maua_nsat
|
||||
cmp cx,sat_start[bx] ! je maua_nabs ;?exact?
|
||||
sub cx,sat_start[bx]
|
||||
push si
|
||||
call mau_split ;make exact
|
||||
pop si
|
||||
jmps maua_start
|
||||
maua_err:
|
||||
mov bx,0ffffh ! mov cx,e_no_memory
|
||||
jmps maua_out
|
||||
maua_nabs:
|
||||
mov cx,es:mpb_min[si]
|
||||
mov ax,sat_length[bx]
|
||||
cmp cx,ax ! ja maua_nsat
|
||||
mov cx,es:mpb_max[si]
|
||||
cmp cx,ax ! jae maua_alloc
|
||||
cmp sat_nall[bx],0 ! je maua_splitit
|
||||
mov ax,es:mpb_flags[si]
|
||||
and ax,mf_share ! jz maua_nsat
|
||||
jmps maua_alloc
|
||||
maua_splitit: push si ! call mau_split ! pop si
|
||||
maua_alloc: mov ax,sat_length[bx]
|
||||
mov es:mpb_min[si],ax
|
||||
mov es:mpb_max[si],ax
|
||||
mov ax,sat_start[bx]
|
||||
mov es:mpb_start[si],ax
|
||||
inc sat_nall[bx]
|
||||
call mau_collapse
|
||||
sub bx,bx ! mov cx,bx
|
||||
jmps maua_out
|
||||
maua_out:
|
||||
mov ds,sysdat
|
||||
pop es ! ret
|
||||
|
||||
;=============
|
||||
maufree_entry: ; Free from MAU
|
||||
;=============
|
||||
; free SAT in given MAU
|
||||
; input: DX = address of MAF in u_wrkseg
|
||||
; output: CX = 0 if successful
|
||||
; CX = 0ffffh on failure
|
||||
; if CX = 0,
|
||||
; BX = 0 if MAU still in use
|
||||
; BX = 0ffffh if MAU is empty
|
||||
; if CX = 0ffffh
|
||||
; BX = 0ffffh
|
||||
|
||||
push es ! mov es,u_wrkseg
|
||||
mov si,dx
|
||||
mov bx,es:maf_mau[si]
|
||||
mov ds,m_start[bx]
|
||||
|
||||
; ES:SI -> MAF
|
||||
; DS: 0 -> SAT table
|
||||
|
||||
sub bx,bx ! mov cx,bx
|
||||
mov dx,es:maf_sat[si]
|
||||
|
||||
; DS:BX -> current SAT
|
||||
; CX = SAT entry number
|
||||
; DX = MAF_SAT start
|
||||
|
||||
mauf_nsat:
|
||||
add bx,satlen ! inc cx
|
||||
cmp cx,.0 ! ja mauf_err
|
||||
cmp dx,sat_start[bx] ; This SAT?
|
||||
jne mauf_nsat
|
||||
cmp dx,es:maf_start[si] ; Freeing all of it?
|
||||
je mauf_free
|
||||
cmp sat_nall[bx],1 ; Is it shared?
|
||||
je mauf_nsha
|
||||
jmps mauf_out ; Can't split it
|
||||
; since its shared.
|
||||
; But, no error
|
||||
|
||||
mauf_nsha: mov cx,es:maf_start[si] ; Not shared,
|
||||
mov ax,sat_start[bx]
|
||||
add ax,sat_length[bx]
|
||||
cmp ax,cx ! jb mauf_err ; Within range?
|
||||
|
||||
; must split this SAT
|
||||
; this can only be done if not shared
|
||||
|
||||
sub cx,dx ! call mau_split
|
||||
sub cx,cx ! mov bx,cx ! jmps mauf_c
|
||||
mauf_free: dec sat_nall[bx]
|
||||
mauf_c: call mau_collapse ! jmps mauf_out
|
||||
mauf_err:
|
||||
mov bx,0ffffh ! mov cx,e_no_memory
|
||||
mauf_out:
|
||||
pop es ! mov ds,sysdat
|
||||
ret
|
||||
|
||||
mau_split: ;split SAT into 2
|
||||
;--------- -----------------
|
||||
; new SAT element starting at split boundary
|
||||
; with nall=0, old has same nall.
|
||||
; input: BX = address of SAT element
|
||||
; CX = length to split at
|
||||
; output: BX = address of original SAT element
|
||||
|
||||
push bx ! push cx
|
||||
add bx,satlen ! call mau_insert
|
||||
cmp cx,0 ! pop cx
|
||||
pop bx ! jne maus_err ;create hole if error
|
||||
lea di,satlen[bx] ! mov dx,sat_length[bx]
|
||||
sub dx,cx ! mov sat_length[di],dx
|
||||
mov dx,cx ! add dx,sat_start[bx]
|
||||
mov sat_start[di],dx ! mov sat_nall[di],0
|
||||
maus_err:
|
||||
mov sat_length[bx],cx
|
||||
ret
|
||||
|
||||
mau_collapse: ;collapse adjacent unallocated SATs
|
||||
;------------ -----------------------------------
|
||||
; collapse adjacent unallocated SATs and holes in table
|
||||
; if possible
|
||||
; return: BX = 0 if not empty
|
||||
; = 0ffffh if empty
|
||||
; CX = 0
|
||||
|
||||
sub bx,bx ! mov cx,bx
|
||||
mauc_nsat:
|
||||
inc cx
|
||||
cmp cx,.0 ! je mauc_mtchk
|
||||
add bx,satlen ! lea di,satlen[bx]
|
||||
cmp sat_start[bx],0 ! je mauc_mtchk
|
||||
cmp sat_start[di],0 ! je mauc_mtchk
|
||||
cmp sat_nall[bx],0 ! jne mauc_notfree
|
||||
;this SAT is free
|
||||
mov ax,sat_start[bx] ! add ax,sat_length[bx]
|
||||
cmp ax,sat_start[di] ! je mauc_fnohole
|
||||
;followed by a hole
|
||||
mov ax,sat_start[di] ! sub ax,sat_start[bx]
|
||||
mov sat_length[bx],ax
|
||||
mauc_fnohole:
|
||||
;free SAT., no hole
|
||||
cmp sat_nall[di],0 ! jne mauc_nsat
|
||||
;followed by free SAT
|
||||
mov ax,sat_length[di]
|
||||
add sat_length[bx],ax
|
||||
push bx ! push cx
|
||||
mov bx,di ! call mau_release
|
||||
pop cx ! pop bx
|
||||
sub bx,satlen ! dec cx
|
||||
jmp mauc_nsat
|
||||
mauc_notfree:
|
||||
;allocated SAT
|
||||
mov ax,sat_start[bx] ! add ax,sat_length[bx]
|
||||
cmp ax,sat_start[di] ! je mauc_nsat
|
||||
;followed by a hole
|
||||
cmp sat_nall[di],0 ! je mauc_nfhole
|
||||
;next SAT is allocated
|
||||
push bx ! push cx
|
||||
mov di,bx ! call mau_insert
|
||||
pop cx ! pop bx
|
||||
jmp mauc_nsat
|
||||
mauc_nfhole: ;Alloc SAT, followed by hole
|
||||
;next SAT is free
|
||||
mov ax,sat_start[di] ! sub ax,sat_start[bx]
|
||||
sub sat_start[di],ax ! add sat_length[di],ax
|
||||
jmp mauc_nsat
|
||||
|
||||
mauc_mtchk:
|
||||
mov bp,0ffffh
|
||||
xor cx,cx ! xor bx,bx
|
||||
mauc_mtn:
|
||||
inc cx
|
||||
cmp cx,.0 ! je mauc_out
|
||||
add bx,satlen
|
||||
cmp sat_start[bx],0 ! je mauc_out
|
||||
cmp sat_nall[bx],0 ! je mauc_mtn
|
||||
mov bp,0
|
||||
mauc_out:
|
||||
mov bx,bp ! xor cx,cx ! ret
|
||||
|
||||
mau_release:
|
||||
;-----------
|
||||
; input: BX = SAT to release
|
||||
|
||||
push es ! mov ax,ds ! mov es,ax
|
||||
mov ax,satlen
|
||||
mul byte ptr .0
|
||||
push ax ! mov cx,ax ! sub cx,bx
|
||||
mov di,bx ! add bx,satlen
|
||||
mov si,bx ! rep movs al,al
|
||||
pop bx ! mov sat_length[bx],0
|
||||
mov sat_start[bx],0
|
||||
mov sat_nall[bx],0
|
||||
pop es ! ret
|
||||
|
||||
mau_insert:
|
||||
;----------
|
||||
; input: BX = SAT to place new SAT in front
|
||||
; output: CX = 0 if successful
|
||||
|
||||
mov ax,satlen ! mul byte ptr .0
|
||||
mov si,ax ! mov cx,0ffffh
|
||||
cmp sat_start[si],0 ! jne maui_r
|
||||
mov cx,si ! sub cx,bx
|
||||
dec si ! lea di,satlen[si]
|
||||
push es ! push ds ! pop es
|
||||
std ! rep movsb ! cld
|
||||
pop es ! sub cx,cx
|
||||
mov sat_start[bx],cx
|
||||
mov sat_length[bx],cx
|
||||
mov sat_nall[bx],cl
|
||||
maui_r: ret
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
include cpyright.def
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* MP/M-86 Memory Management Module
|
||||
;*
|
||||
;*****************************************************
|
||||
eject ! include system.def
|
||||
eject ! include modfunc.def
|
||||
eject ! include pd.def
|
||||
eject ! include qd.def
|
||||
eject ! include err.def
|
||||
eject ! include mem.def
|
||||
eject ! include mpb.def
|
||||
eject ! include uda.def
|
||||
eject ! include memif.mem
|
||||
eject ! include cpmmem.mem
|
||||
eject ! include memory.mem
|
||||
eject ! include share.mem
|
||||
eject ! include mau.mem
|
||||
eject ! include ml.mem
|
||||
eject ! include util.mem
|
||||
eject ! include patch.cod
|
||||
eject ! include uda.fmt
|
||||
eject ! include lstk.fmt
|
||||
eject ! include sysdat.dat
|
||||
eject ! include data.bdo
|
||||
eject ! end
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,480 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* MEM Entry Points
|
||||
;*
|
||||
;* Each process descriptor points to a linked
|
||||
;* list of MDs that describe memory segments that
|
||||
;* it owns. The MDs note the starting paragraph
|
||||
;* and a MAU that the Memory Segment is in.
|
||||
;*
|
||||
;* Format of MDs on p_mem lists:
|
||||
;*
|
||||
;* +----+----+----+----+----+----+----+----+----+----+
|
||||
;* | link | start | length | flags | mau |
|
||||
;* +----+----+----+----+----+----+----+----+----+----+
|
||||
;*
|
||||
;* link link field for p_mem list
|
||||
;* start starting paragraph of memory segment
|
||||
;* length length in paragraphs of memory segment
|
||||
;* flags load,code,and share as in MPB
|
||||
;* mau offset of MAU in SYSDAT that segment is
|
||||
;* allocated from
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;============
|
||||
malloc_entry:
|
||||
;============
|
||||
; Allocate Memory - memory is allocated from MAUs.
|
||||
; First we try to allocate memory from MAUs that has
|
||||
; memory segments already allocated by this process.
|
||||
; If that fails, we try to create a new MAU from the
|
||||
; Memory Free List (MFL). If both fails, an error is
|
||||
; is returned to the user.
|
||||
;
|
||||
; input: DX = MPB in u_wrkseg
|
||||
; output: BX = 0 if successful (unused memory)
|
||||
; = 1 if successful (shared code)
|
||||
; = 0ffffh if failure
|
||||
; CX = error code
|
||||
;
|
||||
; Format of MPB:
|
||||
;
|
||||
; +----+----+----+----+----+----+----+----+----+----+
|
||||
; | start | min | max | pdadr | flags |
|
||||
; +----+----+----+----+----+----+----+----+----+----+
|
||||
;
|
||||
; start - if non-zero, an absolute request
|
||||
; min - minimum length that will satisfy the request
|
||||
; max - maximum length wanted
|
||||
; We will try to allocate the maximum
|
||||
; but will be satisfied with as little as the
|
||||
; minimum.
|
||||
; pdadr - Process Descriptor to allocate memory to.
|
||||
; Note - PD can not be a current process unless
|
||||
; it is the calling process.
|
||||
; The Calling process must explicitly release
|
||||
; the memory if the PD never becomes a process.
|
||||
; Otherwise, memory is released upon termination.
|
||||
; If pdadr is 0, then calling process allocates
|
||||
; the memory.
|
||||
; flags - 00001h Load This segment initialized from
|
||||
; a disk file
|
||||
; 00002h Shared This is a sharable segment
|
||||
; 00004h Code This is a Code segment
|
||||
|
||||
; Get a MD for use in the p_mem list
|
||||
|
||||
; DX -> MPB (u_wrkseg)
|
||||
push dx ! call getmd ! pop dx ; BX -> MD
|
||||
jcxz mall_gmd
|
||||
mov bx,0ffffh ! ret
|
||||
mall_gmd:
|
||||
; fill PDADR field in case its zero
|
||||
|
||||
push es ! mov es,u_wrkseg ;save UDA
|
||||
mov di,dx ! mov ax,es:mpb_pdadr[di]
|
||||
cmp ax,0 ! jne mall_gpd
|
||||
mov ax,rlr
|
||||
mov es:mpb_pdadr[di],ax
|
||||
mall_gpd:
|
||||
pop es ;ES=UDA
|
||||
cmp ax,rlr ! je mall_pdv1
|
||||
|
||||
push ax ! push bx
|
||||
push dx ! push di
|
||||
mov bx,offset thrd_spb ;ok to call sync on
|
||||
mov cx,f_sync ;thread after sync-ing
|
||||
call osif ;on memory
|
||||
pop di ! pop dx
|
||||
pop bx ! pop ax
|
||||
mov si,(offset thrdrt)-p_thread
|
||||
|
||||
mall_pdnxt: mov si,p_thread[si]
|
||||
cmp si,0 ! je mall_pdver
|
||||
cmp si,ax ! jne mall_pdnxt
|
||||
cmp si,rlr ! je mall_pdver
|
||||
mov cx,e_active_pd
|
||||
push bx ; save MD addr
|
||||
mov bx,offset thrd_spb
|
||||
mov cx,f_unsync
|
||||
call osif
|
||||
pop bx ; restore MD addr
|
||||
jmp mall_err
|
||||
mall_pdver:
|
||||
push ax ! push bx
|
||||
push dx ! push di
|
||||
mov bx,offset thrd_spb
|
||||
mov cx,f_unsync
|
||||
call osif
|
||||
pop di ! pop dx
|
||||
pop bx ! pop ax
|
||||
|
||||
; verify MIN <= MAX
|
||||
|
||||
mall_pdv1:
|
||||
push es ! mov es,u_wrkseg
|
||||
mov cx,es:mpb_min[di]
|
||||
cmp cx,es:mpb_max[di]
|
||||
jbe mpb_ok
|
||||
mov es:mpb_max[di],cx
|
||||
mpb_ok:
|
||||
|
||||
; Make sure total allocation <= MMP
|
||||
|
||||
mov si,ax ! add si,(p_mem - ms_link)
|
||||
sub cx,cx ! push si
|
||||
max_chk_nxt:
|
||||
mov si,ms_link[si]
|
||||
cmp si,0 ! je max_chk_done
|
||||
add cx,ms_length[si]
|
||||
jmps max_chk_nxt
|
||||
max_chk_done:
|
||||
pop si ! mov ax,mmp
|
||||
sub ax,cx
|
||||
cmp ax,0 ! jne not_zero
|
||||
no_min: pop es
|
||||
mall_nomem: mov cx,e_no_memory
|
||||
mall_err: call freemd ; Free the Memory Descriptor
|
||||
mov bx,0ffffh ! ret ; CX=Error Code set previously
|
||||
not_zero:
|
||||
cmp ax,es:mpb_min[di] ! jb no_min
|
||||
cmp ax,es:mpb_max[di] ! jae max_ok
|
||||
mov es:mpb_max[di],ax
|
||||
max_ok:
|
||||
|
||||
; initialize local variables
|
||||
|
||||
push di ! mov di,offset beststart
|
||||
mov cx,11 ! sub ax,ax
|
||||
mov es,sysdat
|
||||
rep stosw ! pop di
|
||||
|
||||
sub cx,cx
|
||||
pop es
|
||||
; try to allocate memory
|
||||
|
||||
mall_next:
|
||||
mov si,ms_link[si]
|
||||
cmp si,0 ! je mall_ml
|
||||
cmp cx,ms_mau[si] ! je mall_next
|
||||
; here's a MAU we haven't tried...
|
||||
; CX=last MAU tried
|
||||
; DX=MPB adr in u_wrkseg
|
||||
; BX=New MD
|
||||
; SI=current MD
|
||||
push cx ! push dx ! push bx ! push si
|
||||
mov bx,ms_mau[si]
|
||||
call mall_try_mau
|
||||
pop si ! pop bx ! pop dx
|
||||
; Plus DI=MAU address
|
||||
cmp cx,0 ! pop cx ! jne mall_next
|
||||
; exact allocation
|
||||
; succesful allocation
|
||||
jmp mall_linkit
|
||||
|
||||
mall_ml: ; We must create a new MAU from MFL
|
||||
push bx ! push dx
|
||||
mov ds,u_wrkseg
|
||||
mov bx,offset mfl ! mov cx,f_mlalloc
|
||||
call osif
|
||||
mov ds,sysdat
|
||||
;BX=MAU, (New MD,MPB on stack)
|
||||
jcxz mall_ml0
|
||||
pop dx ! pop bx
|
||||
jmp mall_linkit
|
||||
mall_ml0: ; We have a new MAU
|
||||
;place MAU on MAL
|
||||
mov si,mal
|
||||
mov m_link[bx],si
|
||||
mov mal,bx
|
||||
;allocate memory
|
||||
pop dx ! push dx
|
||||
sub si,si
|
||||
call mall_try_mau
|
||||
pop dx ! pop bx
|
||||
;DI=MAU, BX=New MD, DX=MPB in u_wrkseg
|
||||
|
||||
mall_linkit:
|
||||
;BX -> MD
|
||||
;DX -> MPB in u_wrkseg
|
||||
|
||||
cmp beststart,0 ! jne yesmem
|
||||
|
||||
;if ccpm
|
||||
; jmp mall_nomem
|
||||
;endif
|
||||
|
||||
;if mpm
|
||||
|
||||
; We couldn't find any memory ...
|
||||
; lets take something off the SCL
|
||||
|
||||
pushf ! cli
|
||||
mov di,scl
|
||||
cmp di,0 ! jne take_one_off
|
||||
|
||||
; No where else to try, giveup.
|
||||
popf ! jmp mall_nomem
|
||||
|
||||
; take first SHARE PD off SCL
|
||||
take_one_off:
|
||||
mov ax,p_thread[di]
|
||||
mov scl,ax
|
||||
popf
|
||||
|
||||
; Free its memory
|
||||
; We can assume only one memory segment
|
||||
|
||||
push bx ! push dx
|
||||
mov bx,p_mem[di]
|
||||
push di ! push ds
|
||||
push di ! push ms_start[bx]
|
||||
push ss ! pop ds
|
||||
mov dx,sp ! mov cx,f_memfree
|
||||
call osif
|
||||
pop ax ! pop ax
|
||||
pop ds ! pop di
|
||||
|
||||
; There should be no error.
|
||||
; Put SHARE PD on PUL
|
||||
pushf ! cli
|
||||
mov ax,pul
|
||||
mov p_link[di],ax
|
||||
mov pul,di
|
||||
popf
|
||||
|
||||
; Let's assume we just released a partition
|
||||
; and try the ML Alloc again.
|
||||
|
||||
pop dx ! pop bx
|
||||
jmp mall_ml
|
||||
;endif
|
||||
|
||||
; We have memory ...
|
||||
yesmem:
|
||||
push es ! mov es,u_wrkseg
|
||||
mov di,dx
|
||||
mov ax,beststart
|
||||
mov es:mpb_start[di],ax
|
||||
mov ms_start[bx],ax
|
||||
mov ax,bestlen
|
||||
mov es:mpb_min[di],ax
|
||||
mov es:mpb_max[di],ax
|
||||
mov ms_length[bx],ax
|
||||
mov ax,es:mpb_flags[di]
|
||||
mov ms_flags[bx],ax
|
||||
mov si,bestsi
|
||||
cmp si,0 ! jne mall_l0
|
||||
mov si,es:mpb_pdadr[di]
|
||||
add si,(p_mem-ms_link)
|
||||
mall_l0:mov ax,ms_link[si] ! mov ms_link[bx],ax
|
||||
mov ms_link[si],bx
|
||||
mov di,bestmau
|
||||
mov ms_mau[bx],di
|
||||
pop es ! sub cx,cx ! mov bx,cx ! ret
|
||||
|
||||
mall_try_mau:
|
||||
;------------
|
||||
; input: BX -> MAU
|
||||
; DX -> MPB in u_wrkseg
|
||||
; SI = MS Root that MAU came from
|
||||
; output: CX = 0, found exact allocation
|
||||
; else, exact not found
|
||||
|
||||
; save root,mau
|
||||
mov currsi,si
|
||||
mov currmau,bx
|
||||
|
||||
; copy user's MPB into local MPB
|
||||
push dx ! push ds ! push es
|
||||
mov ds,u_wrkseg
|
||||
mov es,sysdat
|
||||
mov si,dx ! mov di,offset currmpb
|
||||
mov cx,5 ! rep movsw
|
||||
pop es ! pop ds
|
||||
|
||||
mov dx,offset currmpb
|
||||
mov cx,f_maualloc ! call osif
|
||||
|
||||
pop di
|
||||
jcxz chkbest
|
||||
ret
|
||||
chkbest:
|
||||
push es ! mov es,u_wrkseg
|
||||
mov si,offset currmpb
|
||||
mov ax,mpb_max[si]
|
||||
sub cx,cx
|
||||
cmp ax,es:mpb_max[di]
|
||||
pop es
|
||||
jz replacebest
|
||||
mov cx,3 ! mov bx,currmau
|
||||
mov di,si
|
||||
cmp ax,bestlen ! jbe freeworst
|
||||
replacebest:
|
||||
mov di,offset beststart
|
||||
mov bx,bestmau
|
||||
call freeworst
|
||||
mov si,offset currmpb
|
||||
mov ax,mpb_start[si] ! mov beststart,ax
|
||||
mov ax,mpb_max[si] ! mov bestlen,ax
|
||||
mov ax,currmau ! mov bestmau,ax
|
||||
mov ax,currsi ! mov bestsi,ax
|
||||
savret: ret
|
||||
freeworst: ; DI->Start, CX=Return Code, BX=MAU
|
||||
cmp word ptr [di],0 ! je savret
|
||||
|
||||
; free worst memory
|
||||
push cx ! push ds
|
||||
push word ptr [di] ! push word ptr [di]
|
||||
push bx ! push ss ! pop ds
|
||||
mov dx,sp ! mov cx,f_maufree
|
||||
call osif
|
||||
|
||||
; if MAU empty, free MAU
|
||||
cmp cx,0 ! jne mflret
|
||||
cmp bx,0ffffh ! jne mflret
|
||||
pop bx ! pop ax ! pop ax ! pop ds
|
||||
|
||||
; take off MAL
|
||||
; BX = MAU address
|
||||
mov ax,bx ! mov bx,(offset mal)-m_link
|
||||
mfl1: mov si,bx ! mov bx,m_link[si]
|
||||
cmp bx,ax ! jne mfl1
|
||||
push ax
|
||||
mov ax,m_link[bx] ! mov m_link[si],ax
|
||||
pop bx
|
||||
; Replace into MFL
|
||||
mov cx,f_mlfree
|
||||
mov dx,bx ! mov bx,offset mfl
|
||||
call osif ! pop cx ! ret
|
||||
|
||||
mflret: pop bx ! pop ax ! pop ax
|
||||
pop ds ! pop cx ! ret
|
||||
|
||||
;===========
|
||||
mfree_entry: ; 130 - Memory Free
|
||||
;===========
|
||||
; Free the memory segment with the given segment addr.
|
||||
; input: DX = MFPB in u_wrkseg
|
||||
; output: BX = 0 if successful
|
||||
; = 0ffffh on failure
|
||||
; CX = error code
|
||||
;
|
||||
; Memory Free Parameter Block (MFPB)
|
||||
;
|
||||
; +----+----+----+----+
|
||||
; | start | pdadr |
|
||||
; +----+----+----+----+
|
||||
;
|
||||
; start - starting paragraph of area to be freed.
|
||||
; pdadr - PD to free memory from. If 0, then calling
|
||||
; process. If non-zero, the PD must not be
|
||||
; a current process.
|
||||
|
||||
push es ! mov es,u_wrkseg
|
||||
mov si,dx
|
||||
mov bx,es:mfpb_pd[si]
|
||||
mov dx,es:mfpb_start[si]
|
||||
pop es
|
||||
; BX = pdadr
|
||||
; DX = start paragraph
|
||||
cmp bx,0 ! jne mfree_chkpd
|
||||
mov bx,rlr
|
||||
jmps mfree_g1
|
||||
mfree_chkpd:
|
||||
|
||||
push bx ! push dx
|
||||
mov bx,offset thrd_spb
|
||||
mov cx,f_sync
|
||||
call osif
|
||||
pop dx ! pop bx
|
||||
|
||||
mov si,(offset thrdrt)-p_thread
|
||||
mfree_nxtpd:
|
||||
mov si,p_thread[si]
|
||||
cmp si,0 ! je mfree_gotpd
|
||||
cmp si,bx ! jne mfree_nxtpd
|
||||
cmp si,rlr ! je mfree_gotpd
|
||||
mov bx,offset thrd_spb
|
||||
mov cx,f_unsync
|
||||
call osif
|
||||
mov bx,0ffffh
|
||||
mov cx,e_active_pd
|
||||
ret
|
||||
mfree_gotpd:
|
||||
push bx ! push dx
|
||||
mov bx,offset thrd_spb
|
||||
mov cx,f_unsync
|
||||
call osif
|
||||
pop dx ! pop bx
|
||||
|
||||
mfree_g1:
|
||||
lea si,p_mem[bx]
|
||||
mfree_next:
|
||||
mov bx,si ! mov si,ms_link[bx]
|
||||
cmp si,0 ! je mfree_err
|
||||
cmp ms_start[si],dx ! je mfree_it
|
||||
ja mfree_next
|
||||
mov ax,ms_start[si]
|
||||
add ax,ms_length[si]
|
||||
cmp ax,dx ! jbe mfree_next
|
||||
push dx ! push si
|
||||
call mfree_it
|
||||
pop si ! pop dx
|
||||
cmp cx,0 ! jne mfree_next
|
||||
mfree_exit:
|
||||
sub bx,bx ! mov cx,bx ! ret
|
||||
mfree_err:
|
||||
mov bx,0ffffh ! mov cx,e_no_memory
|
||||
ret
|
||||
|
||||
mfree_it:
|
||||
;--------
|
||||
; input: BX = root
|
||||
; SI = MD ([bx])
|
||||
; DX = segment to free
|
||||
; output: BX = 0,0ffffh (success,failure)
|
||||
; CX = Error Code
|
||||
|
||||
push bx ! push si ! push dx
|
||||
;push MAF structure
|
||||
push dx ! push ms_start[si]
|
||||
push ms_mau[si]
|
||||
mov dx,sp ! push ss ! pop ds
|
||||
mov cx,f_maufree ! call osif
|
||||
mov bp,bx ;if bp=0,MAU not empty
|
||||
mov ds,sysdat
|
||||
;pop MAF structure
|
||||
pop ax ! pop ax ! pop ax
|
||||
pop dx ! pop si ! pop bx
|
||||
;DX=segment to free
|
||||
;BX=root
|
||||
;SI=MD ( [BX] )
|
||||
cmp cx,0
|
||||
jne mfree_err
|
||||
cmp dx,ms_start[si] ! je mfree_off
|
||||
;decrease length
|
||||
sub dx,ms_start[si]
|
||||
mov ms_length[si],dx
|
||||
mfree_r:
|
||||
jmps mfree_exit
|
||||
;take off p_mem list
|
||||
mfree_off: mov ax,ms_link[si] ! mov ms_link[bx],ax
|
||||
;free MD
|
||||
push ms_mau[si] ! push bp
|
||||
mov bx,si ! call freemd
|
||||
pop bp ! pop dx
|
||||
;free MAU if empty
|
||||
cmp bp,0 ! je mfree_exit
|
||||
;find it on MAL
|
||||
mov di,(offset mal)-m_link
|
||||
mfree_nmal: mov si,di ! mov di,m_link[si]
|
||||
cmp di,dx ! jne mfree_nmal
|
||||
;release from MAL
|
||||
mov ax,m_link[di] ! mov m_link[si],ax
|
||||
mov m_link[di],0
|
||||
;release to MFL
|
||||
mov bx,offset mfl ! mov cx,f_mlfree
|
||||
jmp osif
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Memory List Functions
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;=============
|
||||
mlalloc_entry: ; Alloc from Mem List
|
||||
;=============
|
||||
; Create a MAU from a Memory List. Memory List is a
|
||||
; linked list of MDs in memory order (low first). It
|
||||
; is assumed that units in the Memory List are paragraphs
|
||||
; input: DX = address of MPB in u_wrkseg
|
||||
; BX = ML root in SYSDAT
|
||||
; output: BX = address of MAU
|
||||
; = 0ffffh if error
|
||||
; CX = Error Code
|
||||
|
||||
mov si,dx
|
||||
sub ax,ax ! mov cx,ax ! mov dx,0ffffh
|
||||
; AX = MD w/best score
|
||||
; DX = best score
|
||||
; CX = # partitions used
|
||||
; SI -> MPB in u_wrkseg
|
||||
push ax ! push cx
|
||||
mla_nmd:cmp m_link[bx],0 ! je mla_found
|
||||
push bx ! push dx ! push si
|
||||
call mla_value
|
||||
pop si ! pop dx ! pop bx
|
||||
cmp cx,dx ! jae mla_next
|
||||
mov dx,cx ! pop cx ! mov cx,ax
|
||||
pop ax ! mov ax,bx
|
||||
push ax ! push cx
|
||||
cmp dx,0 ! je mla_found
|
||||
mla_next: mov bx,m_link[bx]
|
||||
jmps mla_nmd
|
||||
mla_found:
|
||||
pop cx ! pop ax
|
||||
cmp ax,0 ! je mla_err
|
||||
mov bx,ax ! mov ax,cx
|
||||
jmp mla_makemau
|
||||
mla_err:
|
||||
mov bx,0ffffh ! mov cx,e_no_memory
|
||||
mla_out:ret
|
||||
|
||||
mla_value:
|
||||
;---------
|
||||
; input: BX = ML element Root
|
||||
; SI = MPB in u_wrkseg
|
||||
; output: CX = value (0=perfect,0ffffh=no fit)
|
||||
; AX = # of elements
|
||||
|
||||
xor bp,bp ; Func 129 repair, FMB, 1/20/84
|
||||
|
||||
push es ! mov es,u_wrkseg
|
||||
sub ax,ax ! mov dx,0
|
||||
; AX = # of partitions
|
||||
; DX = total length so far
|
||||
mov di,m_link[bx]
|
||||
cmp di,0 ! je mlav_err
|
||||
; we have a list
|
||||
cmp es:mpb_start[si],0 ! je mlav_next
|
||||
;an absolute request
|
||||
mov cx,m_start[di] ! add cx,(2*satlen)
|
||||
cmp es:mpb_start[si],cx ! jb mlav_err
|
||||
;it starts after our start
|
||||
add cx,m_length[di] ! sub cx,(2*satlen)
|
||||
cmp es:mpb_start[si],cx ! jae mlav_err
|
||||
|
||||
; Func 129 repair, FMB, 1/20/84
|
||||
mov bp,1 ; On an absolute request, the
|
||||
inc ax ; current available length within
|
||||
mov dx,cx ; the partition was not calculated
|
||||
sub dx, es:mpb_start[si] ; correctly.
|
||||
mov bx,di ;
|
||||
mov di, m_link[bx] ;
|
||||
|
||||
;this list satisfies ABS requirement
|
||||
mlav_next: mov cx,es:mpb_max[si]
|
||||
cmp cx,dx ! jb mlav_chk
|
||||
mlav_add: cmp ax,0 ! je mlav_ad1
|
||||
push ax
|
||||
mov ax,m_start[bx]
|
||||
add ax,m_length[bx]
|
||||
cmp ax,m_start[di] ! pop ax ! je mlav_ad1
|
||||
jmps mlav_chkmin
|
||||
mlav_ad1: inc ax ! add dx,m_length[di]
|
||||
mov bx,di ! mov di,m_link[bx]
|
||||
cmp di,0 ! jne mlav_next
|
||||
mlav_chkmin: mov cx,es:mpb_min[si]
|
||||
add cx,(2*satlen)
|
||||
cmp cx,dx ! jbe mlav_calc
|
||||
mlav_err: mov cx,0ffffh ! sub ax,ax
|
||||
pop es ! ret
|
||||
|
||||
mlav_chk:
|
||||
cmp bp,1 ! je mlav_calc ; Func 129 repair, FMB, 1/20/84
|
||||
|
||||
add cx,(2*satlen)
|
||||
cmp cx,dx ! ja mlav_add
|
||||
|
||||
mlav_calc: ; HERE IS WHERE WE GIVE THIS SET A VALUE.
|
||||
; IT CAN SATIFY THE REQUEST.
|
||||
|
||||
; ALGORITHM:
|
||||
; #partitions = #partitions + 1 if next
|
||||
; to contiquous memory
|
||||
; value = (abs(max-length) SHR 4) +
|
||||
; ((#partitions-1) SHL 2)
|
||||
; idea is that 1K = 1 paritition to avoid
|
||||
; gobbling all of our small partitions.
|
||||
; we deal with 256 byte memory units so we
|
||||
; won't overflow a word.
|
||||
|
||||
; AX = # partitions
|
||||
; DX = memory size
|
||||
|
||||
push ax ! dec ax
|
||||
mov cl,2
|
||||
shl ax,cl
|
||||
mov cx,es:mpb_max[si]
|
||||
add cx,(2*satlen)
|
||||
|
||||
; If MAX memory is FFFF, SAT adjustment
|
||||
; wraps around so force FFFF.
|
||||
|
||||
cmp cx,(2*satlen) ! jae mlav_added
|
||||
mov cx,0ffffH
|
||||
mlav_added:
|
||||
|
||||
cmp cx,dx ! jbe mlav_ab
|
||||
xchg dx,cx
|
||||
mlav_ab: sub dx,cx ! mov cl,4 ! shr dx,cl
|
||||
add dx,ax ! mov cx,dx
|
||||
pop ax ! pop es ! ret
|
||||
|
||||
mla_makemau:
|
||||
;-----------
|
||||
; input: BX = address of ML element Root
|
||||
; AX = number of elements
|
||||
; output: BX = MAU address
|
||||
|
||||
cmp ax,1 ! jg mlam_getmd
|
||||
mov si,m_link[bx] ! mov cx,m_link[si]
|
||||
mov m_link[bx],cx ! mov bx,si
|
||||
sub cx,cx ! mov m_plist[bx],cx
|
||||
mov m_link[bx],cx
|
||||
jmp mla_initmau
|
||||
mlam_getmd:
|
||||
push ax ! push bx
|
||||
call getmd
|
||||
mov di,bx ! pop bx ! pop ax
|
||||
jcxz mlam_gotmd
|
||||
sub bx,bx ! ret
|
||||
mlam_gotmd:
|
||||
mov m_link[di],0 ! mov m_length[di],0
|
||||
mov si,m_link[bx] ! mov m_plist[di],si
|
||||
mov cx,m_start[si] ! mov m_start[di],cx
|
||||
mlam_next:
|
||||
mov cx,m_length[si] ! add m_length[di],cx
|
||||
dec ax ! cmp ax,0 ! je mlam_nomore
|
||||
mov si,m_link[si] ! jmps mlam_next
|
||||
mlam_nomore:
|
||||
push bx
|
||||
mov bx,m_link[si]
|
||||
mov m_link[si],0
|
||||
pop si ! mov m_link[si],bx
|
||||
mov bx,di ! sub cx,cx ! ;jmp mla_initmau
|
||||
|
||||
mla_initmau:
|
||||
;----------
|
||||
; input: BX = address of MAU
|
||||
; output: BX = address of MAU
|
||||
; CX = 0
|
||||
|
||||
mov dx,m_start[bx] ! mov cx,m_length[bx]
|
||||
push cx ! push es ! mov es,dx ! sub ax,ax
|
||||
mov di,ax ! mov cx,((32*satlen)/2)
|
||||
rep stos ax ! pop es
|
||||
pop cx ! mov ds,dx
|
||||
mov byte ptr .0,31
|
||||
sub cx,(2*satlen) ! add dx,(2*satlen)
|
||||
mov si,satlen ! mov sat_start[si],dx
|
||||
mov sat_length[si],cx ! mov sat_nall[si],0
|
||||
mov ds,sysdat
|
||||
sub cx,cx ! ret
|
||||
|
||||
;============
|
||||
mlfree_entry: ; Free from Mem List
|
||||
;============
|
||||
; input: DX = MAU address
|
||||
; BX = ML Root
|
||||
|
||||
mov si,dx
|
||||
cmp m_plist[si],0 ! je mlf_freeone
|
||||
mov di,si
|
||||
mov si,m_plist[si]
|
||||
mlf_nmd: cmp si,0 ! je mlf_endfree
|
||||
push m_link[si] ! push bx ! push di
|
||||
call ml_insert
|
||||
pop di ! pop bx ! pop si ! jmps mlf_nmd
|
||||
mlf_endfree:
|
||||
mov bx,di ! call freemd
|
||||
jmps mlf_exit
|
||||
mlf_freeone:
|
||||
call ml_insert
|
||||
mlf_exit:
|
||||
sub bx,bx ! mov cx,bx ! ret
|
||||
|
||||
ml_insert:
|
||||
;---------
|
||||
; input: SI = address of MD to insert
|
||||
; BX = ML Root
|
||||
|
||||
mov di,m_link[bx]
|
||||
cmp di,0 ! je mli_ins
|
||||
mov ax,m_start[di]
|
||||
cmp ax,m_start[si] ! ja mli_ins
|
||||
mov bx,di ! jmps ml_insert
|
||||
mli_ins:mov ax,m_link[bx] ! mov m_link[bx],si
|
||||
mov m_link[si],ax
|
||||
ret
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* PATCH AREA -- 128 bytes long
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
patch:
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;00-0f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;10-1f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;20-2f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;30-3f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;40-4f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;50-5f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;60-6f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
nop ! nop ! nop ! nop ! nop ! nop ;70-7f
|
||||
nop ! nop ! nop ! nop ! nop ! nop
|
||||
nop ! nop ! nop ! nop
|
||||
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Process Routines
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;====== =========================
|
||||
freepd: ; Free Process Descriptor
|
||||
;====== =========================
|
||||
; entry: SI = PD address
|
||||
|
||||
; Assumes no memory and on no list except thread.
|
||||
; Called only from TERM_ACT in the dispatcher
|
||||
|
||||
mov di,(offset thrdrt)-p_thread
|
||||
freepd_npd:
|
||||
mov bx,p_thread[di] ;find pd on thread
|
||||
cmp bx,si ! je freepd_trd
|
||||
mov di,bx ! jmps freepd_npd
|
||||
freepd_trd:
|
||||
mov ax,p_thread[si] ! mov p_thread[di],ax
|
||||
mov ax,p_flag[si] ! and ax,pf_table
|
||||
cmp ax,0 ! jz freepd_exit
|
||||
mov bx,pul ! mov p_link[si],bx
|
||||
mov pul,si
|
||||
freepd_exit:
|
||||
ret
|
||||
|
||||
;========== ================
|
||||
proc_creat: ; Create Process
|
||||
;========== ================
|
||||
; DX = pd address in u_wrkseg
|
||||
|
||||
cmp dx,0 ! jne cp_doit
|
||||
sub bx,bx ! ret
|
||||
cp_doit:
|
||||
call getpdadr ;si->pdaddr in rtm
|
||||
jcxz cp_gpd
|
||||
mov bx,0ffffh ! ret
|
||||
cp_gpd:
|
||||
mov dx,p_link[si]
|
||||
push dx ! push si
|
||||
; init uda fields
|
||||
cp_uda:
|
||||
;set Parent
|
||||
|
||||
mov bx,rlr
|
||||
mov p_parent[si],bx
|
||||
mov p_conmode[si],0 ;console mode - not inherited
|
||||
;unless RSX which aren't yet
|
||||
;implemented
|
||||
mov p_tkcnt[si],0 ;temp keep count
|
||||
and p_flag[bx],not (pf_childabort + pf_resource)
|
||||
mov al,p_lst[si]
|
||||
;cmp al,nlstdev ! jb cp_slst ;removed for network, 1/5/84 FMB
|
||||
; mov al,0 ;make sure its a legal list device
|
||||
cp_slst:
|
||||
;if mpm
|
||||
; add al,ncondev
|
||||
;endif
|
||||
mov p_lst[si],al ;list device is relative to 0 in
|
||||
;CCP/M
|
||||
|
||||
;set up p_userdisp for callf in dispatcher
|
||||
mov word ptr p_userdisp[si],offset def_emultr
|
||||
mov word ptr p_userdisp+2[si],cs
|
||||
|
||||
;share memory
|
||||
|
||||
cmp p_mem[bx],0 ! je cp_nm
|
||||
cmp p_mem[si],0 ! jne cp_nm
|
||||
lea di,p_mem[bx]
|
||||
cp_mnxt: mov di,ms_link[di]
|
||||
cmp di,0 ! je cp_nm
|
||||
push di
|
||||
push ms_start[di] ! push si ! push bx
|
||||
mov cx,f_share ! mov dx,sp
|
||||
push ds ! mov ax,ss ! mov ds,ax
|
||||
call osif ! pop ds
|
||||
pop bx ! pop si ! pop ax ! pop di
|
||||
jmps cp_mnxt
|
||||
cp_nm:
|
||||
;set physical UDA segment
|
||||
|
||||
mov ax,u_wrkseg
|
||||
mov dx,p_uda[si] ! add dx,ax
|
||||
mov p_uda[si],dx
|
||||
|
||||
;inherit password
|
||||
|
||||
push es ! push ds
|
||||
mov cx,es ! mov es,dx ! mov ds,cx
|
||||
mov si,offset u_df_password ! mov di,si
|
||||
mov cx,4 ! rep movsw
|
||||
|
||||
;set initial segment values
|
||||
|
||||
mov ds,dx ! xor dx,dx
|
||||
cmp ds:u_initcs,dx ! jne cp_uda1
|
||||
mov ds:u_initcs,ax
|
||||
cp_uda1:cmp ds:u_initds,dx ! jne cp_uda2 ;DX=0
|
||||
mov ds:u_initds,ax
|
||||
cp_uda2:cmp ds:u_initss,dx ! jne cp_uda3 ;DX=0
|
||||
mov ds:u_initss,ax
|
||||
cp_uda3:cmp ds:u_inites,dx ! jne cp_uda4 ;DX=0
|
||||
mov ds:u_inites,ax
|
||||
cp_uda4:
|
||||
|
||||
;Interrupt vector save areas:
|
||||
;Get parent's interrupt vectors 0,1,3,4,224,225
|
||||
;into child's UDA, if the
|
||||
;interrupt vector is not initialized in the
|
||||
;child's UDA.
|
||||
|
||||
mov ds,dx ;DX,DS=0,ES=child's UDA
|
||||
mov si,dx ;divide error vector, #0
|
||||
mov di,offset u_ivectors
|
||||
call cp_icopy
|
||||
call cp_icopy ;single step, #1
|
||||
add si,4 ! add di,4 ;skip NMI, #2
|
||||
call cp_icopy ;1-byte, #3
|
||||
call cp_icopy ;overflow, #4
|
||||
mov si,offset i_os_ip
|
||||
mov di,offset u_os_ip
|
||||
call cp_icopy ;O.S. entry, #224
|
||||
call cp_icopy ;debugger entry, #225
|
||||
|
||||
; set user's stack
|
||||
|
||||
push es ! pop ds
|
||||
mov ax,ds:u_initss
|
||||
mov ds:u_ss,ax
|
||||
mov ax,ds:u_stack_sp
|
||||
mov ds:u_sp,ax
|
||||
|
||||
; set other uda values
|
||||
|
||||
xor dx,dx
|
||||
mov ds:u_delim,'$' ;console mode init
|
||||
mov ds:u_error_mode,dl
|
||||
mov ds:u_pd_cnt,dl
|
||||
mov ds:u_mult_cnt,1
|
||||
mov ds:u_in_int,true
|
||||
;mov ds:u_insys,dl ;don't set insys
|
||||
mov bx,ds:u_initds
|
||||
mov ds:u_ds_sav,bx
|
||||
mov ds:u_dma_seg,bx
|
||||
mov ax,ds:u_inites
|
||||
mov ds:u_es_sav,ax
|
||||
mov ds:u_dparam,dx
|
||||
mov ds:u_flag_sav,dx
|
||||
mov ds:u_conccb,dx
|
||||
mov ds:u_lstccb,dx
|
||||
|
||||
; setup user stack for iret
|
||||
|
||||
mov ds,ds:u_ss
|
||||
mov di,u_sp ;sp->offset
|
||||
mov ax,u_initcs
|
||||
mov 2[di],ax ; ->segment
|
||||
mov word ptr 4[di],0200h ; ->flags, interrupts on
|
||||
pop ds ! pop es ; DS=SYSDAT, ES=UDA
|
||||
|
||||
; put on thread list
|
||||
|
||||
pop si ! pushf ! cli ; don't need SYNC here
|
||||
mov dx,thrdrt ; but this code cannot
|
||||
mov p_thread[si],dx ; be reentrant
|
||||
mov thrdrt,si
|
||||
|
||||
; put on dispatcher ready list
|
||||
|
||||
mov dx,drl ! mov p_link[si],dx
|
||||
mov drl,si ! popf
|
||||
|
||||
; do the next process
|
||||
|
||||
pop dx ! jmp proc_creat
|
||||
|
||||
|
||||
|
||||
cp_icopy:
|
||||
;--------
|
||||
; Entry: ES:DI = UDA ivector location to store
|
||||
; DS:SI = ivector to copy
|
||||
; DX = 0
|
||||
; Exit:
|
||||
; DI,SI = incremented by 4
|
||||
|
||||
cmp es:word ptr 0[di],dx ;DX=0, DI=UDA ivector to copy
|
||||
jne cp_nocopy ;don't copy interrupt vector
|
||||
cmp es:word ptr 2[di],dx ;if it is <> 0 in the UDA
|
||||
jne cp_nocopy
|
||||
mov cx,2 ;move two words
|
||||
rep movsw ;copy to UDA
|
||||
ret
|
||||
cp_nocopy:
|
||||
add si,4 ! add di,4
|
||||
ret
|
||||
|
||||
|
||||
getpdadr:
|
||||
;--------
|
||||
; entry: DX = PD address in U_WRKSEG
|
||||
; exit: CX = 0 successful
|
||||
; SI = PD address in SYSDAT if success
|
||||
; CX =
|
||||
; Make sure PD address is in SYSDAT. If not, copy into
|
||||
; one in PD table. Make address relative to SYSDAT
|
||||
|
||||
push dx ;save PD in U_WRKSEG
|
||||
mov bx,pdlen
|
||||
call sysdat_chk
|
||||
jcxz gpd_bad
|
||||
mov ax,u_wrkseg ;PD is within SYSDAT
|
||||
mov bx,ds
|
||||
sub ax,bx ;U_WRKSEG-SYSDAT
|
||||
mov cl,4 ! shl ax,cl ;make into bytes
|
||||
pop si ;SI relative to U_WRKSEG
|
||||
add si,ax ;SI->PD relative to SYSDAT
|
||||
jmps gpd_done
|
||||
|
||||
gpd_bad:
|
||||
pop si ;U_WRKSEG:SI->PD to copy
|
||||
pushf ! cli ;turn off interrupts while
|
||||
mov di,pul ;changing the PUL
|
||||
test di,di
|
||||
jnz gpd_have
|
||||
mov cx,e_no_pd ;no free PDs left
|
||||
popf ! ret
|
||||
gpd_have: ;DI->PD in SYSDAT
|
||||
mov ax,p_link[di]
|
||||
mov pul,ax ;update PUL
|
||||
popf ;allow interrupts
|
||||
push di ;save address of PD in SYSDAT
|
||||
push es ;save UDA
|
||||
push ds ;SYSDAT
|
||||
mov ds,u_wrkseg ;DS=U_WRKSEG
|
||||
pop es ;ES=SYSDAT
|
||||
mov cx,pdlen/2
|
||||
rep movsw ;copy PD into SYSDAT PD
|
||||
push es ! pop ds ;DS=SYSDAT
|
||||
pop es ;ES=UDA
|
||||
pop si ;SI=PD in SYSDAT
|
||||
or p_flag[si],pf_table ;got it from PD table
|
||||
|
||||
gpd_done:
|
||||
xor cx,cx
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,456 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Queue Routines
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
; Each queue system entry point is mutually exclusive
|
||||
; of the other queue system entry points.
|
||||
; All the routines called in QUE2.RTM are
|
||||
; subroutines of the entry points in QUE1.RTM and
|
||||
; thus are called only when the process has ownership
|
||||
; of the q system.
|
||||
|
||||
; If a process is already in the queue system another process
|
||||
; will wait until the first process calls Q_UNSYNC.
|
||||
; This allows us to keep interrupts on while using shared variables.
|
||||
|
||||
; To protect against terminating and potentially losing a QD,
|
||||
; a message or neglecting to wake up a DQing or NQing
|
||||
; process; a "no abort region" is entered whenever
|
||||
; we obtain the queue system. In addition if we assign
|
||||
; the queue system to a DQing or NQing process, the new owner
|
||||
; of the q system is forced into a "no abort region". This
|
||||
; makes the environment of the waking NQing or DQing process appear
|
||||
; as if it never went to sleep.
|
||||
|
||||
; A note for the uninitiated: DQing is short for "Decoding from a Queue"
|
||||
; or reading from a queue. NQing is short for "eNcoding to a Queue"
|
||||
; or writing to a queue.
|
||||
|
||||
|
||||
;=========== =======================
|
||||
makeq_entry: ; Create a System Queue
|
||||
;=========== =======================
|
||||
; input : U_WRKSEG:DX = address of QD to create
|
||||
; output: BX = 0 if okay , 0ffffh if error
|
||||
; CX = error Code
|
||||
|
||||
call q_sync ;obtain q system, BX,DX preserved
|
||||
|
||||
call getqdaddr ;get QD and q buffer
|
||||
jcxz qm_gotqd
|
||||
jmp qm_err
|
||||
qm_gotqd: ;DI->QD in SYSDAT
|
||||
;make sure this queue doesn't
|
||||
;already exist
|
||||
qm_chk:
|
||||
push es ;save UDA
|
||||
mov es,sysdat
|
||||
mov si,(offset qlr)-q_link
|
||||
qm_nxt:
|
||||
mov si,q_link[si] ;go down QLR to see if QD already
|
||||
test si,si ! jz qm_go ;exists
|
||||
push di ! push si ;save new QD and QLR ptr
|
||||
mov cx,qnamsiz/2
|
||||
add di,q_name ;ES:DI->QPB.NAME
|
||||
add si,q_name ;DS:SI->QPB.NAME
|
||||
repe cmpsw
|
||||
pop si ! pop di ;restore QLR ptr and new QD
|
||||
jne qm_nxt ;no match try next QD
|
||||
|
||||
pop es ;names match, restore UDA
|
||||
call remqd ;QD pointed to by DS:DI
|
||||
mov cx,e_q_inuse
|
||||
jmps qm_err
|
||||
|
||||
qm_go: ;no match - alright to make this q
|
||||
pop es ;ES=UDA
|
||||
xor dx,dx ;initialize the QD
|
||||
mov q_dq[di],dx
|
||||
mov q_nq[di],dx
|
||||
mov q_msgcnt[di],dx
|
||||
mov q_msgout[di],dx
|
||||
mov ax,qlr ;put QD on QLR
|
||||
mov q_link[di],ax
|
||||
mov qlr,di
|
||||
xor bx,bx ;return success
|
||||
jmps qm_ret
|
||||
qm_err:
|
||||
mov bx,0ffffh
|
||||
qm_ret:
|
||||
jmp q_unsync ;release q system; BX,CX preserved
|
||||
|
||||
;=========== ======================
|
||||
openq_entry: ; Find an active Queue
|
||||
;=========== ======================
|
||||
; input: U_WRKSEG:DX = address of QPB
|
||||
;
|
||||
; output: sets QPB.QADDR to QD offset in SYSDAT
|
||||
; BX = 0 if okay, 0ffffh if not
|
||||
; CX = error Code
|
||||
|
||||
call q_sync ;obtain q system; BX,DX preserved
|
||||
push es ;save UDA
|
||||
mov es,u_wrkseg
|
||||
mov si,(offset qlr)-q_link
|
||||
mov di,dx ;ES:DI->QPB
|
||||
qo_nqd:
|
||||
mov si,q_link[si] ;go down QLR until QD name
|
||||
test si,si ! jnz qo_cmp ;matches QPB name or end of QLR
|
||||
pop es ;ES=UDA
|
||||
mov cx,e_no_queue ;found end of QLR - can't open
|
||||
jmps qo_err
|
||||
qo_cmp:
|
||||
push di ! push si ;compare names
|
||||
mov cx,qnamsiz/2
|
||||
add si,q_name ;DS:SI->QD.NAME
|
||||
add di,qpb_name ;ES:DI->QPB.NAME
|
||||
repe cmpsw
|
||||
pop si ! pop di ;restore QD,QPB
|
||||
jne qo_nqd ;try next QD if no match
|
||||
|
||||
test q_flags[si],qf_hide ;names match
|
||||
jz noprot ;check for protection:
|
||||
mov bx,rlr ;must be system process to
|
||||
test p_flag[bx],pf_sys ;open q with QF_HIDE set
|
||||
jnz noprot
|
||||
pop es ;ES=UDA
|
||||
mov cx,e_q_protected ;QF_HIDE and not SYS PD
|
||||
jmps qo_err
|
||||
noprot:
|
||||
mov es:qpb_qaddr[di],si ;write the QD offset into
|
||||
pop es ;ES=UDA
|
||||
xor bx,bx ;the QPB_QADDR field
|
||||
jmps qo_ret ;to open the q
|
||||
|
||||
qo_err: ;CX=error code
|
||||
mov bx,0ffffh
|
||||
qo_ret:
|
||||
call q_unsync ;release q system; BX,CX preserved
|
||||
ret
|
||||
|
||||
|
||||
;============= =======================
|
||||
deleteq_entry: ; Delete a System Queue
|
||||
;============= =======================
|
||||
; Takes QD off the QLR and place it in the QUL
|
||||
; input: U_WRKSEG:DX = offset of QPB
|
||||
; output: BX = 0 if ok, 0ffffh if error
|
||||
; CX = error code
|
||||
|
||||
mov ax,es ;save UDA
|
||||
mov es,u_wrkseg ;get QD address from user's
|
||||
mov di,dx ;QPB
|
||||
mov di,es:qpb_qaddr[di] ;DS:DI->QD (unverified)
|
||||
mov es,ax ;ES=UDA
|
||||
|
||||
;Check for KEEP, SYS Flags
|
||||
;DS:DI->QD
|
||||
test q_flags[di],qf_keep
|
||||
jnz qd_err1
|
||||
test q_flags[di],qf_hide
|
||||
jz qd_ok1
|
||||
mov bx,rlr ;if hide flag then
|
||||
test p_flag[bx],pf_sys ;SYS flag must be on in PD
|
||||
jnz qd_ok1
|
||||
|
||||
qd_err1: mov cx,e_q_protected
|
||||
mov bx,0ffffh
|
||||
ret
|
||||
qd_ok1:
|
||||
push di ;DI->QD
|
||||
call q_sync ;obtain q system; BX,DX preserved
|
||||
pop di
|
||||
mov ax,q_dq[di] ;if any process is NQing or
|
||||
mov dx,q_nq[di] ;DQing we can't delete
|
||||
or dx,ax ! mov cx,e_q_inuse
|
||||
jnz qd_err2
|
||||
|
||||
mov bx,(offset qlr)-q_link
|
||||
qd_nqd: ;look for QD on QLR
|
||||
mov si,q_link[bx] ;DI=QD to delete
|
||||
test si,si ! jz qd_noq
|
||||
cmp si,di ! je qd_found
|
||||
mov bx,si ! jmps qd_nqd ;try next queue
|
||||
qd_found:
|
||||
mov ax,q_link[di] ;found the queue, remove
|
||||
mov q_link[bx],ax ;it from QLR
|
||||
call remqd
|
||||
xor bx,bx ;return success
|
||||
jmps qd_ret
|
||||
|
||||
qd_noq:
|
||||
mov cx,e_no_queue
|
||||
qd_err2:
|
||||
mov bx,0ffffh
|
||||
qd_ret:
|
||||
jmp q_unsync ;release q system
|
||||
;ret ;BX,CX preserved
|
||||
|
||||
;=========== ============
|
||||
readq_entry: ; Read Queue
|
||||
;=========== ============
|
||||
xor al,al ! jmps readq
|
||||
|
||||
;============
|
||||
creadq_entry: ; Conditional Read Queue
|
||||
;============
|
||||
mov al,0ffh
|
||||
; jmps readq
|
||||
|
||||
readq: ; Read message from queue
|
||||
;----- -------------------------
|
||||
; If no buffer is available the process
|
||||
; making an unconditional READQ is placed into the DQ list.
|
||||
;
|
||||
; input: U_WRKSEG:DX = QPB
|
||||
; AL = 0 if unconditional
|
||||
; <> 0 if not
|
||||
; output: BX = 0 if okay
|
||||
; 0ffffh if error
|
||||
; CX = Error Code
|
||||
|
||||
push ax ;save cond code
|
||||
call q_sync ;get q system; BX,DX preserved
|
||||
call queverify ;is the QPB valid ?
|
||||
pop ax ;AL=cond code
|
||||
mov si,dx ;U_WRKSEG:SI->QPB
|
||||
jcxz qr_ver ;CX=0 QPB is ok
|
||||
jmp qr_err ;CX=error code from
|
||||
qr_ver: ;queverify
|
||||
push es ;save UDA
|
||||
mov es,u_wrkseg ;ES:SI->QPB
|
||||
mov bx,es:qpb_qaddr[si] ;BX->QD
|
||||
cmp q_msgcnt[bx],0 ;is there a msg to read ?
|
||||
jne qr_readit
|
||||
|
||||
qr_wait:
|
||||
pop es ;ES=UDA
|
||||
test al,al ! jz qr_wait1 ;conditional read if AL <> 0
|
||||
mov cx,e_q_empty
|
||||
jmps qr_err
|
||||
qr_wait1: ;ES=UDA
|
||||
push bx ! push si ;QD, QPB
|
||||
lea dx,q_dq[bx] ;DX=addr of DQ List
|
||||
mov bl,ps_dq ;sleep status=DQ
|
||||
call q_wait ;wait for a DQ
|
||||
;we now own the q system
|
||||
;and cannot be aborted
|
||||
pop si ! pop bx ;QPB, QD
|
||||
push es ;save UDA
|
||||
mov es,u_wrkseg
|
||||
qr_readit:
|
||||
mov di,es:qpb_buffptr[si] ;ES:[DI]->user's queue buffer
|
||||
mov cx,q_msglen[bx] ;ES=U_WRKSEG
|
||||
test cx,cx ! jnz qr_lmsg ;check message length
|
||||
xor ax,ax
|
||||
test q_flags[bx],qf_mx ;msglen=0, check for MX q
|
||||
jz qr_end
|
||||
mov ax,rlr ;its a MX queue
|
||||
mov q_buf[bx],ax ;BUF = PD addr of owner
|
||||
xor ax,ax
|
||||
jmps qr_end
|
||||
qr_lmsg: ;msglen > 0
|
||||
mov ax,q_msgout[bx] ! push ax ;MSGOUT is # of message to read
|
||||
mul cx ! add ax,q_buf[bx] ;compute its start in buffer
|
||||
mov si,ax
|
||||
rep movsb ;move to QPB buffer
|
||||
pop ax ! inc ax ;set MSGOUT to next message
|
||||
cmp ax,q_nmsgs[bx] ;circular buffers, so
|
||||
jne qr_end ;check for wrap around
|
||||
xor ax,ax
|
||||
qr_end:
|
||||
pop es ;ES=UDA
|
||||
mov q_msgout[bx],ax
|
||||
dec q_msgcnt[bx]
|
||||
lea dx,q_nq[bx]
|
||||
call q_assign_sync ;give the queue system to
|
||||
;first NQing process if any,
|
||||
call q_unsync ;release q system if we still
|
||||
;own it, exit no abort region
|
||||
xor bx,bx ;indicate success
|
||||
ret
|
||||
|
||||
qr_err:
|
||||
call q_unsync ;release q system, exit no abort
|
||||
;region, BX,CX preserved
|
||||
mov bx,0ffffh ;indicate error
|
||||
ret
|
||||
|
||||
;============ =============
|
||||
writeq_entry: ; Write Queue
|
||||
;============ =============
|
||||
xor al,al ! jmps writeq
|
||||
|
||||
;============= =========================
|
||||
cwriteq_entry: ; conditional Write Queue
|
||||
;============= =========================
|
||||
mov al,0ffh
|
||||
;jmps writeq
|
||||
|
||||
writeq: ; Write message to queue
|
||||
;------ ------------------------
|
||||
; If no buffer is available when making an unconditional
|
||||
; WRITEQ call, the calling process is placed into the NQ list.
|
||||
;
|
||||
; input: U_WRKSEG:DX = QPB
|
||||
; AL = 0 if unconditional
|
||||
; <> 0 if not
|
||||
; output: BX = 0 if okay
|
||||
; 0ffffh if error
|
||||
; CX = Error Code
|
||||
|
||||
push ax ;save cond code
|
||||
call q_sync ;get queue system
|
||||
;BX,DX preserved
|
||||
call queverify ;is the QPB valid ?
|
||||
pop ax ;AL = cond code
|
||||
mov di,dx ;U_WRKSEG:DI->QPB
|
||||
jcxz qw_ver ;CX=0 QPB is ok
|
||||
jmp qw_err ;CX=error code from
|
||||
qw_ver: ;queverify
|
||||
push es ;save UDA
|
||||
mov es,u_wrkseg ;ES:DI->QPB
|
||||
mov bx,es:qpb_qaddr[di] ;BX->QD
|
||||
mov cx,q_msgcnt[bx]
|
||||
cmp cx,q_nmsgs[bx] ;is there a buffer to write ?
|
||||
jne qw_writeit
|
||||
|
||||
qw_wait:
|
||||
pop es ;ES=UDA
|
||||
test al,al ! jz qw_wait1 ;conditional read if AL <> 0
|
||||
mov cx,e_q_full
|
||||
jmps qw_err
|
||||
qw_wait1: ;ES=UDA
|
||||
push bx ! push di ;save QD, QPB
|
||||
lea dx,q_nq[bx] ;DX=addr of NQ List
|
||||
mov bl,ps_nq ;sleep status=NQ
|
||||
call q_wait ;sleep on NQ List
|
||||
;q system is assigned to us,
|
||||
;we are in no abort region
|
||||
;by DQing process that woke us
|
||||
pop di ! pop bx ;QPB,QD
|
||||
push es ;save UDA
|
||||
mov es,u_wrkseg
|
||||
qw_writeit:
|
||||
mov si,es:qpb_buffptr[di] ;U_WRKSEG:[SI]->user's queue buffer
|
||||
mov cx,q_msglen[bx] ;ES=U_WRKSEG
|
||||
test cx,cx ! jnz qw_lmsg ;check message length
|
||||
test q_flags[bx],qf_mx ;msglen=0, check for MX q
|
||||
jz qw_end
|
||||
xor ax,ax
|
||||
mov q_buf[bx],ax ;its a MX queue
|
||||
jmps qw_end ;BUF = 0
|
||||
|
||||
qw_lmsg: ;msglen > 0
|
||||
mov ax,q_msgout[bx]
|
||||
add ax,q_msgcnt[bx] ;AX = # of message to write
|
||||
cmp ax,q_nmsgs[bx] ;check for wrap around
|
||||
jb qw_move
|
||||
sub ax,q_nmsgs[bx]
|
||||
qw_move:
|
||||
mul cx ! add ax,q_buf[bx] ;compute its start in buffer
|
||||
mov di,ax ;DI offset of new msg in buffer
|
||||
mov ax,ds ! mov dx,es
|
||||
mov es,ax ! mov ds,dx ;ES=SYSDAT, DS=U_WRKSEG
|
||||
rep movsb ;move to QPB buffer
|
||||
mov ax,es ! mov ds,ax ;DS=SYSDAT
|
||||
qw_end:
|
||||
pop es ;ES=UDA
|
||||
inc q_msgcnt[bx] ;one more message in the queue
|
||||
lea dx,q_dq[bx] ;wake DQing process if any
|
||||
call q_assign_sync
|
||||
call q_unsync ;release q system if we still
|
||||
xor bx,bx ;own it, exit no abort region
|
||||
ret ;BX=0: success
|
||||
|
||||
qw_err:
|
||||
call q_unsync ;release q system; exit no abort
|
||||
;region BX,CX preserved
|
||||
mov bx,0ffffh ;indicate error
|
||||
ret
|
||||
|
||||
|
||||
q_wait: ;wait on DQ or NQ list
|
||||
;------
|
||||
; entry: DX = list to wait on
|
||||
; BL = sleep status
|
||||
; calling process owns queue system through
|
||||
; a call to q_sync
|
||||
|
||||
; Queue message or buffer space is not available.
|
||||
; Give up queue system and sleep on DQ or NQ list, but
|
||||
; do not allow any other process to read or write to a queue
|
||||
; until we get on the sleep list.
|
||||
|
||||
|
||||
pushf ! cli ;keep abort spec from running ...
|
||||
push bx ! push dx ;save sleep status, list address
|
||||
call q_unsync ;does not go to dispatcher, we can be
|
||||
pop dx ! pop bx ;aborted once on sleep list
|
||||
call sleep_entry ;go to dispatcher
|
||||
popf ;come back after q_assign call
|
||||
ret ;Q_ASSIGN: wakes us up when resource
|
||||
;is ready
|
||||
|
||||
q_sync: ;obtain ownership of q system
|
||||
;------
|
||||
; entry: interrupts should be on
|
||||
; ES=UDA
|
||||
; exit: we own the queue system for make,open,read,write,delete
|
||||
; queue operations, interrupts unchanged
|
||||
; BX,DX preserved - usually entry parameters
|
||||
|
||||
push bx ! push dx
|
||||
call no_abort_entry ;we cannot abort while in the queue system
|
||||
mov bx,offset q_spb
|
||||
call sync_entry
|
||||
pop dx ! pop bx
|
||||
ret
|
||||
|
||||
q_unsync: ;release the queue system
|
||||
;-------- ;to other processes
|
||||
; entry: interrupts can be or off
|
||||
; exit: interrupts unchanged,
|
||||
; have not gone to dispatcher,
|
||||
; BX,CX preserved - usually return codes
|
||||
|
||||
push bx ! push cx
|
||||
mov bx,offset q_spb
|
||||
call unsync_entry ;wait for queue system
|
||||
call ok_abort_entry ;allow calling PD to be terminated
|
||||
pop cx ! pop bx
|
||||
ret
|
||||
|
||||
q_assign_sync:
|
||||
;-------------
|
||||
; entry: DX = address of DQ or NQ list to give the queue
|
||||
; exit: none
|
||||
|
||||
; Assign is used so a process is forced to read or write
|
||||
; after DQing or NQing. Otherwise an awakening DQing or NQing
|
||||
; process could be deleted, leaving a message or buffer space
|
||||
; available with other processes still DQing or NQing.
|
||||
; This message or buffer space would never be reclaimed.
|
||||
; To prevent this situation, the waking DQing or NQing process
|
||||
; is kept from aborting and assigned the QSPB. Note
|
||||
; it is ok for a process to be aborted while it is on the NQ or
|
||||
; DQ list before this routine is called.
|
||||
|
||||
pushf ! cli ;keep abort spec from terminating
|
||||
mov bx,dx ;waking process
|
||||
mov dx,[bx] ;first process on list
|
||||
test dx,dx ;is there a process to wake?
|
||||
jz qa_ret
|
||||
push bx ;save list root
|
||||
call no_abort_spec_entry ;can not abort while in queue
|
||||
pop dx ;system
|
||||
popf ;interrupts are ok now -
|
||||
mov bx,offset q_spb ;present owner and next owner
|
||||
jmp assign_sync_entry ;have TEMPKEEP on
|
||||
|
||||
qa_ret:
|
||||
popf
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
;****************************************************************
|
||||
;* *
|
||||
;* Queue system subroutines: Q System must be owned *
|
||||
;* before calling any of the following routines *
|
||||
;* *
|
||||
;****************************************************************
|
||||
|
||||
queverify: ; check QLR for existence of QD address
|
||||
;--------- ---------------------------------------
|
||||
; entry: U_WRKSEG:DX = offset of QPB
|
||||
; exit: CX = 0 if queue is found
|
||||
; CX = E_NO_QUEUE error code, if not
|
||||
; BX=SI=QD offset
|
||||
; ES,DX preserved
|
||||
|
||||
push es ;save UDA
|
||||
mov es,u_wrkseg
|
||||
mov bx,dx ;ES:BX->QPB
|
||||
mov bx,es:qpb_qaddr[bx] ;get QD from user's QPB
|
||||
pop es ;restore UDA
|
||||
lea si,qlr-q_link
|
||||
qv_nxt:
|
||||
mov si,q_link[si] ;SI addresses of valid QDs
|
||||
test si,si ! jz qv_nqf
|
||||
cmp bx,si ! jne qv_nxt
|
||||
xor cx,cx ! ret ;BX=SI=QD offset, return success
|
||||
qv_nqf:
|
||||
mov cx,e_no_queue ;couldn't find the queue
|
||||
ret
|
||||
|
||||
getqdaddr:
|
||||
;----------
|
||||
; entry: DX = offset of QD in U_WRKSEG
|
||||
; exit: DI = offset of QD in SYSDAT
|
||||
;
|
||||
; If QD address is within SYSDAT use it.
|
||||
; Else get a QD from QDUL and set QF_TABLE flag.
|
||||
; If Q_NMSGS=0 in QD then return error.
|
||||
; If 0 length buffer needed, zero the Q_BUF field.
|
||||
; If buffer space is within SYSDAT use it. Else get buffer
|
||||
; from QMAU. Return the QD address within SYSDAT.
|
||||
|
||||
push dx ;save QD offset
|
||||
mov bx,qdlen
|
||||
call sysdat_chk
|
||||
jcxz g_qul ;CX=0 if not within SYSDAT
|
||||
mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG
|
||||
mov bx,ds
|
||||
sub ax,bx ;from SYSDAT
|
||||
mov cl,4 ! shl ax,cl ;make into # of bytes
|
||||
pop di ;DI=QD in U_WRKSEG
|
||||
add di,ax ;make QD relative to SYSDAT
|
||||
jmps g_qd
|
||||
g_qul:
|
||||
mov di,qul ;get QD from QUL
|
||||
test di,di ;DI=unused QD
|
||||
jnz g_gotqd
|
||||
pop dx
|
||||
mov cx,e_no_qd ;no QD available
|
||||
ret
|
||||
g_gotqd:
|
||||
mov ax,q_link[di]
|
||||
mov qul,ax
|
||||
pop si ;SI=QD in U_WRKSEG
|
||||
push di ;save SYSDAT QD
|
||||
mov cx,qdlen/2
|
||||
; ES=UDA, DS=SYSDAT
|
||||
mov ax,ds
|
||||
mov ds,u_wrkseg ; DS:SI = QD in U_WRKSEG
|
||||
push es ! mov es,ax ; ES:DI = QD in SYSDAT
|
||||
rep movsw ; copy QD into QD in SYSDAT
|
||||
mov ax,es ! mov ds,ax
|
||||
pop es ; ES=UDA, DS=SYSDAT
|
||||
pop di ; SYSDAT:DI -> New QD
|
||||
or q_flags[di],qf_table ; Set "from table" flag
|
||||
|
||||
g_qd: ;DI=QD in SYSDAT
|
||||
xor cx,cx ;CX=0
|
||||
cmp q_nmsgs[di],cx ;must have one or more msgs
|
||||
jne g_buflen ;or illegal queue
|
||||
mov cx,e_no_qbuf
|
||||
jmps g_qdfree
|
||||
g_buflen: ;if MX or buffer length is zero
|
||||
test q_flags[di],qf_mx ;0 Q_BUF field and return
|
||||
jnz g_mx ;CX=0 to indicate success
|
||||
cmp q_msglen[di],cx
|
||||
jne g_getbuf
|
||||
g_mx:
|
||||
mov q_buf[di],cx
|
||||
ret
|
||||
g_getbuf: ;non 0 length buffer needed
|
||||
cmp q_buf[di],0 ;is there a buffer specified?
|
||||
je g_buf
|
||||
mov ax,q_msglen[di] ;yes make sure it fits in SYSDAT
|
||||
mul q_nmsgs[di] ;AX=needed buffer space
|
||||
mov bx,ax
|
||||
mov dx,q_buf[di]
|
||||
call sysdat_chk
|
||||
jcxz g_buf ;CX=0 not within SYSDAT
|
||||
mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG
|
||||
mov bx,ds
|
||||
sub ax,bx ;from SYSDAT
|
||||
mov cl,4 ! shl ax,cl ;make into # of bytes
|
||||
add q_buf[di],ax ;make buffer relative to SYSDAT
|
||||
xor cx,cx ;indicate success
|
||||
ret
|
||||
|
||||
g_buf: ;allocate buffer space to queue
|
||||
call qspace
|
||||
jcxz g_ret
|
||||
mov cx,e_no_qbuf ;no buffer space
|
||||
g_qdfree:
|
||||
mov ax,qul ;error return QD to QUL
|
||||
mov q_link[di],ax
|
||||
mov qul,di ;CX = error code
|
||||
g_ret:
|
||||
ret
|
||||
|
||||
|
||||
sysdat_chk:
|
||||
;----------
|
||||
; entry: DX = offset of data structure to check
|
||||
; relative to U_WRKSEG
|
||||
; BX = length of data structure
|
||||
; exit: CX <> 0 if within SYSDAT
|
||||
; or wrap around
|
||||
; CX = 0 if not within SYSDAT
|
||||
; SI,DI preserved
|
||||
|
||||
; Check data structure for being within SYSDAT
|
||||
; Also check that data structure doesn't wrap
|
||||
; around at 64K, or 1 megabyte.
|
||||
|
||||
add dx,bx ;find end of data structure
|
||||
jc sc_no ;check for 64K wrap around
|
||||
add dx,0fh
|
||||
mov cl,4 ;round up to next paragraph
|
||||
shr dx,cl ;1st paragraph after struct relative
|
||||
add dx,u_wrkseg ;to U_WRKSEG
|
||||
jc sc_no ;next paragraph after struct
|
||||
;check for 1 MB wrap around
|
||||
mov ax,sysdat
|
||||
cmp dx,ax ;check for below SYSDAT
|
||||
jb sc_no
|
||||
add ax,1000h ;check for above SYSDAT
|
||||
cmp ax,endseg ;must be within 64k and ENDSEG
|
||||
jb sc_end ;(use the smaller of the 2)
|
||||
mov ax,endseg
|
||||
sc_end:
|
||||
cmp dx,ax ;DX=next paragraph,
|
||||
ja sc_no
|
||||
mov cl,1 ;indicate within SYSDAT
|
||||
ret
|
||||
sc_no:
|
||||
xor cx,cx
|
||||
ret
|
||||
|
||||
qspace:
|
||||
;------
|
||||
; entry: DI = QD address
|
||||
; exit: CX = 0 if ok else error code
|
||||
; DI preserved
|
||||
; Allocate buffer space for QD
|
||||
; The QMAU describes the Memory Allocation Unit
|
||||
; for the queues. QMAU is set up by GENCCPM or GENSYS.
|
||||
|
||||
mov ax,q_msglen[di] ;compute size of buffer
|
||||
mul q_nmsgs[di] ;AX=size of request
|
||||
xor cx,cx
|
||||
push cx ! push cx ! push ax ;call MALLOC
|
||||
push ax ! push cx ;with MPB on stack
|
||||
mov dx,sp ! mov ax,ss
|
||||
mov ds,ax
|
||||
mov bx,offset qmau
|
||||
push di ;save QD
|
||||
mov cx,f_maualloc ;go through OSIF to
|
||||
call osif ;get U_WRKSEG=SS
|
||||
pop di ;DI=QD
|
||||
mov ds,sysdat
|
||||
cmp cx,0 ! jne qspace_ret
|
||||
mov bp,sp
|
||||
mov ax,mpb_start[bp]
|
||||
mov q_buf[di],ax ;address of buffer
|
||||
|
||||
qspace_ret:
|
||||
add sp,10 ;pop MPB from stack
|
||||
ret
|
||||
|
||||
remqd:
|
||||
;-----
|
||||
; Place QD on queue unused list
|
||||
; entry: DS:DI = QD address
|
||||
; exit: none
|
||||
|
||||
mov ax,q_flags[di]
|
||||
and ax,qf_table ! jz rqd_exit
|
||||
mov ax,qul ! mov q_link[di],ax
|
||||
mov qul,di
|
||||
jmps qrelease
|
||||
rqd_exit:
|
||||
ret
|
||||
|
||||
|
||||
qrelease:
|
||||
;--------
|
||||
; entry: DI = QD address
|
||||
; exit : none
|
||||
;
|
||||
; Release buffer space for QD.
|
||||
; If the released space is ajacent to another
|
||||
; free area, they are joined in the SAT table.
|
||||
; The QMAU describes the Memory Allocation Unit
|
||||
; for the queues. QMAU is set up by GENCCPM or GENSYS.
|
||||
|
||||
|
||||
mov ax,q_buf[di]
|
||||
mov cx,offset qmau
|
||||
push ax ! push ax ! push cx ;MFPB on stack
|
||||
mov cx,f_maufree
|
||||
mov dx,sp ! mov ax,ss ! mov ds,ax
|
||||
call osif
|
||||
add sp,6 ;pop MFPB from stack
|
||||
mov ds,cs:sysdat ;DS=SYSDAT
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
;**********************************************************
|
||||
;*
|
||||
;* Call Resident System Procedure
|
||||
;*
|
||||
;**********************************************************
|
||||
|
||||
cpb_name equ word ptr 0
|
||||
cpb_param equ word ptr cpb_name + qnamsiz
|
||||
|
||||
;=======
|
||||
rpl_ent: ; Call Resident Procedure Library
|
||||
;=======
|
||||
; input: DX = CPB address in u_wrkseg
|
||||
; output: BX = return from RPL (also u_retseg)
|
||||
; 1 if error
|
||||
; CX = error code
|
||||
;
|
||||
; The stack is used like this:
|
||||
;
|
||||
; stack bottom ------------------------- higher memory
|
||||
; 26 | starting DS (sysdat)|
|
||||
; 24 | starting ES (uda) |
|
||||
; 22 | seg of rpl_ret: |
|
||||
; 20 | offset of rpl_ret: |
|
||||
; 18 | seg of the RPL |
|
||||
; 16 | offset or RPL |<-------
|
||||
; 14 | Q /\ | |
|
||||
; 12 | P || | |
|
||||
; 10 | | || | |
|
||||
; 8 | B qname | |
|
||||
; 6 | L buffptr |------>|
|
||||
; 4 | O nmsgs |
|
||||
; 2 | C qaddr |
|
||||
; 0 | K flgs & net |<------SP
|
||||
; stack top ------------------------- lower memory
|
||||
|
||||
|
||||
push ds ! push es
|
||||
mov ds,u_wrkseg ; save ds
|
||||
mov si,dx
|
||||
push cs ; rpl_ret segment
|
||||
mov ax,offset rpl_ret ! push ax ; rpl_ret offset
|
||||
sub ax,ax ! push ax ! push ax ; QPB buffer
|
||||
mov di,sp ; DI -> buffer
|
||||
push (cpb_name+6)[si] ; qpb_name
|
||||
push (cpb_name+4)[si]
|
||||
push (cpb_name+2)[si]
|
||||
push cpb_name[si]
|
||||
mov si,cpb_param[si] ; SI=param
|
||||
push di ; qpb_buffer address
|
||||
inc ax ! push ax ; qpb_nmsgs
|
||||
dec ax ! push ax ! push ax ; qpb_addr,flg,net
|
||||
mov dx,sp ! mov di,dx
|
||||
mov ax,ss ! mov ds,ax
|
||||
mov cx,f_qopen
|
||||
push si ! push di ! call osif
|
||||
pop di ! pop si
|
||||
cmp cx,0 ! jne rpl_err
|
||||
mov bx,qpb_qaddr[di]
|
||||
push ds ! mov ds,sysdat
|
||||
test q_flags[bx],qf_rpl ! pop ds
|
||||
jz rpl_err
|
||||
mov cx,f_qread ! mov dx,di
|
||||
push si ! call osif ! pop si
|
||||
cmp cx,0 ! jne rpl_err
|
||||
add sp,16
|
||||
mov dx,si
|
||||
mov ds,u_wrkseg
|
||||
mov es,u_retseg
|
||||
retf
|
||||
rpl_ret: mov ax,es
|
||||
pop es ! pop ds
|
||||
mov u_retseg,ax
|
||||
ret
|
||||
rpl_err:
|
||||
add sp,24
|
||||
pop es ! pop ds
|
||||
mov bx,1 ! mov cx,e_no_queue
|
||||
ret
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
include cpyright.def
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* RTM - MP/M-86 or CCP/M Real Time Monitor
|
||||
;*
|
||||
;*****************************************************
|
||||
eject ! include system.def
|
||||
eject ! include modfunc.def
|
||||
eject ! include modtab.def
|
||||
eject ! include xioscb.def
|
||||
eject ! include flg.def
|
||||
eject ! include mem.def
|
||||
eject ! include mpb.def
|
||||
eject ! include pd.def
|
||||
eject ! include err.def
|
||||
eject ! include qd.def
|
||||
eject ! include sync.def
|
||||
eject ! include cmdh.def
|
||||
eject ! include apb.def
|
||||
eject ! include vccb.def
|
||||
eject ! include uda.def
|
||||
eject ! include s8087.lib
|
||||
eject ! include rtmif.rtm
|
||||
eject ! include sysent.rtm
|
||||
eject ! include proc.rtm
|
||||
eject ! include dsptch.rtm
|
||||
eject ! include flag.rtm
|
||||
eject ! include que1.rtm
|
||||
eject ! include que2.rtm
|
||||
eject ! include findpd.rtm
|
||||
eject ! include abort.rtm
|
||||
eject ! include patch.cod
|
||||
eject ! include vec.fmt
|
||||
eject ! include uda.fmt
|
||||
eject ! include sysdat.dat
|
||||
eject ! include data.bdo
|
||||
eject ! include xiosdat.fmt ;SUP 5 - DH - 14APR82
|
||||
eject ! end
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Concurrent CP/M-86 RTM Interface Routines
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
cseg
|
||||
org 0
|
||||
|
||||
jmp init ;RTM initialization
|
||||
jmp entry ;RTM entry point
|
||||
|
||||
sysdat dw 0 ;SYSDAT segment
|
||||
supervisor equ offset $
|
||||
rw 2 ;SUP entry point
|
||||
|
||||
org 0ch
|
||||
dev_ver db 6 ;development system data version
|
||||
;set in sysdat.fmt
|
||||
|
||||
db 'COPYRIGHT (C) 1982,1983,1984'
|
||||
db ' DIGITAL RESEARCH '
|
||||
db 'XXXX-0000-'
|
||||
serial db '654321'
|
||||
|
||||
;==== ===========================
|
||||
init: ; RTM module Initialization
|
||||
;==== ===========================
|
||||
|
||||
mov bx,(offset dispatcher) ;init interrupt pdisp
|
||||
mov word ptr [bx],offset fdisp
|
||||
mov word ptr 2[bx],cs
|
||||
mov bx,(offset rtm_pdisp) ;init intermodule pdisp
|
||||
mov word ptr [bx],offset farpdisp
|
||||
mov word ptr 2[bx],cs
|
||||
|
||||
mov bx,rlr ;init the init process's userdisp vec
|
||||
mov word ptr p_userdisp[bx],offset def_emultr
|
||||
mov word ptr p_userdisp + 2[bx],cs
|
||||
|
||||
retf
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* RTM Function Table
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
org ((offset $)+1) AND 0fffeh ;Word Boundary
|
||||
|
||||
function dw sysreset_entry ;0
|
||||
dw poll_entry ;1
|
||||
dw flag_wait_entry ;2
|
||||
dw flag_set_entry ;3
|
||||
dw makeq_entry ;4
|
||||
dw openq_entry ;5
|
||||
dw deleteq_entry ;6
|
||||
dw readq_entry ;7
|
||||
dw creadq_entry ;8-conditional readq
|
||||
dw writeq_entry ;9
|
||||
dw cwriteq_entry ;10-conditional writeq
|
||||
dw delay_entry ;11
|
||||
dw dispatch_entry ;12
|
||||
dw terminate_entry ;13
|
||||
dw creat_proc_entry;14
|
||||
dw set_prior_entry ;15
|
||||
dw pd_entry ;16-get PD address
|
||||
dw abort_spec_entry;17-abort process
|
||||
dw sleep_entry ;18
|
||||
dw wakeup_entry ;19
|
||||
dw findpdname_entry;20
|
||||
dw sync_entry ;21
|
||||
dw unsync_entry ;22
|
||||
dw no_abort_entry ;23
|
||||
dw ok_abort_entry ;24
|
||||
dw no_abort_spec_entry ;25
|
||||
; dw flagalloc ;26
|
||||
|
||||
;===== =================
|
||||
entry: ; RTM Entry Point
|
||||
;===== =================
|
||||
xor ch,ch ! shl cx,1 ! mov si,cx
|
||||
call cs:function[si]
|
||||
rtm_ret:retf
|
||||
|
||||
;==== ================
|
||||
osif: ; O.S. Interface
|
||||
;==== ================
|
||||
callf cs:dword ptr .supervisor ! ret
|
||||
|
||||
;====== ================
|
||||
xiosif: ; XIOS Interface
|
||||
;====== ================
|
||||
mov si,mod_entry
|
||||
callf dword ptr xiosmod[si] ! ret
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
pagesize 45
|
||||
; *****************************
|
||||
; * Codemacros for 8087 *
|
||||
; * numeric data processor: *
|
||||
; ***************************
|
||||
;
|
||||
; stack references:
|
||||
st equ 0 ; stack top (= register 0)
|
||||
st0 equ 0 ; register 0
|
||||
st1 equ 1 ; register 1
|
||||
st2 equ 2 ; register 2
|
||||
st3 equ 3 ; register 3
|
||||
st4 equ 4 ; register 4
|
||||
st5 equ 5 ; register 5
|
||||
st6 equ 6 ; register 6
|
||||
st7 equ 7 ; register 7
|
||||
;
|
||||
;
|
||||
codemacro FRSTOR src:M
|
||||
db 9bh
|
||||
segfix src
|
||||
db 0ddh
|
||||
modrm 4,src
|
||||
endm
|
||||
|
||||
codemacro FSTCW dst:Mw
|
||||
db 9bh
|
||||
segfix dst
|
||||
db 0d9h
|
||||
modrm 7,dst
|
||||
endm
|
||||
|
||||
codemacro FDISI
|
||||
db 9bh
|
||||
dw 0e1dbh
|
||||
endm
|
||||
|
||||
codemacro FSAVE dst:M
|
||||
segfix dst
|
||||
db 0ddh
|
||||
modrm 6,dst
|
||||
endm
|
||||
|
||||
codemacro FNINIT
|
||||
dw 0e3dbh
|
||||
endm
|
||||
|
||||
|
||||
codemacro FNDISI
|
||||
dw 0e1dbh
|
||||
endm
|
||||
|
||||
codemacro FNSTCW dst:Mw
|
||||
segfix dst
|
||||
db 0d9h
|
||||
modrm 7,dst
|
||||
endm
|
||||
|
||||
codemacro FNSTSW dst:Mw
|
||||
segfix dst
|
||||
db 0ddh
|
||||
modrm 7,dst
|
||||
endm
|
||||
|
||||
codemacro FNCLEX
|
||||
dw 0e2dbh
|
||||
endm
|
||||
|
||||
codemacro FNSAVE dst:M
|
||||
db 0ddh
|
||||
modrm 6,dst
|
||||
endm
|
||||
|
||||
codemacro FNSTENV dst:M
|
||||
segfix dst
|
||||
db 0d9h
|
||||
modrm 6,dst
|
||||
endm
|
||||
|
||||
codemacro FLDENV src:M
|
||||
db 9bh
|
||||
segfix src
|
||||
db 0d9h
|
||||
modrm 4,src
|
||||
endm
|
||||
|
||||
codemacro FNOP
|
||||
db 9bh
|
||||
dw 0d0ddh
|
||||
endm
|
||||
|
||||
FWAIT equ WAIT
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
include cpyright.def
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* MP/M or CCP/M Supervisor Module
|
||||
;*
|
||||
;*****************************************************
|
||||
eject ! include system.def
|
||||
eject ! include modfunc.def
|
||||
eject ! include modtab.def
|
||||
eject ! include xioscb.def
|
||||
eject ! include pd.def
|
||||
eject ! include err.def
|
||||
eject ! include qd.def
|
||||
eject ! include fcb.def
|
||||
eject ! include acb.def
|
||||
eject ! include enttab.def
|
||||
eject ! include mem.def
|
||||
eject ! include mpb.def
|
||||
eject ! include clicb.def
|
||||
eject ! include rsp.def
|
||||
eject ! include pcb.def
|
||||
eject ! include cmdh.def
|
||||
eject ! include char.def
|
||||
eject ! include vccb.def
|
||||
eject ! include uda.def
|
||||
eject ! include init.sup
|
||||
eject ! include supif.sup
|
||||
eject ! include sysfunc.sup
|
||||
eject ! include command.sup
|
||||
eject ! include load.sup
|
||||
eject ! include parse.sup
|
||||
eject ! include rpl.sup
|
||||
eject ! include patch.cod
|
||||
eject ! include basep.fmt
|
||||
eject ! include lstk.fmt
|
||||
eject ! include vec.fmt
|
||||
eject ! include uda.fmt
|
||||
eject ! include sysdat.dat
|
||||
eject ! include data.bdo
|
||||
eject ! include xiosdat.fmt
|
||||
eject ! end
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
;*****************************************************
|
||||
;*
|
||||
;* SUPERVISOR INTERFACE ROUTINES
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
;=========
|
||||
user_entry:
|
||||
;=========
|
||||
; User Entry Point - enter here from a INT 224
|
||||
;
|
||||
; REGISTER USAGE
|
||||
; ENTRY EXIT
|
||||
; ----- ----
|
||||
; CL - Function Code AX - Copy of BX
|
||||
; DX - Param BX - Return
|
||||
; DS - Seg Addr CX - Error Code
|
||||
; ES - Segment Return
|
||||
;
|
||||
; DS,SI,DI,BP preserved through call
|
||||
;
|
||||
; SETUP FOR MPM ENVIRONMENT
|
||||
; -------------------------
|
||||
; contents of users stack
|
||||
; Flags
|
||||
; CS
|
||||
; IP <- u_stack_ss,_sp
|
||||
; DS = Sysdat Segment
|
||||
; ES -> user_data_area (UDA)
|
||||
; DX -> function parameter
|
||||
; u_wrkseg == user's DS
|
||||
; u_retseg == user's ES
|
||||
;interrupts are off
|
||||
;set up MPM,CCPM environment
|
||||
cld ! mov ax,ds ;AX = user's DS
|
||||
mov ds,sysdat
|
||||
mov bx,rlr
|
||||
mov ds,p_uda[bx] ;DS = UDA segment
|
||||
mov ds:u_retseg,es ;save user's ES
|
||||
|
||||
;U_INSYS is count of times
|
||||
;through this entry point
|
||||
cmp ds:u_insys,0 ! jne noswt ;change stacks to UDA stack
|
||||
;if U_INSYS = 0
|
||||
;otherwise leave stack alone
|
||||
|
||||
;U_WRKSEG where is user's entry DS
|
||||
;is saved
|
||||
mov ds:u_wrkseg,ax ;wipe out earlier u_wrkseg
|
||||
mov ds:u_stack_ss,ss
|
||||
mov ds:u_stack_sp,sp
|
||||
mov ax,ds
|
||||
mov ss,ax ! mov sp,ulen ;stack starts at end of UDA
|
||||
jmps uecont
|
||||
noswt:
|
||||
push ds:u_wrkseg ;save current u_wrkseg on UDA stack
|
||||
mov ds:u_wrkseg,ax
|
||||
|
||||
uecont:
|
||||
sti
|
||||
inc ds:u_insys
|
||||
mov ax,ds ! mov es,ax ;register moves are faster than
|
||||
mov ds,sysdat ;push and pop, DS=SYSDAT,ES=UDA
|
||||
push si ! push di ! push bp
|
||||
|
||||
mov u_func,cl ;record function number in UDA
|
||||
xor ch,ch ;call function and do
|
||||
call netchk ;netwrk chk, returns BX, ES, CX
|
||||
|
||||
coret:
|
||||
pop bp ! pop di ! pop si
|
||||
mov ax,es ;setup user's environment and return
|
||||
mov ds,ax ;DS = UDA segment
|
||||
mov es,ds:u_retseg ;restore ES from entry unless
|
||||
;function returns a segment value
|
||||
mov ax,ds:u_wrkseg ;AX = user's entry DS
|
||||
cli
|
||||
dec ds:u_insys ! jnz nstk ;switch back to user's stack
|
||||
;if U_INSYS = 0
|
||||
push bx ! push ds ! push cx ;See if process should be suspended.
|
||||
mov ds,sysdat ;Since it's on its way out, it doesn't
|
||||
mov bx,rlr ;own any critical regions and we can
|
||||
;put it to sleep until its console is
|
||||
;switched into the foreground.
|
||||
mov ax,p_sflag[bx]
|
||||
test ax,psf_suspend ;is this a suspendable process ?
|
||||
jz coret1 ;no...
|
||||
mov es,p_uda[bx] ;Set up ES = UDA
|
||||
mov al,p_cns[bx]
|
||||
xor ah,ah ! xor bh,bh ;get vccb's state
|
||||
mov bx,ccblen ! mul bx
|
||||
mov bx,ccb ! add bx,ax
|
||||
mov ax, c_state[bx]
|
||||
test ax,csm_suspend ;is it to be suspended now ?
|
||||
jz coret1 ;no...
|
||||
mov bx,rlr
|
||||
push dx
|
||||
mov dx, offset splr ;get suspend list for sleep_entry
|
||||
mov ud_param,dx
|
||||
mov cx, f_sleep ;call to RTM to place in list
|
||||
xor bh,bh
|
||||
mov bl,ps_ciowait ;user ciowait instead of suspend
|
||||
call osif ;so the abort code will work
|
||||
pop dx
|
||||
coret1:
|
||||
pop cx ! pop ds ! pop bx
|
||||
mov ax,ds:u_wrkseg
|
||||
mov es,ds:u_retseg
|
||||
coret2:
|
||||
mov ss,ds:u_stack_ss
|
||||
mov sp,ds:u_stack_sp
|
||||
jmps ueout
|
||||
nstk:
|
||||
sti
|
||||
pop ds:u_wrkseg ;restore previous U_WRKSEG if not
|
||||
;going back to user's stack
|
||||
ueout: mov ds,ax ;DS = user's entry DS
|
||||
mov ax,bx ;parameter return BX = AX
|
||||
inc ax
|
||||
jz u_err1 ;CX=error code if AX,BX=0FFFFH
|
||||
xor cx,cx ;CX always 0 if no error
|
||||
u_err1:
|
||||
dec ax
|
||||
iret ;back to user ...
|
||||
;restore interrupts as they
|
||||
;were on entry
|
||||
|
||||
sysfunc: ; call system function
|
||||
;------- -----------------------
|
||||
; entry: if CH <> 0 then CH is module number
|
||||
; (usually 1:SUP, 2:RTM, 3:MEM, 4:CIO, 5:BDOS)
|
||||
; network check is bypassed
|
||||
; if CH = 0 then network check is done
|
||||
; CL = function #
|
||||
; DX = arg
|
||||
; BX = arg
|
||||
; exit: BX = return value
|
||||
; ES = segment return value
|
||||
; CX = error code if BX = 0FFFFH
|
||||
|
||||
test ch,ch ! jz netchk ;network or local
|
||||
mov ax,cx ! jmps localfunc ;in local module
|
||||
|
||||
|
||||
illfunc: ;illegal function number
|
||||
jmp i_ent
|
||||
|
||||
netchk:
|
||||
; enter here for network check
|
||||
; check for function numbers represented in function table,
|
||||
; ENTTAB_TABLE. Table space is saved by making the functions
|
||||
; contiguous as we check the range.
|
||||
; The table has entries for functions 0-80, 98-116, 128-164.
|
||||
; Numbers 70-97, 117-127, 165-255 are not in the table.
|
||||
; Illegal functions in this table return the error codes
|
||||
; not implemented (1) or illegal function number (2).
|
||||
; Function not in the table return the illegal function number
|
||||
; code.
|
||||
; To add a new user function modify the files SYSDAT.DAT and
|
||||
; MODFUNC.DEF as well as the ranges immediately
|
||||
; below. All of the modules SUP,RTM,MEM,CIO,BDOS,SYSDAT must
|
||||
; then be reassembled.
|
||||
if netversion
|
||||
mov ax,cx
|
||||
cmp al,80 ! jbe okfunc
|
||||
sub al,17 ! cmp al,81 ! jb illfunc
|
||||
cmp al,99 ! jbe okfunc
|
||||
sub al,11
|
||||
;
|
||||
; 3.1M patch for illegal function numbers 117-127
|
||||
;
|
||||
cmp al,100 ! jb illfunc ;117 -127 are now 89 -99
|
||||
cmp al,136 ! ja illfunc
|
||||
;
|
||||
; end of 3.1M patch
|
||||
;
|
||||
endif
|
||||
if not netversion
|
||||
cmp cl,80 ! jbe okfunc
|
||||
sub cl,17 ! cmp cl,81 ! jb illfunc ;98-116 are now 81-99
|
||||
cmp cl,99 ! jbe okfunc ;128-164 are now 100-136
|
||||
sub cl,11
|
||||
;
|
||||
; 3.1M patch for illegal functions 117-127
|
||||
;
|
||||
cmp cl,100 ! jb illfunc ;117 -127 are now 89 - 99
|
||||
cmp cl,136 ! ja illfunc
|
||||
;
|
||||
; end of 3.1M patch
|
||||
;
|
||||
endif
|
||||
okfunc:
|
||||
if netversion
|
||||
shl ax,1
|
||||
mov si,ax
|
||||
mov ax,word ptr sysent[si]
|
||||
test ah,net_bit
|
||||
jz localfunc
|
||||
and ah, not net_bit
|
||||
mov bl,module_map
|
||||
test bl,netmod_bit
|
||||
je localfunc
|
||||
push ax
|
||||
callf dword ptr .netmod
|
||||
cmp al,0ffh
|
||||
pop ax
|
||||
je localfunc
|
||||
mov ax,bx
|
||||
ret
|
||||
endif
|
||||
if not netversion
|
||||
;CL is now 0 - num entries
|
||||
;- 1 in entry table
|
||||
mov si,cx ! shl si,1 ;times 2 for entry table
|
||||
add si,offset sysent ;AH high nibble flags
|
||||
mov ax,enttab_entry[si] ;AH low nibble module
|
||||
;AL function number
|
||||
;within module
|
||||
test ah,net_bit ! jz localfunc ;not a network function
|
||||
and ah,not net_bit ;turn off network bit
|
||||
mov al,module_map
|
||||
test al,netmod_bit ! je localfunc ;network module is not there
|
||||
push ax
|
||||
callf dword ptr .netmod ;call network CL = func
|
||||
cmp al,true ;if AL=0FFH do func locally
|
||||
pop ax ;in addition over network
|
||||
jne localfunc
|
||||
mov ax,bx ! ret
|
||||
endif
|
||||
|
||||
localfunc: ;not over the network
|
||||
cmp ah,sup ! je insup ;AH=module, AL=function
|
||||
mov cl,ah
|
||||
mov ch,module_map ! shr ch,cl ;does module exist ?
|
||||
jnc badmod
|
||||
xor ch,ch ! dec cx ;make module 0 relative
|
||||
shl cx,1 ! shl cx,1 ! shl cx,1 ;* 8
|
||||
mov si,cx ! mov cl,al ;func # in CL
|
||||
callf dword ptr module_table[si]
|
||||
ret
|
||||
badmod:
|
||||
jmp n_imp
|
||||
insup:
|
||||
xor ah,ah
|
||||
shl ax,1 ! mov si,ax ; mov cx,ax
|
||||
jmp cs:supfunc[si]
|
||||
|
||||
;=====
|
||||
entry: ; Supervisor module entry point
|
||||
;===== -------------------------------
|
||||
;
|
||||
; Arrive here usually on a CALLF using address
|
||||
; at SYSDAT:4. Note: flag set is handled specially.
|
||||
;
|
||||
; entry: if CH <> 0 then CH is module number
|
||||
; (usually 1:SUP, 2:RTM, 3:MEM, 4:CIO, 5:BDOS)
|
||||
; network check is bypassed
|
||||
; if CH = 0 then network check is done;
|
||||
; CL = function #. If CH = 0 then CL is treated
|
||||
; as a function number used with an INT 224:
|
||||
; it is a USER function.
|
||||
; If CH is not 0 then CL is the function number
|
||||
; within the module specified by CH.
|
||||
; The file MODFUNC.DEF contains the equates
|
||||
; used for accessing functions from within the O.S.
|
||||
; These functions are INTERNAL functions.
|
||||
; Note the INTERNAL functions are a superset of
|
||||
; the USER functions. The equates for USER
|
||||
; functions in MODFUNC.DEF have a 0 for the high byte
|
||||
; forcing network checking from this entry point.
|
||||
; An example: if f_conin (from MODFUNC.DEF) is
|
||||
; equal to 0001H. A Console output call to this
|
||||
; entry point thus result in CH = 0, CL = 1.
|
||||
; DX = arg
|
||||
; BX = arg
|
||||
;
|
||||
; exit: BX = return value
|
||||
; ES = segment return value
|
||||
; CX = error code if BX = 0FFFFH
|
||||
|
||||
|
||||
cmp cx,f_flagset ! jne notfs ;flag set is exception:
|
||||
mov cx,f_inflagset ;do not go over network,
|
||||
call sysfunc ;make path shorter,
|
||||
mov ax,bx ;parameter return BX = AX
|
||||
inc ax ;AX=0FFFFH if error
|
||||
jz u_err2 ;CX= error code if AX,BX=0FFFFH
|
||||
xor cx,cx ;CX=0 if no error
|
||||
u_err2:
|
||||
dec ax ;set AX back to 0 or 0FFFFH
|
||||
retf ;DS must equal system
|
||||
notfs: ;data segment
|
||||
|
||||
;mov u_unused,cx ;save 16 bit function number
|
||||
call osif ! retf
|
||||
|
||||
osif: ;point SUP uses to get
|
||||
;to other modules
|
||||
push u_wrkseg ;save current u_wrkseg
|
||||
mov ax,ds
|
||||
mov u_wrkseg,ax
|
||||
mov ax,sysdat
|
||||
mov ds,ax
|
||||
call sysfunc
|
||||
mov ax,u_wrkseg
|
||||
mov ds,ax
|
||||
pop u_wrkseg
|
||||
mov ax,bx ;BX,CX are return codes
|
||||
inc ax ;AX=0FFFFH if error
|
||||
jz u_err3 ;CX= error code if AX,BX=0FFFFH
|
||||
xor cx,cx ;CX=0 if no error
|
||||
u_err3:
|
||||
dec ax ;set AX back to 0 or 0FFFFH
|
||||
ret
|
||||
|
||||
|
||||
;=========
|
||||
user_retf:
|
||||
;=========
|
||||
; If a user process does a RETF to terminate,
|
||||
; the process ends here. The Load function sets up
|
||||
; the default stack to point here.
|
||||
|
||||
mov bx,rlr
|
||||
and p_flag[bx],not pf_keep+pf_tempkeep+pf_ctlc+pf_sys
|
||||
mov cx,f_terminate
|
||||
xor dx,dx
|
||||
int osint ;make sure the terminate
|
||||
;succeed by reseting the
|
||||
;the keep,tempkeep,ctlc,sys flags
|
||||
|
||||
;======
|
||||
xiosif:
|
||||
;======
|
||||
callf dword ptr .xiosmod ! ret
|
||||
|
||||
;*****************************************************
|
||||
;*
|
||||
;* Supervisor function table
|
||||
;*
|
||||
;*****************************************************
|
||||
|
||||
org ((offset $)+1) AND 0fffeh ;Word Boundary
|
||||
|
||||
supfunc dw n_imp ; 0-not implemented
|
||||
dw i_ent ; 1-illegal function number
|
||||
dw bver_ent ; 2-(12)get BDOS version
|
||||
dw cbios_ent ; 3-(50)call bios
|
||||
dw load_ent ; 4-(59)user load function
|
||||
dw cli_ent ; 5-(150)CLI
|
||||
dw rpl_ent ; 6-(151)Call RPL
|
||||
dw parse_ent ; 7-(152)parse filename
|
||||
dw sdat_ent ; 8-(154)get sysdat addr
|
||||
dw tod_ent ; 9-(155)get tod addr
|
||||
dw load ; 10-load function
|
||||
dw over_ent ; 11-O.S. version number
|
||||
dw chain_ent ; 12-(47)Program Chain
|
||||
dw ser_ent ; 13-(107)return serial
|
||||
dw cload_ent ; 14-chain load function
|
||||
|
||||
| ||||