; * * * * * * * * * * * * * * * * * * * * * * * ; * * ; * Hard Disk Auto-Boot Installer * ; * * ; * Copyright (C) 1985 AMPRO Computers, Inc. * ; * All rights reserved. * ; * * ; * * * * * * * * * * * * * * * * * * * * * * * ; ; ; Revision history: ; ; Ver Date Who Description ; --- -------- --- ----------------------------------------- ; ; 1.2 1/7/85 fsw Installs users HD$ALV$AVAIL: information ; in bios at boot time. ; ; 1.0 9/20/85 fsw Initial release. ; ; VERS EQU 12 ; version 1.2 ; ; This version saves all the setup disk parameters that the user ; has defined by running SYSGEN, HINIT, and SWAP to the hard disk. ; This user defined information is stored on the last sector (sector 31) ; of the system track, and is used to "patch" the standard BIOS on boot. ; ; The information on this sector will be read somewhere into memory ; by the hard disk boot prom with an offset of 15872 bytes (3E00 hex) ; from the boot dma address. The user's dpbase (256 bytes), the 64 byte ; PHYTAB with the user's logical/physical configuration, the user's ; hard disk DBP's (176 bytes), the users HD$ALV$AVAIL block (12 bytes), ; and the users hard disk byte/block flag (1 byte) are saved in that order. ; (total 509 bytes) ; ; The boot loader is modified to find this offset and install the users ; changes in bios before jumping to cold boot. ; ; NOTES: ; ; Only the system track of the hard disk with SCSI id 0 and LUN 0 will ; be patched. ; ; Only Little Board's jumpered for SCSI initiator id 7 can run this ; utility. ; ; Sector 31 (1F hex) of the hard disk system track is reserved. ; ; Requires special SCSI boot prom . ; ;------------------------------------------------------------------------ ; ; The following equates are entry points into the boot prom ; SETDMA EQU 800FH READTRK EQU 8012H ; BOOT EQU 9000h ; location of boot loader TPA EQU 100H OFFSET EQU (BOOT-TPA)-3 ; -3 for jmp start before patch area WBOOT EQU 0 ; location of bios warm boot ; CONTROL EQU 0 ; board control port ; SREAD EQU 08H ; scsi read data SWRITE EQU 0AH ; scsi write data ; CR EQU 0DH LF EQU 0AH ;----------------------------------------------------------------- ; ORG TPA ; cp/m tpa JMP START ; ;****************************************************************** ;************************Boot loader******************************* ; values set at 0 are patched to users addresses by the program. ; PATCH$START: MVI A,40H ; must turn off rom out control DMA: lxi H,0 ; set dmaadr address call setdma call readtrk ; read first track call readtrk ; read second track ; ; find the user disk information that was loaded in to memory ; from sector 15 of the hard disk ; lhld (dma+1)+offset ; get load address lxi d,15872 ; offset to where hard disk sector 31 ; landed dad d ; sorce address in 'hl' ; ; move the users dpbase into bios ; DDPBAS: lxi d,0 ; patched to destination address lxi b,256 ; number of bytes to move dw 0b0edh ; z80 ldir ; ; move the users phytab into bios ; DOPHY: lxi d,0 ; patched to address of phytbl lxi b,64 dw 0b0edh ; move the 4 bytes with z80 ldir ; ; move the users dpb's into bios ; DODPB: lxi d,0 ; patched to destination address lxi b,176 ; size hard disk DPB's dw 0b0edh ; z80 ldir ; ; move the users HD$ALV$AVAIL info into bios ; HDAVL: lxi d,0 ; patched to destination address lxi b,12 ; bytes to move dw 0b0edh ; z80 ldir ; ; move the users byte, block mode value to bios ; CTLBYT: lxi d,0 ; patched to destination address mov a,m ; 'hl' has location of byte stax d ; store at 'de' location ; GOBIOS: JMP 0 ; go to cold boot ; SIZE$PATCH: equ $-patch$start ; ;********************End of Boot loader**************************** ;****************************************************************** ; START: lxi h,0 ; init new stack and save old dad sp shld oldstk lxi sp,stack ; ; clear the buffer area to zeros ; lxi h,btsec lxi b,1024 ; do 1024 bytes CLEAR: xra a mov m,a inx h dcx b mov a,b ora c jnz clear ; ; move the bios jump table to use it's io, easier ; lhld wboot+1 ; get address of bios mvi l,0 ; begining of bios jmp table lxi d,bj$tbl ; bios jmp table lxi b,64 ; move 64 bytes dw 0b0edh ; z80 ldir ; ; check id of board ; in 29h ; get board id ani 07h ; mask board id cpi 7 ; must be 7 jz signon adi '0' sta shid ; show id setting call puts db cr,lf,'Little Board ID = ' SHID: db ' , must = 7 to run this utility.',0 jmp exit ; ; bios jmp table moved, give signon ; SIGNON: call puts db cr,lf,lf,lf db ' AMPRO Hard Disk Auto-Boot Installer ',cr,lf db ' Copyright (C) 1985 AMPRO Computers, Inc. ',cr,lf db ' Version ',VERS/10+'0','.',VERS MOD 10+'0' db cr,lf,lf db 'This utility will install your current hard disk ' db 'configuration on the system ',cr,lf db 'tracks of the SCSI hard disk drive located at ' db 'SCSI ID 0, LUN 0. ',cr,lf,lf db 'Prior to using this program you must use SYSGEN ' db 'to write the proper size ',cr,lf db 'CP/M system to the system tracks of the SCSI hard ' db 'disk drive from which you ',cr,lf db 'will boot. In addition, you must have already ' db 'used the HINIT and SWAP ',cr,lf db 'utilities to customize your system. ',cr,lf,lf db 'NOTE: The CP/M system you install on the hard ' db 'disk must identical to ',cr,lf db 'the system you are running now. ',cr,lf,lf db 'WARNING!!! ',cr,lf db 'As a safety measure, be sure to backup your hard ' db 'disk before you perform ',cr,lf db 'this function or attempt hard disk auto-booting! ',cr,lf,lf db cr,lf,'Do you wish to continue? (Y/N) ',0 call conin ani 5fh ; make it upper case cpi 'Y' jnz exit ; exits if input not Y ; ; read the current boot sector into memory ; DOIT: mvi a,sread ; scsi read command sta scsicmd lxi h,scsicmd ; point to scsi command lxi d,btsec ; data area mvi a,1 ; target address call scsi jnz scsierr ; not zero results=error ; ; we have the boot sector in memory lets see if sysgen has been ; done on the hard disk. two choices are present for the first byte ; of the AMPRO boot sector either mvi a,xx or lxi h,xxxx , check for ; both. ; ldax d ; call to scsi returns data pointer cpi 3eh ; see if mvi a,x jz next cpi 21h ; could be lxi h,xxx jz next call puts ; neither db cr,lf,'Valid Boot sector not present on hard disk, ' db 'do SYSGEN, HINIT, and SWAP, then retry.',0 jmp exit ; ; figure out the dma address to load track 0 at ; the rest if the info we will find in the bios jmp table ; NEXT: ldax d ; find the lxi h,xxx instruction for cpi 21h ; dma address inx d jnz next xchg ; location of dma address in 'hl' mov a,m inx h mov h,m ; dma address in 'hl' mov l,a shld dma+1 ; set dma address in new boot loader ; ; fix the cold boot address ; lhld wboot+1 ; get address of warm boot from cp/m mvi l,0 ; make it a cold boot shld gobios+1 ; patch jmp in boot loader ; ; get users dpbase, always at cold boot+80h in AMPRO bios ; mvi l,80h ; offset from cold boot shld ddpbas+1 ; load address in boot loader lxi d,udpbase ; move the dpbase to save area lxi b,256 dw 0b0edh ; move it, ldir push d ; save buffer destination address ; ; get address of phytbl ; call gettbl ; get address of next table lxi d,6 ; offset to phtbac dad d ; 'hl'=address of phtbac routine shld gtbl+1 lxi h,0 ; if 'hl'=00 returns address of phytbl GTBL: call 0 ; call phtbac shld dophy+1 ; patch location of phytab in users bios pop d ; get destination address lxi b,64 ; move 64 bytes dw 0b0edh ; z80 ldir push d ; save address ; ; the patch area now contains the phytab as designated by the user. ; ; lets find the users DPB's for the hard disk. Test first to see ; if SWAP has been run ; mvi c,0 ; drive 'A' mvi e,1 ; not first time select call seldsk ; do select to return dpb header address lxi d,10 ; offset to dpb address dad d mov a,m ; get the address of the dpb in 'hl' inx h mov h,m mov l,a mov a,m ; 'hl' has address of DBP cpi 40+1 ; sectors per track information jnc movdpb ; have hard disk DPB call puts db cr,lf,'Run HINIT and SWAP to set up your system first.' db cr,lf,0 pop d ; restore stack for exit jmp exit ; ; ; find address of first hard disk dpb ; MOVDPB: lhld wboot+1 ; get address of bios mvi l,80h ; offset to dpbase lxi d,16*5 ; offset to first hard disk dpb header dad d ; 'hl'= first hard disk lxi d,10 ; offset to dpb address dad d mov a,m ; get the address of the dpb in 'hl' inx h mov h,m mov l,a pop d ; restore destination address shld dodpb+1 ; address of users hd dpb for boot loader lxi b,176 ; move 176 bytes, 11 dpb's dw 0b0edh ; z80 ldir ; ; find the HD$ALV$AVAIL block to save and the scsi controller burst/byte ; mode value and save. needed for Shugart and other non-burst controllers ; push d ; save 'de' call gettbl ; get address of next table lxi d,3 ; dad d ; shld brst+1 BRST: CALL 0 ; call get hd$info pop d ; get table address back push h ; save address of HD$ALV$AVAIL shld hdavl+1 ; save bios address in boot loader lxi b,12 ; bytes to move into table dw 0b0edh ; z80 ldir pop h ; get location of HD$ALV$AVAIL back push d ; save table address lxi d,4 ; dad d ; 'hl' points to address of byte, burst mov a,m inx h mov h,m mov l,a ; address of byte,burst mode byte mov a,m ; get current value, 0 or 1 pop d stax d ; save value shld ctlbyt+1 ; save bios address in boot loader ; ; we have all the information from the users bios in the patch area ; read to overlay the first sector and write back to disk. ; lxi h,btsec ; clean the boot sector lxi b,128 CLEAN: xra a mov m,a inx h dcx b mov a,b ora c jnz clean ; ; overlay the new boot loader on the boot sector ; lxi h,patch$start ; begining of new boot loader lxi d,btsec ; location of boot sector in ram lxi b,size$patch ; number of patch bytes dw 0b0edh ; z80 ldir, movit ; ; now write it back to hard disk ; mvi a,swrite ; scsi write sta scsicmd mvi a,1 ; target address lxi h,scsicmd ; the scsi command lxi d,btsec ; data area call scsi ; do the write jnz scsierr ; if error ; ; boot sector written, now do users swap and disk information ; mvi a,swrite ; scsi write sta scsicmd mvi a,31 ; sector 31 sta lowaddr ; lxi h,scsicmd lxi d,user$tab ; users bios information mvi a,1 call scsi ; do the write jnz scsierr call puts db cr,lf,'Done! You may now boot from hard disk.',cr,lf,lf,0 jmp exit ; ; show any scsi error that may have occured ; SCSIERR: ldax d ; 'de' has address of sense info push psw ; save it ani 0f0h rar ; convert upper nibble to ascii rar rar rar cpi 10 ; alpha or numeric jc num0 adi '7' ; alpha offset (A thru F) jmp num0+1 ; NUM0: adi '0' ; numeric offset (0 thru 9) sta errtyp ; ; do second digit ; pop psw ani 0fh cpi 10 jc num1 ; numeric adi '7' ; alpha offset (A thru F) jmp num1+2 NUM1: adi '0' ; numeric offset (0 thru 9) sta errtyp+1 ; ERRMSG: call puts db cr,lf,'SCSI read/write error, Sense byte = ' ERRTYP: db ' ',cr,lf,lf,0 ; fall thru and exit ; EXIT: xra a lhld oldstk sphl ret ; ; SEND BYTES TO CONSOLE UNTIL ZERO ENCOUNTERED ; PUTS: pop h ; 'hl' has address of msg mov c,m ; get char call conout ; send to comsole mov a,m cpi lf cz wait ; wait 10 ms after lf for slow terminals inx h ; next byte mov a,m ; ana a ; see if end=0 jnz puts+1 ; nope pchl ; hl has return address ; WAIT: mvi b,4 lxi d,0 WAIT1: inx d mov a,e cmp d jnz wait1 dcr b rz jmp wait1 ; ; scsi command block ; SCSICMD db sread ; db 0 ; high address db 0 ; middle address LOWADDR db 0 ; low address db 1 ; number of sectors=1 db 0 ; reserved ;***********************Save area************************** ; OLDSTK: ds 2 ; storage for old stack pointer ; BJ$TBL: ; table of bios jumps CBOOT ds 3 ; cold boot address ds 3 ; warm boot CONST: ds 3 ; console status CONIN: ds 3 ; console character in CONOUT: ds 3 ; console character out ds 3 ; list char out ds 3 ; punch char out ds 3 ; reader char in ds 3 ; home SELDSK: ds 3 ; select disk SETTRK: ds 3 ; set track number SETSEC: ds 3 ; set sector number ds 3 ; set dma address ds 3 ; read disk ds 3 ; write disk ds 3 ; return list status ds 3 ; sector translate GETTBL: ds 3 ; point to next jmp table ds 3 ; getedsk, pointer to 'e' disk prameters ds 3 ; ioinit SCSI: ds 3 ; scsi direct driver ; ds 32 ; 32 byte stack area STACK: EQU $ ; BTSEC: DS 512 ; USER$TAB: UDPBASE: DS 256 ; users dpbase UPHYTAB: DS 64 ; users phytab UHDDPB: DS 176 ; users hd dpb's UHDAVAL: DS 12 ; users hd$alv$avail values BYTEBLK: DS 1 ; scsi controller byte, block value TBL$SIZE: EQU $-user$tab END