diff options
author | Mark Wenning <wenning@us.ibm.com> | 2012-04-05 18:23:58 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-04-09 07:29:59 -0500 |
commit | 5b536ece6c453b4662de8ec8e74ef2ff20a930ea (patch) | |
tree | f6d5422b757da9e82c6f8cb4332263ff1fe805b3 /src/usr | |
parent | 3dc6710d0ada5bbc248161cb67919faa5615ee05 (diff) | |
download | talos-hostboot-5b536ece6c453b4662de8ec8e74ef2ff20a930ea.tar.gz talos-hostboot-5b536ece6c453b4662de8ec8e74ef2ff20a930ea.zip |
Implement FSP Mailbox
Modify IStepDisp to communicate over the mailbox Q to FSP.
If there is no FSP, spin off a task to emulate FSP and communicate
with the hb-istep user console on VPO or Simics.
RTC: 38871
Change-Id: I2a75a05fbdc559db516a711bff46a49e82580bb0
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/812
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr')
-rw-r--r-- | src/usr/initservice/istepdispatcher/istep_mbox_msgs.H | 52 | ||||
-rw-r--r-- | src/usr/initservice/istepdispatcher/istepdispatcher.C | 990 | ||||
-rw-r--r-- | src/usr/initservice/istepdispatcher/istepdispatcher.H | 91 | ||||
-rw-r--r-- | src/usr/initservice/istepdispatcher/makefile | 3 | ||||
-rw-r--r-- | src/usr/initservice/istepdispatcher/splesscommon.H | 116 | ||||
-rw-r--r-- | src/usr/initservice/istepdispatcher/sptask.C | 324 |
6 files changed, 1019 insertions, 557 deletions
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 |