/*=======================================================================*/ /*+---------------------------------------------------------------------+*/ /*| |*/ /*| CP/M-Z8K(tm) Bootstrap Writer for the OLIVETTI M20 (Z8000) |*/ /*| |*/ /*| Copyright 1984, Digital Research Inc. |*/ /*| |*/ /*+---------------------------------------------------------------------+*/ /*=======================================================================*/ char *copyrt = "CP/M-Z8K(tm) Ver. 1.1, Copyright 1984, Digital Research Inc."; char *serial = "XXXX-0000-654321"; /* HISTORY ** ** 830801 F. Zlotnick (Zilog) -- written ** 840524 rfw modified includes */ #include "portab.h" #include "osif.h" /* cpm.h and bdos.h replaces with */ #include "stdio.h" /* osif.h 03-15-84 rfw */ #include "bdos.h" #include "xout.h" #define CDATA 0 /* Parameter for map_adr() */ #define DIRSEC 1 /* Parameter for BIOS Write call */ #define SETTRK 10 /* BIOS Function 10 = Set Track */ #define SETSEC 11 /* BIOS Function 11 = Set Sector */ #define BSETDMA 12 /* BIOS Function 12 = Set DMA Addr */ #define WSECTOR 14 /* BIOS Function 14 = Write Sector */ XADDR physdir; /* Segmented address of dirbuf */ struct dpbs idpb; /* Disk Parameter Block */ struct bios_parm ibp; /* BIOS param block for BDOS call 50*/ XADDR physibp; /* physical address of ibp structure*/ extern long map_adr(); /* Function to return physical addr */ #define BPLS 128 /* Bytes per logical sector */ #define BPS 256 /* Bytes per sector */ #define BPS0 128 /* Bytes per sector, trk 0 */ #define SPT 16 /* sectors per track */ #define LSPT 32 /* Logical sectors per track */ #define SYSTRKS 2 /* Number of boot tracks */ #define SYSSIZE SPT*BPS*SYSTRKS /* Max size of bootstrap */ #define STARTRK 1 /* Track number to start on */ FILE *fin; char syscode[SYSSIZE]; /* Hold the entire bootstrap here! */ char *system = "CPMLDR.SYS"; /* Name of the prog to boot */ #ifdef OLIVETTI extern char T0S0[]; /* Track 0 Sector 0 */ extern char T1S0[]; /* Track 1 Sector 0 */ extern char T1S1[]; /* Track 1 Sector 1 */ #define HDRSIZE 24 /* # bytes in track 1 sect 1 header */ #endif struct x_hdr xh; struct x_sg xs; int dsknum; /* Drive number 0-15 = A-P */ main(argc,argv) int argc; char *argv[]; { register int i, j, c; register char *p; long fsize; int curdsk; /* Good to remember, & reset*/ if(argc != 3) usage(); system = *++argv; if( (dsknum = **++argv - 'a') < 0 || dsknum > 15) { printf("putboot: Illegal drive code %c\n", *argv[0]); exit(1); } curdsk = _ret_cdisk(); _get_dpb(map_adr((long) &idpb, CDATA)); /* Physaddr of idpb */ if( (fin = fopenb(system, "r")) == NULL) { printf("putboot: Can't open bootstrap file %s\n", system); exit(1); } fsize = 0L; /* read file header */ p = (char *) &xh; for (i = 0; i < sizeof(xh); i++) *p++ = (char) getc(fin); /* read and count segment headers to get file size */ for (i = 0; i < xh.x_nseg; i++) { p = (char *) &xs; for( j = 0; j < sizeof(xs); j++) *p++ = (char) getc(fin); if( xs.x_sg_typ != X_SG_BSS && xs.x_sg_typ != X_SG_STK) fsize += xs.x_sg_len; } if (fsize > SYSSIZE) { printf("Bootstrap too big\n"); exit(1); } else printf("Bootstrap file is %ld bytes\n", fsize); p = syscode; #ifdef OLIVETTI for( i = 0; i < BPS; i++) *p++ = T1S0[i]; for( i = 0; i < HDRSIZE; i++) *p++ = T1S1[i]; #endif while(fsize--) { if( (c = getc(fin)) == EOF) { printf("Unexpected EOF in %s, %ld left\n",system,fsize); exit(1); } *p++ = c; } /* ** At this point, the entire bootstrap program code and data has been loaded ** into the array named "syscode", preceded by a bunch of PCOS garbage ** which the Olivetti boot PROM expects to find there. Now we use direct ** BIOS calls to write the syscode array out to the proper area on disk. ** For the Olivetti, this is tracks 1 and 2, since track 0 is special. */ putboot(syscode); printf("Bootstrap has been written.\n"); _sel_disk(curdsk); /* reselect original disk*/ } putboot(code) char *code; { register int i; /* Handy index */ register int nlsecs; /* # logical sectors in boot*/ register char *p; /* ptr to next part of code */ int track; /* Current track */ int sector; /* Current sector */ physibp = map_adr( (long) &ibp, CDATA ); nlsecs = SYSTRKS * LSPT; /* size / log secs per trk */ /* Pause for the user to insert disk */ /* pause(drvname); */ #ifdef OLIVETTI /* Olivetti Track 0 Sector 0 is special */ _sel_disk(dsknum); /* select as current disk */ putblk(0, 0, T0S0); #endif p = code; for(i = 0; i < nlsecs; i++) { track = STARTRK + i/LSPT; sector = i%LSPT; putblk(track, sector, p); p += BPLS; } } /* * Function to select a given track for writing on, on the current disk. * Makes use of the BDOS direct BIOS call to issue Bios function 10. */ settrk(n) int n; { ibp.req = SETTRK; /* BIOS request number 10 */ ibp.p1 = (long) n; /* parameter = track # */ _bios_call( physibp ); /* Pass seg ibp address */ } /* * Function to put block i of the boot track. */ putblk(trk, sec, addr) int trk, sec; char *addr; { register int n; _sel_disk(dsknum); /* select as current disk */ settrk(trk); n = sec + 1; /* sector number */ ibp.req = SETSEC; /* BIOS request number 11 */ ibp.p1 = (long) n; /* parameter = sector # */ _bios_call( physibp ); /* Pass seg ibp address */ /* Sector is now set; now set dma address. */ ibp.req = BSETDMA; /* BIOS Request number 12 */ ibp.p1 = map_adr( (long) addr, CDATA); /* param = seg address of I/O buffer */ _bios_call( physibp ); /* Call BIOS */ /* Now can do a write */ ibp.req = WSECTOR; /* BIOS Request number 14 */ ibp.p1 = DIRSEC; /* Complete write immediately */ _bios_call( physibp ); /* Do it! */ } /* * If the user invoked us with the wrong number of args... */ usage() { printf("Usage: putboot \n"); exit(1); } the wrong number of args... */ usage() { printf("Usage: putboot \n"); exit(1); }