TITLE "NZBLITZ - SAVE/LOAD NZCOM SYSTEM IN BINARY" ;********************************************************** ; NZBLITZ ; Save NZCOM system image as COM file with loader. The ; saved image starts at the base address of the CCP (or ; optionally at the lowest RSX in memory if RSXOKF is ; true) and saves the entire OS up to but not including ; CBIOS. This will save the ENV, Shell stack, Error handler, ; MCL, etc. ; ; This program consists of two separate parts. The first ; part is the system saver. The second part, located ; between .PHASE and .DEPHASE instructions, is the system ; loader. The loader segment is saved off as part of the ; system image COM file. ; ; Thanks to Joe Wright, for challanging me to write NZBLITZ ; and Carson Wilson for his suggestions for improvement. ; ; Copyright 1989,90 by Cameron W. Cotrill - All rights reserved. ; Released to the public domain for non-commercial use. ;********************************************************** ; VERS EQU 10 ; ; ASCII EQUATES: BELL EQU 07H CR EQU 0DH LF EQU 0AH TAB EQU 09H ; ; DOS EQUATES: BOOT EQU 0 ; Warm boot vector IOBYTE EQU BOOT+3 ; Io redirection byte CUSER EQU BOOT+4 ; Current user number BDOS EQU BOOT+5 ; Bdos vector FCB1 EQU BOOT+5CH ; First fcb set by ccp FCB2 EQU BOOT+6CH ; Second fcb set by ccp DMABUF EQU BOOT+80H ; Default disk transfer (dma) buffer TPA EQU BOOT+100H ; Base of tpa ; ; DOS FUNCTION CODES: B$SRST EQU 0 ; Bdos system reset B$CONI EQU 1 ; Bdos read conole byte B$CONO EQU 2 ; Bdos write console byte B$RDRI EQU 3 ; Bdos read reader byte B$PUNO EQU 4 ; Bdos write punch byte B$LSTO EQU 5 ; Bdos write list byte B$DCIO EQU 6 ; Bdos direct console i/o B$GIOB EQU 7 ; Bdos get io byte B$SIOB EQU 8 ; Bdos set io byte B$OCS EQU 9 ; Bdos print console string B$ICS EQU 10 ; Bdos read console string B$RCS EQU 11 ; Bdos read console status B$GVER EQU 12 ; Bdos get cp/m version B$DRST EQU 13 ; Bdos disk system reset B$SELD EQU 14 ; Bdos select disk B$OPEN EQU 15 ; Bdos file open B$CLOS EQU 16 ; Bdos file close B$SCHF EQU 17 ; Bdos search for first name match B$SCHN EQU 18 ; Bdos search for next name match B$ERA EQU 19 ; Bdos erase file B$RSEQ EQU 20 ; Bdos read sequential B$WSEQ EQU 21 ; Bdos write sequential B$CRAT EQU 22 ; Bdos create file B$REN EQU 23 ; Bdos rename file B$GAD EQU 24 ; Bdos get active disks B$GCD EQU 25 ; Bdos get current (default) disk B$SDMA EQU 26 ; Bdos set disk buffer (dma) address B$GALV EQU 27 ; Bdos get allocation vector B$SDRO EQU 28 ; Bdos set disk to read only B$GDRO EQU 29 ; Bdos get read only disks B$SFA EQU 30 ; Bdos set file attributes B$GDPB EQU 31 ; Bdos get disk parameter block address B$USER EQU 32 ; Bdos get/set user number B$RRAN EQU 33 ; Bdos read random B$WRAN EQU 34 ; Bdos write random B$GFS EQU 35 ; Bdos get file size B$SRR EQU 36 ; Bdos set random record number B$RSTD EQU 37 ; Bdos reset drive B$WRZF EQU 40 ; Bdos write random with zero fill ; JP START Z3ST: DEFB 'Z3ENV' DEFB 1 ENVADR: DEFW 0 RSXOKF: DEFB 0 ; Rsx save ok (0=no) START: LD HL,(ENVADR) LD (ENV),HL ; Save in loader while handy LD A,H OR L ; Test if any env JP Z,BARF PUSH HL LD DE,SIGNON CALL PRSTR XOR A LD (ERFLG),A ; No errors - yet ; VALIDATE ENV PASSED TO US IN HL INC HL INC HL INC HL ; Point to z3env message in env LD B,5 LD DE,Z3ST START1: LD A,(DE) ; Get local char to compare CP (HL) ; See if we were passed env pointer INC HL INC DE ; Bump pointers JP NZ,BARF ; Gag if we didn't (can't be nzcom) DJNZ START1 LD A,(HL) ; We have env, see if extended type RLCA ; By rolling msb into carry JP NC,BARF ; If no extended env, than no nzcom ; FOLLOWING CODE IS JOE WRIGHT'S NZCOM CHECK EXTRACTED FROM Z3LOC17 LD HL,(1) ; Get bios vector LD A,90-3 ; Offset to potential id ADD A,L LD L,A LD DE,NZCID ; Local id (below) LD B,6 ; Six bytes to check NZCHK: LD A,(DE) ; Get the byte at (de) CP (HL) ; Compare it with (hl) JP NZ,BARF ; Not nz-com INC DE INC HL ; Bump the pointers DJNZ NZCHK ; Next.. ; OK, WE HAVE A VALID ENV AND NZCOM IS RUNNING. LD A,(FCB1+1) CP ' ' ; Any file named? JP Z,HELP ; Show help if no file CP '?' ; This also means help JP Z,HELP CP '/' ; Zcpr sytle help? JP Z,HELP ; If in fcb1, must be... LD DE,FCB1+9 ; Point to file type in fcb LD HL,COM ; Point to file type LD C,3 ; B=0 from above LDIR ; Force com filetype ; SAVE SYSTEM ADDRESSES. LD HL,(1) LD (BIOSV),HL ; Save the bios vector LD HL,(6) LD (BDOSV),HL ; Likewise the bdos ; SET SAVE START ADDRESS TO LOWER OF CCP OR PROTECT POINTED TO BY 0006H LD IX,(ENVADR) LD E,(IX+3FH) LD D,(IX+40H) ; Put ccp address in de LD A,(IX+41H) LD (CCPBAS),DE ; Save in loader LD (CCPSIZ),A ; Save size too PUSH HL XOR A ; Clear the carry SBC HL,DE ; Test if any rsx's present POP HL JP C,RSXLOW ; Rsx present, so hl holds lower address EX DE,HL ; Else put address into hl RSXOK: LD (IBASE),HL ; Save as start address ; NOW SET TOP OF SAVE TO CBIOS (SAVE PATCH AREA ALSO - SPEEDS ZSDOS LOADS) EX DE,HL ; Save address in de XOR A LD L,A ; A=0 from above LD H,(IX+2) ; Put cbios address in hl SBC HL,DE ; Calculate save size LD (IMGSIZ),HL ; Save for later LD B,H LD C,L PUSH BC ; Save image size EX DE,HL LD DE,SAVBUF ; Point to our save address LDIR ; Move the shooting match down to our buffer FILSAV: LD A,0FFH CALL GSUSER ; Get logged user LD (USER),A LD A,(FCB1+13) CALL GSUSER ; Set to fcb LD DE,FCB1 ; Point to fcb PUSH DE LD C,B$ERA ; Kill any file of same name CALL BDOS POP DE ; Restore fcb pointer LD C,B$CRAT CALL BDOS ; Create dest file POP BC ; Restore size in bytes RL C ; Roll msb into carry LD A,B ; Get page count RLCA ; *2 LD C,A LD A,0 RLCA LD B,A ; A=0 from above LD A,[SAVBUF-LOADER+127]/128 ADD A,C LD C,A LD A,0 ADC A,B LD B,A ; Do this way to eliminate foreward ref ; Phase problems ; ADJUST FOR LOADER SIZE LD DE,LOADER-80H ; ; SAVE LOOP ; FXFER7: LD A,B OR C ; Test store completed JR Z,FXFER8 ; If stored FXFE7A: LD HL,80H ADD HL,DE PUSH HL ; Save dma address EX DE,HL CALL SETDMA ; Point to next xfer area LD DE,FCB1 CALL FWRITE ; Write record POP DE ; Restore dma address JP NZ,WRERR ; Error - prob. disk full DEC BC ; Put another JR FXFER7 ; Do the next record FXFER8: CALL DSTCLO ; Close the destination file INC A ; Test for error JP Z,WRERR ; If there was one LD DE,OKMSG JR EXIT1 ; Print summary and exit ; ; WRITE ERROR HANDLER ; WRERR: OR 0FFH LD (ERFLG),A ; Show error CALL DSTCLO ; Close the destination LD DE,FCB1 LD C,B$ERA CALL BDOS ; Erase the file LD DE,WRTERM EXIT1: CALL PRSTR ; Print error message and exit LD HL,FCB1+1 LD B,11 EXIT2: LD A,(HL) AND 7FH ; Mask any attributes CALL CHAROT ; And display filename INC HL DJNZ EXIT2 LD A,(ERFLG) AND A ; Is this an error? LD DE,WRTER1 CALL NZ,PRSTR ; Print aborting message if so EXIT3: LD A,(USER) ; Get default user CALL GSUSER LD DE,CRLF CALL PRSTR ; Turn up a line and exit EXIT4: LD HL,(ENVADR) ; Get env pointer LD A,H OR L RET Z LD DE,18H ; Offset to mcl pointer ADD HL,DE LD A,(HL) INC HL LD H,(HL) LD L,A ; Now pointing to mcl base XOR A ; Get a cheap zero EX DE,HL LD L,4 ; H=0 from above ADD HL,DE ; Point to start of text on mcl EX DE,HL LD (HL),E INC HL LD (HL),D ; Reset mcl pointer to start of line INC HL ; Skip buffer length INC HL LD (HL),A ; Set char count to 0 INC HL LD (HL),A ; Null line RET ; ; HELP ; HELP: LD DE,HELPM ; Point to help message JR PERR1 ; Send it and exit ; ; ERROR HANDLERS ; RSXLOW: LD A,(RSXOKF) AND A JP NZ,RSXOK ; Don't trip error handler if ok to save LD DE,RSXERR ; Don't save rsx's JR PERR BARF: LD DE,NFGSYS PERR: OR 0FFH LD (ERFLG),A ; Indicate error CALL PERR1 ; Print why error CALL EXIT4 ; Cancel pending commands LD DE,ABORTM ; And inform we're aborting PERR1: LD C,B$OCS JP BDOS ; Print error message and quit RSXERR: DEFB BELL,'Can''t save with RSX''s loaded!$' NFGSYS: DEFB BELL,'Not ' NZCID: DEFB 'NZ-' COM: DEFB 'COM' DEFB ' system!$' SIGNON: DEFB 'NZBLITZ, Version ' DEFB VERS/10+'0','.',VERS MOD 10+'0',CR,LF,'$' HELPM: DEFB ' Saves running NZCOM system as .COM file. Any commands',CR,LF DEFB ' remaining on the ZCPR multiple command line will execute',CR,LF DEFB ' each time the program image is loaded.',CR,LF DEFB CR,LF,' Syntax:',CR,LF DEFB ' NZBLITZ [DIR:]IMAGE[.COM]',CR,LF,'$' WRTERM: DEFB BELL,'Disk write error ' WRTER1: DEFB ' -' ABORTM: DEFB ' Aborting!' CRLF: DEFB CR,LF,'$' OKMSG: DEFB ' System saved as $' ; ; UTILITY SUBROUTINES ; SETDMA: PUSH BC LD C,B$SDMA ; Set dma to de DOSCAL: PUSH DE DOSCA1: PUSH HL CALL BDOS ; Do bdos function call POP HL POP DE POP BC AND A ; Set flags to result RET ; CHAROT: PUSH BC LD C,B$CONO DOSCA2: PUSH DE LD E,A JR DOSCA1 ; FWRITE: PUSH BC LD C,B$WSEQ ; Sequential write JR DOSCAL ; DSTCLO: PUSH BC LD DE,FCB1 LD C,B$CLOS JR DOSCAL ; Close the destination file ; PRSTR: PUSH BC LD C,B$OCS JR DOSCAL ; Print string to console ; GSUSER: PUSH BC LD C,B$USER JR DOSCA2 ; ; RAM AREA ; USER: DEFB 0 ; Storage for default user number ERFLG: DEFB 0 ; Error flag PAGE ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; LOADER MODULE ; ; THIS SECTION IS WRITTEN OUT AS A STAND ALONE COM FILE ; AFTER THE SYSTEM IMAGE IS MOVED DOWN IMMEDIATELY ABOVE ; THIS MODULE. ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ; EQUATES SO SAVE ROUTINES CAN ACCESS HEADER OF LOADER ENV EQU $+0BH BIOSV EQU $+0DH BDOSV EQU $+0FH CCPBAS EQU $+11H CCPSIZ EQU $+13H IMGSIZ EQU $+14H IBASE EQU $+16H LOADER: .PHASE 100H JP LDSTRT DEFB 'Z3ENV' DEFB 1 DEFW 0 ; Current system env address LENV: DEFW 0 ; Env storage address for sys to load LBIOSV: DEFW 0 ; Storage for location 1 LBDOSV: DEFW 0 ; Storage for location 5 LCCPBA: DEFW 0 ; Storage for ccp load address LCCPSZ: DEFB 0 ; Size of ccp in records LIMGSZ: DEFW 0 ; Image block size LDBASE: DEFW 0 ; Target address ; The CCP is saved to this file. Be sure to patch the NZCOM BIOS ; FCB if the name of the file is changed or the drive is changed. CCPFCB: DEFB 'A'-'@' ; Drive to write CCP to (autoselect) DEFB 'NZCOM CCP',0 CCUSER: DEFB 0 ; User area for CCP file (normally 0) DEFB 0,0 DEFS 14H,0 ; FIRST TASK IS TO SAVE NZCOM.CCP USING EXISTING SYSTEM LDSTRT: LD SP,100H ; Set stack up in a safe place LD DE,LSGNON CALL LPRSTR LD HL,(LCCPBA) LD DE,(LDBASE) XOR A SBC HL,DE ; Get relative offset to ccp in image LD DE,BUFFER-80H ; Get buffer start address ADD HL,DE ; Point to start of ccp PUSH HL ; Save start address ; LD A,0FFH CALL LGSUSR LD (LUSER),A ; Get current user CALL LGCD LD (LDRIVE),A ; And current drive LD A,(FCB1+1) CP '?' ; This means help JP Z,LHELP CP '/' ; Option? JR NZ,CPERA ; No, erase nzcom.ccp LD A,(FCB1+2) CP 'F' ; Fast? JP Z,LFAST JP LHELP ; Else help CPERA: LD A,(CCUSER) CALL LGSUSR ; Set user for write of ccp LD DE,CCPFCB ; Point to fcb PUSH DE LD C,B$ERA ; Kill any file of same name CALL BDOS POP DE ; Restore fcb pointer LD C,B$CRAT CALL BDOS ; Create dest file POP DE ; Get save address back LD A,(LCCPSZ) LD C,A LD B,0 ; Set record count ; ; SAVE LOOP ; CPSAV: LD A,B OR C ; Test store completed JR Z,CPSAV1 ; If stored LD HL,80H ADD HL,DE PUSH HL ; Save dma address EX DE,HL CALL LSTDMA ; Point to next xfer area LD DE,CCPFCB CALL LFWRT ; Write record POP DE ; Restore dma address JP NZ,LWRERR ; Error - prob. disk full DEC BC ; Put another JR CPSAV ; Do the next record CPSAV1: CALL LFCLOS ; Close the destination file INC A ; Test for error JP Z,LWRERR ; If there was one ; . . LD HL,CCPFCB+3 ; No datestamp attribute SET 7,(HL) LD C,B$SFA ; Set attributes CALL BDOS ; NOW THAT CCP IS SAVED, MOVE NEW SYSTEM INTO POSITION LFAST: ; LD HL,(LBIOSV) LD (1),HL ; Set warm boot address LD HL,(LBDOSV) LD (6),HL ; And bdos vector LD BC,(LIMGSZ) ; Get number of bytes to move LD DE,(LDBASE) ; And target address LD HL,BUFFER ; Where image is LDIR LD C,37 LD DE,0FFFFH ; Reset all hard drives CALL BDOS LD HL,(LENV) ; Get env address LD DE,22H ADD HL,DE LD A,(HL) INC HL LD H,(HL) LD L,A ; Get message buffer address LD E,2EH ADD HL,DE ; Point to user LD A,(LUSER) LD (HL),A ; Save in message buffer CALL LGSUSR ; Restore user INC HL LD A,(LDRIVE) LD (HL),A ; Set drive in message buffer CALL LSETDK LD A,(004H) ; Get logged du LD C,A ; Into c register for ccp LD HL,(LCCPBA) JP (HL) ; And exit to ccp (which does an f13) ; ; WRITE ERROR HANDLER ; LWRERR: CALL LFCLOS ; Close the destination LD DE,CCPFCB LD C,B$ERA CALL BDOS ; Erase the ccp file LD DE,LWRTRM LPRTXT: CALL LPRSTR ; Print error message and exit LD A,(LUSER) CALL LGSUSR ; Restore user LD A,(LDRIVE) CALL LSETDK JP 0 ; LHELP: LD DE,LHELPM ; Point to help message JR LPRTXT ; Print it and exit ; LSGNON: DEFB 'NZBLITZ loader Vers ' DEFB VERS/10+'0','.',VERS MOD 10+'0',CR,LF,'$' LWRTRM: DEFB BELL,'Disk write error on NZCOM.CCP - aborting!',CR,LF,'$' LHELPM: DEFB ' This program contains a NZCOM operating system.',CR,LF DEFB ' The NZCOM system will replace the current system if',CR,LF DEFB ' the name of this file is typed with no arguments.',CR,LF,LF DEFB ' If a single NZCOM system is always used, the /F option',CR,LF DEFB ' may be used to skip writing NZCOM.CCP.',CR,LF,'$' ; ; UTILITY SUBROUTINES ; LSTDMA: PUSH BC LD C,B$SDMA ; Set dma to de LDOSCA: PUSH DE PUSH HL CALL BDOS ; Do bdos function call POP HL POP DE POP BC AND A ; Set flags to result RET ; LGCD: PUSH BC LD C,B$GCD ; Return current disk JR LDOSCA ; LSETDK: PUSH BC LD C,B$SELD JR LDOSC1 ; LFWRT: PUSH BC LD C,B$WSEQ ; Sequential write JR LDOSCA ; LFCLOS: PUSH BC LD DE,CCPFCB LD C,B$CLOS JR LDOSCA ; Close the destination file ; LPRSTR: PUSH BC LD C,B$OCS JR LDOSCA ; Print string to console ; LGSUSR: PUSH BC LD C,B$USER LDOSC1: LD E,A JR LDOSCA ; ; RAM AREA ; LDRIVE: DEFB 0 LUSER: DEFB 0 BUFFER: .DEPHASE SAVBUF: END