;       SECURITY.ASM ver 2.0
;        (revised 4/24/81)
;   by Keith Petersen and Bob Mathias
;
;--->For use with CP/M 2.x only.
;
;This program runs up in high RAM.  It gets there
;by being moved there when 'MINICBBS' is typed.
;
;The program in high RAM does the following:
;
;Signs in on desired user number, selects desired
;drive and loads and executes file 'MINICBBS.COM'.
;When done with MINICBBS, the user will return to
;whatever drive and user area was previously active.
;
;Why this program is useful:  It offers a means for
;a remote CP/M system to allow execution of programs
;residing in areas other than USER 0 without having
;to give the user access to these areas.
;
;If you change the name at 'MYFCB', this program may
;be used to load and execute any COM file that does
;not need an arguement on the command line.
;
;------------------------------------------------
;Change the following equate to an area in your
;high memory where this program may patch itself in.
;(This may be below BDOS, provided that sufficient
;space exists below this program to load MINICBBS).
;
DEST    EQU     0FA00H  ;RUNNING LOCATION OF CODE
;
;------------------------------------------------
;
;Change the following equate to the desired drive
;(where 0=A, 1=B, etc).
;
DRIVE   EQU     0       ;CURRENTLY SET FOR DRIVE A:
;
;Change the following equate to the USER area desired
;
USERNR  EQU     15      ;CURRENT SET FOR USER 15
;
BASE    SET     0
ALTCPM  EQU     0       ;PUT 1 HERE FOR ALTERNATE CP/M
;
       IF      ALTCPM
BASE    SET     4200H   ;BASE ADDRESS OF ALT CP/M
       ENDIF
;
PRINT   EQU     9
SELDSK  EQU     14
OPEN    EQU     15
READ    EQU     20
STDMA   EQU     26
SGUSR   EQU     32      ;SET/GET USER FUNCTION
BDOS    EQU     BASE+5
FCB     EQU     BASE+5CH
;
CR      EQU     0DH
LF      EQU     0AH
;
       ORG     BASE+100H
;
;Move the program up to high RAM and jump to it.
;
MOVEUP: LXI     B,PEND-START+1      ;NUMBER OF BYTES TO MOVE
       LXI     H,DEST+PEND-START+1 ;END OF MOVED CODE
       LXI     D,SOURCE+PEND-START ;END OF SOURCE CODE
;
MVLP:   LDAX    D       ;GET BYTE
       DCX     H       ;BUMP POINTERS
       MOV     M,A     ;NEW HOME
       DCX     D
       DCX     B       ;BUMP BYTE COUNT
       MOV     A,B     ;CHECK IF ZERO
       ORA     C
       JNZ     MVLP    ;IF NOT, DO SOME MORE
       PCHL            ;JUMP TO "START"
;
SOURCE  EQU     $       ;BOUNDARY MEMORY MARKER
;
OFFSET  EQU     DEST-SOURCE     ;RELOC AMOUNT
;-----------------------------------------------;
;       The following code gets moved           ;
;       to high RAM located at "DEST",          ;
;           where it is executed.               ;
;-----------------------------------------------;
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XX   C A U T I O N :  If modifying anything    XX
;XX     in this program from here on:           XX
;XX     A-L-L  lables must be of the form:      XX
;XX     LABEL   EQU     $+OFFSET                XX
;XX     in order that the relocation to high    XX
;XX     RAM work successfully.  Forgetting to   XX
;XX     specify '$+OFFSET' will cause the pro-  XX
;XX     gram to JMP into whatever is currently  XX
;XX     in LOW memory, with unpredictable       XX
;XX     results.  Be careful....                XX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;
START   EQU     $+OFFSET
       LXI     SP,STACK ;SET UP LOCAL STACK POINTER
;Set user number
       MVI     E,USERNR
       MVI     C,SGUSR
       CALL    BDOS
;Select desired drive
       MVI     E,DRIVE
       MVI     C,SELDSK
       CALL    BDOS
;Open the file
       XRA     A
       STA     MYFCB+32 ;ZERO RECORD NUMBER
       LXI     D,MYFCB
       MVI     C,OPEN
       CALL    BDOS
;Did it exist?
       INR     A       ;A=> 0 MEANS "NO"
       JZ      BYERR   ;NO FILE, EXIT ERROR MSG
;
OPENOK  EQU     $+OFFSET
       LXI     D,BASE+100H ;POINT TO TPA
;
READLP  EQU     $+OFFSET
       PUSH    D       ;SAVE BUFFER ADDRESS
       PUSH    B
       PUSH    H
       MVI     C,STDMA
       CALL    BDOS
;Read a sector
       LXI     D,MYFCB
       MVI     C,READ
       CALL    BDOS
       POP     H
       POP     B
       ORA     A       ;OK?
       JNZ     EOF     ;NOT OK, MUST BE EOF
       POP     D       ;GET DMA ADDR
       LXI     H,80H   ;LENGTH OF 1 SECT.
       DAD     D       ;CALC NEXT BUFF ADDR
       XCHG            ;PUT IT BACK IN DE
       JMP     READLP  ;LOOP
;
;Got return code on read, see if error or EOF
;
EOF     EQU     $+OFFSET
       POP     D       ;DELETE STACKED BUFFER ADDR
;A has return code from read
       DCR     A       ;EOF?
       JZ      RSDMA   ;YES, EXIT
;
;Read error - exit with message
;
BYERR   EQU     $+OFFSET
       CALL    ERXIT   ;PRINT:
       DB      CR,LF,'++DISK READ ERROR++',CR,LF,'$'
;
;Exit with error message
;
ERXIT   EQU     $+OFFSET
       POP     D
       MVI     C,PRINT
       CALL    BDOS
       XRA     A
       STA     BASE+4  ;SET DRIVE A:, USER 0
       JMP     BASE
;
;Reset DMA address to normal
;
RSDMA   EQU     $+OFFSET
       LXI     D,BASE+80H
       MVI     C,STDMA
       CALL    BDOS
;
;Leave warm boot address on stack, then execute MINICBBS
       LXI     H,0
       PUSH    H
       JMP     BASE+100H       ;EXECUTE MINICBBS
;
MYFCB   EQU     $+OFFSET
       DB      0,'MINICBBSCOM',0
;Filename goes here^^^^^^^^^^^
;Default drive  ^               ^extent number
;
PEND    EQU     $+OFFSET ;END OF RELOCATED CODE
;
       DS      20       ;ROOM FOR OUR FCB
       DS      40       ;ROOM FOR LOCAL STACK
STACK   EQU     $+OFFSET ;LOCAL STACK
;
       END