diff options
27 files changed, 2320 insertions, 795 deletions
diff --git a/src/build/doxygen/doxygen.conf b/src/build/doxygen/doxygen.conf index f8f2f4015..ec64e3b5c 100644 --- a/src/build/doxygen/doxygen.conf +++ b/src/build/doxygen/doxygen.conf @@ -433,7 +433,7 @@ WARN_IF_DOC_ERROR = YES # wrong or incomplete parameter documentation, but not about the absence of # documentation. -WARN_NO_PARAMDOC = NO +WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text @@ -448,7 +448,7 @@ WARN_FORMAT = "$file:$line: $text" # and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = doxywarnings.log #--------------------------------------------------------------------------- # configuration options related to the input files @@ -821,7 +821,7 @@ LATEX_HIDE_INDICES = NO # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. -GENERATE_RTF = NO +GENERATE_RTF = YES # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be @@ -1121,7 +1121,7 @@ GROUP_GRAPHS = YES # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. -UML_LOOK = NO +UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. diff --git a/src/build/tools/addCopyright.pl b/src/build/tools/addCopyright.pl index 9d12fe921..256be9d3e 100755 --- a/src/build/tools/addCopyright.pl +++ b/src/build/tools/addCopyright.pl @@ -133,13 +133,15 @@ while (defined($_ = shift)) ## if ( $operation =~ m/validate/i ) { + if ( ! -e $_ ) { print "---------------------------------------------------------\n"; print "Skipping deleted file: $_\n"; print "---------------------------------------------------------\n"; next; - } + } + if ("Unknown" eq $filetype) { print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; diff --git a/src/include/usr/initservice/initsvcreasoncodes.H b/src/include/usr/initservice/initsvcreasoncodes.H index 4ff3fb076..bc4eb3c44 100644 --- a/src/include/usr/initservice/initsvcreasoncodes.H +++ b/src/include/usr/initservice/initsvcreasoncodes.H @@ -20,6 +20,7 @@ // Origin: 30 // // IBM_PROLOG_END + /** * @file initsvcreasoncodes.H * @@ -92,7 +93,10 @@ enum InitServiceReasonCode INVALID_TASK_TYPE = INITSVC_COMP_ID | 0x02, START_FN_FAILED = INITSVC_COMP_ID | 0x03, NULL_FN_PTR = INITSVC_COMP_ID | 0x04, - + ISTEP_FAILED_NO_ERRLOG = INITSVC_COMP_ID | 0x05, + INITSVC_FAILED_NO_ERRLOG = INITSVC_COMP_ID | 0x06, + EXTINITSVC_FAILED_NO_ERRLOG = INITSVC_COMP_ID | 0x07, + CXXTEST_FAILED_NO_ERRLOG = INITSVC_COMP_ID | 0x08, }; diff --git a/src/usr/initservice/common/initsvcstructs.H b/src/include/usr/initservice/initsvcstructs.H index bf351cc6d..bc459da4b 100644 --- a/src/usr/initservice/common/initsvcstructs.H +++ b/src/include/usr/initservice/initsvcstructs.H @@ -20,19 +20,20 @@ // Origin: 30 // // IBM_PROLOG_END - #ifndef __COMMON_INITSVCSTRUCTS_H #define __COMMON_INITSVCSTRUCTS_H /** * @file initsvcstructs.H * * common structs for initservice, extinitsvc, istepdispatcher + * */ /******************************************************************************/ // Includes /******************************************************************************/ #include <stdint.h> +#include <sys/vfs.h> // VFS_MODULE_MAX namespace INITSERVICE { @@ -54,11 +55,11 @@ namespace INITSERVICE * - START_TASK == BASE_IMAGE: call _start() function entry point * EXT_IMAGE: call _init(), then _start() * - START_FN == task with function pointer entry point - * - BARRIER == set barrier for next N tasks. * - UNINIT_TASK == call _fini() to call static destructor(s) on the task. * (extended image only) * - END_TASK_LIST == last entry in the task list. */ + enum TaskType { UNDEFINED_TT = 0, @@ -66,7 +67,6 @@ enum TaskType INIT_TASK, START_TASK, START_FN, - BARRIER, UNINIT_TASK, END_TASK_LIST, }; @@ -95,7 +95,7 @@ enum ModuleType */ struct TaskFlags { - TaskType task_type; // this is a task, run _start() function + TaskType task_type; // task execution flags ModuleType module_type; // BASE_IMAGE or EXT_IMAGE InitServiceModuleID module_id; // module id for errorlog }; diff --git a/src/include/usr/initservice/taskargs.H b/src/include/usr/initservice/taskargs.H index c4d81e1a5..fdc24e291 100644 --- a/src/include/usr/initservice/taskargs.H +++ b/src/include/usr/initservice/taskargs.H @@ -66,7 +66,7 @@ namespace INITSERVICE { /** - * @const TASKARGS_UNDEFINED64 + * @def TASKARGS_UNDEFINED64 * iv_taskreturncode and iv_taskcommand are initialized to this value - * if parent or child change them, it can be easily recognized * @@ -112,6 +112,7 @@ public: * Currently there is no difference between parent and child * but this may change. * + * @return none */ void waitParentSync(); @@ -124,6 +125,7 @@ public: * Currently there is no difference between parent and child * but this may change. * + * @return none */ void waitChildSync(); @@ -135,6 +137,7 @@ public: * * @param[in] i_returncode; * + * @return none. */ void postReturnCode( const uint64_t i_returncode ); @@ -156,6 +159,8 @@ public: * Parent can pass commands and info to the child using this function * * @param[in] i_command; + * + * @return none */ void setCommand( const uint64_t i_command ); @@ -165,7 +170,7 @@ public: * * Child can get commands from the parent using this function * - *@return value of iv_taskcommand; + * @return value of iv_taskcommand; * * @todo might overload this later if we need to pass structs, * buffers, etc. @@ -182,6 +187,7 @@ public: * * @param[in] i_errl; * + * @return none */ void postErrorLog( errlHndl_t i_errl ); @@ -191,6 +197,11 @@ public: * * Parent task can use this to get an errorlog from the child * + * @note This routine sets the iv_errl pointer to the errorlog to NULL + * after returning it, so we do not end up with 2 copies of the + * pointer. The caller must commit or otherwise handle the + * errorlog to avoid a memory leak. + * * @return iv_errl * */ @@ -202,6 +213,8 @@ public: * - barrier is left alone, * - if iv_errl is non zero, we commit it here just to avoid * a memory leak. + * + * @return none */ void clear(); diff --git a/src/include/usr/isteps/isteplist.H b/src/include/usr/isteps/isteplist.H new file mode 100644 index 000000000..730310b87 --- /dev/null +++ b/src/include/usr/isteps/isteplist.H @@ -0,0 +1,155 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/include/usr/isteps/isteplist.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// 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 __ISTEPS_H +#define __ISTEPS_H + +/** + * @file isteplist.H + * + * TaskInfo structs for each task that will run in the extended image. + */ + +#include <vector> + +#include <initservice/initsvcreasoncodes.H> +#include <initservice/initsvcstructs.H> + +#include "isteps.H" + + +namespace INITSERVICE +{ + +const uint64_t MAX_SUBSTEPS = 25; + +/** + * @struct ExtTaskInfo + * + * struct to store the TaskInfo for this IStep, plus the number of items in + * the istep (calculated at compiletime). + */ +struct ExtTaskInfo +{ + const TaskInfo *const pti; + const uint64_t numitems; +}; + +const TaskInfo istep0[] = { + + { + "istep0_substep0" , // istep name + ISTEPS::IStep0sub0, // pointer to fn + { + NONE, // task type + EXT_IMAGE, // Extended Module + ISTEP_1_ERRL_ID, // module id + } + }, + + { + "istep0_substep1" , // istep name + ISTEPS::IStep0sub1, // pointer to fn + { + NONE, // task type + EXT_IMAGE, // Extended Module + ISTEP_1_ERRL_ID, // module id + } + }, + + // --------------------------------------------------------------- + // ----- END OF LIST!!! --------------------------------------- + // --------------------------------------------------------------- + /** + * @brief last task in the list + */ + { + "end_istep0" , // dummy string + NULL, // pointer to fn + { + END_TASK_LIST, // end of list + UNDEFINED_MT, // dummy module type + UNDEFINED_MODULE_ERRL_ID, // dummy errorlog + } + }, +}; + +// make a struct from the above with the number of items included +const ExtTaskInfo g_istep0 = { + &(istep0[0]), + ( sizeof(istep0)/sizeof(TaskInfo) ) // numitems +}; + + +const TaskInfo istep1[] = { + + /** + * @brief targeting task, initializes extended module area + */ + { + "istep1_sub0" , // istep name + ISTEPS::IStep1sub0, // pointer to fn + { + NONE, // task type + EXT_IMAGE, // Extended Module + ISTEP_1_ERRL_ID, // module id + } + }, + + // --------------------------------------------------------------- + // ----- END OF LIST!!! --------------------------------------- + // --------------------------------------------------------------- + + /** + * @brief last task in the list + */ + { + "end" , // dummy string + NULL, // pointer to fn + { + END_TASK_LIST, // end of list + UNDEFINED_MT, // dummy module type + UNDEFINED_MODULE_ERRL_ID, // dummy errorlog + } + }, +}; + +// make a struct from the above with the number of items included +ExtTaskInfo g_istep1 = { + istep1, + ( sizeof(istep1)/sizeof(TaskInfo) ) +}; + + +// initialize an array of ExtTaskInfo +const ExtTaskInfo g_isteps[] = { + g_istep0, + g_istep1, +}; + +// publish the size of the g_isteps array +const uint64_t MAX_ISTEPS = sizeof(g_isteps)/sizeof(TaskInfo *) ; + + +}; // namespace + +#endif diff --git a/src/include/usr/isteps/isteps.H b/src/include/usr/isteps/isteps.H new file mode 100644 index 000000000..b8dac9132 --- /dev/null +++ b/src/include/usr/isteps/isteps.H @@ -0,0 +1,50 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/include/usr/isteps/isteps.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// 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 isteps.H + * + * Prototypes of ISteps launched by IStepDispatcher + * used by isteplist.H + * + */ + + +/******************************************************************************/ +// Includes +/******************************************************************************/ +#include <stdint.h> + +namespace ISTEPS +{ + +extern "C" +void IStep0sub0( void * io_pArgs ); + +extern "C" +void IStep0sub1( void * io_pArgs ); + +extern "C" +void IStep1sub0( void * io_pArgs ); + + +} // namespace diff --git a/src/makefile b/src/makefile index 542c7db34..e7db13c28 100644 --- a/src/makefile +++ b/src/makefile @@ -50,8 +50,8 @@ DIRECT_BOOT_MODULES = example RUNTIME_MODULES = TESTCASE_MODULES = cxxtest testerrl testdevicefw testsyslib \ testscom testxscom testtargeting testinitservice testkernel \ - testhwpf testecmddatabuffer tasktest2 testcxxtest testpnor \ - testi2c + testhwpf testecmddatabuffer initsvctasktest2 testcxxtest \ + testpnor testi2c RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic diff --git a/src/usr/initservice/baseinitsvc/initservice.C b/src/usr/initservice/baseinitsvc/initservice.C index ca56b626a..38458f12f 100644 --- a/src/usr/initservice/baseinitsvc/initservice.C +++ b/src/usr/initservice/baseinitsvc/initservice.C @@ -29,74 +29,50 @@ * */ -#include <kernel/console.H> -#include <sys/vfs.h> -#include <vfs/vfs.H> -#include <sys/task.h> -#include <trace/interface.H> -#include <errl/errlentry.H> -#include <errl/errlmanager.H> -#include <sys/sync.h> - - -#include "initservice.H" -#include "initsvctasks.H" - - +#include <kernel/console.H> +#include <sys/vfs.h> +#include <vfs/vfs.H> +#include <sys/task.h> +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <sys/sync.h> + +#include "initservice.H" +#include "initsvctasks.H" namespace INITSERVICE { trace_desc_t *g_trac_initsvc = NULL; -TRAC_INIT(&g_trac_initsvc, "INITSERVICE", 4096); +TRAC_INIT(&g_trac_initsvc, "INITSERVICE", 4096 ); -/******************************************************************************/ -// InitService::getTheInstance return the only instance -/******************************************************************************/ -InitService& InitService::getTheInstance() +errlHndl_t InitService::startTask( const TaskInfo *i_ptask, + TaskArgs::TaskArgs *io_pargs ) const { - return Singleton<InitService>::instance(); -} + tid_t l_tidrc = 0; + errlHndl_t l_errl = NULL; -/******************************************************************************/ -// InitService::Initservice constructor -/******************************************************************************/ -InitService::InitService() -{ - -} - -/******************************************************************************/ -// InitService::~InitService destructor -/******************************************************************************/ -InitService::~InitService() -{ - -} - - -errlHndl_t InitService::startTask( const TaskInfo *i_ptask, - TaskArgs::TaskArgs *io_pargs ) const -{ - tid_t tidrc = 0; - errlHndl_t lo_errl = NULL; - - assert(i_ptask->taskflags.task_type == START_TASK); + assert( i_ptask != NULL ); + assert( i_ptask->taskflags.task_type == START_TASK ); // Base modules have already been loaded and initialized, // extended modules have not. - if(i_ptask->taskflags.module_type == EXT_IMAGE) + if ( i_ptask->taskflags.module_type == EXT_IMAGE ) { // load module and call _init() - lo_errl = VFS::module_load( i_ptask->taskname ); + l_errl = VFS::module_load( i_ptask->taskname ); } - if( !lo_errl) + if ( ! l_errl ) { - tidrc = task_exec( i_ptask->taskname, io_pargs ); // launch the child + // launch a task and wait for it. + l_tidrc = task_exec( i_ptask->taskname, io_pargs ); - if ( static_cast<int16_t>(tidrc) < 0 ) + // process the return - kernel returns a 16-bit signed # as a + // threadid/error + if ( static_cast<int16_t> (l_tidrc) < 0 ) { // task failed to launch, post an errorlog and dump some trace /*@ errorlog tag @@ -110,293 +86,284 @@ errlHndl_t InitService::startTask( const TaskInfo *i_ptask, * The module id will identify the task. * */ - lo_errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, // severity - i_ptask->taskflags.module_id, // moduleid - INITSERVICE::START_TASK_FAILED, // reason Code - tidrc, // user1 = tidrc - 0 - ); - TRACDBIN( g_trac_initsvc, - "ERROR starting task:", + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + i_ptask->taskflags.module_id, + INITSERVICE::START_TASK_FAILED, + l_tidrc, + 0 ); + TRACFCOMP( g_trac_initsvc, + "ERROR starting task %s : tidrc=%d, errlog p = %p", i_ptask->taskname, - strlen(i_ptask->taskname) ); - TRACDCOMP( g_trac_initsvc, - "tidrc=%d, errlog p = %p" , - (int16_t)tidrc, lo_errl ); - - } // endif tidrc + l_tidrc, + l_errl ); + } // endif tidrc else { // task launched OK. - TRACDBIN( g_trac_initsvc, - "Task finished OK :", - i_ptask->taskname, - strlen(i_ptask->taskname) ); TRACDCOMP( g_trac_initsvc, - "task number %d, errlog p = %p", - tidrc, lo_errl ); + "Task %s launched OK: tid=%d", + i_ptask->taskname, + l_tidrc ); + // if InitService passed in a taskargs, wait for barrier. if ( io_pargs ) { - io_pargs->waitParentSync(); // sync up childtask + io_pargs->waitParentSync(); } - } - } - // else module load failed. have error log + } // endelse + } // endif ! l_errl - return lo_errl; -} + // return any errorlog to the caller + return l_errl; +} -errlHndl_t InitService::executeFn( const TaskInfo *i_ptask, - TaskArgs *io_pargs ) const +errlHndl_t InitService::executeFn( const TaskInfo *i_ptask, + TaskArgs *io_pargs ) const { - tid_t tidrc = 0; - errlHndl_t lo_errl = NULL; + tid_t l_tidrc = 0; + errlHndl_t l_errl = NULL; - if ( i_ptask->taskfn == NULL ) + assert( i_ptask != NULL ); + assert( i_ptask->taskfn != NULL ) ; + + // valid function, launch it + l_tidrc = task_create( i_ptask->taskfn, io_pargs); + if (static_cast<int16_t> (l_tidrc) < 0) { - TRACDBIN( g_trac_initsvc, - "ERROR: NULL function pointer:", - i_ptask->taskname, - strlen(i_ptask->taskname) ); /*@ errorlog tag * @errortype ERRL_SEV_CRITICAL_SYS_TERM * @moduleid see task list - * @reasoncode NULL_FN_PTR + * @reasoncode START_FN_FAILED * @userdata1 0 * @userdata2 0 * * @devdesc Initialization Service attempted to start a - * function within a module but found a NULL pointer - * instead of the function. + * function within a module but the function + * failed to launch * The module id will identify the task. */ - lo_errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, // severity - i_ptask->taskflags.module_id, // moduleid - INITSERVICE::NULL_FN_PTR, // reason Code - 0, - 0 ); - - // fall through to end and return bad error log - } + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + i_ptask->taskflags.module_id, + INITSERVICE::START_FN_FAILED, + l_tidrc, + 0 ); + + TRACFCOMP( g_trac_initsvc, + "ERROR starting function %s: tidrc=%d, errlog p = %p" , + i_ptask->taskname, + l_tidrc, + l_errl ); + + } // endif tidrc else { - // valid function, launch it - tidrc = task_create( i_ptask->taskfn, io_pargs ); - if ( static_cast<int16_t>(tidrc) < 0 ) - { - /*@ errorlog tag - * @errortype ERRL_SEV_CRITICAL_SYS_TERM - * @moduleid see task list - * @reasoncode NULL_FN_PTR - * @userdata1 0 - * @userdata2 0 - * - * @devdesc Initialization Service attempted to start a - * function within a module but the function - * failed to launch - * The module id will identify the task. - */ - lo_errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, // severity - i_ptask->taskflags.module_id, // moduleid - INITSERVICE::START_FN_FAILED, // reason Code - tidrc, // user1 = tidrc - 0 ); - - TRACDBIN( g_trac_initsvc, - ENTER_MRK "ERROR starting function:", - i_ptask->taskname, - strlen(i_ptask->taskname) ); - TRACDCOMP( g_trac_initsvc, - EXIT_MRK "tidrc=%d, errlog p = %p" , - (int16_t)tidrc, lo_errl ); + TRACDCOMP( g_trac_initsvc, + "Function %s launched OK : task number %d", + i_ptask->taskname, + l_tidrc ); - } // endif tidrc - else + // task launched OK. + if ( io_pargs ) { - TRACDBIN( g_trac_initsvc, - ENTER_MRK "function launched OK :", - i_ptask->taskname, - strlen(i_ptask->taskname) ); - TRACDCOMP( g_trac_initsvc, - EXIT_MRK "task number %d, errlog p = %p", - tidrc, lo_errl ); - - // task launched OK. - if ( io_pargs ) - { - io_pargs->waitParentSync(); // sync up parent task - } + io_pargs->waitParentSync(); // sync up parent task } + } - } // end else + return l_errl; +} - return lo_errl; +/** + * @todo this will make a system call to post the progress code. + * + */ +void InitService::setProgressCode( uint64_t i_progresscode ) const +{ + + // do nothing for now } -void InitService::reportError(errlHndl_t &io_rerrl ) const +errlHndl_t InitService::dispatchTask( const TaskInfo *i_ptask, + TaskArgs *io_pargs ) const { + errlHndl_t l_errl = NULL; - if ( io_rerrl == NULL ) - { - // this is OK, do nothing - } - else - { + // dispatch tasks... + switch ( i_ptask->taskflags.task_type) + { + case NONE: + // task is a place holder, skip TRACDCOMP( g_trac_initsvc, - "Committing the error log %p.", - io_rerrl ); - - errlCommit( io_rerrl ); + "task_type==NONE : %s", + i_ptask->taskname ); + break; + case START_TASK: + TRACDCOMP( g_trac_initsvc, + "task_type==START_TASK: %s", + i_ptask->taskname ); + l_errl = startTask( i_ptask, + io_pargs ); + break; + case START_FN: + TRACDCOMP( g_trac_initsvc, + "task_type==START_FN : %s %p", + i_ptask->taskname, + i_ptask->taskfn ); + l_errl = executeFn( i_ptask, + io_pargs ); + break; + case UNINIT_TASK: + TRACDCOMP( g_trac_initsvc, + "task_type=UNINIT_TASK : %s ", + i_ptask->taskname ); + l_errl = VFS::module_unload( i_ptask->taskname ); + break; + default: + /** + * @note If there is a bad TaskInfo struct we just stop here. + */ + TRACFCOMP( g_trac_initsvc, + "Invalid task_type %d: ABORT", + i_ptask->taskflags.task_type ); + assert( 0 ); + break; - } + } // endswitch + return l_errl; } -/** - * @todo this will make a system call to post the error code. - */ -void InitService::setProgressCode( uint64_t i_progresscode ) const +void InitService::init( void *i_ptr ) { - - // do nothing for now -} + errlHndl_t l_errl = NULL; + uint64_t l_task = 0; + const TaskInfo *l_ptask = NULL; + TaskArgs::TaskArgs l_args; + uint64_t l_childrc = 0; -/** - * @note For task_type = NONE case, I'm assuming that trace will not crash - * if we have a NULL taskname string, printing it is useful for debug. - */ -void InitService::init( void *i_ptr ) -{ - errlHndl_t errl = NULL; // steps will return an error handle if failure - uint64_t nextTask = 0; - const TaskInfo *ptask = NULL; - TaskArgs::TaskArgs args; - TRACFCOMP( g_trac_initsvc, - ENTER_MRK "Initialization Service is starting." ); + ENTER_MRK "Initialization Service is starting." ); - // ---------------------------------------------------------------- - // loop through the task list and start up any tasks necessary - // ---------------------------------------------------------------- - for ( nextTask=0; - nextTask<INITSERVICE::MAX_TASKS; - nextTask++ ) + // loop through the task list and start up any tasks necessary + for ( l_task=0; + l_task < INITSERVICE::MAX_TASKS; + l_task++ ) { // make a local copy of the base image task - ptask = &(g_taskinfolist[nextTask]); - if ( ptask->taskflags.task_type == END_TASK_LIST ) + l_ptask = &(g_taskinfolist[ l_task]); + if ( l_ptask->taskflags.task_type == END_TASK_LIST ) { TRACDCOMP( g_trac_initsvc, "End of Initialization Service task list.\n" ); break; } - args.clear(); // clear args struct for next task - - // dispatch tasks... - switch ( ptask->taskflags.task_type) - { - case NONE: - // task is a place holder, skip - TRACDBIN( g_trac_initsvc, - "task_type==NONE", - ptask->taskname, - strlen( ptask->taskname) ); - break; - case START_TASK: - TRACDBIN( g_trac_initsvc, - "task_type==START_TASK", - ptask->taskname, - strlen( ptask->taskname) ); - errl = startTask( ptask, // task struct - &args ); // args - break; - case START_FN: - TRACDCOMP( g_trac_initsvc, - "task_type==START_FN : %p", - ptask->taskfn ); - errl = executeFn( ptask, - &args ); - break; - case BARRIER: - TRACDCOMP( g_trac_initsvc, - "task_type==BARRIER" ); - // $$TODO - break; + l_args.clear(); // clear args struct for next task - case UNINIT_TASK: - TRACDBIN( g_trac_initsvc, - "task_type=UNINIT_TASK : ", - ptask->taskname, - strlen(ptask->taskname) ); - errl = VFS::module_unload( ptask->taskname ); - break; + // dispatch the task and return good or errorlog + l_errl = dispatchTask( l_ptask, + &l_args ); - default: - TRACDCOMP( g_trac_initsvc, - "Invalid task_type %d: ", - ptask->taskflags.task_type ); - /*@ errorlog tag - * @errortype ERRL_SEV_CRITICAL_SYS_TERM - * @moduleid BASE_INITSVC_ERRL_ID - * @reasoncode INVALID_TASK_TYPE - * @userdata1 task_type value - * @userdata2 0 - * - * @devdesc Initialization Service found an invalid - * Task Type in the task list. - * The module id will identify the task. - * task_type value will be the invalid type. - */ - errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, // severity - BASE_INITSVC_ERRL_ID, // moduleid - INVALID_TASK_TYPE, // reason Code - ptask->taskflags.task_type, - 0 ); + // process errorlogs returned from the task that was launched + if ( l_errl ) + { + TRACFCOMP( g_trac_initsvc, + "ERROR: dispatching task, errorlog=0x%p", + l_errl ); + // drop out with the error break; + } - } // endswitch - // report an error - reportError( errl ); + // make local copies of the values in TaskArgs that are returned from + // the child. + // this also clears the errorlog from the TaskArgs struct, so + // use it or lose it ( see taskargs.H for details ). + l_childrc = l_args.getReturnCode(); + l_errl = l_args.getErrorLog(); - if ( args.getReturnCode() != TASKARGS_UNDEFINED64 ) + if ( l_errl ) { TRACFCOMP( g_trac_initsvc, - ERR_MRK "InitService TaskArgs returned 0x%llx, errlog=%p", - args.getReturnCode(), - args.getErrorLog() - ); - - errlHndl_t childerrl = args.getErrorLog(); // local copy - reportError( childerrl ); // report child error + " ERROR: Child task returned 0x%llx, errlog=0x%p", + l_childrc, + l_errl ); + // drop out with the error + break; } - - - - } // endfor + else + { + // Check child results for a valid nonzero return code. + // If we have one, and no errorlog, then we create and + // post our own errorlog here. + if ( ( l_childrc != TASKARGS_UNDEFINED64 ) + && ( l_childrc != 0 ) + ) + { + TRACFCOMP( g_trac_initsvc, + "Child task returned 0x%llx, no errlog", + l_childrc ); + + /*@ errorlog tag + * @errortype ERRL_SEV_CRITICAL_SYS_TERM + * @moduleid see task list + * @reasoncode INITSVC_FAILED_NO_ERRLOG + * @userdata1 returncode from task + * @userdata2 0 + * + * @devdesc The task returned with an error, + * but there was no errorlog returned. + * + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + l_ptask->taskflags.module_id, + INITSERVICE::INITSVC_FAILED_NO_ERRLOG, + l_childrc, + 0 ); + // drop out with the error + break; + } // end if + } // end else + } // endfor // die if we drop out with an error - assert( errl == NULL); - + if ( l_errl ) + { + // commit the log first, then stop right here. + TRACFCOMP( g_trac_initsvc, + "ERROR: extra errorlog found: %p", + l_errl ); + errlCommit( l_errl ); + assert( 0 ); + } TRACFCOMP( g_trac_initsvc, EXIT_MRK "Initilization Service finished."); - // return to _start(), which may end the task or die. + // return to _start() +} + + +InitService& InitService::getTheInstance( ) +{ + return Singleton<InitService>::instance(); } -} // namespace +InitService::InitService( ) +{ } + + +InitService::~InitService( ) +{ } + +} // namespace diff --git a/src/usr/initservice/baseinitsvc/initservice.H b/src/usr/initservice/baseinitsvc/initservice.H index 80a4a2d81..a31d108c8 100644 --- a/src/usr/initservice/baseinitsvc/initservice.H +++ b/src/usr/initservice/baseinitsvc/initservice.H @@ -26,6 +26,7 @@ /** * @file initservice.H * + * Base image Initialization Service * - Manage high-level host boot IPL flow * - Perform can-continue processing * - Perform automatic and manual Istep execution @@ -33,14 +34,6 @@ * */ -/** - * High-level todo list - * - * @todo SP3: move startTask() and reportError() to private - * @todo SP3: add (NULL) detection to printk - * @@todo Add more macros to trace, discuss with Andrew and Nick - */ - /******************************************************************************/ // Includes /******************************************************************************/ @@ -53,7 +46,7 @@ #include <initservice/initsvcreasoncodes.H> #include <initservice/taskargs.H> -#include "../common/initsvcstructs.H" +#include <initservice/initsvcstructs.H> namespace INITSERVICE { @@ -71,8 +64,9 @@ namespace INITSERVICE /******************************************************************************/ /** - * @class InitService Singleton Class + * @class InitService * + * Singleton Class * This class is launched by _start() (see initservicetaskentry.C), * which is launched by the kernel (init_main.C). * @@ -84,6 +78,7 @@ class InitService public: + friend class InitServiceTest; /** @@ -97,18 +92,18 @@ public: * @brief Provide an entry function into the class, called from _start() * * @param[in] i_args pointer to any arguments passed in from - * _start() and by extension the kernel, - * currently this is NULL . + * _start() and by extension the kernel, + * currently this is always NULL . + * + * @return nothing + * */ void init( void *i_args); - /** - * @todo InitServiceTest should be able to find protected functions. - */ - // $$protected: - /** - * @brief start a task using the taskname string in the TaskInfo struct. + /** + * @brief Start a task using the taskname string in the TaskInfo struct. + * * taskname string will be something like "libtargeting.so", which * is the name of the compiled and linked targetting module. * The module is expected to have implemented a extern "C" @@ -122,9 +117,14 @@ public: * * * @param[in] i_ptask pointer to a TaskInfo struct - * @param[in] io_pargs pointer to a TaskArgs struct, or NULL + * @param[in,out] io_pargs pointer to a TaskArgs struct, or NULL + * On input, TaskArgs struct will have + * command, returncode, and errlog fields + * cleared. task can fill in these values + * on return. * - * @return NULL if success, errorlog handle for failure + * @return pointer to errorlog + * @retval NULL if success, filled in errorlog handle for failure * * @note startTask() can also be used to launch an asynchronous task * by calling it with i_pargs set to NULL. This will disable @@ -132,46 +132,54 @@ public: * */ errlHndl_t startTask( const TaskInfo *i_ptask, - TaskArgs::TaskArgs *i_pargs ) const; + TaskArgs::TaskArgs *io_pargs ) const; /** - * @brief executeFn - * Execute an function + * @brief Execute an function * * @param[in] i_ptask - pointer to an TaskInfo struct * @param[in,out] i_pargs - pointer to a TaskArgs struct + * On input, TaskArgs struct will have + * command, returncode, and errlog fields + * cleared. Task can fill in these values + * on return. * - * @return errlHndl_t handle, NULL if success, filled out errorlog - * if failure + * @return pointer to errorlog + * @retval NULL if success, filled out errorlog if failure */ errlHndl_t executeFn( const TaskInfo *i_ptask, TaskArgs *i_pargs ) const; - /** - * @brief report Error to the system. + * @brief set progress code for task. + * This is supposed to make a system call to post the error to + * SP and will also write a SCOM reg + * + * @TODO need progress code categories defined. * - * @param[in] io_rerrl - errlHndl_t pointer to a filled-out error entry - * errorlog will be committed, errorlog - * will be deleted, and pointer will be - * set to NULL on exit + * @param[in] i_progresscode - 64-bit progress code. * * @return nothing + * */ - void reportError( errlHndl_t &io_rerrl) const; + void setProgressCode( uint64_t i_progresscode ) const; /** - * @brief set progress code for task. + * @brief dispatch Task depending on what type of task it is, + * etc. * - * @param[in] i_progresscode - 64-bit progress code. - * - * @return nothing + * @param[in] i_ptask - pointer to a TaskInfo struct, which should + * contain all the info to run the task. + * @param[in,out] io_pargs - pointer to a TaskArgs struct. It is + * possible that this will not be used at all. * + * @return pointer to errlog + * @retval returns NULL, or a pointer to a filled out errorlog */ - void setProgressCode( uint64_t i_progresscode ) const; - + errlHndl_t dispatchTask( const TaskInfo *i_ptask, + TaskArgs *io_pargs ) const; protected: diff --git a/src/usr/initservice/extinitsvc/extinitsvc.C b/src/usr/initservice/extinitsvc/extinitsvc.C index 886176375..b5ab6b64e 100644 --- a/src/usr/initservice/extinitsvc/extinitsvc.C +++ b/src/usr/initservice/extinitsvc/extinitsvc.C @@ -29,20 +29,20 @@ * */ -#include <kernel/console.H> -#include <vfs/vfs.H> -#include <sys/task.h> -#include <sys/sync.h> -#include <sys/misc.h> -#include <sys/time.h> -#include <usr/cxxtest/TestSuite.H> +#include <kernel/console.H> +#include <vfs/vfs.H> +#include <sys/task.h> +#include <sys/sync.h> +#include <sys/misc.h> +#include <sys/time.h> +#include <usr/cxxtest/TestSuite.H> -#include <trace/interface.H> -#include <errl/errlentry.H> -#include <initservice/taskargs.H> // task entry routine +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <initservice/taskargs.H> // task entry routine -#include "extinitsvc.H" -#include "extinitsvctasks.H" +#include "extinitsvc.H" +#include "extinitsvctasks.H" namespace INITSERVICE @@ -50,62 +50,21 @@ namespace INITSERVICE extern trace_desc_t *g_trac_initsvc; + /** - * @brief _start() - task entry point for this module - * - * @parms[in,out] - pointer to TaskArgs struct - * + * @brief set up _start() task entry procedure using the macro in taskargs.H */ -extern "C" -void _start( void *io_pArgs ) -{ - TaskArgs::TaskArgs *pTaskArgs = - reinterpret_cast<TaskArgs::TaskArgs *>(io_pArgs); - - // initialize the extended modules in Hostboot. - ExtInitSvc::getTheInstance().init( io_pArgs ); - - if ( pTaskArgs ) - { - pTaskArgs->waitChildSync(); - } - - task_end(); -} - - - -/******************************************************************************/ -// ExtInitSvc::getTheInstance return the only instance -/******************************************************************************/ -ExtInitSvc& ExtInitSvc::getTheInstance() -{ - return Singleton<ExtInitSvc>::instance(); -} - -/******************************************************************************/ -// ExtInitSvc::ExtInitSvc constructor -/******************************************************************************/ -ExtInitSvc::ExtInitSvc() -{ - -} - -/******************************************************************************/ -// ExtInitSvc::~ExtInitSvc destructor -/******************************************************************************/ -ExtInitSvc::~ExtInitSvc() -{ - -} +TASK_ENTRY_MACRO( ExtInitSvc::getTheInstance().init ); void ExtInitSvc::init( void *i_ptr ) { - errlHndl_t errl = NULL; // steps will return an error handle if failure - uint64_t nextTask = 0; - const TaskInfo *ptask = NULL; - TaskArgs::TaskArgs args; + errlHndl_t l_errl = NULL; + uint64_t l_task = 0; + const TaskInfo *l_ptask = NULL; + TaskArgs::TaskArgs l_args; + uint64_t l_childrc = 0; + TRACFCOMP( g_trac_initsvc, "Extended Initialization Service is starting." ); @@ -113,165 +72,207 @@ void ExtInitSvc::init( void *i_ptr ) // ---------------------------------------------------------------- // loop through the task list and start up any tasks necessary // ---------------------------------------------------------------- - for ( nextTask=0; - nextTask<MAX_EXT_TASKS; - nextTask++ ) + for ( l_task=0; + l_task<INITSERVICE::MAX_EXT_TASKS; + l_task++ ) { // make a local copy of the extended image task - ptask = &(g_exttaskinfolist[nextTask]); - if ( ptask->taskflags.task_type == END_TASK_LIST ) + l_ptask = &(g_exttaskinfolist[l_task]); + if ( l_ptask->taskflags.task_type == END_TASK_LIST ) { TRACDCOMP( g_trac_initsvc, "End of ExtInitSvc task list." ); break; } - args.clear(); // clear args for next task - - // dispatch tasks... - switch ( ptask->taskflags.task_type) - { - case NONE: - // task is a place holder, skip - TRACDBIN( g_trac_initsvc, - "task_type=NONE : ", - ptask->taskname, - strlen(ptask->taskname) ); - break; - case INIT_TASK: - TRACDBIN( g_trac_initsvc, - "task_type==INIT_TASK : ", - ptask->taskname, - strlen(ptask->taskname) ); - errl = VFS::module_load( ptask->taskname ); - break; - - case START_TASK: // call _init(), _start(), stay resident - TRACDBIN( g_trac_initsvc, - "task_type=START_TASK : ", - ptask->taskname, - strlen(ptask->taskname) ); - errl = InitService::getTheInstance().startTask( ptask, - &args ); - break; - - case START_FN: - TRACDCOMP( g_trac_initsvc, - "task_type==START_FN : %p", - ptask->taskfn ); - errl = InitService::getTheInstance().executeFn( ptask, - &args ); - // $$TODO - break; - case BARRIER: - TRACDCOMP( g_trac_initsvc, - "task_type==BARRIER" ); - // $$TODO - break; + l_args.clear(); - case UNINIT_TASK: - TRACDBIN( g_trac_initsvc, - "task_type=UNINIT_TASK : ", - ptask->taskname, - strlen(ptask->taskname) ); - errl = VFS::module_unload( ptask->taskname ); - break; + // dispatch the task + l_errl = InitService::getTheInstance().dispatchTask( l_ptask, + &l_args ); - default: - TRACDCOMP( g_trac_initsvc, - "Invalid task_type: %d", - ptask->taskflags.task_type ); - /*@ errorlog tag - * @errortype ERRL_SEV_CRITICAL_SYS_TERM - * @moduleid START_EXTINITSVC_ERRL_ID - * @reasoncode INVALID_TASK_TYPE - * @userdata1 task_type value - * @userdata2 0 - * - * @devdesc Extended Initialization Service found an invalid - * Task Type in the task list. - * The module id will identify the task. - * task_type value will be the invalid type. - */ - errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, // severity - START_EXTINITSVC_ERRL_ID, // moduleid - INVALID_TASK_TYPE, // reason Code - 0, // user1 = tidrc - 0 ); + // process errorlogs returned from the task that was launched + if ( l_errl ) + { + TRACFCOMP( g_trac_initsvc, + "ERROR: dispatching task, errlog=0x%p", + l_errl ); + // break out of loop with error. break; - } // endswitch + } - // report an error - InitService::getTheInstance().reportError( errl ); + // make local copies of the values in TaskArgs that are returned from + // the child. + // this also clears the errorlog from the TaskArgs struct, so + // use it or lose it ( see taskargs.H for details ). + l_childrc = l_args.getReturnCode(); + l_errl = l_args.getErrorLog(); - if ( args.getReturnCode() != TASKARGS_UNDEFINED64 ) + if ( l_errl ) { TRACFCOMP( g_trac_initsvc, - ERR_MRK "ExtInitSvc TaskArgs returned 0x%llx, errlog=%p", - args.getReturnCode(), - args.getErrorLog() - ); + " Child task returned 0x%llx, errlog=0x%p", + l_childrc, + l_errl ); + // break out of loop with error + break; } - + else + { + // Check child results for a valid nonzero return code. + // If we have one, and no errorlog, then we create and + // post our own errorlog here. + if ( ( l_childrc != TASKARGS_UNDEFINED64 ) + && ( l_childrc != 0 ) + ) + { + TRACFCOMP( g_trac_initsvc, + "Child task returned 0x%llx, no errlog", + l_childrc ); + + /*@ errorlog tag + * @errortype ERRL_SEV_CRITICAL_SYS_TERM + * @moduleid see task list + * @reasoncode EXTINITSVC_FAILED_NO_ERRLOG + * @userdata1 returncode from task + * @userdata2 0 + * + * @devdesc The task returned with an error, + * but there was no errorlog returned. + * + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + l_ptask->taskflags.module_id, + INITSERVICE::EXTINITSVC_FAILED_NO_ERRLOG, + l_childrc, + 0 ); + + // break out of loop with error + break; + } // end if + } // end else } // endfor + // die if we drop out with an error + if ( l_errl ) + { + // dropped out of loop with error. + // Commit the log first, then stop right here. + TRACFCOMP( g_trac_initsvc, + "ERROR: extra errorlog found: %p", + l_errl ); + errlCommit( l_errl ); + assert( 0 ); + } TRACFCOMP( g_trac_initsvc, EXIT_MRK "ExtInitSvc finished."); + + // ===================================================================== // ----- Unit Tests ------------------------------------------------- // ===================================================================== /** - * @note run all the unit tests after we finish the rest - * there are 2 images generated in the build: + * @note run all of the unit tests after we finish the rest + * There are 2 images generated in the build: * hbicore.bin (HostBoot shippable image) * hbicore_test.bin (runs all unit tests) * Only hbicore_test.bin has the libcxxtest.so module, so when * we execute startTask() below on hbicore.bin, it will return -1, * no module present. This is OK. * + * @todo can we call call module_load() to see if libcxxtest.so exists? + * ask Doug or Patrick + * */ - // Pass it a set of args so we can wait on the barrier - // This is a bit wasteful since it is always allocated; we need a - // system call to check if a module exists. - TaskArgs::TaskArgs cxxtestargs; // create a new one for cxxtest - cxxtestargs.clear(); // clear it - - TRACFCOMP( g_trac_initsvc, - ENTER_MRK " "); // leave whitespace in trace - TRACDBIN( g_trac_initsvc, - ENTER_MRK "Run Unit Tests (if libcxxtests.so is present): ", - CXXTEST_TASK.taskname, - strlen(CXXTEST_TASK.taskname) ); - - errl = InitService::getTheInstance().startTask( &CXXTEST_TASK, - &cxxtestargs ); - - // check the returncode and errorlog in the returned args - if ( ( cxxtestargs.getReturnCode() != TASKARGS_UNDEFINED64 ) - || ( cxxtestargs.getErrorLog() != NULL ) - ) + // add a do-while loop so there is only one return at the bottom.... + do { - TRACFCOMP( g_trac_initsvc, - ERR_MRK "CxxTests returned an error 0x%lx and an errorlog %p", - cxxtestargs.getReturnCode(), - cxxtestargs.getErrorLog() - ); - // report an error - errlHndl_t childerrl = cxxtestargs.getErrorLog(); - InitService::getTheInstance().reportError( childerrl ); - } + // Pass it a set of args so we can wait on the barrier + errlHndl_t l_cxxerrl = NULL; + TaskArgs::TaskArgs l_cxxtestargs; + const TaskInfo *l_pcxxtask = &CXXTEST_TASK; + uint64_t l_cxxchildrc = 0; + errlHndl_t l_cxxchilderrl = NULL; + + l_cxxtestargs.clear(); + + TRACDCOMP( g_trac_initsvc, + ENTER_MRK "Run Unit Tests (if libcxxtests.so is present): %s", + l_pcxxtask->taskname ); + + l_cxxerrl = InitService::getTheInstance().startTask( l_pcxxtask, + &l_cxxtestargs ); + + // process errorlogs returned from the task that was launched + // @TODO if we are running the non-test version of HostBoot, this + // will always post an extra errorlog. We need a way to know + // if we are running the _test version or not. + if ( l_cxxerrl ) + { + TRACFCOMP( g_trac_initsvc, + "Committing error from cxxtask launch" ); + errlCommit( l_cxxerrl ); + break; // ERROR, break out of do-while. + } - TRACDCOMP( g_trac_initsvc, - EXIT_MRK "Unit Tests finished."); - TRACFCOMP( g_trac_initsvc, - EXIT_MRK " "); // leave whitespace in trace + // make local copies of the values in TaskArgs that are returned from + // the child. + // this also clears the errorlog from the TaskArgs struct, so + // use it or lose it ( see taskargs.H for details ). + l_cxxchildrc = l_cxxtestargs.getReturnCode(); + l_cxxchilderrl = l_cxxtestargs.getErrorLog(); + + if ( l_cxxchilderrl ) + { + TRACFCOMP( g_trac_initsvc, + " Child task returned 0x%llx, errlog=0x%p", + l_cxxchildrc, + l_cxxchilderrl ); + errlCommit( l_cxxchilderrl ); + } + else + { + // Check child results for a valid nonzero return code. + // If we have one, and no errorlog, then we create and + // post our own errorlog here. + if ( ( l_cxxchildrc != TASKARGS_UNDEFINED64 ) + && ( l_cxxchildrc != 0 ) + ) + { + TRACFCOMP( g_trac_initsvc, + "Child task returned 0x%llx, no errlog", + l_cxxchildrc ); + + /*@ errorlog tag + * @errortype ERRL_SEV_CRITICAL_SYS_TERM + * @moduleid see task list + * @reasoncode CXXTEST_FAILED_NO_ERRLOG + * @userdata1 returncode from istep + * @userdata2 0 + * + * @devdesc The unit test dispatcher returned with an + * error, but there was no errorlog returned. + */ + l_cxxerrl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + l_pcxxtask->taskflags.module_id, + INITSERVICE::CXXTEST_FAILED_NO_ERRLOG, + l_cxxchildrc, + 0 ); + errlCommit( l_cxxerrl ); + } // end if + } // end else + + } while(0); // end do-while - // Shutdown all CPUs + // ===================================================================== + // ----- Shutdown all CPUs ----------------------------------------- + // ===================================================================== uint64_t l_shutdownStatus = SHUTDOWN_STATUS_GOOD; if (CxxTest::g_FailedTests) @@ -286,4 +287,18 @@ void ExtInitSvc::init( void *i_ptr ) } +ExtInitSvc& ExtInitSvc::getTheInstance() +{ + return Singleton<ExtInitSvc>::instance(); +} + + +ExtInitSvc::ExtInitSvc() +{ } + + +ExtInitSvc::~ExtInitSvc() +{ } + + } // namespace diff --git a/src/usr/initservice/extinitsvc/extinitsvc.H b/src/usr/initservice/extinitsvc/extinitsvc.H index 49733c025..5664a0359 100644 --- a/src/usr/initservice/extinitsvc/extinitsvc.H +++ b/src/usr/initservice/extinitsvc/extinitsvc.H @@ -36,15 +36,15 @@ /******************************************************************************/ // Includes /******************************************************************************/ -#include <stdint.h> -#include <util/singleton.H> -#include <sys/vfs.h> // VFS_MODULE_NAME_MAX +#include <stdint.h> +#include <util/singleton.H> +#include <sys/vfs.h> // VFS_MODULE_NAME_MAX -#include <errl/errlentry.H> -#include <initservice/taskargs.H> -#include <initservice/initsvcreasoncodes.H> +#include <errl/errlentry.H> +#include <initservice/taskargs.H> +#include <initservice/initsvcreasoncodes.H> -#include "../baseinitsvc/initservice.H" +#include "../baseinitsvc/initservice.H" namespace INITSERVICE { @@ -73,8 +73,9 @@ enum ShutdownStatus /******************************************************************************/ /** - * @class ExtInitSvc Singleton Class + * @class ExtInitSvc * + * Singleton Class * This extended image module is launched by InitService * */ @@ -98,7 +99,6 @@ public: * @param[in] i_args pointer to any arguments passed in from * _start() and by extension the kernel, * currently this is NULL . - * */ void init( void *i_args); diff --git a/src/usr/initservice/initsvctasktest2/makefile b/src/usr/initservice/initsvctasktest2/makefile new file mode 100644 index 000000000..40d0d6c38 --- /dev/null +++ b/src/usr/initservice/initsvctasktest2/makefile @@ -0,0 +1,28 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/initservice/initsvctasktest2/makefile $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2011 +# +# 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 +ROOTPATH = ../../../.. +MODULE = initsvctasktest2 + +OBJS = tasktest2.o + +include ${ROOTPATH}/config.mk diff --git a/src/usr/initservice/initsvcunittesttask2/tasktest2.C b/src/usr/initservice/initsvctasktest2/tasktest2.C index fdf830518..fdf830518 100644 --- a/src/usr/initservice/initsvcunittesttask2/tasktest2.C +++ b/src/usr/initservice/initsvctasktest2/tasktest2.C diff --git a/src/usr/initservice/initsvcunittesttask2/tasktest2.H b/src/usr/initservice/initsvctasktest2/tasktest2.H index 9dc1434d0..227013990 100644 --- a/src/usr/initservice/initsvcunittesttask2/tasktest2.H +++ b/src/usr/initservice/initsvctasktest2/tasktest2.H @@ -25,7 +25,9 @@ #define __INITSVC_TASK_TEST_2_H /** - * @file initsvctasktest2.H + * @file tasktest2.H + * + * dummy file for use in initservice unit tests * */ @@ -51,7 +53,7 @@ namespace INITSERVICE /******************************************************************************/ /** - * @class InitSvcTestTask2 Class + * @class InitSvcTestTask2 * * test module launched */ diff --git a/src/usr/initservice/istepdispatcher/istepdispatcher.C b/src/usr/initservice/istepdispatcher/istepdispatcher.C index 5dfb5a53e..002cc59d4 100644 --- a/src/usr/initservice/istepdispatcher/istepdispatcher.C +++ b/src/usr/initservice/istepdispatcher/istepdispatcher.C @@ -24,7 +24,9 @@ /** * @file istepdispatcher.C * - * IStep Dispatcher interface. Launched from Extended Initialization Service + * IStep Dispatcher code. Launched from Extended Initialization Service + * + * PNOR Driver and Trace should be available by the time this is launched. * */ @@ -36,12 +38,18 @@ #include <stdio.h> #include <string.h> -#include <sys/task.h> // tid_t, task_create, etc -#include <trace/interface.H> // trace support -#include <errl/errlentry.H> // errlHndl_t +#include <sys/task.h> // tid_t, task_create, etc +#include <sys/time.h> // nanosleep +#include <trace/interface.H> // trace support +#include <errl/errlentry.H> // errlHndl_t +#include <devicefw/userif.H> // targeting +#include <sys/mmio.h> // mmio_scratch_read() #include "istepdispatcher.H" -#include "isteplist.H" + +#include "splesscommon.H" + +#include <isteps/isteplist.H> namespace INITSERVICE @@ -53,102 +61,502 @@ namespace INITSERVICE extern trace_desc_t *g_trac_initsvc; /** - * @brief set up _start() task entry procedure using the macro + * @enum + * SPLess Task return codes + * + * task return codes for SPless single step + * @note future errors will be passed from task_create() and task_exec() + * and should be documented in errno.h + * + */ +enum { + SPLESS_TASKRC_INVALID_ISTEP = -3, // invalid istep or substep + SPLESS_TASKRC_LAUNCH_FAIL = -4, // failed to launch the task + SPLESS_TASKRC_RETURNED_ERRLOG = -5, // istep returned an errorlog + SPLESS_TASKRC_TERMINATED = -6, // terminated the polling loop +}; + +/** + * @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 100 ms - the actual value will be determined empirically. + * + * @debug simics "feature" - set polling time to 1 sec for demo + * + */ + +const uint64_t SINGLESTEP_PAUSE_S = 1; +const uint64_t SINGLESTEP_PAUSE_NS = 100000000; + + +/** + * @brief set up _start() task entry procedure using the macro in taskargs.H */ TASK_ENTRY_MACRO( IStepDispatcher::getTheInstance().init ); -IStepDispatcher::IStepDispatcher() -: iv_istepmodeflag(false), - iv_nextistep( 0 ), - iv_cancontinueflag(false) +const TaskInfo *IStepDispatcher::findTaskInfo( const uint16_t i_IStep, + const uint16_t i_SubStep ) const { + const TaskInfo *l_pistep = NULL; + + TRACDCOMP( g_trac_initsvc, + "g_isteps[%d].numitems = 0x%x", + i_IStep, + g_isteps[i_IStep].numitems ); + + // apply filters + do + { + + // check input range - IStep + if ( i_IStep >= MAX_ISTEPS ) + { + TRACDCOMP( g_trac_initsvc, + "IStep 0x%x out of range.", + i_IStep ); + 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 0x%x Substep 0x%x 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 0x%x SubSStep 0x%x task_type==END_TASK_LIST.", + i_IStep, + i_SubStep ); + break; + } + + // looks good, send it back to the caller + TRACDCOMP( g_trac_initsvc, + "Found TaskInfo 0x%x 0x%x", + i_IStep, + i_SubStep ); + l_pistep = &( g_isteps[i_IStep].pti[i_SubStep] ); + } while ( 0 ); + + return l_pistep; } -IStepDispatcher::~IStepDispatcher() +void IStepDispatcher::init( void * io_ptr ) { + TRACFCOMP( g_trac_initsvc, + ENTER_MRK "starting IStepDispatcher, io_ptr=%p ", + io_ptr ); + + if ( getIStepMode() ) + { + TRACFCOMP( g_trac_initsvc, + "IStep single-step" ); + // IStep single-step + singleStepISteps( io_ptr ); + } + else + { + TRACFCOMP( g_trac_initsvc, + "IStep run all" ); + // Run all the ISteps sequentially + runAllISteps( io_ptr ); + } // endelse + + + TRACFCOMP( g_trac_initsvc, + EXIT_MRK "IStepDispatcher finished."); } -IStepDispatcher& IStepDispatcher::getTheInstance() +bool IStepDispatcher::getIStepMode( ) const { - return Singleton<IStepDispatcher>::instance(); + + return iv_istepmodeflag; +} + + +/** + * @todo revisit this when PNOR Driver is implemented + * + */ +void IStepDispatcher::initIStepMode( ) +{ + uint64_t l_readData = 0; + + l_readData = mmio_scratch_read( MMIO_SCRATCH_IPLSTEP_CONFIG ); + + TRACDCOMP( g_trac_initsvc, + "SCOM ScratchPad read, Offset 0x%x, Data 0x%llx", + MMIO_SCRATCH_IPLSTEP_CONFIG, + l_readData ); + + // check for IStep Mode signature + if ( l_readData == ISTEP_MODE_SIGNATURE ) + { + iv_istepmodeflag = true; + } + else + { + iv_istepmodeflag = false; + } + } -void IStepDispatcher::init( void * ptr ) +void IStepDispatcher::singleStepISteps( void * io_ptr ) const { - errlHndl_t errl = NULL; - uint64_t nextIStep = 0; - const TaskInfo *pistep = NULL; - TaskArgs::TaskArgs args; + errlHndl_t l_errl = NULL; + TaskArgs::TaskArgs l_args; + const TaskInfo *l_pistep = NULL; + bool l_gobit = false; + uint16_t l_nextIStep = 0; + uint16_t l_nextSubstep = 0; + uint16_t l_taskStatus = 0; + uint16_t l_istepStatus = 0; + uint32_t l_progresscode = 0; + uint64_t l_isteprc = 0; + + TRACFCOMP( g_trac_initsvc, "Start IStep single-step.\n" ); + + // initialize command reg + SPLESSCMD::write( false, // go bit is false + 0, // istep = 0 + 0 ); // substep = 0 + + SPLESSSTS::write( false, // running bit + true, // ready bit + 0, // istep running + 0, // substep running + 0, // task status + 0 ); // istep status + + // + // @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 ) + { + // read command reg, updates l_gobit, l_nextIStep, l_nextSubstep + SPLESSCMD::read( l_gobit, + l_nextIStep, + l_nextSubstep ); - TRACFCOMP( g_trac_initsvc, - ENTER_MRK "starting IStepDispatcher, ptr=%p. &args=%p", - ptr, &args ); + // process any commands + if ( l_gobit ) + { + TRACDCOMP( g_trac_initsvc, + "gobit turned on, istep=0x%x, substep=0x%x", + l_nextIStep, + l_nextSubstep ); + + // look up istep+substep + l_pistep = findTaskInfo( l_nextIStep, + l_nextSubstep ); + if ( l_pistep == NULL ) + { + // no istep TaskInfo returned, update status & drop to end. + TRACFCOMP( g_trac_initsvc, + "Invalid IStep 0x%x / substep 0x%x, try again.", + l_nextIStep, + l_nextSubstep ); + SPLESSSTS::write( false, + true, + l_nextIStep, + l_nextSubstep, + SPLESS_TASKRC_INVALID_ISTEP, + 0 ); + } + else + { + // set running bit, fill in istep and substep + SPLESSSTS::write( true, // set running bit + true, // ready bit + l_nextIStep, // running istep + l_nextSubstep, // running substep + 0, // task status (=0) + 0 ); // istep status(=0) + + /** + * @todo placeholder - set progress code before starting + * This will not be finalized until the progress code driver + * is designed and implemented. + */ + l_progresscode = ( (l_nextIStep<<16) | l_nextSubstep ); + InitService::getTheInstance().setProgressCode( l_progresscode ); + + // launch the istep + TRACDCOMP( g_trac_initsvc, + "execute Istep=0x%x / Substep=0x%x", + l_nextIStep, + l_nextSubStep ); + + // clear status, etc for the next istep + l_taskStatus = 0; + l_istepStatus = 0; + l_args.clear(); + + // launch the istep + l_errl = InitService::getTheInstance().executeFn( l_pistep, + &l_args ); + // filter errors returning from executeFn + if ( l_errl ) + { + // handle an errorlog from the parent. This means the + // launch failed, set the task Status to Bad. + // no need to process child info, thus the else. + // set the taskStatus to LAUNCH_FAIL; this will fall + // out the bottom and be written to SPLESS Status + l_taskStatus = SPLESS_TASKRC_LAUNCH_FAIL; + TRACFCOMP( g_trac_initsvc, + "ERROR 0x%x: function launch FAIL", + l_taskStatus ); + errlCommit( l_errl ); + } + else + { + // process information returned from the IStep. + // make local copies of the info; this has a secondary + // effect of clearing the errorlog pointer inside + // the TaskArgs struct. + l_isteprc = l_args.getReturnCode(); // local copy + l_errl = l_args.getErrorLog(); // local copy + + TRACDCOMP( g_trac_initsvc, + "IStep TaskArgs return 0x%llx, errlog=%p", + l_isteprc, + l_errl ); + + // check for child errorlog + if ( l_errl ) + { + // tell the user that the IStep returned an errorlog + l_taskStatus = SPLESS_TASKRC_RETURNED_ERRLOG; + // go ahead and commit the child errorlog + errlCommit( l_errl); + } + + // massage the return code from the IStep - + // If the istep did not set an errorcode, + // then we report 0 + if ( l_isteprc == TASKARGS_UNDEFINED64 ) + { + l_istepStatus = 0; + } + else + { + // truncate IStep return status to 16 bits. + l_isteprc &= 0x000000000000ffff; + l_istepStatus = static_cast<uint16_t>(l_isteprc); + } + + } // end else parent errlog + + // l_taskStatus and l_istepStatus should be set correctly now, + // send it to the user. + // clear runningbit, report status + TRACDCOMP( g_trac_initsvc, + "Write IStep Status: istep=0x%x, substep=0x%x, taskstatus=0x%x, istepstatus=0x%x", + l_nextIStep, + l_nextSubstep, + l_taskStatus, + l_istepStatus ); + SPLESSSTS::write( false, // clear running bit + true, // ready bit + l_nextIStep, // running istep + l_nextSubstep, // running substep + l_taskStatus, // task status + l_istepStatus // istepStatus + ); + + SPLESSCMD::setgobit( false ); // clear gobit + } // end else l_pistep + } // endif gobit + + // sleep, and wait for user to give us something else to do. + nanosleep( SINGLESTEP_PAUSE_S, SINGLESTEP_PAUSE_NS ); + } // endwhile + + + // @note + // Fell out of loop, clear sts reg and turn off readybit + // Currently this will never be reached. Later there may be + // a reason to break out of the loop, if this happens we want to + // disable the ready bit so the user knows. + SPLESSSTS::write( false, + false, + 0, + 0, + SPLESS_TASKRC_TERMINATED, + 0 + ); + + // all errorlogs should have been committed in the loop, we should + // not have any errorlogs still set. + if ( l_errl ) + { + // if we do then commit it and stop here. + errlCommit( l_errl ); + assert(0); + } + +} - for ( nextIStep=0; - nextIStep<INITSERVICE::MAX_ISTEPS; - nextIStep++ ) + +void IStepDispatcher::runAllISteps( void * io_ptr ) const +{ + errlHndl_t l_errl = NULL; + uint16_t l_IStep = 0; + uint16_t l_SubStep = 0; + const TaskInfo *l_pistep = NULL; + TaskArgs::TaskArgs l_args; + uint64_t l_progresscode = 0; + uint64_t l_isteprc = 0; + + for ( l_IStep=0; + l_IStep<INITSERVICE::MAX_ISTEPS; + l_IStep++ ) { - pistep = &(g_isteps[nextIStep]); - if ( pistep->taskflags.task_type == END_TASK_LIST ) + for ( l_SubStep=0; + l_SubStep < INITSERVICE::MAX_SUBSTEPS; + l_SubStep++) { TRACDCOMP( g_trac_initsvc, - "End of IStep list.\n" ); - break; - } + "Find IStep=%d, SubStep=%d", + l_IStep, + l_SubStep ); + l_pistep = findTaskInfo( l_IStep, + l_SubStep ); + if ( l_pistep == NULL ) + { - args.clear(); // clear the args struct for the next istep - errl = InitService::getTheInstance().executeFn( pistep, - &args ); + TRACDCOMP( g_trac_initsvc, + "End of ISubStep list." ); + break; // break out of inner for loop + } - // handle an errorlog from the parent, if it exists - InitService::getTheInstance().reportError( errl ); + // @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 ); - /** - * @todo call getCanContinueProcedure when we have some ISteps that - * require them. - */ + l_args.clear(); - if ( args.getReturnCode() != TASKARGS_UNDEFINED64 ) - { TRACFCOMP( g_trac_initsvc, - ERR_MRK "IStep TaskArgs returned 0x%llx, errlog=%p", - args.getReturnCode(), - args.getErrorLog() - ); + "Run IStep 0x%x / Substep 0x%x", + l_IStep, + l_SubStep ); + + l_errl = InitService::getTheInstance().executeFn( l_pistep, + &l_args ); + if ( l_errl ) + { + // Handle an errorlog from the parent, if it exists + // an error here is probably fatal, it means we can't + // launch the task or it doesn't exist. In either + // case we should exit the loop. + // Can't commit the errorlog here because we are using it + // as a flag to exit the loop. + break; + } + + // make local copies of the status returned from the istep. + // note that this also removes the errorlog from the TaskArgs + // struct - it is read-once. See taskargs.H for details + l_isteprc = l_args.getReturnCode(); + l_errl = l_args.getErrorLog(); + + TRACDCOMP( g_trac_initsvc, + "IStep TaskArgs returned 0x%llx, errlog=%p", + l_isteprc, + l_errl ); + if ( l_errl ) + { + // if we have an errorlog, break out of the inner loop + // and handle it. + break; + } + else + { + // Check child results for a valid nonzero return code. + // If we have one, and no errorlog, then we create an + // errorlog here. + if ( ( l_isteprc != TASKARGS_UNDEFINED64 ) + && ( l_isteprc != 0 ) + ) + { + TRACFCOMP( g_trac_initsvc, + "istep returned 0x%llx, no errlog", + l_isteprc ); + + /*@ errorlog tag + * @errortype ERRL_SEV_CRITICAL_SYS_TERM + * @moduleid see task list + * @reasoncode ISTEP_FAILED_NO_ERRLOG + * @userdata1 returncode from istep + * @userdata2 0 + * + * @devdesc The Istep returned with an error, + * but there was no errorlog posted + * from the IStep. + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, + l_pistep->taskflags.module_id, + INITSERVICE::ISTEP_FAILED_NO_ERRLOG, + l_isteprc, + 0 ); + // drop out of inner loop with errlog set. + break; + } // end if ( ) + } + } // endfor l_SubStep + + if ( l_errl ) + { + // something left an error log in the inner loop, breakout + break; } + } // endfor l_IStep - // report an error from the child, if it exists. - reportIStepErrorLog( pistep, args.getErrorLog() ); - } // endfor + /** + * @todo detect Can-Continue condition here and reset/rerun ISteps. + * For now this is pushed to a later sprint. + */ - TRACFCOMP( g_trac_initsvc, - EXIT_MRK "IStepDispatcher finished."); + // Post any errorlogs. If one exists, stop here. Otherwise, return + // to caller. + if ( l_errl ) + { + TRACFCOMP( g_trac_initsvc, + "ERROR: istep=0x%x, substep=0x%x, committing errorlog %p", + l_IStep, + l_SubStep, + l_errl ); + errlCommit( l_errl ); + assert( 0 ); + } } -/** - * @note IStep Mode is hardwired to false for now - * - * @todo revisit this when PNOR Driver is implemented - */ -bool IStepDispatcher::getIStepMode( ) const -{ - - return false; -} - - bool IStepDispatcher::getCanContinueProcedure( const TaskInfo &i_failingIStep, errlHndl_t &i_failingError, @@ -159,11 +567,21 @@ bool IStepDispatcher::getCanContinueProcedure( const TaskInfo &i_failingIStep, return false; } -void IStepDispatcher::reportIStepErrorLog( const TaskInfo *i_failingIStep, - errlHndl_t io_errl ) + +IStepDispatcher& IStepDispatcher::getTheInstance() +{ + return Singleton<IStepDispatcher>::instance(); +} + + +IStepDispatcher::IStepDispatcher() { + initIStepMode(); // set up internal flag - InitService::getTheInstance().reportError( io_errl ); } + +IStepDispatcher::~IStepDispatcher() +{ } + } // namespace diff --git a/src/usr/initservice/istepdispatcher/istepdispatcher.H b/src/usr/initservice/istepdispatcher/istepdispatcher.H index 46f4f87e3..352b0f450 100644 --- a/src/usr/initservice/istepdispatcher/istepdispatcher.H +++ b/src/usr/initservice/istepdispatcher/istepdispatcher.H @@ -21,8 +21,8 @@ // // IBM_PROLOG_END -#ifndef __ISTEP_DISPATCHER_H -#define __ISTEP_DISPATCHER_H +#ifndef __ISTEPDISPATCHER_ISTEPDISPATCHER_H +#define __ISTEPDISPATCHER_ISTEPDISPATCHER_H /** * @file istepdispatcher.H * @@ -34,21 +34,22 @@ /******************************************************************************/ // Includes /******************************************************************************/ -#include <stdint.h> -#include <sys/vfs.h> // VFS_MODULE_NAME_MAX +#include <stdint.h> +#include <util/singleton.H> -#include <errl/errlentry.H> -#include <initservice/taskargs.H> -#include <initservice/initsvcreasoncodes.H> +#include <errl/errlentry.H> +#include <initservice/taskargs.H> +#include <initservice/initsvcreasoncodes.H> +#include <initservice/initsvcstructs.H> -#include "../baseinitsvc/initservice.H" -#include "../common/initsvcstructs.H" +#include "../baseinitsvc/initservice.H" + +#include "splesscommon.H" namespace INITSERVICE { - /******************************************************************************/ // Globals/Constants /******************************************************************************/ @@ -58,7 +59,7 @@ namespace INITSERVICE /******************************************************************************/ /******************************************************************************/ -// Class +// Class IStepDispatcher /******************************************************************************/ /** @@ -85,6 +86,8 @@ public: * * @param[in] i_pargs pointer to any arguments passed in from * _start(). + * + * @return nothing */ void init( void *i_pargs); @@ -109,51 +112,115 @@ private: IStepDispatcher(const IStepDispatcher& i_right); IStepDispatcher& operator=(const IStepDispatcher& i_right); + /** - * @brief getIStepMode - * call into PNOR and fetch the "IStepMode flag" . - * This will tell us if we are locked to the SP (IStepMode=ON) or - * can run all the ISteps available (IStepMode=OFF). + * @brief init iv_istepmode flag, called in constructor + * + * Call into PNOR and fetch the "IStepMode flag" . + * + * @todo currently this calls into the kernel to get the value of + * an SCOM Scratch Reg - this will change when PNOR is finished + * + * @return nothing * - * @return false if IStep Mode is "OFF" + */ + void initIStepMode( ); + + + /** + * @brief getIStepMode - return value of IStep Mode + * + * @return bool - value of iv_istepmodeflag + * @retval false if IStep Mode is "OFF" * true if IStep Mode is "ON" */ - bool getIStepMode( ) const; + bool getIStepMode( ) const; + + + /** + * @brief Find a TaskInfo struct in the global istep list(s), + * addressed by { IStep, SubStep } + * + * + * @param[in] i_IStep - IStepNumber + * @param[in] i_SubStep - SubStepNumber + * + * @return pointer to a TaskInfo struct + * @retval pointer to a TaskInfo struct, or NULL + * + */ + const TaskInfo *findTaskInfo( uint16_t i_IStep, + uint16_t i_SubStep ) const; + + + /** + * @brief singleStepISteps + * + * Stop and wait for SP to send the next IStep to run. Run that, then + * wait for the next one. + * This is not expected to return - errors etc are sent to the user to + * handle. + * + * @param[in,out] io_ptr - pointer to any args passed in from + * ExtInitSvc. This may be a pointer to an + * TaskArgs struct (or something else) which + * can be filled out on return + * + * @return none + */ + void singleStepISteps( void * io_ptr ) const; + + + /** + * @brief runAllISteps + * + * Run all available ISteps sequentially. + * If an IStep gets an error, report it and stop. + * Otherwise, return. + * + * @param[in,out] io_ptr - pointer to a TaskArgs struct on input + * command, returncode and errorlog will be + * clear on input + * one or more may be filled in on return + * + * @return none + */ + void runAllISteps( void * io_ptr ) const; /** * @brief getCanContinueProcedure * If an IStep fails, this routine will fetch the recovery procedure + * This is only used in "normal" mode, it will not be used when IStep Mode + * is ON (i.e. it will not be used when single-stepping). * - * @param[in] reference to IStepInfo struct for failing Istep - * @param[in] reference to errorlog for the failure - * @param[in,out] reference to IStepInfo struct for next IStep to run + * @param[in] i_failingIStep - ref to IStepInfo struct for failing + * Istep + * @param[in] i_failingError - ref to errorlog for the failure + * @param[in,out] io_nextIStep - ref to TaskInfo struct for next + * IStep to run. struct will be filled + * out with info on the next IStep to + * run. * - * @return false if there is no Can-Continue procedure + * @return bool + * @retval false if there is no Can-Continue procedure, * true otherwise * + * @todo 2011-08-22 currently the defs for this procedure are pretty + * vague - requirements for Can-Continue behaviour have not been + * defined yet. */ bool getCanContinueProcedure( const TaskInfo &i_failingIStep, errlHndl_t &i_failingError, - TaskInfo &io_nextIstep ) const; - - /** - * @brief reportIStepErrorLog - * If an IStep returns an error log, commit it. - * - * @todo Later there may be some decision about whether to report it - * based on the IStep. - */ - void reportIStepErrorLog( const TaskInfo *i_failingIStep, - errlHndl_t io_errl ); + TaskInfo &io_nextIStep ) const; + // ----- internal vars ----------------------------- bool iv_istepmodeflag; - uint64_t iv_nextistep; - bool iv_cancontinueflag; }; // class IStepDispatcher + } // namespace #endif diff --git a/src/usr/initservice/istepdispatcher/isteplist.H b/src/usr/initservice/istepdispatcher/isteplist.H deleted file mode 100644 index 612fde725..000000000 --- a/src/usr/initservice/istepdispatcher/isteplist.H +++ /dev/null @@ -1,81 +0,0 @@ -// IBM_PROLOG_BEGIN_TAG -// This is an automatically generated prolog. -// -// $Source: src/usr/initservice/istepdispatcher/isteplist.H $ -// -// IBM CONFIDENTIAL -// -// COPYRIGHT International Business Machines Corp. 2011 -// -// 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 __ISTEPS_H -#define __ISTEPS_H - -/** - * @file isteplist.H - * - * TaskInfo structs for each task that will run in the extended image. - */ - -#include <initservice/initsvcreasoncodes.H> -#include "istepdispatcher.H" -#include "../../isteps/isteps.H" - -namespace INITSERVICE -{ - -const uint64_t MAX_ISTEPS = 25; - -const TaskInfo g_isteps[] = { - - // ----- ISteps Image ------------------------------------------ - - /** - * @brief targeting task, initializes extended module area - */ - { - "istep1" , // istep name - ISTEPS::IStep1, // pointer to fn - { - NONE, // task type - EXT_IMAGE, // Extended Module - ISTEP_1_ERRL_ID, // module id - } - }, - - // --------------------------------------------------------------- - // ----- END OF LIST!!! --------------------------------------- - // --------------------------------------------------------------- - - /** - * @brief last task in the list - */ - { - "end" , // dummy string - NULL, // pointer to fn - { - END_TASK_LIST, // end of list - UNDEFINED_MT, // dummy module type - UNDEFINED_MODULE_ERRL_ID, // dummy errorlog - } - }, - -}; - - -}; // namespace - -#endif diff --git a/src/usr/initservice/istepdispatcher/makefile b/src/usr/initservice/istepdispatcher/makefile index 013c6a8f9..d18adfc4f 100644 --- a/src/usr/initservice/istepdispatcher/makefile +++ b/src/usr/initservice/istepdispatcher/makefile @@ -20,10 +20,11 @@ # Origin: 30 # # IBM_PROLOG_END + ROOTPATH = ../../../.. MODULE = istepdisp -OBJS = istepdispatcher.o +OBJS = istepdispatcher.o splesscommand.o splessstatus.o ## SUBDIRS = test.d diff --git a/src/usr/initservice/istepdispatcher/splesscommand.C b/src/usr/initservice/istepdispatcher/splesscommand.C new file mode 100644 index 000000000..563a4be3a --- /dev/null +++ b/src/usr/initservice/istepdispatcher/splesscommand.C @@ -0,0 +1,113 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/initservice/istepdispatcher/splesscommand.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// 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 splesscommand.C + * + * Collection of routines to read/write the spless command reg + * + */ + + +/******************************************************************************/ +// Includes +/******************************************************************************/ +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <errl/errlentry.H> // errlHndl_t +#include <sys/mmio.h> // mmio_scratch_read/write + +#include "splesscommon.H" + + +/******************************************************************************/ +// Globals/Constants +/******************************************************************************/ + +/******************************************************************************/ +// Typedef/Enumerations +/******************************************************************************/ + +namespace SPLESSCMD +{ + + +void read( bool &io_rgobit, + uint16_t &io_ristep, + uint16_t &io_rsubstep ) +{ + InternalCommand l_cmd; + + l_cmd.val64 = mmio_scratch_read(MMIO_SCRATCH_IPLSTEP_COMMAND); + + io_rgobit = l_cmd.f.gobit; + io_ristep = l_cmd.f.istep; + io_rsubstep = l_cmd.f.substep; + +} + + +void write( const bool i_gobit, + const uint16_t i_istep, + const uint16_t i_substep ) +{ + InternalCommand l_cmd; + + // copy into union + l_cmd.f.gobit = i_gobit; + l_cmd.f.istep = i_istep; + l_cmd.f.substep = i_substep; + + mmio_scratch_write( MMIO_SCRATCH_IPLSTEP_COMMAND, l_cmd.val64 ); + +} + + +void getgobit( bool &o_rgobit ) +{ + uint16_t l_istep = 0; + uint16_t l_substep = 0; + + // re-use above call... + read( o_rgobit, + l_istep, + l_substep ); + +} + + +void setgobit( const bool i_gobit ) +{ + InternalCommand l_cmd; + + l_cmd.val64 = mmio_scratch_read( MMIO_SCRATCH_IPLSTEP_COMMAND); + + l_cmd.f.gobit = i_gobit; + + mmio_scratch_write( MMIO_SCRATCH_IPLSTEP_COMMAND, l_cmd.val64 ); + +} + +} // namespace diff --git a/src/usr/initservice/istepdispatcher/splesscommon.H b/src/usr/initservice/istepdispatcher/splesscommon.H new file mode 100644 index 000000000..113d712fd --- /dev/null +++ b/src/usr/initservice/istepdispatcher/splesscommon.H @@ -0,0 +1,269 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/initservice/istepdispatcher/splesscommon.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// 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 __ISTEPDISP_SPLESS_COMMON_H +#define __ISTEPDISP_SPLESS_COMMON_H +/** + * @file splesscommon.H + * + * Prototypes for routines to access SPLESS Command and + * and SPLESS Status interfaces + * + */ + +/******************************************************************************/ +// Includes +/******************************************************************************/ +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +/******************************************************************************/ +// Globals/Constants +/******************************************************************************/ +const uint64_t ISTEP_MODE_SIGNATURE = 0x4057b0074057b007; + +/******************************************************************************/ +// SPLESS Command Prototypes +/******************************************************************************/ + +/** + * @namespace SPLESSCMD + * + * Contains functions to manipulate the SPLESS Command Register + * @todo overload these later to get command and seq fields + * + */ +namespace SPLESSCMD +{ + +/** + * @union InternalCommand + * + * define the fields within the 64-bit Command Register + * + + * Bit numbers are in ppc notation, where bit 0 is the most significant bit. + * Go Bit : bit 0 (ppc notation, msbit) + * - set to 1 by the user to start the IStep + * - cleared to 0 by HostBoot + * Reserved: bit 1: always 0 + * Sequence #: bits 2-7 + * Command Number: bits 8:15 - always 0 (for now) + * Reserved: bits 16:31 + * Reserved: bits 32:39 - always 0 + * IStep Number: bits 40:47 + * Substep Number: bits 48:63gobit: + * + */ +union InternalCommand +{ + uint64_t val64; + struct + { + bool gobit:1; + uint8_t reserved0:1; + uint8_t seqnum:6; + uint8_t cmdnum; + + uint16_t reserved2; + + uint16_t reserved3:2; + uint16_t istep:14; + + uint16_t substep; + } f PACKED; + + // init struct to 0 + InternalCommand() : val64(0) {}; +} ; + + +/** + * @brief Read the command register and return the necessary fields. + * + * @param[in,out] io_rgobit - ref to a gobit var that will be filled in + * on return + * @param[in,out] io_ristep - ref to a istep var that will be filled in + * on return + * @param[in,out] io_rsubstep - ref to a substep var that will be filled + * in on return + * + * @return pointer to errorlog + * @retval NULL if success, filled-in errorlog if failure + * + */ +void read( bool &io_rgobit, + uint16_t &io_ristep, + uint16_t &io_rsubstep ); + + +/** + * @brief Write all the necessary fields to the command reg. + * + * Normally the user writes the command reg; this is only used to + * init the command reg at the beginning + * + * @param[in] i_gobit - gobit value to write + * @param[in] i_istep - istep value to write + * @param[in] i_substep - substep value to write + * + * @return errorlog pointer + * @retval NULL if success, filled-in errorlog if failure + * + */ +void write( const bool i_gobit, + const uint16_t i_istep, + const uint16_t i_substep ); + + +/** + * @brief Read the gobit from the command register + * + * @param o_rgobit - ref to a gobit var that will be filled in + * on return. + * + * @return errorlog pointer + * @retval NULL if success, filled-in errorlog on failure + */ +void getgobit( bool &o_rgobit ); + + +/** + * @brief Write the gobit to the command register + * + * @param i_gobit - gobit value to be written + * + * @return pointer to errlog + * @retval NULL if success, filled-in errorlog on failure + */ +void setgobit( const bool i_gobit ) ; + +} // namespace + + +/******************************************************************************/ +// SPLESS Status Prototypes +/******************************************************************************/ + +/** + * @namespace SPLESSSTS + * + * Contains functions to manipulate the SPLESS Status Register + * @todo overload these to get seq # later + * + */ +namespace SPLESSSTS +{ + +/** + * @union InternalStatus + * + * define the fields within the 64-bit status register + * Running bit, bit 0 (ppc notation, msbit): + * = 1 when IStep is running + * = 0 when IStep is finished + * Ready bit, bit 1: + * = 1 when IStep Dispatcher is ready to run individual ISteps + * = 0 if IStep Dispatcher is not ready: + * - System has not loaded the IStep Dispatcher yet + * - IStep Mode Flag = 0 + * Sequence # : bits 2-7 - echoes the sequence number in the associated + * command frame. + * IStep Running, bits 8:15 - the IStep number that is currently running. + * Sub-step Running, bits 16:31 - the substep that is currently running. + * Task Status, bits 32:47 - the status that IStep Dispatcher returns when + * trying to run the task. For example: + * -3 IStep number is invalid + * -1, -2 (return code from kernel) IStep could not be launched as a + * task or as a function within a task + * IStep Status, bits 48:63 - status returned from the IStep. + * + */ +union InternalStatus { + uint64_t val64; + struct { + bool runningbit:1; // | + bool readybit:1; // | + uint8_t seqnum:6; // | + uint8_t istep; // | 16 bits + uint16_t substep; // 16 bits + uint16_t taskStatus; // 16 bits + uint16_t istepStatus; // 16 bits + } f PACKED; + + // init struct to 0 + InternalStatus() : val64(0) {}; +} ; + + + +/** + * @brief Read the SPLess Status SCOM Reg and return all its fields + * + * @param[in,out] io_rrunningbit - ref to runningbit var, to be + * filled in on return + * @param[in,out] io_rreadybit - ref to readybit var, to be filled in + * on return + * @param[in,out] io_ristep - ref to istep var, to be filled in on + * return + * @param[in,out] io_rsubstep - ref to substep var, to be filled in + * on return + * @param[in,out] io_rtaskStatus - ref to taskStatus var, to be filled + * in on return + * @param[in,out] io_ristepStatus - ref to istepStatus var, to be filled + * in on return + * + * @return none. + */ +void read( bool &io_rrunningbit, + bool &io_rreadybit, + uint16_t &io_ristep, + uint16_t &io_rsubstep, + uint16_t &io_rtaskStatus, + uint16_t &io_ristepStatus ); + +/** + * @brief write + * + * Read the SPLess Status SCOM Reg and return all its fields + * + * @param[in] i_runningbit - runningbit val to write + * @param[in] i_readybit - readybit val to write + * @param[in] i_istep - istep val to write + * @param[in] i_substep - substep val to write + * @param[in] i_taskStatus - taskStatus val to write + * @param[in] i_istepStatus - istepStatus val to write + * + * @return none + */ +void write( const bool i_runningbit, + const bool i_readybit, + const uint16_t i_istep, + const uint16_t i_substep, + const uint16_t i_taskStatus, + const uint16_t i_istepStatus ); + +} // namespace + +#endif diff --git a/src/usr/initservice/istepdispatcher/splessstatus.C b/src/usr/initservice/istepdispatcher/splessstatus.C new file mode 100644 index 000000000..30818778c --- /dev/null +++ b/src/usr/initservice/istepdispatcher/splessstatus.C @@ -0,0 +1,93 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/initservice/istepdispatcher/splessstatus.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// 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 splessstatus.C + * + * Routines to read and write spless status reg + * + */ + +/******************************************************************************/ +// Includes +/******************************************************************************/ +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <errl/errlentry.H> // errlHndl_t +#include <sys/mmio.h> // mmio_scratch_read/write + +#include "splesscommon.H" + +/******************************************************************************/ +// Globals/Constants +/******************************************************************************/ + +/******************************************************************************/ +// Typedef/Enumerations +/******************************************************************************/ + + +void SPLESSSTS::read( bool &io_rrunningbit, + bool &io_rreadybit, + uint16_t &io_ristep, + uint16_t &io_rsubstep, + uint16_t &io_rtaskStatus, + uint16_t &io_ristepStatus ) +{ + InternalStatus l_sts; + + l_sts.val64 = mmio_scratch_read(MMIO_SCRATCH_IPLSTEP_STATUS); + + // read was good + io_rrunningbit = l_sts.f.runningbit; + io_rreadybit = l_sts.f.readybit; + io_ristep = l_sts.f.istep; + io_rsubstep = l_sts.f.substep; + io_rtaskStatus = l_sts.f.taskStatus; + io_ristepStatus = l_sts.f.istepStatus; + +} + + +void SPLESSSTS::write( const bool i_runningbit, + const bool i_readybit, + const uint16_t i_istep, + const uint16_t i_substep, + const uint16_t i_taskStatus, + const uint16_t i_istepStatus ) +{ + InternalStatus l_sts; + + // copy in all the values + l_sts.f.runningbit = i_runningbit; + l_sts.f.readybit = i_readybit; + l_sts.f.istep = i_istep; + l_sts.f.substep = i_substep; + l_sts.f.taskStatus = i_taskStatus; + l_sts.f.istepStatus = i_istepStatus; + + mmio_scratch_write( MMIO_SCRATCH_IPLSTEP_STATUS, l_sts.val64 ); + +} + diff --git a/src/usr/initservice/makefile b/src/usr/initservice/makefile index 5c5b2a415..28240f386 100644 --- a/src/usr/initservice/makefile +++ b/src/usr/initservice/makefile @@ -20,14 +20,15 @@ # Origin: 30 # # IBM_PROLOG_END + ROOTPATH = ../../.. # MODULE = # OBJS = -# NOTE: initsvcunittesttask2 is a dummy module that is executed by +# NOTE: initsvctasktest2 is a dummy module that is executed by # unit test 2 in the test directory. Please do not rename. SUBDIRS = baseinitsvc.d extinitsvc.d taskargs.d istepdispatcher.d \ - test.d initsvcunittesttask2.d + test.d initsvctasktest2.d include ${ROOTPATH}/config.mk diff --git a/src/usr/initservice/taskargs/taskargs.C b/src/usr/initservice/taskargs/taskargs.C index 6d95c9031..ecb4cd88c 100644 --- a/src/usr/initservice/taskargs/taskargs.C +++ b/src/usr/initservice/taskargs/taskargs.C @@ -125,8 +125,12 @@ void TaskArgs::postErrorLog( errlHndl_t i_errl ) errlHndl_t TaskArgs::getErrorLog( ) { + errlHndl_t l_errl = iv_errl; - return iv_errl; + // null out iv_errl after returning it to someone. + iv_errl = NULL; + + return l_errl; } @@ -164,6 +168,7 @@ TaskArgs::~TaskArgs() { clear(); barrier_destroy( &iv_sync_barrier ); + // add an assert here to check if there is still an errorlog pending? } }; // namespace diff --git a/src/usr/initservice/test/initservicetest.H b/src/usr/initservice/test/initservicetest.H index 4c62f3e6d..6a32d73fd 100644 --- a/src/usr/initservice/test/initservicetest.H +++ b/src/usr/initservice/test/initservicetest.H @@ -24,17 +24,14 @@ /** * @file initservicetest.H * - * Private functions for VFS2 phase. + * Unit tests for initservice module + * */ #ifndef __TEST_INIT_SERVICETEST_H #define __TEST_INIT_SERVICETEST_H -/** - * @file initservicetest.H - * - * @brief Unit tests for initservice module - */ + #include <cxxtest/TestSuite.H> @@ -62,7 +59,7 @@ const INITSERVICE::TaskInfo TASK_TEST1 = { * */ const INITSERVICE::TaskInfo TASK_TEST2 = { - "libtasktest2.so" , // taskname + "libinitsvctasktest2.so" , // taskname NULL, // ptr to fn { INITSERVICE::START_TASK, // startflag=true, try to start @@ -107,25 +104,27 @@ public: void testInitServiceStartTask1(void) { - errlHndl_t errl = NULL; + errlHndl_t l_errl = NULL; /** * @todo use a separate instance here, not the singleton */ - INITSERVICE::InitService &l_is = INITSERVICE::InitService::getTheInstance(); + INITSERVICE::InitService &l_is + = INITSERVICE::InitService::getTheInstance(); - TS_TRACE( "=====>Attempt to run a nonexistent task, expect an ERROR."); - errl = l_is.startTask( &TASK_TEST1, // task struct - NULL ); // args - if ( errl ) + TS_TRACE( "=====>Run a nonexistent task, expect an ERROR."); + l_errl = l_is.startTask( &TASK_TEST1, + NULL ); + if ( l_errl ) { TS_TRACE( "SUCCESS: startTask returned an errorlog.\n"); + // clean up + errlCommit( l_errl ); } else { TS_FAIL( "ERROR: no error log was returned.\n"); } - return; } @@ -136,25 +135,26 @@ public: */ void testInitServiceStartTask2(void) { - errlHndl_t errl = NULL; + errlHndl_t l_errl = NULL; /** * @todo use a separate instance here, not the singleton */ - INITSERVICE::InitService &l_is = INITSERVICE::InitService::getTheInstance(); + INITSERVICE::InitService &l_is + = INITSERVICE::InitService::getTheInstance(); - TS_TRACE( "=====>Attempt to run a task with a _start() function, expect SUCCESS."); - errl = l_is.startTask( &TASK_TEST2, // task struct - NULL ); // args - if ( errl ) + TS_TRACE( "=====>Run a task with _start() function, expect SUCCESS."); + l_errl = l_is.startTask( &TASK_TEST2, + NULL ); + if ( l_errl ) { TS_FAIL( "ERROR: StartTask returned an error log.\n"); + errlCommit( l_errl ); } else { TS_TRACE( "SUCCESS: startTask returned OK.\n"); } - return; } @@ -166,18 +166,20 @@ public: */ void testInitServiceStartTask3(void) { - errlHndl_t errl = NULL; + errlHndl_t l_errl = NULL; /** * @todo use a separate instance here, not the singleton */ - INITSERVICE::InitService &l_is = INITSERVICE::InitService::getTheInstance(); + INITSERVICE::InitService &l_is + = INITSERVICE::InitService::getTheInstance(); - TS_TRACE( "====>Attempt to run a task with NO _start() function, expect an ERROR."); - errl = l_is.startTask( &TASK_TEST3, // task struct - NULL ); // args - if ( errl ) + TS_TRACE( "====>Run a task with NO _start() function, expect an ERROR."); + l_errl = l_is.startTask( &TASK_TEST3, + NULL ); + if ( l_errl ) { TS_TRACE( "SUCCESS: startTask returned an error log.\n"); + errlCommit( l_errl ); } else { @@ -187,73 +189,6 @@ public: return; } - /** - * @brief testInitServicereportError1 - * This will call reportError with a NULL errlHndl_t . It should handle it - * OK (reportError() will print an error message to trace) - */ - void testInitServicereportError1(void) - { - errlHndl_t errl = NULL; - /** - * @todo use a separate instance here, not the singleton - */ - INITSERVICE::InitService &l_is = INITSERVICE::InitService::getTheInstance(); - - TS_TRACE( "====> call reportError with NULL handle, should handle it OK\n "); - l_is.reportError( errl ); - - // reportError() might crash, if it returns, just make sure it didn't modify - // the input pointer - if ( errl != NULL) - { - TS_FAIL( "ERROR: expected the NULL errlHndl_t to stay NULL\n"); - } - else - { - TS_TRACE( "SUCCESS: reportError returned OK."); - } - - return; - } - - /** - * @brief testInitServicereportError1 - * This will call reportError with a good errorlog. - * on return, it should be NULLED out - * @todo can we check with the errorlogging facility to see if it got - * posted?? - */ - void testInitServicereportError2(void) - { - errlHndl_t errl = NULL; - /** - * @todo use a separate instance here, not the singleton - */ - INITSERVICE::InitService &l_is = INITSERVICE::InitService::getTheInstance(); - - errl = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_INFORMATIONAL, - INITSERVICE::INIT_SVC_TEST5_ERRL_ID, - INITSERVICE::START_TASK_FAILED, - 0, - 0 - ); - - TS_TRACE( "====> call reportError with good error handle, should commit and then delete "); - l_is.reportError( errl ); - if ( errl !=NULL ) - { - TS_FAIL( "ERROR: reportError did not delete the errlHndl_t handle!\n" ); - } - else - { - TS_TRACE( "SUCCESS: reportError returned OK."); - } - - return; - } - }; // class InitServiceTest diff --git a/src/usr/initservice/test/splesstest.H b/src/usr/initservice/test/splesstest.H new file mode 100644 index 000000000..f89d2d4a8 --- /dev/null +++ b/src/usr/initservice/test/splesstest.H @@ -0,0 +1,396 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/initservice/test/splesstest.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// 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 __TEST_SPLESS_H +#define __TEST_SPLESS_H + +/** + * @file splesstest.H + * + * Test SP-less interface to + */ + +#include <sys/time.h> // nanosleep +#include <sys/mmio.h> // mmio_scratch_write/read + +#include <cxxtest/TestSuite.H> +#include <devicefw/userif.H> + +#include "../istepdispatcher/istepdispatcher.H" + +#include "../istepdispatcher/splesscommon.H" + +using namespace INITSERVICE; // SPLessCommand and SPLessStatus +using namespace TARGETING; // getIStepMode() + +/** + * @class SPLessTest + * + * attempts to run ISteps using the SP-Less interface + * + */ +class SPLessTest: public CxxTest::TestSuite +{ + +public: + /** + * @brief testSPLessTest1 + * + * - test that IStep Mode is enabled + * - read SPLess status: + * - ready bit should be on + * - running bit shold be off + * - status should be 0 + * + */ + void testSPLessTest1( ) + { + bool l_runningbit = false; + bool l_readybit = false; + uint16_t l_IStep = 0; + uint16_t l_Substep = 0; + uint16_t l_taskStatus = 0; + uint16_t l_istepStatus = 0; + + if ( ! checkIStepMode() ) + { + // IStepMode is off, don't bother running this + TS_TRACE("IStepMode disabled, can't run unit test" ); + return; + } + + SPLESSSTS::read( l_runningbit, + l_readybit, + l_IStep, + l_Substep, + l_taskStatus, + l_istepStatus ); + if ( l_readybit == false ) + { + TS_FAIL( "Ready bit should be on"); + } + + if ( l_runningbit == true ) + { + TS_FAIL( "Running bit should be off"); + } + + if ( ( l_IStep != 0 ) || + ( l_Substep != 0 ) + + ) + { + TS_FAIL( "IStep and SubStep fields should be 0"); + } + + + if ( ( l_taskStatus != 0 ) || + ( l_istepStatus != 0 ) + + ) + { + TS_FAIL( "Status fields should be 0"); + } + + } + + /** + * @brief testSPLessTest2 + * + * - Execute IStep 0, substep 0 + * + * - this should succeed. + * + */ + void testSPLessTest2( ) + { + uint16_t l_taskStatus = 0; + uint16_t l_istepStatus = 0; + bool l_pass = false; + + if ( ! checkIStepMode() ) + { + // IStepMode is off, don't bother running this + TS_TRACE("IStepMode disabled, can't run unit test" ); + return; + } + + if ( ! checkReadyBit() ) + { + TS_FAIL( "readybit is not enabled"); + return; + } + + // + l_pass = runIStep( 0, // IStep = 0 + 0, // Substep=0 + l_taskStatus, // task status + l_istepStatus // istep status + ); + + if ( !l_pass ) + { + TS_FAIL( "FAILED to run IStep"); + // dump errorlog? + } + + if ( l_taskStatus != 0 ) + { + TS_FAIL( "bad status: taskStatus expected 0, got %d", + l_taskStatus); + } + + + if ( l_istepStatus != 0 ) + { + TS_FAIL( "bad status: istepStatus expected 0, got %d", + l_istepStatus); + } + + + } + + + /** + * @brief testSPLessTest3 + * + * - Execute Invalid IStep + * + */ + void testSPLessTest3( ) + { + uint16_t l_taskStatus = 0; + uint16_t l_istepStatus = 0; + bool l_pass = false; + + if ( ! checkIStepMode() ) + { + // IStepMode is off, don't bother running this + TS_TRACE("IStepMode disabled, can't run unit test" ); + return; + } + + + if ( ! checkReadyBit() ) + { + TS_FAIL( "readybit is not enabled"); + return; + } + + // run invalid istep/substep + l_pass = runIStep( 55, // IStep = 55 + 55, // Substep=55 + l_taskStatus, // return task status + l_istepStatus // return istep status + ); + + if ( !l_pass ) + { + TS_FAIL( "FAILED to run IStep"); + // dump errorlog? + } + + if ( (l_taskStatus != 0 ) || + (l_istepStatus != 0 ) + ) + { + TS_FAIL( "bad status: taskStatus expected 0, got %d", + l_taskStatus); + } + + + if ( + (l_istepStatus != 0 ) + ) + { + TS_FAIL( "bad status: istepStatus expected 0, got %d", + l_istepStatus); + } + + } + + + /** + * @brief testSPLessTest4 + * + * - Execute Several ISteps + * + * + * + */ + void testSPLessTest4( ) + { + + } + + +private: + + /** + * @brief checkIStepMode + * + * check that IStepMode is enabled, by reading the IStepModeSCOM for + * a signature value. + * + * @return bool + * @retval true if IStepMode is on, false otherwise + */ + bool checkIStepMode() + { + uint64_t l_readData = 0; + bool l_flag = false; + + l_readData = mmio_scratch_read( MMIO_SCRATCH_IPLSTEP_CONFIG ); + + // check for IStep Mode signature, this is temporary + if ( l_readData == ISTEP_MODE_SIGNATURE ) + { + l_flag = true; + } + else + { + l_flag = false; + } + + + return l_flag; + } + + /** + * @brief checkReadyBit + * + * check if the ready bit is on before starting any ISteps. + * + * This calls TS_FAIL and returns false if it cannot read the SCOM. + * + * @return bool + * @retval true if readybit is on, false otherwise + */ + bool checkReadyBit( ) + { + bool l_runningbit = false; + bool l_readybit = false; + uint16_t l_IStep = 0; + uint16_t l_Substep = 0; + uint16_t l_taskStatus = 0; + uint16_t l_istepStatus = 0; + + SPLESSSTS::read( l_runningbit, + l_readybit, + l_IStep, + l_Substep, + l_taskStatus, + l_istepStatus ); + + return l_readybit; + } + + + /** + * @brief runIStep + * + * run one IStep /substep and return results. + * + * Assumes that readybit is on (i.e. you should have checked it + * before calling this) + * + * calls TS_FAIL and returns false if cannot read the SCOM regs + * calls TS_FAIL and returns false if times out waiting for runningbit + * calls TS_FAIL and returns false if ready bit goes off + * + * @param[in] i_IStep - IStep to run + * @param[in] i_Substep - Substep to run + * @param[out] o_taskStatus - taskStatus returned from IStep/substep + * @param[out] o_istepStatus - istepStatus retured from IStep/substep + * + * @return bool + * @retval true if IStep runs OK, false otherwise + */ + bool runIStep( uint16_t i_IStep, + uint16_t i_Substep, + uint16_t &o_taskStatus, + uint16_t &o_istepStatus + ) + { + bool l_runningbit = false; + bool l_readybit = false; + uint16_t l_IStep = 0; + uint16_t l_Substep = 0; + bool l_pass = false; + + // init outputs + + l_IStep = 0; + l_Substep = 0; + o_taskStatus = 0; + o_istepStatus = 0; + + l_pass = true; // assume things will be OK + + + // Write gobit, istep, substep + // + SPLESSCMD::write( true, // gobit + i_IStep, // istep + i_Substep // substep + ); + // loop up waiting for test to finish + int timeoutctr = 10; + do { + // give it 500 millseconds to finish + nanosleep( 0, 500000000 ); + + SPLESSSTS::read( l_runningbit, + l_readybit, + l_IStep, + l_Substep, + o_taskStatus, + o_istepStatus + ); + + // timeout probably means the singlestep loop died. + // do a TS_FAIL + if ( --timeoutctr <= 0 ) + { + TS_FAIL( "TIMEOUT waiting for runningbit to turn off"); + l_pass = false; + } + + } while (l_runningbit); + + // check readybit - if it's off it means the singlestep loop died. + // do a TS_FAIL + if ( ! l_readybit ) + { + TS_FAIL( "FAIL: readybit is off"); + l_pass = false; + } + + return l_pass; + } + +}; // class + + +#endif + diff --git a/src/usr/isteps/istep1.C b/src/usr/isteps/istep1.C index 9d1e311b1..97bf3ab73 100644 --- a/src/usr/isteps/istep1.C +++ b/src/usr/isteps/istep1.C @@ -20,10 +20,13 @@ // Origin: 30 // // IBM_PROLOG_END + /** - * @file isteps.C + * @file istep1.C + * + * test ISTep file * - * Collection of IStep modules + * @note, you must update isteps.h if you change this one * */ @@ -43,7 +46,8 @@ #include <initservice/taskargs.H> // task args // pull in stuff to run HW procedure - from Andrew's hwpf testcase 2 -// NOTE: there are extra include paths in isteps/makefile to find the fapi includes: +// NOTE: there are extra include paths in isteps/makefile to find the fapi +// includes: // EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer // EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi // EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat @@ -66,7 +70,7 @@ trace_desc_t *g_trac_istep1 = NULL; TRAC_INIT(&g_trac_istep1, "ISTEP1", 4096); extern "C" -void IStep1( void * io_pArgs ) +void IStep0sub0( void * io_pArgs ) { INITSERVICE::TaskArgs::TaskArgs *pTaskArgs = reinterpret_cast<INITSERVICE::TaskArgs::TaskArgs *>(io_pArgs); @@ -77,7 +81,7 @@ void IStep1( void * io_pArgs ) // print out stuff from taskargs TRACFCOMP( g_trac_istep1, - "starting IStep 1, command=0x%llx, returncode=0x%llx", + ENTER_MRK "starting IStep0sub0, command=0x%llx, returncode=0x%llx", command, returncode ); // ----- start ISTEP -------------------------------------------------- @@ -89,7 +93,7 @@ void IStep1( void * io_pArgs ) if (l_err) { TRACFCOMP( g_trac_istep1, - "IStep1 failed, posting error code 1"); + "Failed, posting error code 1"); // Commit/delete error errlCommit(l_err); @@ -99,7 +103,7 @@ void IStep1( void * io_pArgs ) else { TRACFCOMP( g_trac_istep1, - "ISTep1 finished successfully."); + "Finished successfully."); pTaskArgs->postReturnCode( 0 ); } @@ -107,8 +111,9 @@ void IStep1( void * io_pArgs ) // ----- end ISTEP ------------------------------------------------------ TRACFCOMP( g_trac_istep1, - EXIT_MRK "ending IStep 1"); + EXIT_MRK "ending IStep0sub0"); + // if non-null, wait for the barrier, otherwise just return if ( pTaskArgs ) { pTaskArgs->waitChildSync(); @@ -117,5 +122,64 @@ void IStep1( void * io_pArgs ) task_end(); } +extern "C" +void IStep0sub1( void * io_pArgs ) +{ + INITSERVICE::TaskArgs::TaskArgs *pTaskArgs = + reinterpret_cast<INITSERVICE::TaskArgs::TaskArgs *>(io_pArgs); + uint64_t command = pTaskArgs->getCommand(); + uint64_t returncode = pTaskArgs->getReturnCode(); + + + // print out stuff from taskargs + TRACFCOMP( g_trac_istep1, + ENTER_MRK "starting IStep0sub1, command=0x%llx, returncode=0x%llx", + command, returncode ); + // ----- start ISTEP -------------------------------------------------- + + pTaskArgs->postReturnCode( 0 ); + + // ----- end ISTEP ------------------------------------------------------ + TRACFCOMP( g_trac_istep1, + EXIT_MRK "ending IStep0sub1"); + + // if non-null, wait for the barrier, otherwise just return + if ( pTaskArgs ) + { + pTaskArgs->waitChildSync(); + } + + task_end(); +} + +extern "C" +void IStep1sub0( void * io_pArgs ) +{ + INITSERVICE::TaskArgs::TaskArgs *pTaskArgs = + reinterpret_cast<INITSERVICE::TaskArgs::TaskArgs *>(io_pArgs); + uint64_t command = pTaskArgs->getCommand(); + uint64_t returncode = pTaskArgs->getReturnCode(); + + + // print out stuff from taskargs + TRACFCOMP( g_trac_istep1, + ENTER_MRK "starting IStep1sub0, command=0x%llx, returncode=0x%llx", + command, returncode ); + // ----- start ISTEP -------------------------------------------------- + + pTaskArgs->postReturnCode( 0 ); + + // ----- end ISTEP -------------------------------------------------- + TRACFCOMP( g_trac_istep1, + EXIT_MRK "ending IStep1sub0"); + + // if non-null, wait for the barrier, otherwise just return + if ( pTaskArgs ) + { + pTaskArgs->waitChildSync(); + } + + task_end(); +} } // namespace |