Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

534 lines
20 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**************************************************************************
* 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 <genccpm.h>
/*****************************/
#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; ii<SECSIZ; ii++ ) /* zero out command header */
cmdhdr[ii] = '\0';
cg = cmdhdr; /* code group first */
cg->gtype = 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);
}