mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-04-10 22:24:32 +02:00
1139 lines
30 KiB
C
1139 lines
30 KiB
C
/* HSCPUFUN.C (c) Copyright Roger Bowler, 1999-2012 */
|
|
/* (c) Copyright Jan Jaeger, 1999-2012 */
|
|
/* (c) Copyright "Fish" (David B. Trout), 2002-2009 */
|
|
/* (c) Copyright TurboHercules, SAS 2010-2011 */
|
|
/* CPU functions */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
#include "hstdinc.h"
|
|
|
|
#define _HSCPUFUN_C_
|
|
#define _HENGINE_DLL_
|
|
|
|
#include "hercules.h"
|
|
|
|
/* Issue generic Missing device number message */
|
|
static inline void missing_devnum()
|
|
{
|
|
WRMSG(HHC02201,"E");
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* cpu command - define target cpu for panel display and commands */
|
|
/*-------------------------------------------------------------------*/
|
|
int cpu_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
BYTE c;
|
|
int rc = 0;
|
|
int cpu = -1;
|
|
int currcpu = sysblk.pcpu;
|
|
char cmd[32768];
|
|
|
|
memset(cmd,0,sizeof(cmd));
|
|
|
|
if (argc < 2)
|
|
{
|
|
WRMSG(HHC02202, "E", argv[0] );
|
|
return -1;
|
|
}
|
|
|
|
if (sscanf(argv[1], "%x%c", &cpu, &c) != 1
|
|
|| cpu < 0 || cpu >= sysblk.maxcpu)
|
|
{
|
|
WRMSG(HHC02205, "E", argv[1], ": target processor is invalid" );
|
|
return -1;
|
|
}
|
|
|
|
sysblk.dummyregs.cpuad = cpu;
|
|
sysblk.pcpu = cpu;
|
|
|
|
strlcpy(cmd,cmdline,sizeof(cmd));
|
|
|
|
if ( argc > 2 )
|
|
{
|
|
u_int i = 0;
|
|
u_int j = 0;
|
|
u_int n = (u_int)strlen(cmd);
|
|
|
|
/* Skip leading blanks, if any */
|
|
for ( ; i < n && cmd[i] == ' '; i++ );
|
|
|
|
/* Skip two words */
|
|
for ( ; j < 2; j++ )
|
|
{
|
|
for ( ; i < n && cmd[i] != ' '; i++ );
|
|
for ( ; i < n && cmd[i] == ' '; i++ );
|
|
}
|
|
|
|
/* Issue command to temporary target cpu */
|
|
if (i < n)
|
|
{
|
|
rc = HercCmdLine(cmd+i);
|
|
sysblk.pcpu = currcpu;
|
|
sysblk.dummyregs.cpuad = currcpu;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* startall command - start all CPU's */
|
|
/*-------------------------------------------------------------------*/
|
|
int startall_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
int i;
|
|
int rc = 0;
|
|
CPU_BITMAP mask;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if ( argc == 1 )
|
|
{
|
|
OBTAIN_INTLOCK(NULL);
|
|
mask = (~sysblk.started_mask) & sysblk.config_mask;
|
|
for (i = 0; mask; i++)
|
|
{
|
|
if (mask & 1)
|
|
{
|
|
REGS *regs = sysblk.regs[i];
|
|
regs->opinterv = 0;
|
|
regs->cpustate = CPUSTATE_STARTED;
|
|
signal_condition(®s->intcond);
|
|
}
|
|
mask >>= 1;
|
|
}
|
|
RELEASE_INTLOCK(NULL);
|
|
}
|
|
else
|
|
{
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
rc = -1;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* stopall command - stop all CPU's */
|
|
/*-------------------------------------------------------------------*/
|
|
DLL_EXPORT int stopall_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
int i;
|
|
int rc = 0;
|
|
CPU_BITMAP mask;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if ( argc == 1 )
|
|
{
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
mask = sysblk.started_mask;
|
|
for (i = 0; mask; i++)
|
|
{
|
|
if (mask & 1)
|
|
{
|
|
REGS *regs = sysblk.regs[i];
|
|
regs->opinterv = 1;
|
|
regs->cpustate = CPUSTATE_STOPPING;
|
|
ON_IC_INTERRUPT(regs);
|
|
signal_condition(®s->intcond);
|
|
}
|
|
mask >>= 1;
|
|
}
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
}
|
|
else
|
|
{
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#ifdef _FEATURE_CPU_RECONFIG
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* cf command - configure/deconfigure a CPU */
|
|
/*-------------------------------------------------------------------*/
|
|
int cf_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
int on = -1;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if (argc == 2)
|
|
{
|
|
if ( CMD(argv[1],on,2) )
|
|
on = 1;
|
|
else if ( CMD(argv[1],off,3) )
|
|
on = 0;
|
|
}
|
|
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
if (IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
if (on < 0)
|
|
WRMSG(HHC00819, "I", PTYPSTR(sysblk.pcpu), sysblk.pcpu );
|
|
else if (on == 0)
|
|
deconfigure_cpu(sysblk.pcpu);
|
|
}
|
|
else
|
|
{
|
|
if (on < 0)
|
|
WRMSG(HHC00820, "I", PTYPSTR(sysblk.pcpu), sysblk.pcpu );
|
|
else if (on > 0)
|
|
configure_cpu(sysblk.pcpu);
|
|
}
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
if (on >= 0)
|
|
{
|
|
cf_cmd (1, argv, argv[0]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* cfall command - configure/deconfigure all CPU's */
|
|
/*-------------------------------------------------------------------*/
|
|
int cfall_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
static char *qproc[] = { "qproc", NULL };
|
|
int rc = 0;
|
|
int on = -1;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if (argc == 2)
|
|
{
|
|
if ( CMD(argv[1],on,2) )
|
|
on = 1;
|
|
else if ( CMD(argv[1],off,3) )
|
|
on = 0;
|
|
else
|
|
{
|
|
WRMSG( HHC17000, "E" );
|
|
rc = -1;
|
|
}
|
|
if ( rc == 0 )
|
|
{
|
|
rc = configure_numcpu(on ? sysblk.maxcpu : 0);
|
|
}
|
|
}
|
|
else if ( argc == 1 )
|
|
{
|
|
rc = qproc_cmd(1, qproc, *qproc);
|
|
}
|
|
else
|
|
{
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
rc = -1;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
#else
|
|
int cf_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
UNREFERENCED(cmdline);
|
|
|
|
WRMSG( HHC02310, "S", "cf", "FEATURE_CPU_RECONFIG" );
|
|
return -1;
|
|
}
|
|
int cfall_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
UNREFERENCED(cmdline);
|
|
|
|
WRMSG( HHC02310, "S", "cfall", "FEATURE_CPU_RECONFIG" );
|
|
return -1;
|
|
}
|
|
#endif /*_FEATURE_CPU_RECONFIG*/
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* system reset/system reset clear function */
|
|
/*-------------------------------------------------------------------*/
|
|
static int reset_cmd(int ac,char *av[],char *cmdline,int clear)
|
|
{
|
|
int rc;
|
|
|
|
UNREFERENCED(ac);
|
|
UNREFERENCED(av);
|
|
UNREFERENCED(cmdline);
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
/* CPU does not have to be stopped to issue reset */
|
|
/* SA22-7201-05: */
|
|
/* p. 12-5, System-Reset-Clear Key */
|
|
/* p. 12-5, System-Reset-Normal Key */
|
|
/* p. 4-36 -- 4-37, CPU Reset */
|
|
rc = system_reset (sysblk.pcpu, clear, sysblk.arch_mode);
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* system reset command */
|
|
/*-------------------------------------------------------------------*/
|
|
int sysreset_cmd(int ac,char *av[],char *cmdline)
|
|
{
|
|
int rc;
|
|
|
|
if (ac < 2)
|
|
rc = reset_cmd( ac, av, cmdline, 0 );
|
|
else if (ac == 2)
|
|
{
|
|
if (!strcasecmp( "clear", av[1] ))
|
|
{
|
|
rc = reset_cmd( ac, av, cmdline, 1 );
|
|
}
|
|
else if (!strcasecmp( "normal", av[1] ))
|
|
{
|
|
rc = reset_cmd( ac, av, cmdline, 0 );
|
|
}
|
|
else
|
|
{
|
|
// "Invalid argument %s%s"
|
|
WRMSG( HHC02205, "E", av[1], "" );
|
|
rc = -1;
|
|
}
|
|
}
|
|
else // (ac > 2)
|
|
{
|
|
// "Invalid argument %s%s"
|
|
WRMSG( HHC02205, "E", av[2], "" );
|
|
rc = -1;
|
|
}
|
|
|
|
if (rc >= 0)
|
|
WRMSG( HHC02311, "I", cmdline ); // "%s completed"
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* system reset clear command */
|
|
/*-------------------------------------------------------------------*/
|
|
int sysclear_cmd(int ac,char *av[],char *cmdline)
|
|
{
|
|
int rc;
|
|
|
|
if (ac > 1)
|
|
{
|
|
// "Invalid argument %s%s"
|
|
WRMSG( HHC02205, "E", av[1], "" );
|
|
rc = -1;
|
|
}
|
|
|
|
if ((rc = reset_cmd( ac, av, cmdline, 1 )) >= 0)
|
|
WRMSG( HHC02311, "I", av[0] ); // "%s completed"
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ipl function */
|
|
/* Format:
|
|
* ipl xxxx | cccc [loadparm xxxxnnnn | parm xxxxxxx ] [clear]
|
|
*/
|
|
/*-------------------------------------------------------------------*/
|
|
int ipl_cmd2(int argc, char *argv[], char *cmdline, int clr_prm)
|
|
{
|
|
BYTE c; /* Character work area */
|
|
int rc; /* Return code */
|
|
int i;
|
|
int clear = clr_prm; /* Called with Clear option */
|
|
int j;
|
|
size_t maxb;
|
|
U16 lcss;
|
|
U16 devnum;
|
|
char *cdev, *clcss;
|
|
char save_loadparm[16];
|
|
int rest_loadparm = FALSE;
|
|
|
|
save_loadparm[0] = '\0';
|
|
|
|
UNREFERENCED( cmdline );
|
|
|
|
/* Primary CPU must be online */
|
|
if (!IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
WRMSG(HHC00816, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
return -1;
|
|
}
|
|
|
|
/* Check that target processor type allows IPL */
|
|
if (sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_IFA
|
|
|| sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_SUP)
|
|
{
|
|
WRMSG(HHC00818, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu);
|
|
return -1;
|
|
}
|
|
|
|
/* Check the parameters of the IPL command */
|
|
if (argc < 2)
|
|
{
|
|
missing_devnum();
|
|
return -1;
|
|
}
|
|
#define MAXPARMSTRING sizeof(sysblk.iplparmstring)
|
|
sysblk.haveiplparm=0;
|
|
maxb=0;
|
|
if ( argc > 2 )
|
|
{
|
|
if ( CMD( argv[2], clear, 2 ) )
|
|
{
|
|
clear = 1;
|
|
}
|
|
else if ( CMD( argv[2], loadparm, 4 ) )
|
|
{
|
|
strlcpy( save_loadparm, str_loadparm(), sizeof(save_loadparm) );
|
|
rest_loadparm = TRUE;
|
|
if ( argc == 4 )
|
|
set_loadparm(argv[3]);
|
|
}
|
|
else if ( CMD(argv[2], parm, 4) )
|
|
{
|
|
memset(sysblk.iplparmstring,0,MAXPARMSTRING);
|
|
sysblk.haveiplparm=1;
|
|
for ( i = 3; i < argc && maxb < MAXPARMSTRING; i++ )
|
|
{
|
|
if ( i !=3 )
|
|
{
|
|
sysblk.iplparmstring[maxb++]=0x40;
|
|
}
|
|
for ( j = 0; j < (int)strlen(argv[i]) && maxb < MAXPARMSTRING; j++ )
|
|
{
|
|
if ( islower(argv[i][j]) )
|
|
{
|
|
argv[i][j]=toupper(argv[i][j]);
|
|
}
|
|
sysblk.iplparmstring[maxb]=host_to_guest(argv[i][j]);
|
|
maxb++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
/* The ipl device number might be in format lcss:devnum */
|
|
if ( (cdev = strchr(argv[1],':')) )
|
|
{
|
|
clcss = argv[1];
|
|
cdev++;
|
|
}
|
|
else
|
|
{
|
|
clcss = NULL;
|
|
cdev = argv[1];
|
|
}
|
|
|
|
/* If the ipl device is not a valid hex number we assume */
|
|
/* This is a load from the service processor */
|
|
if (sscanf(cdev, "%hx%c", &devnum, &c) != 1)
|
|
rc = load_hmc(argv[1], sysblk.pcpu, clear);
|
|
else
|
|
{
|
|
#if defined(_FEATURE_SCSI_IPL)
|
|
DEVBLK *dev;
|
|
#endif /*defined(_FEATURE_SCSI_IPL)*/
|
|
|
|
*--cdev = '\0';
|
|
|
|
if (clcss)
|
|
{
|
|
if (sscanf(clcss, "%hd%c", &lcss, &c) != 1)
|
|
{
|
|
WRMSG(HHC02205, "E", clcss, ": LCSS id is invalid" );
|
|
if ( rest_loadparm ) set_loadparm( save_loadparm );
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
lcss = 0;
|
|
|
|
#if defined(_FEATURE_SCSI_IPL)
|
|
if((dev = find_device_by_devnum(lcss,devnum))
|
|
&& support_boot(dev) >= 0)
|
|
rc = load_boot(dev, sysblk.pcpu, clear, 0);
|
|
else
|
|
#endif /*defined(_FEATURE_SCSI_IPL)*/
|
|
rc = load_ipl (lcss, devnum, sysblk.pcpu, clear);
|
|
}
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ipl command */
|
|
/*-------------------------------------------------------------------*/
|
|
int ipl_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
return ipl_cmd2(argc,argv,cmdline,0);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ipl clear command */
|
|
/*-------------------------------------------------------------------*/
|
|
int iplc_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
return ipl_cmd2(argc,argv,cmdline,1);
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* capping - limit MIPS rate */
|
|
/*-------------------------------------------------------------------*/
|
|
int capping_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
U32 cap;
|
|
BYTE c;
|
|
int rc = HNOERROR;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
/* Update capping value */
|
|
if ( argc == 2 )
|
|
{
|
|
if( CMD( argv[1], off, 3))
|
|
rc = configure_capping(0);
|
|
else
|
|
if (strlen(argv[1]) >= 1
|
|
&& sscanf(argv[1], "%u%c", &cap, &c) == 1)
|
|
{
|
|
rc = configure_capping(cap);
|
|
}
|
|
else
|
|
{
|
|
WRMSG( HHC01451, "E", argv[1], argv[0] );
|
|
rc = HERROR;
|
|
}
|
|
}
|
|
else
|
|
if ( argc > 2 )
|
|
{
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
rc = HERROR;
|
|
}
|
|
else
|
|
{
|
|
if ( sysblk.capvalue == 0 )
|
|
WRMSG( HHC00838, "I" );
|
|
else
|
|
WRMSG( HHC00832, "I", sysblk.capvalue );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* restart command - generate restart interrupt */
|
|
/*-------------------------------------------------------------------*/
|
|
int restart_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
UNREFERENCED(cmdline);
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
|
|
/* Check that target processor type allows IPL */
|
|
if (sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_IFA
|
|
|| sysblk.ptyp[sysblk.pcpu] == SCCB_PTYP_SUP)
|
|
{
|
|
WRMSG(HHC00818, "E", PTYPSTR(sysblk.pcpu), sysblk.pcpu);
|
|
return -1;
|
|
}
|
|
|
|
WRMSG(HHC02228, "I", "restart");
|
|
|
|
/* Obtain the interrupt lock */
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
if (!IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
RELEASE_INTLOCK(NULL);
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
return 0;
|
|
}
|
|
|
|
/* Indicate that a restart interrupt is pending */
|
|
ON_IC_RESTART(sysblk.regs[sysblk.pcpu]);
|
|
|
|
/* Ensure that a stopped CPU will recognize the restart */
|
|
if (sysblk.regs[sysblk.pcpu]->cpustate == CPUSTATE_STOPPED)
|
|
sysblk.regs[sysblk.pcpu]->cpustate = CPUSTATE_STOPPING;
|
|
|
|
sysblk.regs[sysblk.pcpu]->checkstop = 0;
|
|
|
|
/* Signal CPU that an interrupt is pending */
|
|
WAKEUP_CPU (sysblk.regs[sysblk.pcpu]);
|
|
|
|
/* Release the interrupt lock */
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ext command - generate external interrupt */
|
|
/*-------------------------------------------------------------------*/
|
|
int ext_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
UNREFERENCED(cmdline);
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
ON_IC_INTKEY;
|
|
|
|
WRMSG(HHC02228, "I", "interrupt");
|
|
|
|
/* Signal waiting CPUs that an interrupt is pending */
|
|
WAKEUP_CPUS_MASK (sysblk.waiting_mask);
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* timerint - display or set the timer interval */
|
|
/*-------------------------------------------------------------------*/
|
|
int timerint_cmd( int argc, char *argv[], char *cmdline )
|
|
{
|
|
int rc = 0;
|
|
UNREFERENCED( cmdline );
|
|
|
|
if (argc == 2) /* Define a new value? */
|
|
{
|
|
if (CMD( argv[1], default, 7 ) || CMD( argv[1], reset, 5 ))
|
|
{
|
|
sysblk.timerint = DEF_TOD_UPDATE_USECS;
|
|
if (MLVL( VERBOSE ))
|
|
{
|
|
// "%-14s set to %s"
|
|
WRMSG( HHC02204, "I", argv[0], argv[1] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int timerint = 0; BYTE c;
|
|
|
|
if (1
|
|
&& sscanf( argv[1], "%d%c", &timerint, &c ) == 1
|
|
&& timerint >= MIN_TOD_UPDATE_USECS
|
|
&& timerint <= MAX_TOD_UPDATE_USECS
|
|
)
|
|
{
|
|
sysblk.timerint = timerint;
|
|
if (MLVL( VERBOSE ))
|
|
{
|
|
char buf[25];
|
|
MSGBUF( buf, "%d", sysblk.timerint );
|
|
// "%-14s set to %s"
|
|
WRMSG( HHC02204, "I", argv[0], buf );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// "Invalid argument '%s'%s"
|
|
WRMSG( HHC02205, "E", argv[1], ": must be 'default' or n where "
|
|
QSTR( MIN_TOD_UPDATE_USECS ) " <= n <= "
|
|
QSTR( MAX_TOD_UPDATE_USECS ) );
|
|
rc = -1;
|
|
}
|
|
}
|
|
}
|
|
else if (argc == 1)
|
|
{
|
|
/* Display the current value */
|
|
char buf[25];
|
|
MSGBUF( buf, "%d", sysblk.timerint );
|
|
// "%-14s: %s"
|
|
WRMSG( HHC02203, "I", argv[0], buf );
|
|
}
|
|
else
|
|
{
|
|
// "Invalid command usage. Type 'help %s' for assistance."
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/* format_tod - generate displayable date from TOD value */
|
|
/* always uses epoch of 1900 */
|
|
char * format_tod(char *buf, U64 tod, int flagdate)
|
|
{
|
|
int leapyear, years, days, hours, minutes, seconds, microseconds;
|
|
|
|
if ( tod >= ETOD_YEAR )
|
|
{
|
|
tod -= ETOD_YEAR;
|
|
years = (tod / ETOD_4YEARS * 4) + 1;
|
|
tod %= ETOD_4YEARS;
|
|
if ( ( leapyear = tod / ETOD_YEAR ) == 4 )
|
|
{
|
|
tod %= ETOD_YEAR;
|
|
years--;
|
|
tod += ETOD_YEAR;
|
|
}
|
|
else
|
|
tod %= ETOD_YEAR;
|
|
|
|
years += leapyear;
|
|
}
|
|
else
|
|
years = 0;
|
|
|
|
days = tod / ETOD_DAY;
|
|
tod %= ETOD_DAY;
|
|
hours = tod / ETOD_HOUR;
|
|
tod %= ETOD_HOUR;
|
|
minutes = tod / ETOD_MIN;
|
|
tod %= ETOD_MIN;
|
|
seconds = tod / ETOD_SEC;
|
|
microseconds = (tod % ETOD_SEC) / ETOD_USEC;
|
|
|
|
if (flagdate)
|
|
{
|
|
years += 1900;
|
|
days += 1;
|
|
}
|
|
|
|
sprintf(buf,"%4d.%03d %02d:%02d:%02d.%06d",
|
|
years,days,hours,minutes,seconds,microseconds);
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* clocks command - display tod clkc and cpu timer */
|
|
/*-------------------------------------------------------------------*/
|
|
int clocks_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
REGS *regs;
|
|
char clock_buf[30];
|
|
ETOD tod_now;
|
|
ETOD hw_now;
|
|
S64 epoch_now;
|
|
U64 epoch_now_abs;
|
|
char epoch_sign;
|
|
U64 clkc_now;
|
|
S64 cpt_now;
|
|
#if defined(_FEATURE_SIE)
|
|
U64 vtod_now = 0;
|
|
S64 vepoch_now = 0;
|
|
U64 vepoch_now_abs = 0;
|
|
char vepoch_sign = ' ';
|
|
U64 vclkc_now = 0;
|
|
S64 vcpt_now = 0;
|
|
char sie_flag = 0;
|
|
#endif
|
|
U32 itimer = 0;
|
|
char itimer_formatted[32];
|
|
char arch370_flag = 0;
|
|
char buf[64];
|
|
int rc = 0;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if ( argc == 1 ) for (;;)
|
|
{
|
|
obtain_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
if (!IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
break;
|
|
}
|
|
regs = sysblk.regs[sysblk.pcpu];
|
|
|
|
/* Get the clock values all at once for consistency and so we can
|
|
release the CPU lock more quickly. */
|
|
etod_clock(regs, &tod_now, ETOD_fast);
|
|
hw_now.high = hw_tod.high;
|
|
hw_now.low = hw_tod.low;
|
|
epoch_now = regs->tod_epoch;
|
|
clkc_now = regs->clkc;
|
|
cpt_now = cpu_timer(regs);
|
|
#if defined(_FEATURE_SIE)
|
|
if ( regs->sie_active )
|
|
{
|
|
vtod_now = TOD_CLOCK(regs->guestregs);
|
|
vepoch_now = regs->guestregs->tod_epoch;
|
|
vclkc_now = regs->guestregs->clkc;
|
|
vcpt_now = cpu_timer_SIE(regs->guestregs);
|
|
sie_flag = 1;
|
|
}
|
|
#endif
|
|
if (regs->arch_mode == ARCH_370)
|
|
{
|
|
itimer = INT_TIMER(regs);
|
|
/* The interval timer counts 76800 per second, or one every
|
|
13.0208 microseconds. */
|
|
MSGBUF(itimer_formatted,"%02u:%02u:%02u.%06u",
|
|
(itimer/(76800*60*60)),((itimer%(76800*60*60))/(76800*60)),
|
|
((itimer%(76800*60))/76800),((itimer%76800)*13));
|
|
arch370_flag = 1;
|
|
}
|
|
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
MSGBUF( buf, "tod = %16.16" I64_FMT "X %s",
|
|
ETOD2TOD(tod_now), format_tod(clock_buf,tod_now.high,TRUE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
MSGBUF( buf, "h/w = %16.16" I64_FMT "X %s",
|
|
ETOD2TOD(hw_now), format_tod(clock_buf,hw_now.high,TRUE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
if (epoch_now < 0)
|
|
{
|
|
epoch_now_abs = -(epoch_now);
|
|
epoch_sign = '-';
|
|
}
|
|
else
|
|
{
|
|
epoch_now_abs = epoch_now;
|
|
epoch_sign = ' ';
|
|
}
|
|
MSGBUF( buf, "off = %16.16" I64_FMT "X %c%s",
|
|
etod2tod(epoch_now), epoch_sign,
|
|
format_tod(clock_buf,epoch_now_abs,FALSE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
MSGBUF( buf, "ckc = %16.16" I64_FMT "X %s",
|
|
etod2tod(clkc_now), format_tod(clock_buf,clkc_now,TRUE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
if (regs->cpustate != CPUSTATE_STOPPED)
|
|
MSGBUF( buf, "cpt = %16.16" I64_FMT "X", cpt_now );
|
|
else
|
|
MSGBUF( buf, "cpt = %16.16" I64_FMT "X not decrementing", cpt_now );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
#if defined(_FEATURE_SIE)
|
|
if (sie_flag)
|
|
{
|
|
|
|
MSGBUF( buf, "vtod = %16.16" I64_FMT "X %s",
|
|
etod2tod(vtod_now), format_tod(clock_buf,vtod_now,TRUE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
if (vepoch_now < 0)
|
|
{
|
|
vepoch_now_abs = -(vepoch_now);
|
|
vepoch_sign = '-';
|
|
}
|
|
else
|
|
{
|
|
vepoch_now_abs = vepoch_now;
|
|
vepoch_sign = ' ';
|
|
}
|
|
MSGBUF( buf, "voff = %16.16" I64_FMT "X %c%s",
|
|
etod2tod(vepoch_now), vepoch_sign,
|
|
format_tod(clock_buf,vepoch_now_abs,FALSE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
MSGBUF( buf, "vckc = %16.16" I64_FMT "X %s",
|
|
etod2tod(vclkc_now), format_tod(clock_buf,vclkc_now,TRUE) );
|
|
WRMSG(HHC02274, "I", buf);
|
|
|
|
MSGBUF( buf, "vcpt = %16.16" I64_FMT "X", vcpt_now );
|
|
WRMSG(HHC02274, "I", buf);
|
|
}
|
|
#endif
|
|
|
|
if (arch370_flag)
|
|
{
|
|
MSGBUF( buf, "itm = %8.8" I32_FMT "X %s",
|
|
itimer, itimer_formatted );
|
|
WRMSG(HHC02274, "I", buf);
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* store command - store CPU status at absolute zero */
|
|
/*-------------------------------------------------------------------*/
|
|
int store_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
REGS *regs;
|
|
|
|
UNREFERENCED(cmdline);
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
|
|
obtain_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
if (!IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
return 0;
|
|
}
|
|
regs = sysblk.regs[sysblk.pcpu];
|
|
|
|
/* Command is valid only when CPU is stopped */
|
|
if (regs->cpustate != CPUSTATE_STOPPED)
|
|
{
|
|
WRMSG(HHC02224, "E");
|
|
return -1;
|
|
}
|
|
|
|
/* Store status in 512 byte block at absolute location 0 */
|
|
store_status (regs, 0);
|
|
|
|
#if defined(_FEATURE_HARDWARE_LOADER)
|
|
ARCH_DEP(sdias_store_status)(regs);
|
|
#endif /*defined(_FEATURE_HARDWARE_LOADER)*/
|
|
|
|
release_lock(&sysblk.cpulock[sysblk.pcpu]);
|
|
|
|
WRMSG(HHC00817, "I", PTYPSTR(regs->cpuad), regs->cpuad);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* start command - start current CPU */
|
|
/*-------------------------------------------------------------------*/
|
|
int start_cmd_cpu(int argc, char *argv[], char *cmdline)
|
|
{
|
|
int rc = 0;
|
|
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
UNREFERENCED(cmdline);
|
|
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
if (IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
REGS *regs = sysblk.regs[sysblk.pcpu];
|
|
if ( regs->cpustate == CPUSTATE_STARTED )
|
|
{
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "stopped");
|
|
rc = 1;
|
|
}
|
|
else
|
|
{
|
|
regs->opinterv = 0;
|
|
regs->cpustate = CPUSTATE_STARTED;
|
|
regs->checkstop = 0;
|
|
WAKEUP_CPU(regs);
|
|
WRMSG( HHC00834, "I", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "running state selected" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
rc = 1;
|
|
}
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* stop command - stop current CPU */
|
|
/*-------------------------------------------------------------------*/
|
|
int stop_cmd_cpu(int argc, char *argv[], char *cmdline)
|
|
{
|
|
int rc = 0;
|
|
|
|
UNREFERENCED(argc);
|
|
UNREFERENCED(argv);
|
|
UNREFERENCED(cmdline);
|
|
|
|
OBTAIN_INTLOCK(NULL);
|
|
|
|
if (IS_CPU_ONLINE(sysblk.pcpu))
|
|
{
|
|
REGS *regs = sysblk.regs[sysblk.pcpu];
|
|
if ( regs->cpustate != CPUSTATE_STARTED )
|
|
{
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "started");
|
|
rc = 1;
|
|
}
|
|
else
|
|
{
|
|
regs->opinterv = 1;
|
|
regs->cpustate = CPUSTATE_STOPPING;
|
|
ON_IC_INTERRUPT(regs);
|
|
WAKEUP_CPU (regs);
|
|
WRMSG( HHC00834, "I", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "manual state selected" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WRMSG(HHC00816, "W", PTYPSTR(sysblk.pcpu), sysblk.pcpu, "online");
|
|
rc = 1;
|
|
}
|
|
|
|
RELEASE_INTLOCK(NULL);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#if defined(_FEATURE_ASN_AND_LX_REUSE)
|
|
/*-------------------------------------------------------------------*/
|
|
/* alrf command - display or set asn_and_lx_reuse */
|
|
/*-------------------------------------------------------------------*/
|
|
int alrf_cmd(int argc, char *argv[], char *cmdline)
|
|
{
|
|
char buffer[128] = {0};
|
|
char *archlvl_func;
|
|
|
|
UNREFERENCED(cmdline);
|
|
|
|
if (argc < 1 || argc > 2)
|
|
{
|
|
WRMSG( HHC02299, "E", argv[0] );
|
|
return -1;
|
|
}
|
|
|
|
// HHC02256 "Command %s is deprecated, use %s instead"
|
|
|
|
if (argc == 1)
|
|
{
|
|
archlvl_func = "query";
|
|
}
|
|
else /* (argc == 2) */
|
|
{
|
|
archlvl_func = argv[1];
|
|
}
|
|
|
|
MSGBUF( buffer, "archlvl %s asn_lx_reuse", archlvl_func );
|
|
WRMSG( HHC02256, "W", "ALRF", buffer );
|
|
return InternalHercCmd( buffer );
|
|
}
|
|
#endif /*defined(_FEATURE_ASN_AND_LX_REUSE)*/
|
|
|
|
#if defined(_FEATURE_CMPSC_ENHANCEMENT_FACILITY)
|
|
/*-------------------------------------------------------------------*/
|
|
/* cmpscpad command - set CMPSC instruction padding alignment */
|
|
/*-------------------------------------------------------------------*/
|
|
int cmpscpad_cmd( int argc, char* argv[], char* cmdline )
|
|
{
|
|
int bits, i;
|
|
const char* ptr;
|
|
char* nxt;
|
|
char buf[8];
|
|
|
|
UNREFERENCED( cmdline );
|
|
|
|
if ( argc > 2 )
|
|
{
|
|
// "Invalid number of arguments for %s"
|
|
WRMSG( HHC01455, "E", argv[0] );
|
|
return HERROR;
|
|
}
|
|
|
|
/* Ensure all CPUs have been stopped */
|
|
|
|
OBTAIN_INTLOCK( NULL );
|
|
|
|
if (sysblk.cpus)
|
|
{
|
|
for (i = 0; i < sysblk.maxcpu; i++)
|
|
{
|
|
if (IS_CPU_ONLINE( i ) &&
|
|
sysblk.regs[ i ]->cpustate == CPUSTATE_STARTED)
|
|
{
|
|
RELEASE_INTLOCK( NULL );
|
|
// "CPUs must be offline or stopped"
|
|
WRMSG( HHC02389, "E" );
|
|
return HERRCPUONL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( argc == 2 )
|
|
{
|
|
ptr = argv[1];
|
|
errno = 0;
|
|
bits = (int) strtoul( ptr, &nxt, 10 );
|
|
|
|
if (0
|
|
|| errno != 0
|
|
|| nxt == ptr
|
|
|| *nxt != 0
|
|
|| bits < MIN_CMPSC_ZP_BITS
|
|
|| bits > MAX_CMPSC_ZP_BITS
|
|
)
|
|
{
|
|
RELEASE_INTLOCK( NULL );
|
|
// "Specified value is invalid or outside of range %d to %d"
|
|
WRMSG( HHC17014 , "E", MIN_CMPSC_ZP_BITS,
|
|
MAX_CMPSC_ZP_BITS );
|
|
return HERROR;
|
|
}
|
|
|
|
/* Update SYSBLK with new value */
|
|
sysblk.zpbits = (BYTE) bits;
|
|
RELEASE_INTLOCK( NULL );
|
|
|
|
MSGBUF( buf, "%d", bits );
|
|
// "%-14s set to %s"
|
|
WRMSG( HHC02204, "I", argv[0], buf );
|
|
}
|
|
else
|
|
{
|
|
/* Display current SYSBLK value */
|
|
bits = sysblk.zpbits;
|
|
RELEASE_INTLOCK( NULL );
|
|
|
|
MSGBUF( buf, "%d", bits );
|
|
// "%-14s: %s"
|
|
WRMSG( HHC02203, "I", argv[0], buf );
|
|
}
|
|
|
|
return HNOERROR;
|
|
}
|
|
#endif /* defined(_FEATURE_CMPSC_ENHANCEMENT_FACILITY) */
|