Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 3.X/CPM 3.0/3.0 PLM SOURCE/DIRLBL.ASM
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

537 lines
20 KiB
NASM

;Function 100 RSX (set/create directory label
; Only for Non banked systems
;
; Procedure:
; 1. If this BDOS call ~= f100 then go to NEXT
; 2. select the current disk for BIOS calls
; 3. search for current label
; 4. if no label then do
; a. find first empty dir slot
; b. if no empties then return error
; c. create dir label from user FCB in DE
; d. call update SFCB
; e. return
; 5. if password protected then ok = password()
; 6. if ~ok then return error
; 7. update label from user info
; 8. call update SFCB
; 9. return
;
; P. Balma
;
; RSX PREFIX
;
serial: db 0,0,0,0,0,0
jmp1: jmp ftest
NEXTj: db 0c3h ; next RSX or BDOS
NEXTa: db 0,0 ; next address
prev: dw 0 ; where from
remove: db 0ffh ; remove RSX at warm start
nbank: db 0FFh ; non banked RSX
rsxname: db 'DIRLBL '
space: dw 0
patch: db 0
;
;
ftest:
push a ;save user regs
mov a,c
cpi 64h ;compare BDOS func 100
jz func100
pop a ;some other BDOS call
goto$next:
lhld NEXTa ; go to next and don't return
pchl
; Set directory label
; de -> .fcb
; drive location
; name & type fields user's discretion
; extent field definition
; bit 1 (80h): enable passwords on drive
; bit 2 (40h): enable file access
; bit 3 (20h): enable file update stamping
; bit 4 (10h): enable file create stamping
; bit 8 (01h): assign new password to dir lbl
func100:
pop a
lxi h,0 ! dad sp ! shld ret$stack ; save user stack
lxi sp,loc$stack
xchg ! shld info ! xchg
mvi c,19h ! call goto$next ! sta curdsk ; get current disk
mvi c,1dh ! call goto$next ; is drive R/O ?
lda curdsk ! mov c,a ! call hlrotr
mov a,l ! ani 01h ! jnz read$only
lhld info ! call getexta ! push a ; if user tries to set time
ani 0111$0000b ! sta set$time ; stamps and no SFCB's...error
mov a,m ! ani 7fh ! mov m,a ; mask off password bit
ani 1 ! sta newpass ; but label can have password
mvi c,69h ! push d ! lxi d,stamp ; get time for possible
call goto$next ! pop d ; update later
mvi c,31h ! lxi d,SCBPB ! call goto$next; get BDOS current dma
shld curdma
lda curdsk ! call dsksel ; BIOS select and sets
; disk parameters
; Does dir lbl exist on drive?
call search ; return if found or
push h ! mvi b,0 ; successfully made
lxi d,20h ! lda nfcbs ! mov c,a ; Are there SFCB's in directory
main0: dad d ! mov a,m ! cpi 21h ! jz main1
inr b ! lda i ! inr a ! sta i ! cmp c
jnz main0
lda set$time ! ora a ! jnz no$SFCB ; no, but user wants to set
; time stamp
sta SFCB ; SFCB = false
main1: shld SFCB$addr ! mov a,b ! sta j ! lhld info
xchg ! pop h ! push h ! inx h ; HL => dir FCB, DE => user FCB
inx d ! mvi c,0ch ; prepare to move DE to HL
call move ! lda newpass ; find out if new password ?
ora a
cnz scramble ; scramble user pass & put in
; dFCB
lda SFCB ! inr a ! jnz mainx1 ; any SFCB's
main2: ; update time & date stamp
lda j ! mov b,a ! mvi a,2 ; j = FCB position from SFCB
sub b ; in 4 FCB sector (0,1,2), thus
; FCBx - 2
; FCBy - 1
; FCBz - 0
; SFCB
; So, 2-j gives FCB offset in
; SFCB
mvi b,0 ! mov c,a ! lhld SFCB$addr
inx h ! lxi d,0ah ! inr c
mainx0: dcr c ! jz mainx1
dad d ! jmp mainx0
mainx1: pop d ! push d ! push h ; HL => dFCB
xchg ! lxi d,18h ! dad d ; HL => dfcb(24) (TS field)
xchg ! pop h ! push d ; of DIR LABEL
; HL => Time/stamp pos in SFCB
lda NEW ! inr a ! jnz st0 ; did we create a new DL?
call stamper ! jmp st1 ; yes
st0: lxi d,4 ! dad d ; update time stamp
pop d ! push h ! xchg ! lxi d,4 ; DFCB position
dad d ! xchg ! pop h ! push d
st1: call stamper
pop h
mainr: pop h ! call getexta ! ori 1 ! mov m,a ; set lsb extent
call write$dir
xra a ! lxi h,0 !jmp goback ; no SFCB, so finished
no$SFCB:
mvi a,0ffh ! lxi h,0ffh ! jmp goback
read$only:
mvi a,0ffh ! lxi h,02ffh
goback: push h ! lhld aDIRBCB ! mvi m,0ffh ; tell BDOS not to use buffer
; contents
push a
mvi c,0dh ! call goto$next ; BDOS reset
lda curdsk ! mov e,a ! mvi c,0eh
call goto$next
lda curdsk ! call seldsk ; restore BDOS environment
pop a ! pop d
lhld ret$stack ! sphl ; restore user stack
xchg ; move error return to h
ret
dsksel: ; select disk and get parameters
call seldsk ; Bios select disk
call gethl ; DE = XLT addr
shld XLT ! xchg
lxi b,0ah ! dad b ; HL = addr DPB
call gethl
shld aDPB ! xchg
lxi b,4 ! dad b ; HL = addr DIR BCB
call gethl ! shld aDIRBCB
lxi b,0ah ! dad b ; Hl => DIR buffer
shld bufptr ; use BDOS buffer for
; BIOS reads & writes
; must jam FF into it to
; signal don't use when done
lhld aDPB
call gethl ; get [HL]
shld spt ! xchg
inx h! inx h! inx h ! inx h! inx h! ; HL => dirmax
call gethl ! shld dirmax ! xchg
inx h ! inx h !
call gethl ! shld checkv ! xchg
call gethl ! shld offset ! xchg
; HL => phys shift
call gethl ! xchg ; E = physhf, D = phymsk
inr d ! mov a,d ; phys mask+1 = # 128 byte rcd
; phymsk * 4 = nfcbs/rcd
ora a ! ral ! ora a ! ral ; clear carry & shift phymsk
sta nfcbs
lhld spt ; spt = spt/phymsk
mov c,e ! call hlrotr ; => spt = shl(spt,physhf)
shld spt
ret
search: ; search dir for pattern in
; info of length in c
xra a ! sta sect ! sta empty
lxi h,0 ! shld dcnt
lhld bufptr ! mov b,h ! mov c,l ; set BIOS dma
call setdma
src0: call read$dir
cpi 0 ! jnz oops ; if A ~= 0 then BIOS error
mvi b,0 ! lda nfcbs ! mov c,a ; BC always = nfcbs
lhld bufptr ! lxi d,20h ; start of buffer and FCB
xra a ; do i = 0 to nfcbs - 1
src1: sta i ! mov a,m ; user #
cpi 20h ! jnz src2 ; dir label mark
push h ! lxi d,10h ! dad d ! mov a,m ; found label, move to DM to
ora a ! pop h ! rz ; check if label is pass prot
push h ! cpi 20h ! pop h ! jnz checkpass
ret
src2: lda empty ! inr a ! jz src3 ; record first sect with empty
mov a,m
cpi 0e5h ! jnz src3 ! lda sect ; save sector #
sta savsect ! mvi a,0ffh ! sta empty ; set empty found = true
src3: dad d ; position to next FCB
lda i ! inr a ; while i < nfcbs
cmp c ! jnz src1
lhld dirmax ! xchg ! lhld dcnt ; while (dcnt < dirmax) &
; dir label not found
dad b ! shld dcnt ! call subdh ; is dcnt <= dirmax ?
jc not$found ; no
lda sect ! inr a ! sta sect ! jmp src0
oops: mvi a,0ffh ! lxi h,1ffh
pop b ! jmp goback ; return perm. error
not$found: ; must make a label
lda empty ! inr a ! jnz no$space ; if empty = false...
lda savsect ! sta sect
call read$dir ; get sector
lhld bufptr ! lxi d,20h ! mvi c,0 ; C = FCB offset in buffer
nf0: mov a,m ! cpi 0e5h ! jz nf1
dad d ! inr c !jmp nf0 ; know that empty occurs here
; so don't need bounds test
nf1: mvi m,20h ! mov a,c ! sta i
mvi a,0 ! push h ! mvi c,32 ; clear fcb to spaces
nf2: inx h ! dcr c ! jz nf3
mov m,a ! jmp nf2
nf3: pop h
mvi a,0ffh ! sta NEW
ret ; HL => dir FCB
no$space: mvi a,0ffh ! lxi h,0ffh ! pop b ! jmp goback
check$pass: ; Dir is password protected, check dma for
; proper password
push h ; save addr dir FCB
lxi d,0dh ! dad d ! mov c,m ; get XOR sum in S1, C = S1
lxi d,0ah ! dad d ; position to last char in label pass
mvi b,8 ; # chars in pass
xchg ! lhld curdma ! xchg ; DE => user pass, HL => label pass
cp0: mov a,m ! xra c ! push b ; HL = XOR(HL,C)
mov c,a ! ldax d ! cmp c ; compare user and label passwords
jnz wrong$pass
pop b ! inx d ! dcx h ! dcr b
jnz cp0
xchg ! shld curdma ; curdma => 2nd pass in field if there
pop h ; restore dir FCB addr
mvi a,0ffh ! sta oldpass
ret
wrong$pass:
mvi a,0ffh ! lxi h,07ffh ! pop b ! pop b
jmp goback
scramble: ; encrypt password at curdma
; 1. sum each char of pass.
; 2. XOR each char with sum
; 3. reverse order of encrypted pass
lxi b,8 ! lhld curdma ;checkpass sets to 2nd pos if
lda oldpass ! inr a ! jz scr0 ;old pass else must move dma
dad b ! shld curdma
; B = sum, C = max size of pass
scr0: mov a,m ! add b ! mov b,a ! dcr c
inx h ! jnz scr0
pop d ! pop h ! push d ; H => dFCB, D was return
lxi d,0dh ! dad d ! mov m,b ; S1 = sum
lxi d,0ah ! dad d ; position to last char in pass
mvi c,8 ! xchg ! lhld curdma
scr1: mov a,m ! xra b ! xchg ! mov m,a ; XOR(char) => dFCB
xchg ! inx h ! dcx d ! dcr c ! jnz scr1
ret
read$dir: ; read directory into bufptr
call track
call sector
call rdsec
ret
writedir: ; write directory from bufptr
lda sect
call track
call sector
call wrsec
ret
track: ; set the track for the BIOS call
lhld spt ! call intdiv ; E = integer(sect/spt)
lhld offset ! dad d ! xchg ! call settrk
ret
sector: ; set the sector for the BIOS
lda sect
lhld spt ! call intdiv ; get mod(sect,spt)
mov a,c ! sub l ; D = x * spt such that D > sect
; D - spt = least x*spt s.t. D < sect
mov c,a ! lda sect ! sub c ; a => remainder of sect/spt
mvi b,0 ! mov c,a ! lhld XLT ; BC = logical sector #, DE = translate
xchg ! call sectrn ; table address
xchg ! call setsec ; BC = physical sector #
ret
intdiv: ; compute the integer division of A/L
mvi c,0 ! lxi d,0
int0: push a ; compute the additive sum of L such
mov a,l ! add c ! mov c,a ; that C = E*L where C = 1,2,3,...
pop a
cmp C ! inr e ! jnc int0 ; if A < E*L then return E - 1
dcr e
ret
getexta:
; Get current extent field address to hl
lxi d,0ch ! dad d ; hl=.fcb(extnum)
mov a,m
ret
move: ; Move data length of length c from source de to
; destination given by hl
inr c ; in case it is zero
move0:
dcr c! rz ; more to move
ldax d! mov m,a ; one byte moved
inx d! inx h ; to next byte
jmp move0
gethl: ; get the word pointed at by HL
mov e,m ! inx h ! mov d,m ! inx h
xchg ! ret
subdh: ; HL = DE - HL
ora a ; clear carry
mov a,e ! sub l ! mov l,a
mov a,d ! sbb h ! mov h,a
ret
hlrotr:
; rotate HL right by amount c
inr c ; in case zero
hlr: dcr c! rz ; return when zero
mov a,h! ora a! rar! mov h,a ; high byte
mov a,l! rar! mov l,a ; low byte
jmp hlr
stamper: ; move time stamp into SFCB & FCB
lda SFCB ! inr a ; no SFCB, update DL only
cz stmp ! pop b ! pop d ! push h ! xchg
push b ! call stmp ! pop b ! xchg ! pop h ! push d
push b
ret
stmp: lxi d,stamp ! mvi c,4 ! call move
ret
;**********************************************************************
curdsk: db 0
set$time: db 0
oldpass: db 0
newpass: db 0
pass$prot db 0
sect: db 0
empty: db 0
stamp: ds 4
NEW: db 0
nfcbs: db 0
i: db 0
j: db 0
SFCB: db 0ffh
savsect: db 0
SFCB$addr: dw 0
info: dw 0
checkv dw 0
offset: dw 0
XLT: dw 0
bufptr: dw 0
spt: dw 0
dcnt: dw 0
curdma: dw 0
aDIRBCB dw 0
aDPB: dw 0
dFCB: dw 0
dirmax: dw 0
SCBPB:
Soff: db 3ch
Sset: db 0
Svalue: dw 0
;
;***********************************************************
;* *
;* bios calls from for track, sector io *
;* *
;***********************************************************
;***********************************************************
;* *
;* equates for interface to cp/m bios *
;* *
;***********************************************************
;
;
base equ 0
wboot equ base+1h ;warm boot entry point stored here
sdsk equ 18h ;bios select disk entry point
strk equ 1bh ;bios set track entry point
ssec equ 1eh ;bios set sector entry point
stdma equ 21h
read equ 24h ;bios read sector entry point
write equ 27h ;bios write sector entry point
stran equ 2dh ;bios sector translation entry point
;
;***********************************************************
;* *
;***********************************************************
seldsk: ;select drive number 0-15, in C
;1-> drive no.
;returns-> pointer to translate table in HL
mov c,a ;c = drive no.
lxi d,sdsk
jmp gobios
;
;***********************************************************
;* *
;***********************************************************
settrk: ;set track number 0-76, 0-65535 in BC
;1-> track no.
mov b,d
mov c,e ;bc = track no.
lxi d,strk
jmp gobios
;
;***********************************************************
;* *
;***********************************************************
setsec: ;set sector number 1 - sectors per track
;1-> sector no.
mov b,d
mov c,e ;bc = sector no.
lxi d,ssec
jmp gobios
;
;***********************************************************
;* *
;***********************************************************
rdsec: ;read current sector into sector at dma addr
;returns in A register: 0 if no errors
; 1 non-recoverable error
lxi d,read
jmp gobios
;***********************************************************
;* *
;***********************************************************
wrsec: ;writes contents of sector at dma addr to current sector
;returns in A register: 0 errors occured
; 1 non-recoverable error
lxi d,write
jmp gobios
;
;***********************************************************
;* *
;***********************************************************
sectrn: ;translate sector number
;1-> logical sector number (fixed(15))
;2-> pointer to translate table
;returns-> physical sector number
push d
lxi d,stran
lhld wboot
dad d ;hl = sectran entry point
pop d
pchl
;
;
setdma: ; set dma
; 1 -> BC = dma address
lxi d,stdma
jmp gobios
;
;
;***********************************************************
;***********************************************************
;***********************************************************
;* *
;* compute offset from warm boot and jump to bios *
;* *
;***********************************************************
;
;
gobios: ;jump to bios entry point
;de -> offset from warm boot entry point
lhld wboot
dad d
lxi d,0
pchl
;
ret$stack: dw 0
ds 32
loc$stack:
end