/************************************************************************** * G E N C C P M - generates an operating system * * Written by Bill Fitler Nov. 1982 * * GENCCPM is designed to edit the system image for the operating system * and construct an initialized, loadable image for execution. * GENCCPM was originally designed for Concurrent CP/M-86 v2.0, and was * modelled after the old GENSYS. * * Revision history: * 10 Feb 84 whf: bug fixes: addmem, fixupxios_info, and qbuf limits (glp) * 08 Jan 84 glp: added support for Extended DPB * 15 Dec 83 fmb: changed ncondev,nciodev initialization * 5 Oct 83 whf: converted to DRC, broke apart modules, added ADDRs * 9 Sep 83 fmb: compiler bug fix for daend in gentables * 4 Aug 83 fmb: version number -> 3.1 * 14 Jun 83 whf: fix flags & large xios bugs * 8 Jun 83 fmb: handles Multi-User Concurrent 3.1 * 31 May 83 fmb: added sd_xpcns init for Multi-User CCP/M 3.1 . * 23 Feb 83 whf: add patch module * 25 Jan 83 whf: combine all modules for easier maintenance * 20 Jan 83 whf: handles SYSDAT overflow * 19 Nov 82 whf: added BDOS buffering generation. * ************************************************************************/ /*******************************/ /* for serialization purposes: */ char *copynote = "COPYRIGHT (C) 1983, DIGITAL RESEARCH XXXX-0000-654321 $"; /****************************************************/ /* up front for patching: Note the internal EOS (0) */ char *clearx = "\033H\033E\0\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; /****************************************************/ /****** include files ********/ #define MAINMODULE 1 #include /*****************************/ #ifdef CCPM BYTE *edsysver = "GENCCPM v2.1 [2/7/84]\n"; #endif #ifdef CMPM BYTE *edsysver = "GENCCPM v3.1 [2/7/84]\n"; #endif BYTE mainmtitle[50] = ""; /* room for title of main menu */ MENU *mainmenu = NULLPTRI; /* pointers to main menu items */ MENU *memmenu=NULLPTRI; /* memory management menu */ MENU *syspmenu=NULLPTRI; /* system parameters menu */ MENU *rspmenu=NULLPTRI; /* rsp edit menu */ /**************************************************************************/ /* main module */ /**************************************************************************/ main(ac,av) WORD ac; BYTE **av; { BYTE cmds[CMDSLEN]; /* input area of commands */ BOOLEAN sysvalid(); /* is the system data valid? */ fprintf(stderr,edsysver); if( isatty(1) ) /* standard output to a tty? */ clearit = clearx; /* yes, do clear screens */ else clearit = ""; /* no, don't do clear screens */ init_sysdat(); /* initialize system data */ init_edsys(); /* initialize menus */ if( ac>1 ) { /* if any command line arguments */ copyargs(ac-1,av+1,cmds); /* simplify cmd parser */ verbose = TRUE; /* turn on wordiness by default */ domenu(cmds,mainmenu); /* do what they've asked for */ } FOREVER { /* work with user for a while */ if(doit) { /* does user want to quit? */ if( sysvalid() ) /* has evrything been defined? */ break; /* let them if everything okay */ press_return(); /* let them view the message(s) */ } printf("%s",clearit); /* clear the screen */ prtmenu(mainmtitle,mainmenu); /* display user options */ printf(PROMPT); /* prompt user */ if( gets(cmds)!=cmds ){ /* on end of file */ close(0); /* standard input */ open("CON:",0); /* reopen to the console */ close(1); /* standard output: assume redirection */ open("CON:",1); /* reopen to console */ clearit = clearx; /* do the clear screen routine */ continue; /* force user to input blank line */ } if( *cmds==NULL ) /* blank line of input */ continue; /* don't bother with blank lines here */ domenu(cmds,mainmenu); /* do what they've asked for */ } /*****************************/ /* we've got user input */ make_sysfile(); /* construct system image/use old one*/ gentables(); /* generate the tables */ fixups(); /* odds and ends on the system image */ wrapup(); /* close files, etc. */ } /* copyargs: copies args to cbuf for uniform parsing */ copyargs(ac,av,cbuf) WORD ac; BYTE **av; BYTE *cbuf; { for( *cbuf=NULL; ac>0; --ac, ++av ) { strcat(cbuf,*av); strcat(cbuf," "); } } /**************************************************************************/ /* init_sysdat: reads SYStem DATa info from: /* 1. SYSFILE, if it exists /* 2. SYSMOD, o.w. if this is the case, it also checks /* for existence of all other required modules /**************************************************************************/ VOID init_sysdat() { REG WORD sf; /* file descriptor for SysData read */ LONG grpseek(); /* seek the data group */ UWORD goffs; /* loc of group */ EXTERN DLIST *rsps, *dirsearch(); /* directory search fn */ BYTE *addmem(); /* for initializing memory */ BYTE *chkmodules(), *xlist[80]; /* list of missing modules */ printf("GENerate SYStem image for %s\n",VERLABEL); init_sds(sdat_area); /* initialize program ptrs */ /***************************************************/ if(chkmodules(xlist)==NULLPTR && (sf=BROPEN(SYSMOD)) > 0 ) { printf("Constructing new %s file\n",SYSFILE); /*** procedureize this? for cmd use */ dogensys=TRUE; /* no SYSFILE, read from modules */ if(grpseek(sf,GTYPDATA)<0) /* seek start of data group */ CRASH("no data group in SYSDAT module\n"); read(sf,sdat_area,SDLEN); /* read in the data group */ /**** may have to init arbitrarily some MAX values here ****/ xtrapds = *sd_pul; /* default number of extra process descriptors */ totqcbs = *sd_qul; /* default number of qcbs */ totopen = 0x40; /* arbitrary total open files & locked recs */ qbuflen = *sd_qmalen; /* init'ed to bytes */ rsps = dirsearch("*.RSP"); /* init RSP list */ addmem("400,6000,400"); /* start out with this memory allocation */ close(sf); /* don't need it for a while */ sf=BROPEN(XIOSMOD); /* let's go read the XIOS info */ if( grpseek(sf,GTYPDATA) <= 0 ) /* if there is not a data group */ grpseek(sf,GTYPCODE); /* use the code group instead */ goffs = lseek( sf,0L,1 ); /* where did we end up? */ initxios_info(sf,goffs); /* grab info from there */ close(sf); /* don't need it for a while */ } else if( FALSE && /****** temporarily disable this option!!! ***/ (sf=BROPEN(SYSFILE)) >= 0 ){ /* does SYSFILE exist? *******/ printf("Editting %s file\n",SYSFILE); dogensys = FALSE; /* tell them not to gen a new system */ grpseek(sf,GTYPDATA); /* get data module in OS */ read(sf,sdat_area,SDLEN); /* read in the info */ /**** may have to trace down some lists for MAX values ****/ close(sf); /* don't need it for a while */ } else { /***************************************************/ if( xlist == NULLPTR ) { fprintf(stderr,"Can't find %s module\n",SYSMOD); } else { fprintf(stderr,"Can't find these modules:\n%s\n",xlist); } fprintf(stderr,"Please find the correct modules\n"); exit(1); } /**** end module check ****/ if( VERSION != *sd_mpmvn ){ /* a little version number checking */ USERR("%s works on OS version %x\n",edsysver,VERSION); USERR("Sys Data area found was from OS version %x\n",*sd_mpmvn); USERR("Please find correct .SYS or %s files\n",MODEXT); exit(1); } } /**************************************************************************/ #define RDAC 4 /* Read Access mode for 'access' */ BYTE * chkmodules(badbuf) /* place to put missing module names */ BYTE *badbuf; { *badbuf=0; if( access(SYSMOD,RDAC) ) {strcat(badbuf,SYSMOD);strcat(badbuf," ");} if( access(SUPMOD,RDAC) ) {strcat(badbuf,SUPMOD);strcat(badbuf," ");} if( access(RTMMOD,RDAC) ) {strcat(badbuf,RTMMOD);strcat(badbuf," ");} if( access(MEMMOD,RDAC) ) {strcat(badbuf,MEMMOD);strcat(badbuf," ");} if( access(CIOMOD,RDAC) ) {strcat(badbuf,CIOMOD);strcat(badbuf," ");} if( access(BDOSMOD,RDAC) ) {strcat(badbuf,BDOSMOD);strcat(badbuf," ");} if( access(XIOSMOD,RDAC) ) {strcat(badbuf,XIOSMOD);strcat(badbuf," ");} if( *badbuf ) return badbuf; else return NULLPTR; } /**************************************************************************/ /* init_edsys: initializes program variables and menus /**************************************************************************/ VOID init_edsys() { MENU *m; /* mainmenu pointer */ MENU *me; /* memory partitions menu */ MENU *s; /* sys params menu */ MENU *r; /* rsp menu */ MENU *bldmenu(); /* func to build the menu list */ BYTE *drvmsg; /* destination drive message */ BYTE *delmsg; /* delete old SYSFILE msg */ BYTE getdrive(); /* get default drive */ BYTE *help(); /* func to help user */ BYTE *doxios(); /* func to do xios menu */ BYTE *dosysp(); /* func to do sys param menu */ BYTE *dorsp(); /* func to display & handle RSPs */ BYTE *dolbl(); /* func to modify version label */ BYTE *domem(); /* handle memory partitions */ BYTE *doxbufs(); /* func to construct bdos buffers */ BYTE *addmem(); /* add mem part */ BYTE *delmem(); /* delete mem part */ BYTE *rspinclude(); /* include a bunch of RSPs */ BYTE *rspexclude(); /* exclude a bunch of RSPs */ BYTE *doexit(); /* exit the main menu */ sprintf(mainmtitle,"*** %s %s Main Menu ***",VERLABEL,PROGNAME); destdrv = getdrive(); /* returns the default drive */ drvmsg = malloc(50); sprintf(drvmsg,"%s Output To (Destination) Drive",SYSFILE); delmsg = malloc(55); sprintf(delmsg,"Delete (instead of rename) old %s file\n",SYSFILE); m=NULLPTR; me=NULLPTR; s=NULLPTR; r=NULLPTR; /* init menu pointers */ /***** initialize menus *****/ m=bldmenu(m,MPROC,help,"help","GENCCPM Help"); m=bldmenu(m,MBOOL,&verbose,"verbose","More Verbose GENCCPM Messages"); m=bldmenu(m,MDRIV,&destdrv,"destdrive",drvmsg); m=bldmenu(m,MBOOL,&doclean,"deletesys",delmsg); m=bldmenu(m,MPROC,dosysp,"sysparams","Display/Change System Parameters"); s=bldmenu(s,MDRIV,sd_srchdisk,"sysdrive","System Drive"); s=bldmenu(s,MDRIV,sd_tempdisk,"tmpdrive","Temporary File Drive"); s=bldmenu(s,MBOOL,sd_dayfile,"cmdlogging","Command Day/File Logging at Console"); s=bldmenu(s,MBOOL,sd_cmode,"compatmode","CP/M FCB Compatibility Mode"); s=bldmenu(s,MWORD,sd_mmp,"memmax","Maximum Memory per Process (paragraphs)"); s=bldmenu(s,MBYTE,sd_popen_max,"openmax","Open Files per Process Maximum"); s=bldmenu(s,MBYTE,sd_plock_max,"lockmax","Locked Records per Process Maximum\n"); s=bldmenu(s,MWORD,sd_mpmseg,"osstart","Starting Paragraph of Operating System"); s=bldmenu(s,MWORD,&totopen,"nopenfiles","Number of Open File and Locked Record Entries"); s=bldmenu(s,MBYTE,&xtrapds,"npdescs","Number of Process Descriptors"); s=bldmenu(s,MBYTE,&totqcbs,"nqcbs","Number of Queue Control Blocks"); s=bldmenu(s,MWORD,&qbuflen,"qbufsize","Queue Buffer Total Size in bytes"); s=bldmenu(s,MBYTE,sd_nflags,"nflags","Number of System Flags"); m=bldmenu(m,MPROC,domem,"memory","Display/Change Memory Allocation Partitions"); me=bldmenu(me,MPROC,addmem,"add","ADD Memory Partition(s)"); me=bldmenu(me,MPROC,delmem,"delete","DELETE Memory Partition(s)"); m=bldmenu(m,MPROC,doxbufs,"diskbuffers","Display/Change Disk Buffer Allocation"); if( dogensys ) m=bldmenu(m,MPROC,dolbl,"oslabel","Display/Change Operating System Label"); m=bldmenu(m,MPROC,dorsp,"rsps","Display/Change RSP list\n"); r=bldmenu(r,MPROC,rspinclude,"include","Include RSPs"); r=bldmenu(r,MPROC,rspexclude,"exclude","Exclude RSPs"); m=bldmenu(m,MPROC,doexit,"gensys","I'm finished changing things, go GEN a SYStem\n"); mainmenu=m; /* assign now to longer name */ memmenu=me; /* yah yah */ syspmenu=s; /* " " */ rspmenu=r; /* " " */ } BYTE * doexit() /* this is really a boolean... */ { doit = TRUE; return NULLPTR; } /**************************************************************************/ /* sysvalid: validates system data. /* also calculates certain SYSDAT variables, in the course of validation. /**************************************************************************/ #define BYTE_ADJUST(xx) if( xx > 0xFF ) xx = 0xFF #define ALIGN(xx) (((xx)+0xF) & 0xFFF0) BOOLEAN sysvalid() { REG BOOLEAN isv; /* is valid? */ BOOLEAN xiosvalid(); /* check xios info */ LOCAL WORD nmparts; /* number of memory partitions */ isv = TRUE; /* innocent until proven guilty */ if( totopen < *sd_popen_max ) { USERR("'nopenfiles' is less than 'openmax'. Please adjust.\n"); isv = FALSE; } if( totopen < *sd_plock_max ) { USERR("'nopenfiles' is less than 'lockmax'. Please adjust.\n"); isv = FALSE; } if( (nmparts=cntmlist(memroot)) <= 0 ) { USERR("Memory Partitions need to be adjusted\n"); isv = FALSE; } if( !xiosvalid() ) { /* xios info needs work? */ USERR("Disk Performance Buffers need to be adjusted\n"); isv=FALSE; } if( !isv ) USERR("Please correct the System Parameters\n"); return isv; } /**************************************************************************/ /* make_sysfile: responsible for preparing SYSfile image for table generation /* and /* if( dousesys ) /* doctors up SYSFILE for appropriate table generation and fixups /* else constructs a SYSfile from assembled modules /**************************************************************************/ VOID make_sysfile() { BYTE fbuf[20]; /* file name buffer */ PUTDRV(fbuf,NEWSYS); unlink(fbuf); /* this is the file we'll be using */ if( (fns=BWCREAT(fbuf))<0 ) { /* try to open for output */ USERR("can't open new .SYS file (%s)\n",fbuf); exit(1); } if( dogensys ) gensys(); /* make a new SYS file from modules */ else edsys(); /* edit the old SYS file */ } /**************************************************************************/ /* gensys: generates a new SYS file image from modules /**************************************************************************/ VOID gensys() { WORD fxm; /* file descriptor for xios mod */ BYTE fbuf[20]; if( doclean ) { /* clean up the SYSFILE first? */ PUTDRV(fbuf,SYSFILE); unlink(fbuf); /* delete if there... */ } if(verbose) printf("Generating new SYS file\n"); FCHECK(fns); /* File error check */ write(fns,cmdhdr,SECSIZ); /* write out a (dummy) command hdr */ genfix(); /* remember the sysdat & sup fixups */ clsup = xfergrp(SUPMOD,GTYPCODE); clos_label = writelbl(); /* write the OS label (returns 0 if none exists) */ if( clos_label != 0 ) *sd_verptr = clsup<<4; /* fill in offset of label rel sup code seg */ genfix(); clrtm = xfergrp(RTMMOD,GTYPCODE); genfix(); clmem = xfergrp(MEMMOD,GTYPCODE); genfix(); clcio = xfergrp(CIOMOD,GTYPCODE); genfix(); clbdos= xfergrp(BDOSMOD,GTYPCODE); clnet = 0; fxm = BROPEN(XIOSMOD); /* look at XIOS module */ if( grpseek(fxm,GTYPDATA) >= 0){ /* is there a data group?*/ USERR("XIOS has separate code and data (small model)"); USERR("This is not supported in this O.S.: use 8080 model."); exit(1); } else { pure_xios = FALSE; clxios = 0; } cltotal = clsup+clos_label+clrtm+clmem+clcio+clbdos+clnet+clxios; /*** finished writing the code portion of NEWSYS ***/ fldstart = lseek(fns,0L,1); /* where in file SYSDAT gets written */ dsstart = *sd_mpmseg + cltotal; /* where in memory SYSDAT gets loaded */ dlsysdat = xfergrp(SYSMOD,GTYPDATA); /* system data area, fixed later */ if( pure_xios ) dlxios = xferpart_grp(fxm,GTYPDATA,dlsysdat); else { genfix(); dlxios = xferpart_grp(fxm,GTYPCODE,dlsysdat); } close(fxm); /* don't need this file descriptor */ dltotal = dlsysdat+dlxios; /* this will change later */ /*** finished writing STATIC data portion of NEWSYS ***/ /*** fill in sysdat here ***/ sd_supmod->ep_eseg = sd_supmod->ep_iseg = *sd_mpmseg; sd_rtmmod->ep_eseg = sd_rtmmod->ep_iseg = sd_supmod->ep_eseg+clsup+clos_label; sd_memmod->ep_eseg = sd_memmod->ep_iseg = sd_rtmmod->ep_eseg+clrtm; sd_ciomod->ep_eseg = sd_ciomod->ep_iseg = sd_memmod->ep_eseg+clmem; sd_bdosmod->ep_eseg = sd_bdosmod->ep_iseg = sd_ciomod->ep_eseg+clcio; sd_xiosmod->ep_eseg = sd_xiosmod->ep_iseg = sd_bdosmod->ep_eseg+clbdos; if( pure_xios ) /* compute xios offsets */ sd_xiosmod->ep_ioff = 0; /* separate code */ else sd_xiosmod->ep_ioff = dlsysdat<<4; /* mixed code & data, after sysdat */ sd_xiosmod->ep_eoff = sd_xiosmod->ep_ioff + 3; } /****************************************************************************/ genfix() /* subroutine to remember SYSDAT & Super fixups */ { LONG fa; fa = lseek(fns,0L,1); /* where are we in this file? */ fixlater(fa+6,F_PUT,&dsstart); /* fix the SYSDAT address */ fixlater(fa+8,F_PUT,&(sd_supmod->ep_eoff)); /* Supervisor entry offset */ fixlater(fa+10,F_PUT,&(sd_supmod->ep_eseg)); /* " " segment */ } /**************************************************************************/ /* edsys: edit the old SYS file image. /* - copies old sys file into new /* - if( donew_xios ) will patch in a new XIOS from module /**************************************************************************/ VOID edsys() { if(verbose) printf("Editting old SYS file\n"); write(fns,cmdhdr,SECSIZ); /* leave room for command hdr */ cltotal = xfergrp(SYSFILE,GTYPCODE); dltotal = xfergrp(SYSFILE,GTYPDATA); if( donew_xios ) { ; /* need to read 'xt' from XIOS module */ } else { ; /* need to init 'xt' from sysdat */ } } /**************************************************************************/ /* fixups: inserts updated SYSDAT page into NEWSYS file, and does some /* address fixups /**************************************************************************/ VOID fixups() { REG WORD ii; /* counter */ ADDR gg; /* temp var */ GROUP *cg, *dg; /* group ptrs */ UWORD genmfl(); /* (re)Gen Memory Free List */ if(verbose) printf("Doing fixups\n"); FCHECK(fns); /* File error check */ /*** fixup the memory list ***/ if(verbose) { printf("SYS image load map:\n"); printf(" Code starts at %4.4x\n",*sd_mpmseg); printf(" Data starts at %4.4x\n",dsstart); printf(" Tables start at %4.4x\n",(dsotables>>4)+dsstart); printf(" RSPs start at %4.4x\n",(dsotables>>4)+dsstart+dltables); printf(" XIOS buffers start at %4.4x\n",rsvd_seg); printf(" End of OS at %4.4x\n",*sd_endseg); } if( trimlist(*sd_mpmseg,*sd_endseg) ) { /* mem part list trimmed? */ printf("Trimming memory partitions. New list:"); dspmlist(memroot); lseek( fns, locmfl, 0 ); gg = (dlsysdat+dlxios)<<4; genmfl(gg); /*****/ } /*** fixup XIOS info ***/ fixupxios_info(); /* fixes the buffer info (DPH info) */ /*** fixup the command header ***/ for( ii=0; iigtype = GTYPCODE; /* init all code vars */ cg->glen = cltotal; /* total length of code groups */ cg->gmin = cltotal; /* min length of code group */ cg->gabase = *sd_mpmseg; /* loads at absolute address */ dg = cmdhdr + sizeof(*cg); /* data group next */ dg->gtype = GTYPDATA; /* init all data vars */ dg->glen = dltotal; /* total length of data group+tables */ dg->gmin = dltotal; /* min length of data group */ dg->gabase = cg->gabase+cltotal;/* abs addr of start of system data */ lseek( fns, 0L, 0 ); /* seek the beginning of NEWSYS */ write(fns,cmdhdr,SECSIZ); /* write out the command header */ /*** fixup the sysdat page ***/ lseek(fns,fldstart,0); /* seek there in file */ write(fns,sdat_area,SDLEN); /* put it into the file */ /*** take care of the little fixes ***/ fixfile(); /* fixes from the list */ } /**************************************************************************/ /* wrapup: closes files /**************************************************************************/ VOID wrapup() { BYTE buf1[20], buf2[20]; if(verbose) printf("Wrapping up\n"); FCHECK(fns); /* File error check */ lseek(fns,0L,2); /* flush NEWSYS buffers? */ if(strlen(edsysver) != write(fns,edsysver,strlen(edsysver))) { USERR("WRITE FAILURE - the disk may be too full\n"); exit(1); } close(fns); /* all finished with NEWSYS */ PUTDRV(buf1,OLDSYS); unlink(buf1); PUTDRV(buf2,SYSFILE); rename(buf2,buf1); PUTDRV(buf1,NEWSYS); rename(buf1,buf2); }