/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/errldisplay/errldisplay.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2013,2015 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ /** * @file /src/usr/errl/display/errldisplay.C * * @brief Implementation of ErrlDisplay class * This will display human-readable dumps of error log entries. * * The strings displayed are automatically extracted from source code by * the script ../errl/parser/genErrlParsers.pl * * The base image is limited to 512K, and inclusion of the error strings * in the base make it grow beyond that limit, so the text and display * functions are put into the extended image. * * The errl module in the base image will provide an interface for the * display functions to register with it. * When an errl is generated, the base image will see if a display function * has been registered. If so, then it will be called to display the error. * If not, then the base image will display the raw error data and save the * error information into a list. * When the display function does register itself, the errl module in the * base image will pretty-print all of the pending errors from the list * it generated before that point. */ /*****************************************************************************/ // I n c l u d e s /*****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ERRORLOGDISPLAY { // Trace definition trace_desc_t* g_trac_errldisp = NULL; TRAC_INIT(&g_trac_errldisp, "ERRLDISP", KILOBYTE, TRACE::BUFFER_SLOW); /** * @brief Default error log to display when we can't find one in the errorInfo * table. * * The data tables and size variables * static errLogInfo errorInfo [] * static compTableInfo compTable [] * static uint16_t errorInfoTableSize * static uint16_t compTableSize * are automatically generated by the ../errl/parser/genErrlTable.pl script * and placed in the file $GENDIR/errldisplaydata.C */ static const ErrLogDisplay::errLogInfo unknownErrorInfo = { 0, // Module Id 0, // Reason Code "", // Description "unknown", // Module Name "unknown", // Reason "unknown", // User Data 1 string "unknown" // User Data 2 string }; ErrLogDisplay& errLogDisplay() { return Singleton::instance(); } const ErrLogDisplay::errLogInfo* ErrLogDisplay::findErrLogInfo ( uint8_t i_moduleId, uint16_t i_reasonCode) { // Create local errLogInfo to search for struct ErrLogDisplay::errLogInfo l_errLogInfo = {i_moduleId,i_reasonCode, NULL,NULL,NULL,NULL,NULL}; errLogInfo* l_result = std::lower_bound(errorInfo, errorInfo + errorInfoTableSize, l_errLogInfo, ErrLogDisplay::errorLogInfoCompare); // Check if the lower_bound found the correct result if ( (l_result != (errorInfo + errorInfoTableSize)) && (l_result->moduleId == i_moduleId) && (l_result->reasonCode == i_reasonCode) ) { return l_result; } // Couldn't find it, so return the default unknown structure. return &unknownErrorInfo; } const char * ErrLogDisplay::findComponentName (compId_t i_compId) { // Create local compTableInfo to search for struct ErrLogDisplay::compTableInfo l_compTableInfo = {i_compId, NULL}; compTableInfo* l_result = std::lower_bound(compTable, compTable + compTableSize, l_compTableInfo, ErrLogDisplay::compTableCompare); // Check if the lower_bound found the correct result if ( (l_result != (compTable + errorInfoTableSize)) && (l_result->value == i_compId) ) { return l_result->name; } return "unknown"; } void ErrLogDisplay::displayCallout (void *data, size_t size) { // Parse encoded callout data. See ErrlUserDetailsCallout class in // errludcallout.C for (undocumented) encoding details. if (size >= sizeof(HWAS::callout_ud_t)) { HWAS::callout_ud_t* callout = reinterpret_cast(data); size_t l_curSize = sizeof(HWAS::callout_ud_t); switch ( callout->type ) { case HWAS::CLOCK_CALLOUT: CONSOLE::displayf(NULL, " CLOCK ERROR" ); CONSOLE::displayf(NULL, " clockType: %d", static_cast( callout->clockType ) ); break; case HWAS::BUS_CALLOUT: CONSOLE::displayf(NULL, " BUS ERROR" ); CONSOLE::displayf(NULL, " busType: %d", static_cast( callout->busType ) ); // Data is formatted as a callout_ud_t followed by 2 entity paths // representing each side of the link. if (size < (l_curSize + sizeof(uint8_t))) { break; } callout++; CONSOLE::displayf(NULL, " First link: " ); if( *reinterpret_cast( callout ) == HWAS::TARGET_IS_SENTINEL ) { CONSOLE::displayf(NULL, "MASTER PROCESSOR SENTINEL" ); } else { if (size < (l_curSize + sizeof(TARGETING::EntityPath))) { break; } l_curSize += sizeof(TARGETING::EntityPath); TARGETING::EntityPath *ep = reinterpret_cast( callout ); CONSOLE::displayf(NULL, "%s", ep->toString() ); if (size < (l_curSize + sizeof(uint8_t)) ) { break; } ep++; CONSOLE::displayf(NULL, " Second link: " ); if( *reinterpret_cast( ep ) == HWAS::TARGET_IS_SENTINEL ) { CONSOLE::displayf(NULL, "MASTER PROCESSOR SENTINEL" ); } else { if (size < (l_curSize + sizeof(TARGETING::EntityPath))) { break; } CONSOLE::displayf(NULL, "%s", ep->toString() ); } } break; case HWAS::HW_CALLOUT: CONSOLE::displayf(NULL, " HW CALLOUT" ); CONSOLE::displayf(NULL, " Reporting CPU ID: %d", callout->cpuid ); // Data is formatted as a callout_ud_t followed by an entity path. if (size < (l_curSize + sizeof(uint8_t))) { break; } callout++; CONSOLE::displayf(NULL, " Called out entity:" ); if( *reinterpret_cast( callout ) == HWAS::TARGET_IS_SENTINEL ) { CONSOLE::displayf(NULL, "MASTER PROCESSOR SENTINEL" ); } else { if (size < (l_curSize + sizeof(TARGETING::EntityPath))) { break; } TARGETING::EntityPath *ep = reinterpret_cast( callout ); CONSOLE::displayf(NULL, "%s", ep->toString() ); } break; case HWAS::PROCEDURE_CALLOUT: CONSOLE::displayf(NULL, " PROCEDURE ERROR" ); CONSOLE::displayf(NULL, " Procedure: %d", static_cast( callout->procedure ) ); break; } } } void ErrLogDisplay::displayTarget(void *data, size_t size) { char *char_buf = reinterpret_cast( data ); // The first part of the buffer is a TargetLabel_t. ERRORLOG::TargetLabel_t *label = reinterpret_cast( char_buf ); if( label->tag == 0xffffffff ) { CONSOLE::displayf(NULL, " MASTER PROCESSOR SENTINEL" ); } else { // The second part of the buffer contains the encoded target. // See Target::targetFFDC for encoding details. // We only care about the HUID and can look up the Target based on that. char_buf += sizeof(ERRORLOG::TargetLabel_t); TARGETING::AttributeTraits::Type *huid = reinterpret_cast::Type*>( char_buf ); CONSOLE::displayf(NULL, " HUID: %08x", *huid ); // Look up the HUID across all targets. for ( TARGETING::TargetIterator ti = TARGETING::targetService().begin(); ti != TARGETING::targetService().end(); ++ti ) { TARGETING::AttributeTraits::Type tmp_huid; if( ti->tryGetAttr( tmp_huid ) && tmp_huid == *huid ) { TARGETING::Target *target = *ti; CONSOLE::displayf(NULL, " Phys path: %s", target->getAttr().toString() ); CONSOLE::displayf(NULL, " Affinity path: %s", target->getAttr().toString() ); break; } } } } // // Display a human-readable form of an error. void ErrLogDisplay::msgDisplay (const errlHndl_t &i_err, compId_t i_committerComp) { TRACDCOMP( g_trac_errldisp, ENTER_MRK "ErrLogDisplay::msgDisplay" ); do { // Decide whether or not to skip the error log if( i_err->getSkipShowingLog() ) { TRACDCOMP( g_trac_errldisp, INFO_MRK"msgDisplay: %.8X is INFORMATIONAL/RECOVERED; skipping...", i_err->eid()); break; } const errLogInfo *info = findErrLogInfo ( i_err->moduleId(), i_err->reasonCode()); CONSOLE::displayf(NULL, "================================================"); CONSOLE::displayf(NULL, "Error reported by %s (0x%04X)", findComponentName( i_committerComp ), i_committerComp ); CONSOLE::displayf(NULL, " %s", info->descriptString); CONSOLE::displayf(NULL, " ModuleId 0x%02x %s", i_err->moduleId(), info->moduleName); CONSOLE::displayf(NULL, " ReasonCode 0x%04x %s", i_err->reasonCode(), info->reasonString); CONSOLE::displayf(NULL, " UserData1 %s : 0x%016lx", info->userData1String, i_err->getUserData1()); CONSOLE::displayf(NULL, " UserData2 %s : 0x%016lx", info->userData2String, i_err->getUserData2()); // Loop through and print all of the user data sections. for ( size_t i = 0; i < i_err->iv_SectionVector.size(); ++i ) { ERRORLOG::ErrlUD *user_data = i_err->iv_SectionVector[i]; CONSOLE::displayf(NULL, "User Data Section %d, type %c%c", (int) i, (user_data->iv_header.iv_sid >> 8) & 0xff, user_data->iv_header.iv_sid & 0xff ); CONSOLE::displayf(NULL, " Subsection type 0x%02x", user_data->iv_header.iv_sst ); CONSOLE::displayf(NULL, " ComponentId %s (0x%04x)", findComponentName( user_data->iv_header.iv_compId ), user_data->iv_header.iv_compId ); switch ( user_data->iv_header.iv_sst ) { case ERRORLOG::ERRL_UDT_TARGET: CONSOLE::displayf(NULL, " TARGET" ); displayTarget( user_data->iv_pData, user_data->iv_Size ); break; case ERRORLOG::ERRL_UDT_CALLOUT: CONSOLE::displayf(NULL, " CALLOUT" ); displayCallout( user_data->iv_pData, user_data->iv_Size ); break; case ERRORLOG::ERRL_UDT_STRING: CONSOLE::displayf(NULL, " STRING" ); CONSOLE::displayf(NULL, " %s", reinterpret_cast( user_data->iv_pData ) ); break; } } CONSOLE::displayf(NULL, "================================================" ); CONSOLE::flush(); }while( 0 ); TRACDCOMP( g_trac_errldisp, EXIT_MRK "ErrLogDisplay::msgDisplay" ); } /** * @brief This is the task entry point. It will register ErrlDisplay module with * the base image Errl module. * * @param[in/out] io_taskRetErrl Errl module to register with ErrlDisplay * instance * * @return None */ static void errLogDisplayEntryPoint (errlHndl_t &io_taskRetErrl) { TRACFCOMP( g_trac_errldisp, ENTER_MRK "ErrLogDisplay::errLogDisplayEntryPoint" ); io_taskRetErrl = Singleton::instance().init(); TRACFCOMP( g_trac_errldisp, EXIT_MRK "ErrLogDisplay::errLogDisplayEntryPoint" ); } TASK_ENTRY_MACRO( errLogDisplayEntryPoint ); errlHndl_t ErrLogDisplay::init() { ERRORLOG::ErrlManager::errlResourceReady(ERRORLOG::ERRLDISP); return NULL; } } // End namespace