summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xsrc/build/simics/hb-simdebug.py81
-rwxr-xr-xsrc/build/tools/genIStep.pl3
-rw-r--r--src/include/usr/initservice/initsvcreasoncodes.H1
-rw-r--r--src/usr/initservice/istepdispatcher/istep_mbox_msgs.H52
-rw-r--r--src/usr/initservice/istepdispatcher/istepdispatcher.C990
-rw-r--r--src/usr/initservice/istepdispatcher/istepdispatcher.H91
-rw-r--r--src/usr/initservice/istepdispatcher/makefile3
-rw-r--r--src/usr/initservice/istepdispatcher/splesscommon.H116
-rw-r--r--src/usr/initservice/istepdispatcher/sptask.C324
9 files changed, 1071 insertions, 590 deletions
diff --git a/src/build/simics/hb-simdebug.py b/src/build/simics/hb-simdebug.py
index 9daabaf5c..3aa72445c 100755
--- a/src/build/simics/hb-simdebug.py
+++ b/src/build/simics/hb-simdebug.py
@@ -28,6 +28,7 @@ import cli
import binascii
import datetime
import commands ## getoutput, getstatusoutput
+import random
#------------------------------------------------------------------------------
# Function to dump L3
@@ -85,8 +86,10 @@ def findAddr( symsFile, symName ):
def hb_istep_usage():
print "hb-istep usage:"
- print " istepmode - enable IStep Mode. Must be executed before simics run command"
- print " normalmode - disable IStep Mode. "
+ ##print " istepmode - enable IStep Mode and the SPless user console."
+ ##print " normalmode - enable IStep Mode and the FSP interface. "
+ print " splessmode - enable IStep Mode and the SPless user console."
+ print " fspmode - enable IStep Mode and the FSP interface. "
print " list - list all named isteps"
print " sN - execute IStep N"
print " sN..M - execute IStep N through M"
@@ -97,11 +100,13 @@ def hb_istep_usage():
## declare GLOBAL g_SeqNum var, & a routine to manipulate it.
## TODO: make this into a class, etc. to do it The Python Way.
-g_SeqNum = 0
+##g_SeqNum = 0
+g_SeqNum = random.randint(0, 63)
+print "g_SeqNum = %d"%(g_SeqNum)
def bump_g_SeqNum() :
global g_SeqNum
g_SeqNum = ( (g_SeqNum +1) & 0x3f)
- return None
+ return g_SeqNum
## clock a certain amount of CPU cycles so the IStep will run (this will be
## different for each simulation environment) and then return.
@@ -186,17 +191,23 @@ def getSyncStatus( ) :
while True :
## advance HostBoot code by a certain # of cycles, then check the
- ## sequence number to see if it has changed. rinse and repeat.
+ ## running bit and sequence number to see if they have changed.
+ ## IstepDisp will set running bit ASAP and then turn it off when
+ ## the command is complete.
runClocks()
## print a dot (with no carriage return) so that the user knows that
## it's still doing something
- print "." ,
+ # print "." ,
result = getStatus()
- seqnum = ( ( result & 0x3f00000000000000 ) >> 56 )
- if ( seqnum == g_SeqNum ) :
- print # print a final carriage return
+
+ runningbit = ( ( result & 0x8000000000000000 ) >> 63 )
+ seqnum = ( ( result & 0x3f00000000000000 ) >> 56 )
+
+ if ( ( runningbit == 0 )
+ and ( seqnum == g_SeqNum ) ) :
+ # print # print a final carriage return
return result
if ( count <= 0 ):
@@ -205,7 +216,7 @@ def getSyncStatus( ) :
return -1
count -= 1
-## write to scratch reg 3 to set istep or normal mode, check return status
+## write to istepmode reg to set istep or fsp mode, check return status
def setMode( cmd ) :
global g_IStep_DEBUG
global g_SPLess_IStepMode_Reg
@@ -213,25 +224,24 @@ def setMode( cmd ) :
##IStepModeStr = "cpu0_0_0_3->scratch=0x4057b007_4057b007"
##NormalModeStr = "cpu0_0_0_3->scratch=0x700b7504_700b7504"
- IStepModeStr = "phys_mem.write 0x%8.8x 0x4057b007_4057b007 8"%(g_SPLess_IStepMode_Reg)
- NormalModeStr = "phys_mem.write 0x%8.8x 0x700b7504_700b7504 8"%(g_SPLess_IStepMode_Reg)
+ SPlessModeStr = "phys_mem.write 0x%8.8x 0x4057b007_4057b007 8"%(g_SPLess_IStepMode_Reg)
+ FSPModeStr = "phys_mem.write 0x%8.8x 0x700b7504_700b7504 8"%(g_SPLess_IStepMode_Reg)
## @todo revisit
count = 1000
- if ( cmd == "istep" ) :
- (result, out) = quiet_run_command( IStepModeStr )
- # print IStepModeStr
- # print "set istepmode returned 0x%x"%(result) + " : " + out
+ if ( cmd == "spless" ) :
+ (result, out) = quiet_run_command( SPlessModeStr )
expected = 1
- elif ( cmd == "normal" ) :
- (result, out) = quiet_run_command( NormalModeStr )
- # print "set normalmode returned 0x%x"%(result) + " : " + out
- expected = 0
+ elif ( cmd == "fsp" ) :
+ (result, out) = quiet_run_command( FSPModeStr )
+ expected = 1
else :
print "invalid setMode command: %s"%(cmd)
return None
-
+
+ print "setMode: %s :"%( cmd )
+
## Loop, advancing clock, and wait for readybit
while True :
runClocks()
@@ -285,6 +295,7 @@ def print_istep_list( inList ):
def runIStep( istep, substep, inList ):
+ global g_SeqNum
bump_g_SeqNum()
@@ -319,10 +330,10 @@ def runIStep( istep, substep, inList ):
if ( taskStatus == 11 ) :
print "At breakpoint 0x%x"%( istepStatus )
else :
- print "Istep %d.%d FAILED to launch, task status is %d"%( taskStatus )
+ print "Istep %d.%d FAILED to launch, task status is %d"%( stsIStep, stsSubstep, taskStatus )
else:
print "Istep %d.%d returned Status: 0x%x"%( stsIStep, stsSubstep, istepStatus )
- print "-----------------------------------------------------------------"
+ print "-------------------------------------------------------------- %d"%(g_SeqNum)
return
@@ -429,8 +440,8 @@ def find_in_inList( inList, substepname) :
## ---------------------------------------------------------------------------
## possible commands:
## list
-## istepmode
-## normalmode
+## splessmode
+## fspmode
## sN
## sN..M
## <substepname1>..<substepname2>
@@ -460,6 +471,7 @@ def istepHB( symsFile, str_arg1 ):
## start with empty inList. Put some dummy isteps in istep4 for debug.
n = 25 ## size of inlist array
+
inList = [[None]*n for x in xrange(n)] ## init to nothing
## bump seqnum
@@ -472,27 +484,31 @@ def istepHB( symsFile, str_arg1 ):
g_IStep_DEBUG = 1
return
- if ( str_arg1 == "istepmode" ): ## set IStep Mode in SCOM reg
+ if ( str_arg1 == "istepmode" ):
# print "Set Istep Mode"
- setMode( "istep" )
+ print "istepmode no longer used - use splessmode, or fspmode"
return
- if ( str_arg1 == "normalmode" ): ## set Normal Mode in SCOM reg
- # print "Set Normal Mode"
- setMode( "normal" )
+ if ( str_arg1 == "splessmode" ):
+ # print "Start Istep on SPless console"
+ setMode( "spless" )
return
+ if ( str_arg1 == "fspmode" ):
+ # print "Start Istep on FSP "
+ setMode( "fsp" )
+ return
## get readybit to see if we are running in IStep Mode.
StatusReg = getStatus()
readybit = ( ( StatusReg & 0x4000000000000000 ) >> 62 )
if ( not readybit ):
print "ERROR: HostBoot Status reg is 0x%16.16x"%( StatusReg )
- print " Ready bit is not on, did you remember to run hb-istep istepmode ??"
+ print " Ready bit is not on, did you remember to run hb-istep spless ??"
print " "
hb_istep_usage()
return None
-
+
if ( str_arg1 == "resume" ): ## resume from break point
resume_istep()
return None
@@ -504,6 +520,7 @@ def istepHB( symsFile, str_arg1 ):
if ( str_arg1 == "list" ): ## dump command list
print_istep_list( inList )
return
+
## check to see if we have an 's' command (string starts with 's' and a number)
if ( re.match("^s+[0-9].*", str_arg1 ) ):
diff --git a/src/build/tools/genIStep.pl b/src/build/tools/genIStep.pl
index c20b4eec4..cd22aad14 100755
--- a/src/build/tools/genIStep.pl
+++ b/src/build/tools/genIStep.pl
@@ -345,6 +345,7 @@ my $templateCFileSubStep =
void call_\@substepname( void *io_pArgs )
{
fapi::ReturnCode l_fapirc;
+ errlHndl_t l_errl = NULL;
TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, \"call_\@substepname entry\" );
@@ -395,7 +396,7 @@ void call_\@substepname( void *io_pArgs )
TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, \"call_\@substepname exit\" );
- task_end2( NULL );
+ task_end2( reinterpret_cast<void*>( l_errl ) );
}
";
##### end templateCFileSubStep #################################
diff --git a/src/include/usr/initservice/initsvcreasoncodes.H b/src/include/usr/initservice/initsvcreasoncodes.H
index 5de9a3b51..79a5d5a4e 100644
--- a/src/include/usr/initservice/initsvcreasoncodes.H
+++ b/src/include/usr/initservice/initsvcreasoncodes.H
@@ -67,6 +67,7 @@ enum InitServiceReasonCode
WAIT_FN_FAILED = INITSVC_COMP_ID | 0x09,
INITSVC_LOAD_MODULE_FAILED = INITSVC_COMP_ID | 0x0a,
ISTEP_SINGLESTEP_SHUTDOWN = INITSVC_COMP_ID | 0x0b,
+ ISTEP_SINGLESTEP_ASYNC_RCVD = INITSVC_COMP_ID | 0x0c,
};
diff --git a/src/usr/initservice/istepdispatcher/istep_mbox_msgs.H b/src/usr/initservice/istepdispatcher/istep_mbox_msgs.H
new file mode 100644
index 000000000..6799db5fb
--- /dev/null
+++ b/src/usr/initservice/istepdispatcher/istep_mbox_msgs.H
@@ -0,0 +1,52 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/initservice/istepdispatcher/istep_mbox_msgs.H $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+#ifndef __INITSERVICE_ISTEP_MBOX_MSGS_H
+#define __INITSERVICE_ISTEP_MBOX_MSGS_H
+
+/**
+ * @file istep_mbox_msgs.H
+ *
+ * @brief Mailbox types used by IStepDisp to communicate with FSP/SP
+ *
+ */
+
+#include "splesscommon.H"
+
+namespace INITSERVICE
+{
+
+enum
+{
+ SINGLE_STEP_TYPE = MBOX::FIRST_SECURE_MSG |
+ SPLESS::SPLESS_SINGLE_ISTEP_CMD,
+ CLEAR_TRACE_TYPE = MBOX::FIRST_SECURE_MSG |
+ SPLESS::SPLESS_CLEAR_TRACE_CMD,
+ SHUTDOWN_TYPE = MBOX::FIRST_SECURE_MSG |
+ SPLESS::SPLESS_SHUTDOWN_CMD,
+ BREAKPOINT_TYPE = MBOX::FIRST_UNSECURE_MSG |
+ SPLESS::SPLESS_AT_BREAK_POINT
+};
+
+} // namespace
+
+#endif
diff --git a/src/usr/initservice/istepdispatcher/istepdispatcher.C b/src/usr/initservice/istepdispatcher/istepdispatcher.C
index 519369f64..9a97ad38c 100644
--- a/src/usr/initservice/istepdispatcher/istepdispatcher.C
+++ b/src/usr/initservice/istepdispatcher/istepdispatcher.C
@@ -63,6 +63,9 @@
#include <targeting/target.H>
#include <targeting/targetservice.H>
+#include <mbox/mbox_queues.H> // HB_ISTEP_MSGQ
+#include <mbox/mboxif.H> // register mailbox
+
#include "istepdispatcher.H"
#include "splesscommon.H"
@@ -80,6 +83,7 @@ trace_desc_t *g_trac_isteps_trace = NULL;
} // end namespace
// ----- end namespace ISTEPS_TRACE -----------------------------------
+
// ----- namespace INITSERVICE -------------------------------------------
namespace INITSERVICE
{
@@ -93,126 +97,69 @@ using namespace SPLESS; // SingleStepMode
extern trace_desc_t *g_trac_initsvc;
/**
- * @note SPLess PAUSE - These two constants are used in a nanosleep() call
- * below to sleep between polls of the StatusReg. Typically this will
- * be about 10 ms - the actual value will be determined empirically.
- */
-const uint64_t SINGLESTEP_PAUSE_S = 0;
-const uint64_t SINGLESTEP_PAUSE_NS = 10000000;
-
-/**
* _start() task entry procedure using the macro in taskargs.H
*/
TASK_ENTRY_MACRO( IStepDispatcher::getTheInstance().init );
-const TaskInfo *IStepDispatcher::findTaskInfo(
- const uint16_t i_IStep,
- const uint16_t i_SubStep ) const
-{
- // default return is NULL
- const TaskInfo *l_pistep = NULL;
- /**
- * @todo
- * everything calling this should feed into the "real" istep/substep
- * numbers ( starting at 1 ) - this routine should translate to index into
- * the isteplists ( starting at 0 )
- *
- * int16_t l_istepIndex = i_IStep-1;
- * int16_t l_substepIndex = i_SubStep-1;
- *
- * assert( l_istepIndex >= 0 );
- * assert( l_substepIndex >= 0 );
- */
-
- // apply filters
- do
- {
- // Sanity check / dummy IStep
- if ( g_isteps[i_IStep].pti == NULL)
- {
- TRACDCOMP( g_trac_initsvc,
- "g_isteps[%d].pti == NULL (substep=%d)",
- i_IStep,
- i_SubStep );
- break;
- }
-
- // check input range - IStep
- if ( i_IStep >= MAX_ISTEPS )
- {
- TRACDCOMP( g_trac_initsvc,
- "IStep %d out of range. (substep=%d) ",
- i_IStep,
- i_SubStep );
- break; // break out with l_pistep set to NULL
- }
-
- // check input range - ISubStep
- if ( i_SubStep >= g_isteps[i_IStep].numitems )
- {
- TRACDCOMP( g_trac_initsvc,
- "IStep %d Substep %d out of range.",
- i_IStep,
- i_SubStep );
- break; // break out with l_pistep set to NULL
- }
-
- // check for end of list.
- if ( g_isteps[i_IStep].pti[i_SubStep].taskflags.task_type
- == END_TASK_LIST )
- {
- TRACDCOMP( g_trac_initsvc,
- "IStep %d SubStep %d task_type==END_TASK_LIST.",
- i_IStep,
- i_SubStep );
- break;
- }
-
- // check to see if the pointer to the function is NULL.
- // This is possible if some of the substeps aren't working yet
- // and are just placeholders.
- if ( g_isteps[i_IStep].pti[i_SubStep].taskfn == NULL )
- {
- TRACDCOMP( g_trac_initsvc,
- "IStep %d SubStep %d fn ptr is NULL.",
- i_IStep,
- i_SubStep );
- break;
- }
-
-
- // we're good, set the istep & return it to caller
- l_pistep = &( g_isteps[i_IStep].pti[i_SubStep] );
-
- } while ( 0 );
-
- return l_pistep;
-}
-
-
void IStepDispatcher::init( errlHndl_t &io_rtaskRetErrl )
{
+ errlHndl_t l_errl = NULL;
// initialize (and declare) ISTEPS_TRACE here, the rest of the isteps will use it.
ISTEPS_TRACE::g_trac_isteps_trace = NULL;
printk( "IstepDispatcher entry.\n" );
+ TRACFCOMP( g_trac_initsvc,
+ "IStep Dispatcher entry." );
+
TRAC_INIT(&ISTEPS_TRACE::g_trac_isteps_trace, "ISTEPS_TRACE", 2048 );
- TRACFCOMP( g_trac_initsvc,
- "IStep Dispatcher is starting." );
- if ( getIStepMode() )
+ if ( getIStepMode() == true )
{
printk( "IStep single-step\n" );
-
TRACFCOMP( g_trac_initsvc,
- "IStep single-step enable" );
+ "IStep single-step" );
+
+ if ( SPLESS::SPLessAttached( ) )
+ {
+ // SPless user console is attached,
+ // launch SPTask.
- // IStep single-step
- singleStepISteps( io_rtaskRetErrl );
+ TRACFCOMP( g_trac_initsvc,
+ "IStep single-step enable (SPLESS)" );
+
+ tid_t l_spTaskTid = task_create( spTask, iv_msgQ );
+ // should never happen...
+ assert( l_spTaskTid > 0 );
+
+ // IStep single-step
+ singleStepISteps( io_rtaskRetErrl );
+ }
+ else
+ {
+ TRACFCOMP( g_trac_initsvc,
+ "IStep single-step enable (FSP)" );
+
+ // register message Q with FSP Mailbox
+ l_errl = MBOX::msgq_register(
+ MBOX::HB_ISTEP_MSGQ,
+ iv_msgQ ) ;
+ if ( l_errl )
+ {
+ TRACFCOMP( g_trac_initsvc,
+ "ERROR: Failed to register mailbox, terminating" );
+ // fall through and report errorlog
+ io_rtaskRetErrl = l_errl;
+ }
+ else
+ {
+ // IStep single-step
+ singleStepISteps( io_rtaskRetErrl );
+ }
+ }
}
else
{
@@ -227,235 +174,251 @@ void IStepDispatcher::init( errlHndl_t &io_rtaskRetErrl )
TRACFCOMP( g_trac_initsvc,
- EXIT_MRK "IStepDispatcher finished.");
+ "IStepDispatcher finished.");
printk( "IStepDispatcher exit.\n" );
-
task_end2( io_rtaskRetErrl );
}
-
-bool IStepDispatcher::getIStepMode( ) const
+void IStepDispatcher::runAllISteps( errlHndl_t &io_rtaskRetErrl )
{
- using namespace TARGETING;
- Target* l_pTopLevel = NULL;
- bool l_istepmodeflag = false;
- TargetService& l_targetService = targetService();
-
- (void) l_targetService.getTopLevelTarget(l_pTopLevel);
- if (l_pTopLevel == NULL)
- {
- TRACFCOMP( g_trac_initsvc, "Top level handle was NULL" );
- l_istepmodeflag = false;
- }
- else
- {
- l_istepmodeflag = l_pTopLevel->getAttr<ATTR_ISTEP_MODE> ();
- // printk( "IStep Mode flag = 0x%x\n", l_istepmodeflag );
- }
-
-
- return l_istepmodeflag;
-}
-
+ errlHndl_t l_errl = NULL;
+ uint32_t l_IStep = 0;
+ uint32_t l_SubStep = 0;
+ const TaskInfo *l_pistep = NULL;
+ uint64_t l_progresscode = 0;
-void IStepDispatcher::processSingleIStepCmd(
- SPLessCmd &i_rrawcmd )
-{
- errlHndl_t l_errl = NULL;
- const TaskInfo *l_pistep = NULL;
- // init the command 0x00 struct to the incoming command reg values
- SPLessSingleIStepCmd l_cmd( i_rrawcmd );
- // create a cleared status 0x00 reg
- SPLessSingleIStepSts l_sts;
- // look up istep+substep
- l_pistep = IStepDispatcher::getTheInstance().findTaskInfo(
- l_cmd.istep,
- l_cmd.substep );
- do
+ for ( l_IStep=0;
+ l_IStep<INITSERVICE::MAX_ISTEPS;
+ l_IStep++ )
{
- if ( l_pistep == NULL )
+ for ( l_SubStep=0;
+ l_SubStep < INITSERVICE::MAX_SUBSTEPS;
+ l_SubStep++)
{
- // invalid istep, return error
- l_sts.hdr.runningbit = false;
- l_sts.hdr.readybit = true;
- l_sts.hdr.status = SPLESS_TASKRC_INVALID_ISTEP;
- l_sts.istep = l_cmd.istep;
- l_sts.substep = l_cmd.substep;
- l_sts.istepStatus = 0;
-
/**
- * @todo post informational errl here.
+ * @todo refactor - replace the following block with
+ * processSingleIStepCmd()
*/
- TRACFCOMP( g_trac_initsvc,
- "processSingleIStepCmd: ERROR: Cannot find IStep=%d, SubStep=%d",
- l_cmd.istep,
- l_cmd.substep );
-
- // return to caller to write back to user console
- iv_sts.val64 = l_sts.val64;
- break;
- }
-
-
- // set running bit, fill in istep and substep
- l_sts.hdr.runningbit = true;
- l_sts.hdr.readybit = true;
- l_sts.hdr.status = 0;
- l_sts.istep = l_cmd.istep;
- l_sts.substep = l_cmd.substep;
- l_sts.istepStatus = 0;
-
- TRACDCOMP( g_trac_initsvc,
- "processSingleIStepCmd: Running IStep=%d, SubStep=%d",
- l_cmd.istep,
- l_cmd.substep );
+ l_pistep = findTaskInfo(
+ l_IStep,
+ l_SubStep );
+ if ( l_pistep == NULL )
+ {
- // write intermediate value back to user console
- iv_sts.val64 = l_sts.val64;
- writeSts( iv_sts );
+ break; // break out of inner for loop
+ }
- // handleBreakPoint will need sequence number
- iv_sts.hdr.seqnum = l_cmd.hdr.seqnum;
+ // @todo placeholder until progress codes are defined and
+ // progress code driver is implemented.
+ l_progresscode = 0;
+ InitService::getTheInstance().setProgressCode( l_progresscode );
- /**
- * @todo placeholder - set progress code before starting
- * This will not be finalized until the progress code driver
- * is designed and implemented.
- */
- uint64_t l_progresscode = ( (l_cmd.istep<<16) | l_cmd.substep );
- InitService::getTheInstance().setProgressCode( l_progresscode );
+ // print out what we are running
+ TRACFCOMP( g_trac_initsvc,
+ "IStepDisp: Run IStep %d.%d %s",
+ l_IStep,
+ l_SubStep,
+ l_pistep->taskname );
- TRACFCOMP( g_trac_initsvc,
- "processSingleIStepCmd: Running IStep=%d, SubStep=%d %s",
- l_cmd.istep,
- l_cmd.substep,
- l_pistep->taskname );
+ l_errl = InitService::getTheInstance().executeFn(
+ l_pistep,
+ NULL );
- // clear the status struct for the next step
- l_sts.val64 = 0;
+ // check for errors
+ if ( l_errl )
+ {
+ TRACFCOMP( g_trac_initsvc,
+ "IStepDisp: istep %s returned errlog=%p",
+ l_pistep->taskname,
+ l_errl );
+ // if we have an errorlog, break out of the inner loop
+ // and handle it.
+ break;
+ }
+ } // endfor l_SubStep
- // launch the istep
- l_errl = InitService::getTheInstance().executeFn( l_pistep,
- NULL );
- // check for child errorlog
if ( l_errl )
{
- // tell the user that the IStep returned an errorlog
- l_sts.hdr.status = SPLESS_TASKRC_RETURNED_ERRLOG;
- l_sts.istepStatus = SPLESS_TASKRC_RETURNED_ERRLOG;
- // go ahead and commit the child errorlog
- errlCommit( l_errl, INITSVC_COMP_ID );
+ // something left an error log in the inner loop, breakout
+ break;
}
-
- // send status to the user console.
- // clear runningbit, report status
- // set running bit, fill in istep and substep
- l_sts.hdr.runningbit = false;
- l_sts.hdr.readybit = true;
- // l_sts.hdr.seqnum set by caller
- // task status set above
- l_sts.istep = l_cmd.istep;
- l_sts.substep = l_cmd.substep;
- // istepStatus set above
+ } // endfor l_IStep
- /**
- * @todo post informational errl here.
- */
-
- // write to status reg, return to caller to write to user console
- iv_sts = l_sts;
+ /**
+ * @todo detect Can-Continue condition here and reset/rerun ISteps.
+ * For now this is pushed to a later sprint.
+ */
- break;
+ //
+ if ( l_errl )
+ {
+ TRACFCOMP( g_trac_initsvc,
+ "IStepDisp ERROR: errorlog %p",
+ l_errl );
- } while(0);
+ // return to _start() with the errorlog set, parent should do shutdown
+ io_rtaskRetErrl = l_errl;
+ }
+ // return to init with io_rtaskRetErrl set
}
void IStepDispatcher::singleStepISteps( errlHndl_t &io_rtaskRetErrl )
{
- SPLessCmd l_cmd;
- uint8_t l_seqnum = 0;
- bool quitflag = false;
- errlHndl_t l_errl = NULL;
-
- // init to no errorlog
- io_rtaskRetErrl = NULL;
+ SPLESS::SPLessSts l_StsReg;
+ uint32_t l_Type = 0;
+ uint32_t l_IStep = 0;
+ uint32_t l_Substep = 0;
+ bool l_quitflag = false;
+ uint32_t l_RetSts = 0;
+ errlHndl_t l_errl = NULL;
+ uint32_t l_PLID = 0;
+
+ // tell VPO and Simics that we're ready
+ l_StsReg.hdr.readybit = 1;
+ SPLESS::writeSts( l_StsReg );
mutex_lock(&iv_poll_mutex); // make sure this is only poller
- // initialize command reg
- l_cmd.val64 = 0;
- writeCmd( l_cmd );
+ while ( 1 )
+ {
+ TRACDCOMP( g_trac_initsvc,
+ "IStepDisp wait for message." );
- // init status reg, enable ready bit
- iv_sts.val64 = 0;
- iv_sts.hdr.readybit = true;
- writeSts( iv_sts );
+ // wait for message from FSP or Dispatcher
+ iv_pMsg = msg_wait( iv_msgQ );
- //
- // @note Start the polling loop.
- // Currently this has no exit, user should reset the machine and/or
- // load the payload, which will wipe HostBoot from memory.
- // Loop forever, unless something Very Bad happens.
- //
- while( 1 )
- {
+ // unblocked
+ if ( msg_is_async( iv_pMsg ) )
+ {
+ // should not receive async messages here, drop it, post errorlog
+ // and go back to waiting.
+ TRACFCOMP( g_trac_initsvc,
+ "singleStepISteps: ERROR async msg type 0x%x, msg 0x%x.%x",
+ iv_pMsg->type,
+ static_cast<uint32_t>( iv_pMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( iv_pMsg->data[0] & 0xffffffff ) );
- // read command register from user console
- readCmd( l_cmd );
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid BASE_INITSVC_MOD_ID
+ * @reasoncode ISTEP_SINGLESTEP_ASYNC_RCVD
+ * @userdata1 type of packet
+ * @userdata2 first data word
+ *
+ * @devdesc IStepDisp was expecting a synchronous message
+ * and received an asynchonous message.
+ *
+ */
+ errlHndl_t l_errlAsync = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ INITSERVICE::BASE_INITSVC_MOD_ID,
+ INITSERVICE::ISTEP_SINGLESTEP_ASYNC_RCVD,
+ iv_pMsg->type,
+ iv_pMsg->data[0] );
- // get the sequence number
- l_seqnum = l_cmd.hdr.seqnum;
+ errlCommit( l_errlAsync, INITSVC_COMP_ID );
- // process any pending commands
- if ( l_cmd.hdr.gobit )
- {
- switch( l_cmd.hdr.cmdnum )
- {
+ msg_free(iv_pMsg);
+ iv_pMsg = NULL;
- case SPLESS_SINGLE_ISTEP_CMD:
- mutex_unlock(&iv_poll_mutex);
- // command 0: run istep/substep
- processSingleIStepCmd( l_cmd );
- mutex_lock(&iv_poll_mutex);
- break;
+ continue;
+ }
- case SPLESS_RESUME_ISTEP_CMD: // not at break point here
- iv_sts.hdr.status = SPLESS_NOT_AT_BREAK_POINT;
- break;
- case SPLESS_CLEAR_TRACE_CMD:
- TRAC_CLEAR_BUFFERS();
- TRACFCOMP( g_trac_initsvc,
- "Cleared all trace buffers." );
- break;
+ l_Type = iv_pMsg->type;
+ l_IStep = static_cast<uint32_t>( iv_pMsg->data[0] >>32 ) ;
+ l_Substep = static_cast<uint32_t>( iv_pMsg->data[0] & 0x0FFFFFFFF );
- case SPLESS_SHUTDOWN_CMD:
- iv_sts.hdr.status = SPLESS_SHUTTING_DOWN;
- quitflag = true;
- break;
+ TRACDCOMP( g_trac_initsvc,
+ "IStepDisp recv msg type 0x%x, 0x%x.%x",
+ l_Type,
+ l_IStep,
+ l_Substep );
- default:
- iv_sts.hdr.status = SPLESS_INVALID_COMMAND;
- } // endif switch
+ // Clear Status and PLID fields for response msg
+ l_RetSts = 0;
+ l_PLID = 0;
- iv_sts.hdr.seqnum = l_seqnum;
- // status should be set now, write to Status Reg.
- writeSts( iv_sts );
+ switch( l_Type )
+ {
+ case SINGLE_STEP_TYPE:
+ mutex_unlock(&iv_poll_mutex);
+ // command 0: run istep/substep
+ TRACDCOMP( g_trac_initsvc,
+ "Run istep %d.%d ",
+ l_IStep,
+ l_Substep );
+ l_errl = processSingleIStepCmd( l_IStep, l_Substep, l_RetSts );
+ mutex_lock(&iv_poll_mutex);
+ break;
+
+ case BREAKPOINT_TYPE: // not at break point here
+ TRACDCOMP( g_trac_initsvc,
+ "Not at break point." );
+ l_RetSts = SPLESS_NOT_AT_BREAK_POINT;
+ break;
+
+ case CLEAR_TRACE_TYPE:
+ TRAC_CLEAR_BUFFERS();
+ TRACFCOMP( g_trac_initsvc,
+ "Cleared all trace buffers." );
+ l_RetSts = SPLESS_TRACE_BUFFERS_CLEARED;
+ break;
+
+ case SHUTDOWN_TYPE:
+ TRACFCOMP( g_trac_initsvc,
+ "Shutting down HostBoot. " );
+ l_RetSts = SPLESS_SHUTTING_DOWN;
+ l_quitflag = true;
+ break;
+
+ default:
+ TRACFCOMP( g_trac_initsvc,
+ "ERROR: invalid command 0x%x ",
+ l_Type );
+ l_RetSts = SPLESS_INVALID_COMMAND;
+ break;
+ } // end switch
+
+ if ( l_errl )
+ {
+ // tell the user console that the IStep returned an errorlog
+ l_RetSts = SPLESS_TASKRC_RETURNED_ERRLOG;
+ // get the platform log identifier (PLID) to send to FSP
+ l_PLID = l_errl->plid();
+
+ // go ahead and commit the child errorlog
+ errlCommit( l_errl, INITSVC_COMP_ID );
+ }
+
+ iv_pMsg->type = l_Type;
+ // Return l_RetSts as hi word of data[0]
+ // Return l_PLID as lo word of data[0]
+ iv_pMsg->data[0] =
+ ( static_cast<uint64_t>( l_RetSts ) << 32 ) |
+ static_cast<uint64_t>( l_PLID ) ;
- // clear command reg, including go bit (i.e. set to false)
- l_cmd.val64 = 0;
- writeCmd( l_cmd );
- } // endif gobit
+ iv_pMsg->data[1] = 0;
+ iv_pMsg->extra_data = NULL;
+
+ TRACDCOMP( g_trac_initsvc,
+ "IStepDisp send msg type 0x%x, 0x%x.%x",
+ iv_pMsg->type,
+ static_cast<uint32_t>( iv_pMsg->data[0] >> 32),
+ static_cast<uint32_t>( iv_pMsg->data[0] & 0xFFFFFFFF ));
+ // send status back
+ msg_respond( iv_msgQ, iv_pMsg );
- if ( quitflag == true )
+
+ if ( l_quitflag == true )
{
// shutdown command issued, break out of loop
@@ -475,124 +438,186 @@ void IStepDispatcher::singleStepISteps( errlHndl_t &io_rtaskRetErrl )
INITSERVICE::ISTEP_SINGLESTEP_SHUTDOWN,
0,
0 );
-
break;
}
- // sleep, and wait for user to give us something else to do.
- /**
- * @todo Need a common method of doing delays in HostBoot
- * @VBU workaround
- */
- // Don't delay as long in VBU because it will take VERY long to
- // run the simulator
- if( TARGETING::is_vpo() )
- {
- // VBU delay per Patrick
- nanosleep(0,TEN_CTX_SWITCHES_NS);
- }
- else
- {
- nanosleep( SINGLESTEP_PAUSE_S, SINGLESTEP_PAUSE_NS );
- }
- } // endwhile
-
+ } // end while
- // @note
- // Fell out of loop, clear sts reg and turn off readybit
- // disable the ready bit so the user knows.
- iv_sts.val64 = 0;
- iv_sts.hdr.status = SPLESS_TASKRC_TERMINATED;
- iv_sts.hdr.seqnum = l_seqnum;
- writeSts( iv_sts );
+ // fell out of loop, return with rtaskRetErrl set
mutex_unlock(&iv_poll_mutex);
-
- // return with io_rtaskRetErrl set
io_rtaskRetErrl = l_errl;
}
-void IStepDispatcher::runAllISteps( errlHndl_t &io_rtaskRetErrl ) const
+errlHndl_t IStepDispatcher::processSingleIStepCmd(
+ const uint32_t i_IStep,
+ const uint32_t i_Substep,
+ uint32_t &o_rSts )
{
- errlHndl_t l_errl = NULL;
- uint16_t l_IStep = 0;
- uint16_t l_SubStep = 0;
- const TaskInfo *l_pistep = NULL;
- uint64_t l_progresscode = 0;
+ errlHndl_t l_errl = NULL;
+ const TaskInfo *l_pistep = NULL;
- // init, just to be sure.
- io_rtaskRetErrl = NULL;
+ o_rSts = 0;
- for ( l_IStep=0;
- l_IStep<INITSERVICE::MAX_ISTEPS;
- l_IStep++ )
+ // look up istep+substep
+ l_pistep = IStepDispatcher::getTheInstance().findTaskInfo(
+ i_IStep,
+ i_Substep );
+ do
{
- for ( l_SubStep=0;
- l_SubStep < INITSERVICE::MAX_SUBSTEPS;
- l_SubStep++)
+ if ( l_pistep == NULL )
{
- l_pistep = findTaskInfo( l_IStep,
- l_SubStep );
- if ( l_pistep == NULL )
- {
+ // invalid istep, return error
+ TRACDCOMP( g_trac_initsvc,
+ "processSingleIStepCmd: Invalid IStep %d.%d\n",
+ i_IStep,
+ i_Substep );
- break; // break out of inner for loop
- }
- // @todo placeholder until progress codes are defined and
- // progress code driver is implemented.
- l_progresscode = ( (l_IStep<<16) | l_SubStep );
- InitService::getTheInstance().setProgressCode( l_progresscode );
+ o_rSts = SPLESS_INVALID_COMMAND;
+ break;
+ }
- // print out what we are running
- TRACFCOMP( g_trac_initsvc,
- "IStepDisp: Run IStep %d.%d %s",
- l_IStep,
- l_SubStep,
- l_pistep->taskname );
+ /**
+ * @todo placeholder - set progress code before starting
+ * This will not be finalized until the progress code driver
+ * is designed and implemented.
+ */
+ uint64_t l_progresscode = 0;
+ InitService::getTheInstance().setProgressCode( l_progresscode );
- l_errl = InitService::getTheInstance().executeFn( l_pistep,
- NULL );
- if ( l_errl )
- {
- TRACFCOMP( g_trac_initsvc,
- "IStepDisp: istep %s returned errlog=%p",
- l_pistep->taskname,
- l_errl );
- // if we have an errorlog, break out of the inner loop
- // and handle it.
- break;
- }
- } // endfor l_SubStep
+ TRACDCOMP( g_trac_initsvc,
+ "processSingleIStepCmd: Run IStep=%d.%d %s",
+ i_IStep,
+ i_Substep,
+ l_pistep->taskname );
+
+ // launch the istep
+ l_errl = InitService::getTheInstance().executeFn(
+ l_pistep,
+ NULL );
if ( l_errl )
{
- // something left an error log in the inner loop, breakout
+ // @todo post informational errl here?
+
break;
}
- } // endfor l_IStep
+
+ } while(0);
+
+
+ return l_errl;
+}
+const TaskInfo *IStepDispatcher::findTaskInfo(
+ const uint32_t i_IStep,
+ const uint32_t i_SubStep ) const
+{
+ // default return is NULL
+ const TaskInfo *l_pistep = NULL;
/**
- * @todo detect Can-Continue condition here and reset/rerun ISteps.
- * For now this is pushed to a later sprint.
+ * @todo
+ * everything calling this should feed into the "real" istep/substep
+ * numbers ( starting at 1 ) - this routine should translate to index into
+ * the isteplists ( starting at 0 )
+ *
+ * int32_t l_istepIndex = i_IStep-1;
+ * int32_t l_substepIndex = i_SubStep-1;
+ *
+ * assert( l_istepIndex >= 0 );
+ * assert( l_substepIndex >= 0 );
*/
-
- if ( l_errl )
+ // apply filters
+ do
{
- TRACFCOMP( g_trac_initsvc,
- "IStepDisp ERROR: errorlog %p",
- l_errl );
+ // Sanity check / dummy IStep
+ if ( g_isteps[i_IStep].pti == NULL)
+ {
+ TRACDCOMP( g_trac_initsvc,
+ "g_isteps[%d].pti == NULL (substep=%d)",
+ i_IStep,
+ i_SubStep );
+ break;
+ }
- // return to _start() with the errorlog set, parent should do shutdown
- io_rtaskRetErrl = l_errl;
- }
+ // check input range - IStep
+ if ( i_IStep >= MAX_ISTEPS )
+ {
+ TRACDCOMP( g_trac_initsvc,
+ "IStep %d out of range. (substep=%d) ",
+ i_IStep,
+ i_SubStep );
+ break; // break out with l_pistep set to NULL
+ }
+
+ // check input range - ISubStep
+ if ( i_SubStep >= g_isteps[i_IStep].numitems )
+ {
+ TRACDCOMP( g_trac_initsvc,
+ "IStep %d Substep %d out of range.",
+ i_IStep,
+ i_SubStep );
+ break; // break out with l_pistep set to NULL
+ }
+
+ // check for end of list.
+ if ( g_isteps[i_IStep].pti[i_SubStep].taskflags.task_type
+ == END_TASK_LIST )
+ {
+ TRACDCOMP( g_trac_initsvc,
+ "IStep %d SubStep %d task_type==END_TASK_LIST.",
+ i_IStep,
+ i_SubStep );
+ break;
+ }
+
+ // check to see if the pointer to the function is NULL.
+ // This is possible if some of the substeps aren't working yet
+ // and are just placeholders.
+ if ( g_isteps[i_IStep].pti[i_SubStep].taskfn == NULL )
+ {
+ TRACDCOMP( g_trac_initsvc,
+ "IStep %d SubStep %d fn ptr is NULL.",
+ i_IStep,
+ i_SubStep );
+ break;
+ }
+
+
+ // we're good, set the istep & return it to caller
+ l_pistep = &( g_isteps[i_IStep].pti[i_SubStep] );
+
+ } while ( 0 );
+ return l_pistep;
}
+bool IStepDispatcher::getIStepMode( ) const
+{
+ using namespace TARGETING;
+ Target* l_pTopLevel = NULL;
+ bool l_istepmodeflag = false;
+ TargetService& l_targetService = targetService();
+
+ (void) l_targetService.getTopLevelTarget(l_pTopLevel);
+ if (l_pTopLevel == NULL)
+ {
+ TRACFCOMP( g_trac_initsvc, "Top level handle was NULL" );
+ l_istepmodeflag = false;
+ }
+ else
+ {
+ l_istepmodeflag = l_pTopLevel->getAttr<ATTR_ISTEP_MODE> ();
+ // printk( "IStep Mode flag = 0x%x\n", l_istepmodeflag );
+ }
+
+ return l_istepmodeflag;
+}
bool IStepDispatcher::getCanContinueProcedure( const TaskInfo &i_failingIStep,
@@ -611,127 +636,188 @@ IStepDispatcher& IStepDispatcher::getTheInstance()
}
-IStepDispatcher::IStepDispatcher()
- : iv_sts()
+void IStepDispatcher::handleBreakPoint( uint32_t i_info )
{
- mutex_init(&iv_poll_mutex);
- // set up IStep Mode
- initIStepMode();
-}
+ msg_t *l_pBpMsg = msg_allocate();
+ errlHndl_t l_errl = NULL;
+ // need to be the only poller
+ mutex_lock(&iv_poll_mutex);
-IStepDispatcher::~IStepDispatcher()
-{ }
+ l_pBpMsg->type = BREAKPOINT_TYPE;
+ l_pBpMsg->data[0] =
+ ( static_cast<uint64_t>( i_info ) << 32 ) |
+ static_cast<uint64_t>( 0 ) ;
+ l_pBpMsg->data[1] = 0;
+ l_pBpMsg->extra_data = NULL;
-void IStepDispatcher::handleBreakPoint( uint32_t i_info )
+ // send new message to FSP
+ TRACDCOMP( g_trac_initsvc,
+ "handleBreakPoint: FSP: send sts type 0x%x, msg 0x%x.%x",
+ l_pBpMsg->type,
+ static_cast<uint32_t>( l_pBpMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( l_pBpMsg->data[0] & 0xffffffff ) );
+
+ // send status to FSP
+ l_errl = MBOX::sendrecv( MBOX::HB_ISTEP_MSGQ, l_pBpMsg );
+ if ( l_errl )
+ {
+ TRACFCOMP( g_trac_initsvc,
+ "handleBreakPoint: ERROR on MBOX sendrecv" );
+ errlCommit( l_errl, INITSVC_COMP_ID );
+
+ // If sendrecv fails for some reason, error will be logged and
+ // breakpoint will resume anyway.
+ }
+
+ // unblocked
+
+ TRACDCOMP( g_trac_initsvc,
+ "handleBreakPoint exit: receive msg type 0x%x, msg 0x%x.%x",
+ l_pBpMsg->type,
+ static_cast<uint32_t>( l_pBpMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( l_pBpMsg->data[0] & 0xffffffff ) );
+
+ msg_free( l_pBpMsg );
+ mutex_unlock(&iv_poll_mutex);
+}
+
+
+void IStepDispatcher::handleSPlessBreakPoint( uint32_t i_info )
{
- SPLessCmd l_cmd;
- SPLessSingleIStepSts l_sts;
- uint8_t l_seqnum = 0;
- bool l_istepmode = false;
+
+ TRACDCOMP( g_trac_initsvc,
+ "handleBreakPoint: hijacking message Q" );
// need to be the only poller
mutex_lock(&iv_poll_mutex);
- // init command reg
- l_cmd.val64 = 0;
- writeCmd ( l_cmd );
- // write status
- if(iv_sts.val64 != 0) // istep mode
- {
- l_istepmode = true;
- l_sts = iv_sts;
- l_sts.hdr.runningbit = false;
- }
- // else not in istep mode
+ iv_pMsg->type = BREAKPOINT_TYPE;
+ iv_pMsg->data[0] =
+ ( static_cast<uint64_t>( i_info ) << 32 ) |
+ static_cast<uint64_t>( 0 ) ;
+ iv_pMsg->data[1] = 0;
+ iv_pMsg->extra_data = NULL;
- l_sts.hdr.readybit = true;
- l_sts.hdr.status = SPLESS_AT_BREAK_POINT;
- l_sts.istepStatus = i_info;
+ TRACDCOMP( g_trac_initsvc,
+ "handleBreakPoint: send sts msg type 0x%x, msg 0x%x.%x",
+ iv_pMsg->type,
+ static_cast<uint32_t>( iv_pMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( iv_pMsg->data[0] & 0xffffffff ) );
- iv_sts = l_sts;
- writeSts( iv_sts );
+ // respond to SPtask
+ msg_respond( iv_msgQ, iv_pMsg );
// Poll for cmd to resume
- while(1)
+ while( 1 )
{
- readCmd( l_cmd );
- l_seqnum = l_cmd.hdr.seqnum;
- if( l_cmd.hdr.gobit)
- {
- // only expect this command
- if (l_cmd.hdr.cmdnum == SPLESS_RESUME_ISTEP_CMD)
- {
- iv_sts.hdr.seqnum = l_seqnum;
- writeSts( iv_sts );
- l_cmd.val64 = 0;
- writeCmd( l_cmd );
- break; // return to continue istep
- }
- else // all other commands are not valid here.
- {
- iv_sts.hdr.status = SPLESS_AT_BREAK_POINT;
+ // wait for message from SPtask
+ iv_pMsg = msg_wait( iv_msgQ );
- // write status
- iv_sts.hdr.seqnum = l_seqnum;
- writeSts( iv_sts );
+ // unblocked
- // clear cmd reg, including go bit
- l_cmd.val64 = 0;
- writeCmd( l_cmd );
- }
+ if ( msg_is_async( iv_pMsg ) )
+ {
+ // should not receive async messages here, drop it, post errorlog
+ // and go back to waiting.
+ TRACFCOMP( g_trac_initsvc,
+ "handleBreakPoint: ERROR async msg type 0x%x, msg 0x%x.%x",
+ iv_pMsg->type,
+ static_cast<uint32_t>( iv_pMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( iv_pMsg->data[0] & 0xffffffff ) );
+
+ /*@ errorlog tag
+ * @errortype ERRL_SEV_INFORMATIONAL
+ * @moduleid BASE_INITSVC_MOD_ID
+ * @reasoncode ISTEP_SINGLESTEP_ASYNC_RCVD
+ * @userdata1 type of packet
+ * @userdata2 first data word
+ *
+ * @devdesc IStepDisp was expecting a synchronous message
+ * and received an asynchonous message.
+ *
+ */
+ errlHndl_t l_errlAsync = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ INITSERVICE::BASE_INITSVC_MOD_ID,
+ INITSERVICE::ISTEP_SINGLESTEP_ASYNC_RCVD,
+ iv_pMsg->type,
+ iv_pMsg->data[0] );
+
+ errlCommit( l_errlAsync, INITSVC_COMP_ID );
+
+ msg_free( iv_pMsg );
+ iv_pMsg = NULL;
+ continue;
}
+ TRACDCOMP( g_trac_initsvc,
+ "handleBreakPoint: receive msg type 0x%x, msg 0x%x.%x",
+ iv_pMsg->type,
+ static_cast<uint32_t>( iv_pMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( iv_pMsg->data[0] & 0xffffffff ) );
- // TODO want to do the same kind fo delay as IStepDispatcher::singleStepISteps()
- /**
- * @todo Need a common method of doing delays in HostBoot
- * @VBU workaround
- */
- // Don't delay as long in VBU because it will take VERY long to
- // run the simulator
- if( TARGETING::is_vpo() )
- {
- // VBU delay per Patrick
- nanosleep(0,TEN_CTX_SWITCHES_NS);
- }
- else
- {
- nanosleep( SINGLESTEP_PAUSE_S, SINGLESTEP_PAUSE_NS );
- }
- }
+ // only expect this command
+ if ( iv_pMsg->type == BREAKPOINT_TYPE )
+ {
+ // correct response, return to istep
+ break;
+ }
+ else
+ {
+ // all other commands are not valid here, return the same status
+ iv_pMsg->type = BREAKPOINT_TYPE;
+ iv_pMsg->data[0] =
+ ( static_cast<uint64_t>( i_info ) << 32 ) |
+ static_cast<uint64_t>( 0 ) ;
+ iv_pMsg->data[1] = 0;
+ iv_pMsg->extra_data = NULL;
+
+ TRACDCOMP( g_trac_initsvc,
+ "handleBreakPoint: send sts msg type 0x%x, msg 0x%x.%x",
+ iv_pMsg->type,
+ static_cast<uint32_t>( iv_pMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( iv_pMsg->data[0] & 0xffffffff ) );
+
+ // reply back to SPLEss
+ msg_respond( iv_msgQ, iv_pMsg );
+ } // end else
+ } // end while
- l_sts = iv_sts;
- l_sts.hdr.runningbit = true;
- l_sts.hdr.status = 0;
- l_sts.istepStatus = 0;
+ mutex_unlock(&iv_poll_mutex);
+}
- if(l_istepmode)
+// route to SPless or FSP depending on what's attached
+void iStepBreakPoint(uint32_t i_info)
+{
+ if ( SPLESS::SPLessAttached() )
{
- l_sts.hdr.readybit = true;
- l_sts.hdr.seqnum = 0;
+ IStepDispatcher::getTheInstance().handleSPlessBreakPoint( i_info );
}
- else // not in istep mode - unit testing
+ else
{
- // For unit test, bp is allowed to run outside of istepmode.
- // Return this flag to dispatcher not ready.
- // ie Don't wait for dispatcher of finish the single istep.
- l_sts.hdr.readybit = false;
- // leave seqnum as is
+ IStepDispatcher::getTheInstance().handleBreakPoint( i_info );
}
-
- iv_sts = l_sts;
- writeSts( iv_sts );
-
- mutex_unlock(&iv_poll_mutex);
}
-void iStepBreakPoint(uint32_t i_info)
+
+IStepDispatcher::IStepDispatcher()
+: iv_sts()
{
- IStepDispatcher::getTheInstance().handleBreakPoint( i_info );
+ SPLESS::initIStepMode();
+ mutex_init(&iv_poll_mutex);
+
+ // init mailbox / message Q.
+ iv_msgQ = msg_q_create();
+
}
+
+IStepDispatcher::~IStepDispatcher()
+{ }
+
+
} // namespace
diff --git a/src/usr/initservice/istepdispatcher/istepdispatcher.H b/src/usr/initservice/istepdispatcher/istepdispatcher.H
index b4842f5e9..e05660bd9 100644
--- a/src/usr/initservice/istepdispatcher/istepdispatcher.H
+++ b/src/usr/initservice/istepdispatcher/istepdispatcher.H
@@ -43,6 +43,10 @@
#include <stdint.h>
#include <util/singleton.H>
+#include <sys/msg.h>
+#include <mbox/mboxif.H> // mailbox Q
+#include <mbox/mbox_queues.H> // HB_ISTEP_MSGQ
+
#include <errl/errlentry.H>
#include <initservice/taskargs.H>
#include <initservice/initsvcreasoncodes.H>
@@ -52,20 +56,33 @@
#include "splesscommon.H"
+#include "istep_mbox_msgs.H"
+
namespace INITSERVICE
{
-// using namespace SPLESS;
-
/******************************************************************************/
// Globals/Constants
/******************************************************************************/
+
/******************************************************************************/
// Typedef/Enumerations
/******************************************************************************/
+/**
+ * @brief detached task (daemon) to handle communication from
+ * VPO / Simics user console.
+ *
+ * param[in,out] - pointer to any args
+ *
+ * @return nothing
+ *
+ */
+void spTask( void *io_pArgs );
+
+
/******************************************************************************/
// Class IStepDispatcher
/******************************************************************************/
@@ -100,13 +117,21 @@ public:
/**
- * @brief Handle an istep break point
+ * @brief Handle an istep break point to FSP
+ * @param[in] i_info, @TODO - location/info
+ *
+ * @note blocks until an outside istep cmd to resume is received.
+ */
+ void handleBreakPoint( uint32_t info);
+
+ /**
+ * @brief Handle an istep break point from SPless
* @param[in] i_info, @TODO - location/info
* @pre iv_sts contains current istep status + seqnum or
* 0 if not in step mode
* @note blocks until an outside istep cmd to resume is recieved.
*/
- void handleBreakPoint( uint32_t info);
+ void handleSPlessBreakPoint( uint32_t info);
protected:
@@ -129,7 +154,6 @@ private:
IStepDispatcher(const IStepDispatcher& i_right);
IStepDispatcher& operator=(const IStepDispatcher& i_right);
-
/**
* @brief getIStepMode - return value of IStep Mode
*
@@ -152,46 +176,35 @@ private:
*
*/
const TaskInfo *findTaskInfo(
- const uint16_t i_IStep,
- const uint16_t i_SubStep ) const;
-
- /**
- * @brief Command 0: Run the requested IStep/SubStep
- *
- * param[in] i_rcmd - ref to a filled in SPLessCmd struct
- * @post iv_sts set to current istep status
- *
- * @return none
- */
- void processSingleIStepCmd( SPLESS::SPLessCmd &i_rcmd);
-
+ const uint32_t i_IStep,
+ const uint32_t i_SubStep ) const;
/**
- * @brief singleStepISteps
+ * @brief runAllISteps
+ *
+ * Run all available ISteps sequentially.
+ * If an IStep gets an error, report it and stop.
+ * Otherwise, return.
*
- * Stop and wait for SP to send the next IStep to run. Run that, then
- * wait for the next one.
* @param[in,out] - ref to an errlHndl_t that can be passed back to
* ExtInitSvc .
*
* @return none
*/
- void singleStepISteps( errlHndl_t &io_rtaskRetErrl ) ;
+ void runAllISteps( errlHndl_t &io_rtaskRetErrl ) ;
/**
- * @brief runAllISteps
+ * @brief singleStepISteps
*
- * Run all available ISteps sequentially.
- * If an IStep gets an error, report it and stop.
- * Otherwise, return.
+ * Go into a polling loop, waiting for Istep commands from
+ * the FSP or SPTask.
*
* @param[in,out] - ref to an errlHndl_t that can be passed back to
* ExtInitSvc .
- *
* @return none
*/
- void runAllISteps( errlHndl_t &io_rtaskRetErrl ) const;
+ void singleStepISteps( errlHndl_t &io_rtaskRetErrl ) ;
/**
@@ -222,11 +235,31 @@ private:
TaskInfo &io_nextIStep ) const;
+ /**
+ * @brief Command 0: Run the requested IStep/SubStep
+ *
+ * param[in] i_IStep - IStep number
+ * param[in] i_Substep - Substep number
+ * param[out] o_rSts - lookup status - returns Invalid if the
+ * IStep, Substep doesn't exist
+ *
+ * @post iv_sts set to current istep status
+ *
+ * @return errlHndl_t
+ */
+ errlHndl_t processSingleIStepCmd(
+ const uint32_t i_IStep,
+ const uint32_t i_Substep,
+ uint32_t &o_rSts );
+
+
+
// ----- internal vars -----------------------------
mutex_t iv_poll_mutex; //!< protect who's polling istep cmds
SPLESS::SPLessSts iv_sts; //!< Current status of istep mode
-
+ msg_q_t iv_msgQ; //!< Message Q to FSP & SPTask.
+ msg_t *iv_pMsg; //!< ptr to msg from FSP or user console
}; // class IStepDispatcher
diff --git a/src/usr/initservice/istepdispatcher/makefile b/src/usr/initservice/istepdispatcher/makefile
index c65342107..d2e094b5a 100644
--- a/src/usr/initservice/istepdispatcher/makefile
+++ b/src/usr/initservice/istepdispatcher/makefile
@@ -24,7 +24,8 @@
ROOTPATH = ../../../..
MODULE = istepdisp
-OBJS = istepdispatcher.o initsvcudistep.o
+OBJS = istepdispatcher.o initsvcudistep.o \
+ sptask.o
## SUBDIRS = test.d
diff --git a/src/usr/initservice/istepdispatcher/splesscommon.H b/src/usr/initservice/istepdispatcher/splesscommon.H
index e912b7a85..ecf863f5f 100644
--- a/src/usr/initservice/istepdispatcher/splesscommon.H
+++ b/src/usr/initservice/istepdispatcher/splesscommon.H
@@ -41,15 +41,20 @@
#include <stdio.h>
#include <string.h>
-// undefine this before checking in....
+// $$$$$$$ undefine this before checking in....
// #define SPLESS_DEBUG 1
#ifdef SPLESS_DEBUG
- #include <kernel/console.H> // printk DEBUG
+ #include <kernel/console.H> // printk DEBUG
#endif
#include <sys/mmio.h> // mmio_scratch_read()
+#include <targeting/attributes.H> // ISTEP_MODE attribute
+#include <targeting/entitypath.H>
+#include <targeting/target.H>
+#include <targeting/targetservice.H>
+
// external reference
namespace INITSERVICE
@@ -76,8 +81,9 @@ namespace SPLESS
* we must have a way to turn the attribute both ON and OFF - we
* cannot depend on the FSP to do it since we may not have a FSP.
*/
-const uint64_t ISTEP_MODE_ON_SIGNATURE = 0x4057b0074057b007;
-const uint64_t ISTEP_MODE_OFF_SIGNATURE = 0x700b7504700b7504;
+const uint64_t ISTEP_MODE_SPLESS_SIGNATURE = 0x4057b0074057b007;
+const uint64_t ISTEP_MODE_FSP_SIGNATURE = 0x700b7504700b7504;
+const uint64_t RUN_ALL_MODE_SIGNATURE = 0xBADC0FFEE0DDF00D;
/**
* @enum
@@ -99,6 +105,9 @@ enum {
SPLESS_AT_BREAK_POINT = 11, // at breakpoint
SPLESS_NOT_AT_BREAK_POINT = 12, // resume command w/o breakpoint
SPLESS_SHUTTING_DOWN = 13, // shutdown command issued
+ SPLESS_SENDRCV_FAILED = 14, // could not send cmd to IstepDisp
+ SPLESS_TASKRC_INVALID_RECV_TYPE = 15, // received wrong message type
+ SPLESS_TRACE_BUFFERS_CLEARED = 16, // trace buffers cleared
};
/**
@@ -150,6 +159,25 @@ const uint64_t SPLESS_SINGLE_STEP_STS_MASK = 0x00000000ffffffff;
* @return nothing
*
*/
+inline bool SPLessAttached( )
+{
+ bool l_rc = false;
+
+ // check for IStep Mode signature(s)
+ if ( g_SPLess_IStepMode_Reg == ISTEP_MODE_SPLESS_SIGNATURE )
+ {
+ l_rc = true;
+ }
+
+ return l_rc;
+}
+
+/**
+ * @brief init ISTEP_MODE attribute
+ *
+ * @return nothing
+ *
+ */
inline void initIStepMode( )
{
using namespace TARGETING;
@@ -179,7 +207,9 @@ inline void initIStepMode( )
l_readData );
// check for IStep Mode signature(s)
- if ( l_readData == ISTEP_MODE_ON_SIGNATURE )
+ if ( ( l_readData == ISTEP_MODE_SPLESS_SIGNATURE )
+ || ( l_readData == ISTEP_MODE_FSP_SIGNATURE )
+ )
{
l_pTopLevel->setAttr<ATTR_ISTEP_MODE> (true );
@@ -188,9 +218,8 @@ inline void initIStepMode( )
}
else
{
- // make sure it's set to one or the other after istepdispatcher starts.
- // This makes it easier for hb-istep to find HostBoot's state.
- l_readData = ISTEP_MODE_OFF_SIGNATURE;
+ // If not either of the above, set to run-all
+ l_readData = RUN_ALL_MODE_SIGNATURE;
// $$ save mmio_scratch_write( MMIO_SCRATCH_IPLSTEP_CONFIG, l_readData );
l_pTopLevel->setAttr<ATTR_ISTEP_MODE> ( false );
@@ -238,7 +267,8 @@ union SPLessCmd
struct
{
CommandHdr hdr;
- uint16_t reserved1;
+ uint8_t istep;
+ uint8_t substep;
uint32_t reserved2;
} __attribute__((packed));
@@ -248,38 +278,6 @@ union SPLessCmd
/**
- * @union SPLessSingleIStepCmd
- *
- * Implement Command 0x00, run Istep/Substep
- *
- * Send IStep and SubStep number(s) to run.
- *
- */
-union SPLessSingleIStepCmd
-{
- uint64_t val64;
- struct
- {
- CommandHdr hdr;
- uint8_t istep;
- uint8_t substep;
- uint32_t reserved;
- } __attribute__((packed));
-
- SPLessSingleIStepCmd() : val64(0) {};
-
-
- SPLessSingleIStepCmd( const SPLessCmd &i_cmd )
- : val64(i_cmd.val64) { };
-
-private:
- // disable assignment constructor
- SPLessSingleIStepCmd& operator=(const SPLessSingleIStepCmd& i_right);
-
-} ;
-
-
-/**
* @brief Read the command register and return a filled-in SPLessCmd struct
*
* @param[in,out] io_rcmd - reference to a SPLessCmd struct
@@ -354,7 +352,6 @@ struct StatusHdr
} __attribute__((packed));
-union SPLessSingleIStepSts;
/**
* @union SPLessSts
@@ -366,46 +363,15 @@ union SPLessSts {
uint64_t val64;
struct {
StatusHdr hdr;
- uint16_t reserved1;
- uint32_t reserved2;
- } __attribute__((packed));
-
- // init struct to 0
- SPLessSts() : val64(0) {};
- SPLessSts & operator=(const SPLessSingleIStepSts & i_right);
-} ;
-
-
-/**
- * @union SPLessSts0x00
- *
- * Return Status from IStep/Substep
- *
- */
-union SPLessSingleIStepSts {
- uint64_t val64;
- struct {
- StatusHdr hdr;
uint8_t istep;
uint8_t substep;
uint32_t istepStatus;
} __attribute__((packed));
- SPLessSingleIStepSts() : val64(0) {};
- SPLessSingleIStepSts(const SPLessSts & i_sts ) : val64(i_sts.val64) {};
- SPLessSingleIStepSts & operator=(const SPLessSts & i_right)
- {
- this->val64 = i_right.val64;
- return *this;
- }
+ // init struct to 0
+ SPLessSts() : val64(0) {};
} ;
-SPLessSts & SPLessSts::operator=(const SPLessSingleIStepSts & i_right)
-{
- this->val64 = i_right.val64;
- return *this;
-}
-
/**
* @brief Read the SPLess Status reg and return a filled in struct.
diff --git a/src/usr/initservice/istepdispatcher/sptask.C b/src/usr/initservice/istepdispatcher/sptask.C
new file mode 100644
index 000000000..c8a56221c
--- /dev/null
+++ b/src/usr/initservice/istepdispatcher/sptask.C
@@ -0,0 +1,324 @@
+// IBM_PROLOG_BEGIN_TAG
+// This is an automatically generated prolog.
+//
+// $Source: src/usr/initservice/istepdispatcher/sptask.C $
+//
+// IBM CONFIDENTIAL
+//
+// COPYRIGHT International Business Machines Corp. 2012
+//
+// p1
+//
+// Object Code Only (OCO) source materials
+// Licensed Internal Code Source Materials
+// IBM HostBoot Licensed Internal Code
+//
+// The source code for this program is not published or other-
+// wise divested of its trade secrets, irrespective of what has
+// been deposited with the U.S. Copyright Office.
+//
+// Origin: 30
+//
+// IBM_PROLOG_END
+
+/**
+ * @file sptask.C
+ *
+ * SP / SPless task detached from IStep Dispatcher.
+ * Handles
+ *
+ */
+
+
+/******************************************************************************/
+// Includes
+/******************************************************************************/
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include <sys/task.h> // tid_t, task_create, etc
+#include <sys/time.h> // nanosleep
+#include <sys/misc.h> // shutdown
+#include <sys/msg.h> // message Q's
+#include <mbox/mbox_queues.H> // MSG_HB_MSG_BASE
+
+
+#include <trace/interface.H> // trace support
+#include <errl/errlentry.H> // errlHndl_t
+
+#include <initservice/initsvcudistep.H> // InitSvcUserDetailsIstep
+#include <initservice/taskargs.H> // TASK_ENTRY_MACRO
+
+#include <targeting/util.H> //
+
+#include "istepdispatcher.H"
+#include "splesscommon.H"
+#include "istep_mbox_msgs.H"
+
+
+namespace INITSERVICE
+{
+
+using namespace ERRORLOG; // IStepNameUserDetails
+using namespace SPLESS; // SingleStepMode
+using namespace TARGETING; //
+
+/******************************************************************************/
+// Globals/Constants
+/******************************************************************************/
+extern trace_desc_t *g_trac_initsvc;
+
+/**
+ * @const SPLess PAUSE - These two constants are used in a nanosleep() call
+ * below to sleep between polls of the StatusReg. Typically this will
+ * be about 10 ms - the actual value will be determined empirically.
+ */
+const uint64_t SINGLESTEP_PAUSE_S = 0;
+const uint64_t SINGLESTEP_PAUSE_NS = 10000000;
+
+/**
+ * @brief Translate beween commands on SPless user console and FSP commands
+ *
+ * @param[in] - command from SPLess user console
+ *
+ * @return FSP command
+ *
+ */
+uint32_t SPLessToFSP( const uint8_t i_cmd )
+{
+ uint32_t l_FSPCmd = 0;
+
+ switch( i_cmd )
+ {
+
+ case SPLESS_SINGLE_ISTEP_CMD:
+ l_FSPCmd = SINGLE_STEP_TYPE;
+ break;
+ case SPLESS_RESUME_ISTEP_CMD:
+ l_FSPCmd = BREAKPOINT_TYPE;
+ break;
+ case SPLESS_CLEAR_TRACE_CMD:
+ l_FSPCmd = CLEAR_TRACE_TYPE;
+ break;
+ case SPLESS_SHUTDOWN_CMD:
+ l_FSPCmd = SHUTDOWN_TYPE;
+ break;
+ default:
+ TRACFCOMP( g_trac_initsvc,
+ "spTask ERROR: unknown cmd %d",
+ i_cmd );
+ // should never happen...
+ assert( 0 );
+ }
+
+ return l_FSPCmd;
+}
+
+
+
+/**
+ * @brief userConsoleComm
+ *
+ * Communicate with User Console on VPO or Simics.
+ * Forwards commands to HostBoot (IStep Dispatcher) via a message Q.
+ * Forwards status from HostBoot to VPO or Simics user console.
+ *
+ * Stop and wait for the user console to send the next IStep to run.
+ * Run that, then wait for the next one.
+ *
+ * @param[in,out] - pointer to a message Q, passed in by the parent
+ *
+ * @return none
+ */
+void userConsoleComm( void * io_msgQ )
+{
+ SPLessCmd l_cmd;
+ SPLessSts l_sts;
+ uint8_t l_seqnum = 0;
+ bool l_quitflag = false;
+ int l_sr_rc = 0;
+ msg_q_t l_SendMsgQ = static_cast<msg_q_t>( io_msgQ );
+ msg_t *l_pMsg = msg_allocate();
+ msg_q_t l_RecvMsgQ = msg_q_create();
+ msg_t *l_pCurrentMsg = NULL;
+
+ TRACFCOMP( g_trac_initsvc,
+ "userConsoleComm entry, args=%p",
+ io_msgQ );
+
+ // initialize command reg
+ l_cmd.val64 = 0;
+ writeCmd( l_cmd );
+
+ // init status reg, enable ready bit
+ l_sts.val64 = 0;
+ l_sts.hdr.readybit = true;
+ writeSts( l_sts );
+
+ // set Current to our message on entry
+ l_pCurrentMsg = l_pMsg;
+ //
+ // Start the polling loop.
+ //
+ while( 1 )
+ {
+ // read command register from user console
+ readCmd( l_cmd );
+
+ // process any pending commands
+ if ( l_cmd.hdr.gobit )
+ {
+ // get the sequence number from caller
+ l_seqnum = l_cmd.hdr.seqnum;
+
+ // clear status
+ l_sts.val64 = 0;
+
+ // set running bit, fill in istep and substep
+ l_sts.hdr.runningbit = true;
+ l_sts.hdr.readybit = true;
+
+ // @todo modify hb-istep to check both running bit and seqnum
+ // l_sts.hdr.seqnum = l_seqnum;
+ l_sts.istep = l_cmd.istep;
+ l_sts.substep = l_cmd.substep;
+
+
+ // write the intermediate value back to the console.
+ TRACDCOMP( g_trac_initsvc,
+ "userConsoleComm Write status 0x%x.%x",
+ static_cast<uint32_t>( l_sts.val64 >> 32 ),
+ static_cast<uint32_t>( l_sts.val64 & 0x0ffffffff ) );
+
+ writeSts( l_sts );
+
+ // pass the command on to IstepDisp, block until reply
+ l_pCurrentMsg->type = SPLessToFSP( l_cmd.hdr.cmdnum );
+ l_pCurrentMsg->data[0] =
+ ( static_cast<uint64_t>( l_cmd.istep ) << 32 ) |
+ static_cast<uint64_t>( l_cmd.substep ) ;
+ l_pCurrentMsg->data[1] = 0;
+ l_pCurrentMsg->extra_data = NULL;
+
+ TRACDCOMP( g_trac_initsvc,
+ "userConsoleComm send %p cmd type 0x%x, 0x%x.%x",
+ l_pCurrentMsg,
+ l_pCurrentMsg->type,
+ static_cast<uint32_t>( l_pCurrentMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( l_pCurrentMsg->data[0] & 0x0ffffffff ) );
+
+ //
+ // msg_sendrecv_noblk effectively splits the "channel" into
+ // a send Q and a receive Q
+ //
+ l_sr_rc = msg_sendrecv_noblk( l_SendMsgQ, l_pCurrentMsg, l_RecvMsgQ );
+ // should never happen.
+ assert( l_sr_rc == 0 );
+
+ // This should unblock on any message sent on the Q,
+ l_pCurrentMsg = msg_wait( l_RecvMsgQ );
+
+ // process returned status from IStepDisp
+ l_sts.hdr.status = 0;
+
+ TRACDCOMP( g_trac_initsvc,
+ "spTask: %p recv msg type 0x%x, 0x%x.%x",
+ l_pCurrentMsg,
+ l_pCurrentMsg->type,
+ static_cast<uint32_t>( l_pCurrentMsg->data[0] >> 32 ),
+ static_cast<uint32_t>( l_pCurrentMsg->data[0] & 0x0ffffffff ) );
+
+ if ( l_pCurrentMsg->type == BREAKPOINT_TYPE )
+ {
+ l_sts.hdr.status = SPLESS_AT_BREAK_POINT;
+ }
+ // istep status is the hi word in the returned data 0
+ l_sts.istepStatus =
+ static_cast<uint32_t>( l_pCurrentMsg->data[0] >> 32 );
+
+ // finish filling in status
+ l_sts.hdr.runningbit = false;
+ l_sts.hdr.seqnum = l_seqnum;
+ l_sts.istep = l_cmd.istep;
+ l_sts.substep = l_cmd.substep;
+ // status should be set now, write to Status Reg.
+
+ writeSts( l_sts );
+
+ // if shutdown issued, end this task
+ if ( l_cmd.hdr.cmdnum == SPLESS_SHUTDOWN_CMD )
+ {
+ l_quitflag = true;
+ }
+
+ // clear command reg, including go bit (i.e. set to false)
+ l_cmd.val64 = 0;
+ writeCmd( l_cmd );
+ } // endif gobit
+
+
+ if ( l_quitflag == true )
+ {
+ // shutdown command issued, break out of loop
+ break;
+ }
+
+ // sleep, and wait for user to give us something else to do.
+ /**
+ * @todo Need a common method of doing delays in HostBoot
+ * @VBU workaround
+ */
+ // Don't delay as long in VBU because it will take VERY long to
+ // run the simulator
+ if( TARGETING::is_vpo() )
+ {
+ // VBU delay per Patrick
+ nanosleep(0,TEN_CTX_SWITCHES_NS);
+ }
+ else
+ {
+ nanosleep( SINGLESTEP_PAUSE_S, SINGLESTEP_PAUSE_NS );
+ }
+ } // endwhile
+
+ // free the message struct
+ msg_free( l_pMsg );
+
+ // @note
+ // Fell out of loop, clear sts reg and turn off readybit
+ // disable the ready bit so the user knows.
+ l_sts.val64 = 0;
+ l_sts.hdr.status = SPLESS_TASKRC_TERMINATED;
+ l_sts.hdr.seqnum = l_seqnum;
+ writeSts( l_sts );
+
+ TRACFCOMP( g_trac_initsvc,
+ "userConsoleComm exit" );
+
+ // return to main to end task
+}
+
+void spTask( void *io_pArgs )
+{
+
+ TRACFCOMP( g_trac_initsvc,
+ "spTask entry, args=%p",
+ io_pArgs );
+
+ // IStepDisp should not expect us to come back.
+ task_detach();
+
+ // Start talking to VPO / Simics User console.
+ userConsoleComm( io_pArgs );
+
+ TRACFCOMP( g_trac_initsvc,
+ "spTask exit." );
+
+ // shutdown requested, end the task.
+ task_end();
+}
+
+
+} // namespace
OpenPOWER on IntegriCloud