Files
org-hyperion-cules/config.c
Jan Jaeger dac4c43355 Remove tuntap dependencies
git-svn-id: file:///home/jj/hercules.svn/trunk@1561 956126f8-22a0-4046-8f4a-272fa8102e63
2003-06-30 09:04:34 +00:00

2066 lines
69 KiB
C

/* CONFIG.C (c) Copyright Roger Bowler, 1999-2003 */
/* ESA/390 Configuration Builder */
/* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2003 */
/*-------------------------------------------------------------------*/
/* This module builds the configuration tables for the Hercules */
/* ESA/390 emulator. It reads information about the processors */
/* and I/O devices from a configuration file. It allocates */
/* main storage and expanded storage, initializes control blocks, */
/* and creates detached threads to handle console attention */
/* requests and to maintain the TOD clock and CPU timers. */
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/* Additional credits: */
/* TOD clock offset contributed by Jay Maynard */
/* Dynamic device attach/detach by Jan Jaeger */
/* OSTAILOR parameter by Jay Maynard */
/* PANRATE parameter by Reed H. Petty */
/* CPUPRIO parameter by Jan Jaeger */
/* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2003 */
/*-------------------------------------------------------------------*/
#include "hercules.h"
#include "devtype.h"
#include "opcode.h"
#if !defined(_GEN_ARCH)
#if defined(_ARCHMODE3)
#define _GEN_ARCH _ARCHMODE3
#include "config.c"
#undef _GEN_ARCH
#endif
#if defined(_ARCHMODE2)
#define _GEN_ARCH _ARCHMODE2
#include "config.c"
#undef _GEN_ARCH
#endif
#if defined(OPTION_FISHIO)
#include "w32chan.h"
#endif // defined(OPTION_FISHIO)
typedef struct _DEVARRAY
{
U16 cuu1;
U16 cuu2;
} DEVARRAY;
extern DEVENT device_handler_table[];
/*-------------------------------------------------------------------*/
/* Internal macro definitions */
/*-------------------------------------------------------------------*/
#define SPACE ((BYTE)' ')
/*-------------------------------------------------------------------*/
/* Global data areas */
/*-------------------------------------------------------------------*/
SYSBLK sysblk;
/*-------------------------------------------------------------------*/
/* External GUI control */
/*-------------------------------------------------------------------*/
#ifdef EXTERNALGUI
int extgui = 0; /* 1=external gui active */
#endif /*EXTERNALGUI*/
/*-------------------------------------------------------------------*/
/* Static data areas */
/*-------------------------------------------------------------------*/
static int stmt = 0; /* Config statement number */
#ifdef EXTERNALGUI
static BYTE buf[1024]; /* Config statement buffer */
#else /*!EXTERNALGUI*/
static BYTE buf[256]; /* Config statement buffer */
#endif /*EXTERNALGUI*/
static BYTE *keyword; /* -> Statement keyword */
static BYTE *operand; /* -> First argument */
#define MAX_ARGS 12 /* Max #of additional args */
static int addargc; /* Number of additional args */
static BYTE *addargv[MAX_ARGS]; /* Additional argument array */
/*-------------------------------------------------------------------*/
/* Subroutine to parse an argument string. The string that is passed */
/* is modified in-place by inserting null characters at the end of */
/* each argument found. The returned array of argument pointers */
/* then points to each argument found in the original string. Any */
/* argument that begins with '#' comment indicator causes early */
/* termination of the parsing and is not included in the count. Any */
/* argument found that starts with a double-quote character causes */
/* all characters following the double-quote up to the next double- */
/* quote to be included as part of that argument. The quotes them- */
/* selves are not considered part of any argument and are ignored. */
/* p Points to string to be parsed. */
/* maxargc Maximum allowable number of arguments. (Prevents */
/* overflowing the pargv array) */
/* pargv Pointer to buffer for argument pointer array. */
/* pargc Pointer to number of arguments integer result. */
/* Returns number of arguments found. (same value as at *pargc) */
/*-------------------------------------------------------------------*/
int parse_args (BYTE* p, int maxargc, BYTE** pargv, int* pargc)
{
for (*pargc = 0; *pargc < MAX_ARGS; ++*pargc) addargv[*pargc] = NULL;
*pargc = 0;
*pargv = NULL;
while (*p && *pargc < maxargc)
{
while (*p && isspace(*p)) p++; if (!*p) break; // find start of arg
if (*p == '#') break; // stop on comments
*pargv = p; ++*pargc; // count new arg
while (*p && !isspace(*p) && *p != '\"') p++; if (!*p) break; // find end of arg
if (*p == '\"')
{
if (p == *pargv) *pargv = p+1;
while (*++p && *p != '\"'); if (!*p) break; // find end of quoted string
}
*p++ = 0; // mark end of arg
pargv++; // next arg ptr
}
return *pargc;
}
static void delayed_exit (int exit_code)
{
/* Delay exiting is to give the system
* time to display the error message. */
usleep(100000);
exit(exit_code);
}
/*-------------------------------------------------------------------*/
/* Subroutine to read a statement from the configuration file */
/* The statement is then parsed into keyword, operand, and */
/* additional arguments. The output values are: */
/* keyword Points to first word of statement */
/* operand Points to second word of statement */
/* addargc Contains number of additional arguments */
/* addargv An array of pointers to each additional argument */
/* Returns 0 if successful, -1 if end of file */
/*-------------------------------------------------------------------*/
static int read_config (BYTE *fname, FILE *fp)
{
int i; /* Array subscript */
int c; /* Character work area */
int stmtlen; /* Statement length */
int lstarted; /* Indicate if non-whitespace*/
/* has been seen yet in line */
while (1)
{
/* Increment statement number */
stmt++;
/* Read next statement from configuration file */
for (stmtlen = 0, lstarted = 0; ;)
{
/* Read character from configuration file */
c = fgetc(fp);
/* Check for I/O error */
if (ferror(fp))
{
fprintf(stderr, _("HHCCF001S Error reading file %s line %d: %s\n"),
fname, stmt, strerror(errno));
delayed_exit(1);
}
/* Check for end of file */
if (stmtlen == 0 && (c == EOF || c == '\x1A'))
return -1;
/* Check for end of line */
if (c == '\n' || c == EOF || c == '\x1A')
break;
/* Ignore nulls and carriage returns */
if (c == '\0' || c == '\r') continue;
/* Check if it is a white space and no other character yet */
if(!lstarted && isspace(c)) continue;
lstarted=1;
/* Check that statement does not overflow buffer */
if (stmtlen >= (int)(sizeof(buf) - 1))
{
fprintf(stderr, _("HHCCF002S File %s line %d is too long\n"),
fname, stmt);
delayed_exit(1);
}
/* Append character to buffer */
buf[stmtlen++] = c;
} /* end for(stmtlen) */
/* Remove trailing blanks and tabs */
while (stmtlen > 0 && (buf[stmtlen-1] == SPACE
|| buf[stmtlen-1] == '\t')) stmtlen--;
buf[stmtlen] = '\0';
/* Ignore comments and null statements */
if (stmtlen == 0 || buf[0] == '*' || buf[0] == '#')
continue;
/* Parse the statement just read */
parse_args (buf, MAX_ARGS, addargv, &addargc);
#if defined(OPTION_DYNAMIC_LOAD)
if(config_command)
{
if( config_command(addargc, addargv) )
continue;
}
#endif /*defined(OPTION_DYNAMIC_LOAD)*/
/* Move the first two arguments to separate variables */
keyword = addargv[0];
operand = addargv[1];
addargc = (addargc > 2) ? (addargc-2) : (0);
for (i = 0; i < MAX_ARGS; i++)
{
if (i < (MAX_ARGS-2)) addargv[i] = addargv[i+2];
else addargv[i] = NULL;
}
break;
} /* end while */
return 0;
} /* end function read_config */
/*-------------------------------------------------------------------*/
/* Function to Parse compound device numbers */
/* Syntax : CCUU[-CUU][,CUU..][.nn][...] */
/* Examples : 200-23F */
/* 200,201 */
/* 200.16 */
/* 200-23F,280.8 */
/* etc... */
/* - is the range specification (from CUU to CUU) */
/* , is the separator */
/* . is the count indicator (nn is decimal) */
/* 1st parm is the specification string as specified above */
/* 2nd parm is the address of an array of DEVARRAY */
/* Return value : 0 - Parsing error, etc.. */
/* >0 - Size of da */
/* */
/* NOTE : A basic validity check is made for the following : */
/* All CUUs must belong on the same channel */
/* (this check is to eventually pave the way to a formal */
/* channel/cu/device architecture) */
/* no 2 identical CCUUs */
/* ex : 200,300 : WRONG */
/* 200.12,200.32 : WRONG */
/* 2FF.2 : WRONG */
/* NOTE : caller should free the array returned in da if the return */
/* value is not 0 */
/*-------------------------------------------------------------------*/
static size_t parse_devnums(const char *spec,DEVARRAY **da)
{
size_t gcount; /* Group count */
size_t i; /* Index runner */
char *grps; /* Pointer to current devnum group */
char *sc; /* Specification string copy */
DEVARRAY *dgrs; /* Device groups */
U16 cuu1,cuu2; /* CUUs */
char *strptr; /* strtoul ptr-ptr */
BYTE basechan=0; /* Channel for all CUUs */
int duplicate; /* duplicated CUU indicator */
int badcuu; /* offending CUU */
sc=malloc(strlen(spec)+1);
strcpy(sc,spec);
/* Split by ',' groups */
gcount=0;
grps=strtok(sc,",");
dgrs=NULL;
while(grps!=NULL)
{
if(dgrs==NULL)
{
dgrs=malloc(sizeof(DEVARRAY));
}
else
{
dgrs=realloc(dgrs,(sizeof(DEVARRAY))*(gcount+1));
}
cuu1=strtoul(grps,&strptr,16);
switch(*strptr)
{
case 0: /* Single CUU */
cuu2=cuu1;
break;
case '-': /* CUU Range */
cuu2=strtoul(&strptr[1],&strptr,16);
if(*strptr!=0)
{
fprintf(stderr,_("HHCCF053E Incorrect second device number in device range near character %c\n"),*strptr);
free(dgrs);
return(0);
}
break;
case '.': /* CUU Count */
cuu2=cuu1+strtoul(&strptr[1],&strptr,10);
cuu2--;
if(*strptr!=0)
{
fprintf(stderr,_("HHCCF054E Incorrect Device count near character %c\n"),*strptr);
free(dgrs);
return(0);
}
break;
default:
fprintf(stderr,_("HHCCF055E Incorrect device address specification near character %c\n"),*strptr);
free(dgrs);
return(0);
}
/* Check cuu1 <= cuu2 */
if(cuu1>cuu2)
{
fprintf(stderr,_("HHCCF056E Incorrect device address range. %4.4X < %4.4X\n"),cuu2,cuu1);
free(dgrs);
return(0);
}
if(gcount==0)
{
basechan=(cuu1 >> 8) & 0xff;
}
badcuu=-1;
if(((cuu1 >> 8) & 0xff) != basechan)
{
badcuu=cuu1;
}
else
{
if(((cuu2 >> 8) & 0xff) != basechan)
{
badcuu=cuu2;
}
}
if(badcuu>=0)
{
fprintf(stderr,_("HHCCF057E %4.4X is on wrong channel (1st device defined on channel %2.2X)\n"),badcuu,basechan);
free(dgrs);
return(0);
}
/* Check for duplicates */
duplicate=0;
for(i=0;i<gcount;i++)
{
/* check 1st cuu not within existing range */
if(cuu1>=dgrs[i].cuu1 && cuu1<=dgrs[i].cuu2)
{
duplicate=1;
break;
}
/* check 2nd cuu not within existing range */
if(cuu2>=dgrs[i].cuu1 && cuu1<=dgrs[i].cuu2)
{
duplicate=1;
break;
}
/* check current range doesn't completelly overlap existing range */
if(cuu1<dgrs[i].cuu1 && cuu2>dgrs[i].cuu2)
{
duplicate=1;
break;
}
}
if(duplicate)
{
fprintf(stderr,_("HHCCF058E Some or all devices in %4.4X-%4.4X duplicate devices already defined\n"),cuu1,cuu2);
free(dgrs);
return(0);
}
dgrs[gcount].cuu1=cuu1;
dgrs[gcount].cuu2=cuu2;
gcount++;
grps=strtok(NULL,",");
}
free(sc);
*da=dgrs;
return(gcount);
}
/*-------------------------------------------------------------------*/
/* Function to build system configuration */
/*-------------------------------------------------------------------*/
void build_config (BYTE *fname)
{
int rc; /* Return code */
int i,j; /* Array subscript */
int scount; /* Statement counter */
int cpu; /* CPU number */
FILE *fp; /* Configuration file pointer*/
BYTE *sserial; /* -> CPU serial string */
BYTE *smodel; /* -> CPU model string */
BYTE *sversion; /* -> CPU version string */
BYTE *smainsize; /* -> Main size string */
BYTE *sxpndsize; /* -> Expanded size string */
BYTE *scnslport; /* -> Console port number */
BYTE *snumcpu; /* -> Number of CPUs */
BYTE *snumvec; /* -> Number of VFs */
BYTE *sarchmode; /* -> Architectural mode */
BYTE *sloadparm; /* -> IPL load parameter */
BYTE *ssysepoch; /* -> System epoch */
BYTE *stzoffset; /* -> System timezone offset */
BYTE *sdiag8cmd; /* -> Allow diagnose 8 */
BYTE *stoddrag; /* -> TOD clock drag factor */
BYTE *sostailor; /* -> OS to tailor system to */
BYTE *spanrate; /* -> Panel refresh rate */
BYTE *sdevtmax; /* -> Max device threads */
BYTE *scpuprio; /* -> CPU thread priority */
BYTE *spgmprdos; /* -> Program product OS OK */
BYTE *scodepage; /* -> Code page */
#if defined(_FEATURE_ECPSVM)
BYTE *secpsvmlevel; /* -> ECPS:VM level (or 'no')*/
#endif /*defined(_FEATURE_ECPSVM)*/
#if defined(OPTION_HTTP_SERVER)
BYTE *shttpport; /* -> HTTP port number */
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
BYTE *sshrdport; /* -> Shared device port nbr */
#endif /*defined(OPTION_SHARED_DEVICES)*/
#ifdef OPTION_IODELAY_KLUDGE
BYTE *siodelay; /* -> I/O delay value */
#endif /*OPTION_IODELAY_KLUDGE*/
BYTE *scckd; /* -> CCKD parameters */
BYTE loadparm[8]; /* Load parameter (EBCDIC) */
BYTE version = 0x00; /* CPU version code */
int dfltver = 1; /* Default version code */
U32 serial; /* CPU serial number */
U16 model; /* CPU model number */
U16 mainsize; /* Main storage size (MB) */
U16 xpndsize; /* Expanded storage size (MB)*/
U16 cnslport; /* Console port number */
U16 numcpu; /* Number of CPUs */
U16 numvec; /* Number of VFs */
#if defined(OPTION_HTTP_SERVER)
U16 httpport; /* HTTP port number */
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
U16 shrdport; /* Shared device port number */
#endif /*defined(OPTION_SHARED_DEVICES)*/
int archmode; /* Architectural mode */
S32 sysepoch; /* System epoch year */
S32 tzoffset; /* System timezone offset */
int diag8cmd; /* Allow diagnose 8 commands */
int toddrag; /* TOD clock drag factor */
U64 ostailor; /* OS to tailor system to */
int panrate; /* Panel refresh rate */
int cpuprio; /* CPU thread priority */
BYTE pgmprdos; /* Program product OS OK */
BYTE *sdevnum; /* -> Device number string */
BYTE *sdevtype; /* -> Device type string */
U16 devnum; /* Device number */
DEVARRAY *devnarray; /* Compound device numbers */
size_t devncount; /* size of comp devnum array */
int baddev; /* devblk attach failed ind */
int devtmax; /* Max number device threads */
#if defined(_FEATURE_ECPSVM)
int ecpsvmavail; /* ECPS:VM Available flag */
int ecpsvmlevel; /* ECPS:VM declared level */
#endif /*defined(_FEATURE_ECPSVM)*/
#ifdef OPTION_IODELAY_KLUDGE
int iodelay=-1; /* I/O delay value */
#endif /*OPTION_IODELAY_KLUDGE*/
BYTE c; /* Work area for sscanf */
#ifdef OPTION_SELECT_KLUDGE
int dummyfd[OPTION_SELECT_KLUDGE]; /* Dummy file descriptors --
this allows the console to
get a low fd when the msg
pipe is opened... prevents
cygwin from thrashing in
select(). sigh */
#endif
#if defined(OPTION_CONFIG_SYMBOLS)
BYTE **newargv;
#endif
SET_IC_INITIAL_STATE;
#if !defined(OPTION_CONFIG_SYMBOLS)
UNREFERENCED(j);
#endif
/* Initialize SETMODE and set user authority */
SETMODE(INIT);
#ifdef OPTION_SELECT_KLUDGE
/* Reserve some fd's to be used later for the message pipes */
for (i = 0; i < OPTION_SELECT_KLUDGE; i++)
dummyfd[i] = dup(fileno(stderr));
#endif
if((scodepage = getenv("HERCULES_CP")))
set_codepage(scodepage);
else
set_codepage("default");
/* Open the configuration file */
fp = fopen (fname, "r");
if (fp == NULL)
{
fprintf(stderr, _("HHCCF003S Cannot open file %s: %s\n"),
fname, strerror(errno));
delayed_exit(1);
}
/* Set the default system parameter values */
serial = 0x000001;
model = 0x0586;
mainsize = 2;
xpndsize = 0;
cnslport = 3270;
numcpu = 1;
numvec = MAX_CPU_ENGINES;
memset (loadparm, 0x4B, 8);
sysepoch = 1900;
tzoffset = 0;
diag8cmd = 0;
toddrag = 1;
#if defined(_390)
archmode = ARCH_390;
#else
archmode = ARCH_370;
#endif
ostailor = OS_NONE;
panrate = PANEL_REFRESH_RATE_SLOW;
cpuprio = 15;
pgmprdos = PGM_PRD_OS_RESTRICTED;
devtmax = MAX_DEVICE_THREADS;
#if defined(_FEATURE_ECPSVM)
ecpsvmavail = 0;
ecpsvmlevel = 20;
#endif /*defined(_FEATURE_ECPSVM)*/
#if defined(OPTION_HTTP_SERVER)
httpport = 0;
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
shrdport = 0;
#endif /*defined(OPTION_SHARED_DEVICES)*/
/* Read records from the configuration file */
for (scount = 0; ; scount++)
{
/* Read next record from the configuration file */
if ( read_config (fname, fp) )
{
fprintf(stderr, _("HHCCF004S No device records in file %s\n"),
fname);
delayed_exit(1);
}
/* Exit loop if first device statement found */
if (strlen(keyword) <= 4
&& sscanf(keyword, "%x%c", &rc, &c) == 1)
break;
/* ISW */
/* Also exit if keyword contains '-', ',' or '.' */
/* Added because device statements may now be a compound device number specification */
if(strchr(keyword,'-'))
{
break;
}
if(strchr(keyword,'.'))
{
break;
}
if(strchr(keyword,','))
{
break;
}
/* Clear the operand value pointers */
sserial = NULL;
smodel = NULL;
sversion = NULL;
smainsize = NULL;
sxpndsize = NULL;
scnslport = NULL;
snumcpu = NULL;
snumvec = NULL;
sarchmode = NULL;
sloadparm = NULL;
ssysepoch = NULL;
stzoffset = NULL;
sdiag8cmd = NULL;
stoddrag = NULL;
sostailor = NULL;
spanrate = NULL;
scpuprio = NULL;
sdevtmax = NULL;
spgmprdos = NULL;
scodepage = NULL;
#if defined(_FEATURE_ECPSVM)
secpsvmlevel = NULL;
#endif /*defined(_FEATURE_ECPSVM)*/
#if defined(OPTION_HTTP_SERVER)
shttpport = NULL;
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
sshrdport = NULL;
#endif /*defined(OPTION_SHARED_DEVICES)*/
#ifdef OPTION_IODELAY_KLUDGE
siodelay = NULL;
#endif /*OPTION_IODELAY_KLUDGE*/
scckd = NULL;
/* Check for old-style CPU statement */
if (scount == 0 && addargc == 5 && strlen(keyword) == 6
&& sscanf(keyword, "%x%c", &rc, &c) == 1)
{
sserial = keyword;
smodel = operand;
smainsize = addargv[0];
sxpndsize = addargv[1];
scnslport = addargv[2];
snumcpu = addargv[3];
sloadparm = addargv[4];
}
else
{
#if defined(OPTION_DYNAMIC_LOAD)
if (!strcasecmp (keyword, "ldmod"))
{
hdl_load(operand, 0);
for(i = 0; i < addargc; i++)
hdl_load(addargv[i], 0);
addargc = 0;
}
else
#endif /*defined(OPTION_DYNAMIC_LOAD)*/
if (strcasecmp (keyword, "cpuserial") == 0)
{
sserial = operand;
}
else if (strcasecmp (keyword, "cpumodel") == 0)
{
smodel = operand;
}
else if (strcasecmp (keyword, "mainsize") == 0)
{
smainsize = operand;
}
else if (strcasecmp (keyword, "xpndsize") == 0)
{
sxpndsize = operand;
}
else if (strcasecmp (keyword, "cnslport") == 0)
{
scnslport = operand;
}
else if (strcasecmp (keyword, "numcpu") == 0)
{
snumcpu = operand;
}
else if (strcasecmp (keyword, "numvec") == 0)
{
snumvec = operand;
}
else if (strcasecmp (keyword, "loadparm") == 0)
{
sloadparm = operand;
}
else if (strcasecmp (keyword, "sysepoch") == 0)
{
ssysepoch = operand;
}
else if (strcasecmp (keyword, "tzoffset") == 0)
{
stzoffset = operand;
}
else if (strcasecmp (keyword, "diag8cmd") == 0)
{
sdiag8cmd = operand;
}
#ifdef OPTION_TODCLOCK_DRAG_FACTOR
else if (strcasecmp (keyword, "toddrag") == 0)
{
stoddrag = operand;
}
#endif /*OPTION_TODCLOCK_DRAG_FACTOR*/
#ifdef PANEL_REFRESH_RATE
else if (strcasecmp (keyword, "panrate") == 0)
{
spanrate = operand;
}
#endif /*PANEL_REFRESH_RATE*/
else if (strcasecmp (keyword, "ostailor") == 0)
{
sostailor = operand;
}
else if (strcasecmp (keyword, "archmode") == 0)
{
sarchmode = operand;
}
else if (strcasecmp (keyword, "cpuverid") == 0)
{
sversion = operand;
}
else if (strcasecmp (keyword, "cpuprio") == 0)
{
scpuprio = operand;
}
else if (strcasecmp (keyword, "devtmax") == 0)
{
sdevtmax = operand;
}
else if (strcasecmp (keyword, "pgmprdos") == 0)
{
spgmprdos = operand;
}
else if (strcasecmp (keyword, "codepage") == 0)
{
scodepage = operand;
}
#if defined(_FEATURE_ECPSVM)
/* ECPS:VM support */
else if(strcasecmp(keyword, "ecps:vm") == 0)
{
secpsvmlevel=operand;
}
#endif /*defined(_FEATURE_ECPSVM)*/
#ifdef OPTION_IODELAY_KLUDGE
else if (strcasecmp (keyword, "iodelay") == 0)
{
siodelay = operand;
}
#endif /*OPTION_IODELAY_KLUDGE*/
#if defined(OPTION_CONFIG_SYMBOLS)
else if (strcasecmp(keyword,"defsym")==0)
{
char *subval;
/* Execute this operation immediatelly */
if(operand==NULL)
{
fprintf(stderr, _("HHCCF059S Error in %s line %d: "
"Missing symbol name on DEFSYM statement\n"),
fname, stmt);
delayed_exit(1);
}
if(addargc!=1)
{
fprintf(stderr, _("HHCCF060S Error in %s line %d: "
"DEFSYM requires a single symbol value (include quotation marks if necessary)\n"),
fname, stmt);
delayed_exit(1);
}
subval=resolve_symbol_string(addargv[0]);
if(subval!=NULL)
{
set_symbol(operand,subval);
free(subval);
}
else
{
set_symbol(operand,addargv[0]);
}
addargc--;
}
#endif /* defined(OPTION_CONFIG_SYMBOLS) */
#if defined(OPTION_HTTP_SERVER)
else if (strcasecmp (keyword, "httpport") == 0)
{
shttpport = operand;
if(addargc > 0)
{
if(!strcasecmp(addargv[0],"auth"))
sysblk.httpauth = 1;
else if(strcasecmp(addargv[0],"noauth"))
{
fprintf(stderr, _("HHCCF005S Error in %s line %d: "
"Unrecognized argument %s\n"),
fname, stmt, addargv[0]);
delayed_exit(1);
}
addargc--;
}
if(addargc > 0)
{
sysblk.httpuser = strdup(addargv[1]);
if(--addargc)
sysblk.httppass = strdup(addargv[2]);
else
{
fprintf(stderr, _("HHCCF006S Error in %s line %d: "
"Userid, but no password given %s\n"),
fname, stmt, addargv[1]);
delayed_exit(1);
}
addargc--;
}
}
else if (strcasecmp (keyword, "httproot") == 0)
{
if (operand)
sysblk.httproot = strdup(operand);
else
{
fprintf(stderr, _("HHCCF007S Error in %s line %d: "
"Missing argument.\n"),
fname, stmt);
delayed_exit(1);
}
}
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
else if (strcasecmp (keyword, "shrdport") == 0)
{
sshrdport = operand;
}
#endif /*defined(OPTION_SHARED_DEVICES)*/
else if (strcasecmp (keyword, "cckd") == 0)
{
scckd = operand;
}
else
{
logmsg( _("HHCCF008E Error in %s line %d: "
"Unrecognized keyword %s\n"),
fname, stmt, keyword);
operand = "";
addargc = 0;
}
/* Check for one and only one operand */
if (operand == NULL || addargc != 0)
{
logmsg( _("HHCCF009E Error in %s line %d: "
"Incorrect number of operands\n"),
fname, stmt);
}
}
if(scodepage)
set_codepage(scodepage);
if (sarchmode != NULL)
{
#if defined(_370)
if (strcasecmp (sarchmode, arch_name[ARCH_370]) == 0)
{
archmode = ARCH_370;
}
else
#endif
#if defined(_390)
if (strcasecmp (sarchmode, arch_name[ARCH_390]) == 0)
{
archmode = ARCH_390;
}
else
#endif
#if defined(_900)
if (strcasecmp (sarchmode, arch_name[ARCH_900]) == 0)
{
archmode = ARCH_900;
}
else
#endif
{
fprintf(stderr, _("HHCCF010S Error in %s line %d: "
"Unknown or unsupported ARCHMODE specification %s\n"),
fname, stmt, sarchmode);
delayed_exit(1);
}
}
sysblk.arch_mode = archmode;
#if defined(_900)
/* Indicate if z/Architecture is supported */
sysblk.arch_z900 = sysblk.arch_mode != ARCH_390;
#endif
/* Parse CPU version number operand */
if (sversion != NULL)
{
if (strlen(sversion) != 2
|| sscanf(sversion, "%hhx%c", &version, &c) != 1)
{
fprintf(stderr, _("HHCCF012S Error in %s line %d: "
"%s is not a valid CPU version code\n"),
fname, stmt, sversion);
delayed_exit(1);
}
dfltver = 0;
}
/* Parse CPU serial number operand */
if (sserial != NULL)
{
if (strlen(sserial) != 6
|| sscanf(sserial, "%x%c", &serial, &c) != 1)
{
fprintf(stderr, _("HHCCF051S Error in %s line %d: "
"%s is not a valid serial number\n"),
fname, stmt, sserial);
delayed_exit(1);
}
}
/* Parse CPU model number operand */
if (smodel != NULL)
{
if (strlen(smodel) != 4
|| sscanf(smodel, "%hx%c", &model, &c) != 1)
{
fprintf(stderr, _("HHCCF012S Error in %s line %d: "
"%s is not a valid CPU model\n"),
fname, stmt, smodel);
delayed_exit(1);
}
}
/* Parse main storage size operand */
if (smainsize != NULL)
{
if (sscanf(smainsize, "%hu%c", &mainsize, &c) != 1
|| mainsize < 2 || mainsize > 1024)
{
fprintf(stderr, _("HHCCF013S Error in %s line %d: "
"Invalid main storage size %s\n"),
fname, stmt, smainsize);
delayed_exit(1);
}
}
/* Parse expanded storage size operand */
if (sxpndsize != NULL)
{
if (sscanf(sxpndsize, "%hu%c", &xpndsize, &c) != 1
|| xpndsize > 1024)
{
fprintf(stderr, _("HHCCF014S Error in %s line %d: "
"Invalid expanded storage size %s\n"),
fname, stmt, sxpndsize);
delayed_exit(1);
}
}
/* Parse console port number operand */
if (scnslport != NULL)
{
if (sscanf(scnslport, "%hu%c", &cnslport, &c) != 1
|| cnslport == 0)
{
fprintf(stderr, _("HHCCF015S Error in %s line %d: "
"Invalid console port number %s\n"),
fname, stmt, scnslport);
delayed_exit(1);
}
}
/* Parse CPU thread priority operand */
if (scpuprio != NULL)
{
if (sscanf(scpuprio, "%d%c", &cpuprio, &c) != 1)
{
fprintf(stderr, _("HHCCF016S Error in %s line %d: "
"Invalid CPU thread priority %s\n"),
fname, stmt, scpuprio);
delayed_exit(1);
}
#if !defined(NO_SETUID)
if(sysblk.suid != 0 && cpuprio < 0)
logmsg(_("HHCCF017W Hercules is not running as setuid root, "
"cannot raise CPU priority\n"));
#endif /*!defined(NO_SETUID)*/
}
else
sysblk.cpuprio = cpuprio;
/* Parse number of CPUs operand */
if (snumcpu != NULL)
{
if (sscanf(snumcpu, "%hu%c", &numcpu, &c) != 1
|| numcpu < 1 || numcpu > MAX_CPU_ENGINES)
{
fprintf(stderr, _("HHCCF018S Error in %s line %d: "
"Invalid number of CPUs %s\n"),
fname, stmt, snumcpu);
delayed_exit(1);
}
}
/* Parse number of VFs operand */
if (snumvec != NULL)
{
#ifdef _FEATURE_VECTOR_FACILITY
if (sscanf(snumvec, "%hu%c", &numvec, &c) != 1
|| numvec > MAX_CPU_ENGINES)
{
fprintf(stderr, _("HHCCF019S Error in %s line %d: "
"Invalid number of VFs %s\n"),
fname, stmt, snumvec);
delayed_exit(1);
}
#else /*!_FEATURE_VECTOR_FACILITY*/
logmsg(_("HHCCF020W Vector Facility support not configured\n"));
#endif /*!_FEATURE_VECTOR_FACILITY*/
}
/* Parse load parameter operand */
if (sloadparm != NULL)
{
if (strlen(sloadparm) > 8)
{
fprintf(stderr, _("HHCCF021S Error in %s line %d: "
"Load parameter %s exceeds 8 characters\n"),
fname, stmt, sloadparm);
delayed_exit(1);
}
/* Convert the load parameter to EBCDIC */
memset (loadparm, 0x4B, 8);
for (i = 0; i < (int)strlen(sloadparm); i++)
loadparm[i] = host_to_guest(sloadparm[i]);
}
/* Parse system epoch operand */
if (ssysepoch != NULL)
{
if (strlen(ssysepoch) != 4
|| sscanf(ssysepoch, "%d%c", &sysepoch, &c) != 1
|| ((sysepoch != 1900) && (sysepoch != 1928)
&& (sysepoch != 1960) && (sysepoch != 1988)
&& (sysepoch != 1970)
))
{
fprintf(stderr, _("HHCCF022S Error in %s line %d: "
"%s is not a valid system epoch.\n"
"Patch config.c to expand the table\n"),
fname, stmt, ssysepoch);
delayed_exit(1);
}
}
/* Parse timezone offset operand */
if (stzoffset != NULL)
{
if (strlen(stzoffset) != 5
|| sscanf(stzoffset, "%d%c", &tzoffset, &c) != 1
|| (tzoffset < -2359) || (tzoffset > 2359))
{
fprintf(stderr, _("HHCCF023S Error in %s line %d: "
"%s is not a valid timezone offset\n"),
fname, stmt, stzoffset);
delayed_exit(1);
}
}
/* Parse diag8cmd operand */
if (sdiag8cmd != NULL)
{
if (strcasecmp (sdiag8cmd, "enable") == 0)
diag8cmd = 1;
else
if (strcasecmp (sdiag8cmd, "disable") == 0)
diag8cmd = 0;
else
{
fprintf(stderr, _("HHCCF052S Error in %s line %d: "
"%s: invalid argument\n"),
fname, stmt, sdiag8cmd);
delayed_exit(1);
}
}
#ifdef OPTION_TODCLOCK_DRAG_FACTOR
/* Parse TOD clock drag factor operand */
if (stoddrag != NULL)
{
if (sscanf(stoddrag, "%u%c", &toddrag, &c) != 1
|| toddrag < 1 || toddrag > 10000)
{
fprintf(stderr, _("HHCCF024S Error in %s line %d: "
"Invalid TOD clock drag factor %s\n"),
fname, stmt, stoddrag);
delayed_exit(1);
}
}
#endif /*OPTION_TODCLOCK_DRAG_FACTOR*/
#ifdef PANEL_REFRESH_RATE
/* Parse panel refresh rate operand */
if (spanrate != NULL)
{
switch (toupper((char)spanrate[0]))
{
case 'F': /* fast */
panrate = PANEL_REFRESH_RATE_FAST;
break;
case 'S': /* slow */
panrate = PANEL_REFRESH_RATE_SLOW;
break;
default:
if (sscanf(spanrate, "%u%c", &panrate, &c) != 1
|| panrate < (1000/CLK_TCK) || panrate > 5000)
{
fprintf(stderr, _("HHCCF025S Error in %s line %d: "
"Invalid panel refresh rate %s\n"),
fname, stmt, spanrate);
delayed_exit(1);
}
}
}
#endif /*PANEL_REFRESH_RATE*/
/* Parse OS tailoring operand */
if (sostailor != NULL)
{
if (strcasecmp (sostailor, "OS/390") == 0)
{
ostailor = OS_OS390;
}
else if (strcasecmp (sostailor, "VSE") == 0)
{
ostailor = OS_VSE;
}
else if (strcasecmp (sostailor, "VM") == 0)
{
ostailor = OS_VM;
}
else if (strcasecmp (sostailor, "LINUX") == 0)
{
ostailor = OS_LINUX;
}
else if (strcasecmp (sostailor, "NULL") == 0)
{
ostailor = 0xFFFFFFFFFFFFFFFFULL;
}
else if (strcasecmp (sostailor, "QUIET") == 0)
{
ostailor = 0;
}
else
{
fprintf(stderr, _("HHCCF026S Error in %s line %d: "
"Unknown OS tailor specification %s\n"),
fname, stmt, sostailor);
delayed_exit(1);
}
}
/* Parse Maximum number of device threads */
if (sdevtmax != NULL)
{
if (sscanf(sdevtmax, "%d%c", &devtmax, &c) != 1
|| devtmax < -1)
{
fprintf(stderr, _("HHCCF027S Error in %s line %d: "
"Invalid maximum device threads %s\n"),
fname, stmt, sdevtmax);
delayed_exit(1);
}
}
/* Parse program product OS allowed */
if (spgmprdos != NULL)
{
if (strcasecmp (spgmprdos, "LICENSED") == 0)
{
pgmprdos = PGM_PRD_OS_LICENSED;
}
/* Handle silly British spelling. */
else if (strcasecmp (spgmprdos, "LICENCED") == 0)
{
pgmprdos = PGM_PRD_OS_LICENSED;
}
else if (strcasecmp (spgmprdos, "RESTRICTED") == 0)
{
pgmprdos = PGM_PRD_OS_RESTRICTED;
}
else
{
fprintf(stderr, _("HHCCF028S Error in %s line %d: "
"Invalid program product OS permission %s\n"),
fname, stmt, spgmprdos);
delayed_exit(1);
}
}
#if defined(_FEATURE_ECPSVM)
/* Parse ECPS:VM level */
if(secpsvmlevel != NULL)
{
while(1) /* Dummy while loop for break support */
{
ecpsvmavail=0;
ecpsvmlevel=0;
if(strcasecmp(secpsvmlevel,"no")==0)
{
ecpsvmavail=0;
break;
}
if(strcasecmp(secpsvmlevel,"yes")==0)
{
ecpsvmavail=1;
ecpsvmlevel=20;
break;
}
ecpsvmavail=1;
if (sscanf(secpsvmlevel, "%d%c", &ecpsvmlevel, &c) != 1)
{
fprintf(stderr, _("HHCCF051W Error in %s line %d: "
"Invalid ECPS:VM value : %s. NO Assumed\n"),
fname, stmt, secpsvmlevel);
ecpsvmavail=0;
ecpsvmlevel=0;
break;
}
break;
}
sysblk.ecpsvm.available=ecpsvmavail;
sysblk.ecpsvm.level=ecpsvmlevel;
}
#endif /*defined(_FEATURE_ECPSVM)*/
#if defined(OPTION_HTTP_SERVER)
/* Parse http port number operand */
if (shttpport != NULL)
{
if (sscanf(shttpport, "%hu%c", &httpport, &c) != 1
|| httpport == 0 || (httpport < 1024 && httpport != 80) )
{
fprintf(stderr, _("HHCCF029S Error in %s line %d: "
"Invalid HTTP port number %s\n"),
fname, stmt, shttpport);
delayed_exit(1);
}
}
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
/* Parse shared device port number operand */
if (sshrdport != NULL)
{
if (sscanf(sshrdport, "%hu%c", &shrdport, &c) != 1
|| shrdport < 1024 )
{
fprintf(stderr, _("HHCCF029S Error in %s line %d: "
"Invalid SHRDPORT port number %s\n"),
fname, stmt, sshrdport);
delayed_exit(1);
}
}
#endif /*defined(OPTION_SHARED_DEVICES)*/
#ifdef OPTION_IODELAY_KLUDGE
/* Parse I/O delay value */
if (siodelay != NULL)
{
if (sscanf(siodelay, "%d%c", &iodelay, &c) != 1)
{
fprintf(stderr, _("HHCCF030S Error in %s line %d: "
"Invalid I/O delay value: %s\n"),
fname, stmt, siodelay);
delayed_exit(1);
}
}
#endif /*OPTION_IODELAY_KLUDGE*/
/* Parse cckd value value */
if (scckd)
cckd_command (scckd, 0);
} /* end for(scount) */
/* Obtain main storage */
sysblk.mainsize = mainsize * 1024 * 1024;
sysblk.mainstor = malloc(sysblk.mainsize);
if (sysblk.mainstor == NULL)
{
fprintf(stderr, _("HHCCF031S Cannot obtain %dMB main storage: %s\n"),
mainsize, strerror(errno));
delayed_exit(1);
}
/* Obtain main storage key array */
sysblk.storkeys = malloc(sysblk.mainsize / STORAGE_KEY_UNITSIZE);
if (sysblk.storkeys == NULL)
{
fprintf(stderr, _("HHCCF032S Cannot obtain storage key array: %s\n"),
strerror(errno));
delayed_exit(1);
}
#if 0 /*DEBUG-JJ-20/03/2000*/
/* Mark selected frames invalid for debugging purposes */
for (i = 64 ; i < (sysblk.mainsize / STORAGE_KEY_UNITSIZE); i += 2)
if (i < (sysblk.mainsize / STORAGE_KEY_UNITSIZE) - 64)
sysblk.storkeys[i] = STORKEY_BADFRM;
else
sysblk.storkeys[i++] = STORKEY_BADFRM;
#endif
if (xpndsize != 0)
{
#ifdef _FEATURE_EXPANDED_STORAGE
/* Obtain expanded storage */
sysblk.xpndsize = xpndsize * (1024*1024 / XSTORE_PAGESIZE);
sysblk.xpndstor = malloc(sysblk.xpndsize * XSTORE_PAGESIZE);
if (sysblk.xpndstor == NULL)
{
fprintf(stderr, _("HHCCF033S Cannot obtain %dMB expanded storage: "
"%s\n"),
xpndsize, strerror(errno));
delayed_exit(1);
}
#else /*!_FEATURE_EXPANDED_STORAGE*/
logmsg(_("HHCCF034W Expanded storage support not installed\n"));
#endif /*!_FEATURE_EXPANDED_STORAGE*/
} /* end if(sysblk.xpndsize) */
/* Save the console port number */
sysblk.cnslport = cnslport;
#if defined(OPTION_HTTP_SERVER)
sysblk.httpport = httpport;
#endif /*defined(OPTION_HTTP_SERVER)*/
#if defined(OPTION_SHARED_DEVICES)
sysblk.shrdport = shrdport;
#endif /*defined(OPTION_SHARED_DEVICES)*/
sysblk.diag8cmd = diag8cmd;
#if defined(_370) || defined(_390)
if(dfltver)
version =
#if defined(_900)
(sysblk.arch_mode == ARCH_900) ? 0x00 :
#endif
0xFD;
#endif
/* Build CPU identifier */
sysblk.cpuid = ((U64)version << 56)
| ((U64)serial << 32)
| ((U64)model << 16);
/* Set the load parameter */
memcpy (sysblk.loadparm, loadparm, 8);
/* Initialize locks, conditions, and attributes */
initialize_lock (&sysblk.todlock);
initialize_lock (&sysblk.mainlock);
initialize_lock (&sysblk.intlock);
initialize_lock (&sysblk.sigplock);
initialize_condition (&sysblk.broadcast_cond);
initialize_detach_attr (&sysblk.detattr);
#if defined(OPTION_CPU_UTILIZATION)
for(i = 0; i < MAX_CPU_ENGINES; i++)
initialize_lock (&sysblk.regs[i].accum_wait_time_lock);
#endif /*defined(OPTION_CPU_UTILIZATION)*/
#if defined(OPTION_W32_CTCI)
tt32_init();
#endif /* defined(OPTION_W32_CTCI) */
#if defined(OPTION_FISHIO)
InitIOScheduler // initialize i/o scheduler...
(
sysblk.arch_mode, // (for calling execute_ccw_chain)
DEVICE_THREAD_PRIORITY, // (for calling fthread_create)
MAX_DEVICE_THREAD_IDLE_SECS, // (maximum device thread wait time)
devtmax // (maximum #of device threads allowed)
);
#else // !defined(OPTION_FISHIO)
initialize_lock (&sysblk.ioqlock);
initialize_condition (&sysblk.ioqcond);
/* Set max number device threads */
sysblk.devtmax = devtmax;
sysblk.devtwait = sysblk.devtnbr =
sysblk.devthwm = sysblk.devtunavail = 0;
#endif // defined(OPTION_FISHIO)
init_sockdev();
/* Set up the system TOD clock offset: compute the number of
seconds from the designated year to 1970 for TOD clock
adjustment, then add in the specified time zone offset
The problem here, is that no formular can do it right, as
we have to do it wrong in 1928 and 1988 case !
*/
switch (sysepoch) {
case 1988:
sysblk.todoffset = (18*365 + 4) * -86400ULL;
break;
case 1960:
sysblk.todoffset = (10*365 + 3) * 86400ULL;
break;
case 1928:
sysblk.todoffset = (42*365 + 10) * 86400ULL;
break;
case 1970:
sysblk.todoffset = 0;
break;
default:
sysepoch = 1900;
case 1900:
sysblk.todoffset = (70*365 + 17) * 86400ULL;
break;
}
/* Compute the timezone offset in seconds and crank that in */
tzoffset = (tzoffset/100)*3600 + (tzoffset%100)*60;
sysblk.todoffset += tzoffset;
/* Convert the TOD clock offset to microseconds */
sysblk.todoffset *= 1000000;
/* Convert for the 'hercules internal' format */
sysblk.todoffset <<= 4;
/* Set the TOD clock drag factor */
sysblk.toddrag = toddrag;
/* Set the system OS tailoring value */
sysblk.pgminttr = ostailor;
/* Set the system program product OS restriction flag */
sysblk.pgmprdos = pgmprdos;
#ifdef OPTION_IODELAY_KLUDGE
/* Set I/O delay value */
if (iodelay > 0)
sysblk.iodelay = iodelay;
else if (ostailor == OS_LINUX)
sysblk.iodelay = OPTION_IODELAY_LINUX_DEFAULT;
#endif /*OPTION_IODELAY_KLUDGE*/
/* Set the panel refresh rate */
sysblk.panrate = panrate;
#if defined(_FEATURE_REGION_RELOCATE)
/* Initialize base zone storage view (SIE compat) */
for(i = 0; i < FEATURE_SIE_MAXZONES; i++)
{
sysblk.zpb[i].mso = 0;
sysblk.zpb[i].msl = (sysblk.mainsize - 1) >> 20;
if(sysblk.xpndsize)
{
sysblk.zpb[i].eso = 0;
sysblk.zpb[i].esl = (sysblk.xpndsize * XSTORE_PAGESIZE - 1) >> 20;
}
else
{
sysblk.zpb[i].eso = -1;
sysblk.zpb[i].esl = -1;
}
}
#endif
/* Gabor Hoffer (performance option) */
for (i = 0; i < 256; i++)
{
#if defined(_370)
s370_opcode_table [i] = opcode_table [i][ARCH_370];
#endif
#if defined(_390)
s390_opcode_table [i] = opcode_table [i][ARCH_390];
#endif
#if defined(_900)
z900_opcode_table [i] = opcode_table [i][ARCH_900];
#endif
}
/* Initialize the CPU registers */
for (cpu = 0; cpu < MAX_CPU_ENGINES; cpu++)
{
/* Initialize the processor address register for STAP */
sysblk.regs[cpu].cpuad = cpu;
/* And set the CPU mask bit for this cpu */
sysblk.regs[cpu].cpumask = 0x80000000 >> cpu;
/* Initialize storage views (SIE compat) */
sysblk.regs[cpu].mainstor = sysblk.mainstor;
sysblk.regs[cpu].storkeys = sysblk.storkeys;
sysblk.regs[cpu].mainlim = sysblk.mainsize - 1;
/* Initialize the TOD offset field for this CPU */
sysblk.regs[cpu].todoffset = sysblk.todoffset;
/* Perform initial CPU reset */
initial_cpu_reset (sysblk.regs + cpu);
#if defined(_FEATURE_VECTOR_FACILITY)
sysblk.regs[cpu].vf = &sysblk.vf[cpu];
#endif /*defined(_FEATURE_VECTOR_FACILITY)*/
initialize_condition (&sysblk.regs[cpu].intcond);
#if defined(_FEATURE_SIE)
sysblk.sie_regs[cpu] = sysblk.regs[cpu];
sysblk.sie_regs[cpu].hostregs = &sysblk.regs[cpu];
sysblk.regs[cpu].guestregs = &sysblk.sie_regs[cpu];
#endif /*defined(_FEATURE_SIE)*/
} /* end for(cpu) */
/* Parse the device configuration statements */
while(1)
{
/* First two fields are device number and device type */
sdevnum = keyword;
sdevtype = operand;
if (sdevnum == NULL || sdevtype == NULL)
{
fprintf(stderr, _("HHCCF035S Error in %s line %d: "
"Missing device number or device type\n"),
fname, stmt);
delayed_exit(1);
}
/* Parse devnum */
devncount=parse_devnums(sdevnum,&devnarray);
if(devncount==0)
{
fprintf(stderr, _("HHCCF036S Error in %s line %d: "
"%s is not a valid device number(s) specification\n"),
fname, stmt, sdevnum);
delayed_exit(1);
}
#if defined(OPTION_CONFIG_SYMBOLS)
newargv=malloc(addargc*sizeof(char *));
#endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
for(baddev=0,i=0;i<(int)devncount;i++)
{
for(devnum=devnarray[i].cuu1;devnum<=devnarray[i].cuu2;devnum++)
{
#if defined(OPTION_CONFIG_SYMBOLS)
char wrkbfr[16];
snprintf(wrkbfr,sizeof(wrkbfr),"%3.3x",devnum);
set_symbol("cuu",wrkbfr);
snprintf(wrkbfr,sizeof(wrkbfr),"%4.4x",devnum);
set_symbol("ccuu",wrkbfr);
snprintf(wrkbfr,sizeof(wrkbfr),"%3.3X",devnum);
set_symbol("CUU",wrkbfr);
snprintf(wrkbfr,sizeof(wrkbfr),"%4.4X",devnum);
set_symbol("CCUU",wrkbfr);
for(j=0;j<addargc;j++)
{
newargv[j]=resolve_symbol_string(addargv[j]);
}
/* Build the device configuration block */
rc=attach_device(devnum, sdevtype, addargc, newargv);
for(j=0;j<addargc;j++)
{
free(newargv[j]);
}
#else /* #if defined(OPTION_CONFIG_SYMBOLS) */
/* Build the device configuration block (no syms) */
rc=attach_device(devnum, sdevtype, addargc, addargv);
#endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
if(rc!=0)
{
baddev=1;
break;
}
}
if(baddev)
{
break;
}
}
#if defined(OPTION_CONFIG_SYMBOLS)
free(newargv);
#endif /* #if defined(OPTION_CONFIG_SYMBOLS) */
free(devnarray);
/* Read next device record from the configuration file */
if (read_config (fname, fp))
break;
} /* end while(1) */
#ifdef OPTION_SELECT_KLUDGE
/* Release the dummy file descriptors */
for (i = 0; i < OPTION_SELECT_KLUDGE; i++)
close(dummyfd[i]);
#endif
if (sysblk.pgmprdos == PGM_PRD_OS_LICENSED)
{
logmsg(_("\nHHCCF039W PGMPRDOS LICENSED specified.\n"
" Licensed program product operating systems are "
"enabled.\n You are "
"responsible for meeting all conditions of your\n"
" software "
"license.\n\n"));
}
#ifdef _FEATURE_VECTOR_FACILITY
for(i = 0; i < numvec && i < numcpu; i++)
sysblk.regs[i].vf->online = 1;
#endif /*_FEATURE_VECTOR_FACILITY*/
#ifndef PROFILE_CPU
obtain_lock (&sysblk.intlock);
for(i = 0; i < numcpu; i++)
configure_cpu(sysblk.regs + i);
release_lock (&sysblk.intlock);
#endif
/* close configuration file */
rc = fclose(fp);
} /* end function build_config */
/*-------------------------------------------------------------------*/
/* Function to terminate all CPUs and devices */
/*-------------------------------------------------------------------*/
void release_config()
{
DEVBLK *dev;
int cpu;
/* Stop all CPU's */
obtain_lock (&sysblk.intlock);
for (cpu = 0; cpu < MAX_CPU_ENGINES; cpu++)
if(sysblk.regs[cpu].cpuonline)
{
sysblk.regs[cpu].cpustate = CPUSTATE_STOPPING;
ON_IC_CPU_NOT_STARTED(sysblk.regs + cpu);
}
release_lock (&sysblk.intlock);
#if defined(OPTION_SHARED_DEVICES)
/* Terminate the shared device listener thread */
if (sysblk.shrdtid)
signal_thread (sysblk.shrdtid, SIGUSR2);
#endif
/* Detach all devices */
for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
if (dev->pmcw.flag5 & PMCW5_V)
detach_device(dev->devnum);
#if !defined(OPTION_FISHIO)
/* Terminate device threads */
obtain_lock (&sysblk.ioqlock);
broadcast_condition (&sysblk.ioqcond);
release_lock (&sysblk.ioqlock);
#endif
/* Deconfigure all CPU's */
for(cpu = 0; cpu < MAX_CPU_ENGINES; cpu++)
if(sysblk.regs[cpu].cpuonline)
deconfigure_cpu(sysblk.regs + cpu);
} /* end function release_config */
/*-------------------------------------------------------------------*/
/* Function to start a new CPU thread */
/* Caller MUST own the intlock */
/*-------------------------------------------------------------------*/
int configure_cpu(REGS *regs)
{
if(regs->cpuonline)
return -1;
regs->cpuonline = 1;
regs->cpustate = CPUSTATE_STARTING;
ON_IC_CPU_NOT_STARTED(regs);
regs->arch_mode = sysblk.arch_mode;
if ( create_thread (&(regs->cputid), &sysblk.detattr, cpu_thread, regs) )
{
regs->cpuonline = 0;
#ifdef _FEATURE_VECTOR_FACILITY
regs->vf->online = 0;
#endif /*_FEATURE_VECTOR_FACILITY*/
logmsg(_("HHCCF040E Cannot create CPU%4.4X thread: %s\n"),
regs->cpuad, strerror(errno));
return -1;
}
/* Wait for CPU thread to initialize */
wait_condition (&regs->intcond, &sysblk.intlock);
return 0;
} /* end function configure_cpu */
/*-------------------------------------------------------------------*/
/* Function to remove a CPU from the configuration */
/* This routine MUST be called with the intlock held */
/*-------------------------------------------------------------------*/
int deconfigure_cpu(REGS *regs)
{
if(regs->cpuonline)
{
regs->cpuonline = 0;
regs->cpustate = CPUSTATE_STOPPING;
ON_IC_CPU_NOT_STARTED(regs);
/* Wake up CPU as it may be waiting */
WAKEUP_CPU (regs->cpuad);
return 0;
}
else
return -1;
} /* end function deconfigure_cpu */
/*-------------------------------------------------------------------*/
/* Function to build a device configuration block */
/*-------------------------------------------------------------------*/
int attach_device (U16 devnum, char *type,
int addargc, BYTE *addargv[])
{
DEVBLK *dev; /* -> Device block */
DEVBLK**dvpp; /* -> Device block address */
DEVENT *devent = device_handler_table;
int rc; /* Return code */
int newdevblk = 0; /* 1=Newly created devblk */
/* Check whether device number has already been defined */
if (find_device_by_devnum(devnum) != NULL)
{
logmsg (_("HHCCF041E Device %4.4X already exists\n"), devnum);
return 1;
}
for(;devent->hnd;devent++)
if(!strcasecmp(devent->name, type))
break;
if(!devent->hnd)
{
logmsg (_("HHCCF042E Device type %s not recognized\n"),
type);
return 1;
}
/* Attempt to reuse an existing device block */
dev = find_unused_device();
/* If no device block is available, create a new one */
if (dev == NULL)
{
/* Obtain a device block */
dev = (DEVBLK*)malloc(sizeof(DEVBLK));
if (dev == NULL)
{
logmsg (_("HHCCF043E Cannot obtain device block "
"for device %4.4X: %s\n"),
devnum, strerror(errno));
return 1;
}
memset (dev, 0, sizeof(DEVBLK));
/* Indicate a newly allocated devblk */
newdevblk = 1;
/* Initialize the device lock and conditions */
initialize_lock (&dev->lock);
initialize_condition (&dev->resumecond);
initialize_condition (&dev->iocond);
/* Assign new subchannel number */
dev->subchan = sysblk.highsubchan++;
/* Note : highsubchan incremented NOW otherwise new DEVBLKS
* allocated by some init handlers (LCS for example) flunk */
}
/* Obtain the device lock */
obtain_lock(&dev->lock);
/* Initialize the device block */
dev->hnd = devent->hnd;
dev->cpuprio = sysblk.cpuprio;
dev->devnum = devnum;
dev->chanset = devnum >> 12;
if( dev->chanset >= MAX_CPU_ENGINES )
dev->chanset = MAX_CPU_ENGINES - 1;
dev->devtype = devent->type;
dev->typname = devent->name;
dev->fd = -1;
dev->ioint.dev = dev;
dev->ioint.pending = 1;
dev->pciioint.dev = dev;
dev->pciioint.pcipending = 1;
/* Initialize storage view */
dev->mainstor = sysblk.mainstor;
dev->storkeys = sysblk.storkeys;
dev->mainlim = sysblk.mainsize - 1;
/* Initialize the path management control word */
memset (&dev->pmcw, 0, sizeof(PMCW));
dev->pmcw.devnum[0] = dev->devnum >> 8;
dev->pmcw.devnum[1] = dev->devnum & 0xFF;
dev->pmcw.lpm = 0x80;
dev->pmcw.pim = 0x80;
dev->pmcw.pom = 0xFF;
dev->pmcw.pam = 0x80;
dev->pmcw.chpid[0] = dev->devnum >> 8;
#if defined(OPTION_SHARED_DEVICES)
dev->shrdwait = -1;
#endif /*defined(OPTION_SHARED_DEVICES)*/
/* Call the device handler initialization function */
rc = (dev->hnd->init)(dev, addargc, addargv);
if (rc < 0)
{
logmsg (_("HHCCF044E Initialization failed for device %4.4X\n"),
devnum);
release_lock(&dev->lock);
/* Release the device block if we just acquired it */
if (newdevblk)
{
free(dev);
/* Correction to high subchannel # (needed because of LCS
* DEVBLK allocation strategy) */
sysblk.highsubchan--;
}
return 1;
}
/* Obtain device data buffer */
if (dev->bufsize != 0)
{
dev->buf = malloc (dev->bufsize);
if (dev->buf == NULL)
{
logmsg (_("HHCCF045E Cannot obtain buffer "
"for device %4.4X: %s\n"),
dev->devnum, strerror(errno));
release_lock(&dev->lock);
/* Release the device block if we just acquired it */
if (newdevblk)
{
free(dev);
/* Correction to high subchannel # (needed because of LCS
* DEVBLK allocation strategy) */
sysblk.highsubchan--;
}
if(newdevblk)
free(dev);
return 1;
}
}
/* If we acquired a new device block, add it to the chain */
if (newdevblk)
{
/* Search for the last device block on the chain */
for (dvpp = &(sysblk.firstdev); *dvpp != NULL;
dvpp = &((*dvpp)->nextdev));
/* Add the new device block to the end of the chain */
*dvpp = dev;
dev->nextdev = NULL;
/* Increase highest subchannel number */
/*
* Commented out - highsubchan already corrected
* (needed because LCS device generate some DEVBLKS
* from within the dev init handler)
sysblk.highsubchan++;
*/
}
/* Mark device valid */
dev->pmcw.flag5 |= PMCW5_V;
#ifdef _FEATURE_CHANNEL_SUBSYSTEM
/* Indicate a CRW is pending for this device */
dev->crwpending = 1;
#endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
/* Release device lock */
release_lock(&dev->lock);
#ifdef _FEATURE_CHANNEL_SUBSYSTEM
/* Signal machine check */
machine_check_crwpend();
#endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
return 0;
} /* end function attach_device */
/*-------------------------------------------------------------------*/
/* Function to delete a device configuration block */
/*-------------------------------------------------------------------*/
int detach_device (U16 devnum)
{
DEVBLK *dev; /* -> Device block */
/* Find the device block */
dev = find_device_by_devnum (devnum);
if (dev == NULL)
{
logmsg (_("HHCCF046E Device %4.4X does not exist\n"), devnum);
return 1;
}
/* Obtain the device lock */
obtain_lock(&dev->lock);
/* Mark device invalid */
dev->pmcw.flag5 &= ~(PMCW5_E | PMCW5_V);
#ifdef _FEATURE_CHANNEL_SUBSYSTEM
/* Indicate a CRW is pending for this device */
dev->crwpending = 1;
#endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
/* Close file or socket */
if ((dev->fd > 2) || dev->console)
/* Call the device close handler */
(dev->hnd->close)(dev);
/* Release device lock */
release_lock(&dev->lock);
#ifdef _FEATURE_CHANNEL_SUBSYSTEM
/* Signal machine check */
machine_check_crwpend();
#endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
logmsg (_("HHCCF047I Device %4.4X detached\n"), devnum);
return 0;
} /* end function detach_device */
/*-------------------------------------------------------------------*/
/* Function to rename a device configuration block */
/*-------------------------------------------------------------------*/
int define_device (U16 olddevn, U16 newdevn)
{
DEVBLK *dev; /* -> Device block */
/* Find the device block */
dev = find_device_by_devnum (olddevn);
if (dev == NULL)
{
logmsg (_("HHCCF048E Device %4.4X does not exist\n"), olddevn);
return 1;
}
/* Check that new device number does not already exist */
if (find_device_by_devnum(newdevn) != NULL)
{
logmsg (_("HHCCF049E Device %4.4X already exists\n"), newdevn);
return 1;
}
/* Obtain the device lock */
obtain_lock(&dev->lock);
/* Update the device number in the DEVBLK */
dev->devnum = newdevn;
/* Update the device number in the PMCW */
dev->pmcw.devnum[0] = newdevn >> 8;
dev->pmcw.devnum[1] = newdevn & 0xFF;
/* Disable the device */
dev->pmcw.flag5 &= ~PMCW5_E;
#ifdef _FEATURE_CHANNEL_SUBSYSTEM
/* Indicate a CRW is pending for this device */
dev->crwpending = 1;
#endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
/* Release device lock */
release_lock(&dev->lock);
#ifdef _FEATURE_CHANNEL_SUBSYSTEM
/* Signal machine check */
machine_check_crwpend();
#endif /*_FEATURE_CHANNEL_SUBSYSTEM*/
logmsg (_("HHCCF050I Device %4.4X defined as %4.4X\n"),
olddevn, newdevn);
return 0;
} /* end function define_device */
/*-------------------------------------------------------------------*/
/* Function to find an unused device block entry */
/*-------------------------------------------------------------------*/
DEVBLK *find_unused_device ()
{
DEVBLK *dev;
for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
if (!(dev->pmcw.flag5 & PMCW5_V)) break;
return dev;
} /* end function find_unused_device */
/*-------------------------------------------------------------------*/
/* Function to find a device block given the device number */
/*-------------------------------------------------------------------*/
DEVBLK *find_device_by_devnum (U16 devnum)
{
DEVBLK *dev;
for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
if (dev->devnum == devnum && dev->pmcw.flag5 & PMCW5_V) break;
return dev;
} /* end function find_device_by_devnum */
/*-------------------------------------------------------------------*/
/* Function to find a device block given the subchannel number */
/*-------------------------------------------------------------------*/
DEVBLK *find_device_by_subchan (U16 subchan)
{
DEVBLK *dev;
for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
if (dev->subchan == subchan) break;
return dev;
} /* end function find_device_by_subchan */
#endif /*!defined(_GEN_ARCH)*/