diff options
author | Monte Copeland <copelanm@us.ibm.com> | 2011-08-11 15:57:40 -0500 |
---|---|---|
committer | Monte K. Copeland <copelanm@us.ibm.com> | 2011-08-16 13:24:44 -0500 |
commit | f24bf89ab0cb82fee8ab80ed6f5aa8142e3db462 (patch) | |
tree | 8647432fc82bbd34becc2ebcd7f50f2fccd469b8 /src | |
parent | 802274b948ef4a52deb4285368a086f669d3913b (diff) | |
download | blackbird-hostboot-f24bf89ab0cb82fee8ab80ed6f5aa8142e3db462.tar.gz blackbird-hostboot-f24bf89ab0cb82fee8ab80ed6f5aa8142e3db462.zip |
Changes to errl to commit error logs to L3 RAM 7
Change-Id: Ic058a5b9ea6f8f1d79fc0ff30097cc32f18423bd
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/221
Reviewed-by: Monte K. Copeland <copelanm@us.ibm.com>
Tested-by: Jenkins Server
Diffstat (limited to 'src')
-rwxr-xr-x | src/build/tools/cpfiles.pl | 1 | ||||
-rw-r--r-- | src/include/assert.h | 21 | ||||
-rw-r--r-- | src/include/usr/errl/errlentry.H | 217 | ||||
-rw-r--r-- | src/include/usr/errl/errlmanager.H | 28 | ||||
-rw-r--r-- | src/include/usr/errl/errltypes.H | 99 | ||||
-rw-r--r-- | src/usr/errl/errlentry.C | 143 | ||||
-rw-r--r-- | src/usr/errl/errlffdc.C | 32 | ||||
-rw-r--r-- | src/usr/errl/errlffdc.H | 13 | ||||
-rw-r--r-- | src/usr/errl/errlmanager.C | 150 | ||||
-rw-r--r-- | src/usr/errl/errlsctn.C | 100 | ||||
-rw-r--r-- | src/usr/errl/errlsctn.H | 59 | ||||
-rw-r--r-- | src/usr/errl/errlsctnhdr.C | 1 | ||||
-rw-r--r-- | src/usr/errl/errlsctnhdr.H | 6 | ||||
-rw-r--r-- | src/usr/errl/makefile | 2 | ||||
-rw-r--r-- | src/usr/errl/parser/errlparser.C | 701 | ||||
-rw-r--r-- | src/usr/errl/parser/makefile | 35 | ||||
-rw-r--r-- | src/usr/errl/parser/readcomps.rex | 58 | ||||
-rw-r--r-- | src/usr/errl/test/errltest.H | 87 |
18 files changed, 1554 insertions, 199 deletions
diff --git a/src/build/tools/cpfiles.pl b/src/build/tools/cpfiles.pl index b17764e0f..41182a187 100755 --- a/src/build/tools/cpfiles.pl +++ b/src/build/tools/cpfiles.pl @@ -36,6 +36,7 @@ sub printUsage; my @files = ("src/build/tools/exthbdump.pl", "src/build/simics/post_model_hook.simics", "src/build/trace/traceHB.py", + "src/usr/errl/parser/bin/errlparser", "img/hbotStringFile", "img/hbicore.syms", "img/hbicore_test.syms", diff --git a/src/include/assert.h b/src/include/assert.h index a8f3fb664..1abeb5e2a 100644 --- a/src/include/assert.h +++ b/src/include/assert.h @@ -156,6 +156,27 @@ void __assert(AssertBehavior i_assertb, int i_line); #define crit_assert(expr,...) { } #endif + + +/** @brief Make an assertion at compile time. If Boolean expression exp + * is false, then the compile will stop with an error. Example usage: + * CPPASSERT( 2 == sizeof(compId_t)); + * which would be used in front of errl flattening code that assumes + * compId_t is 2 bytes in size. Also with the use of -f short-enums + * compiler switch, one could assert + * CPPASSERT( 1 == sizeof(errlEventType_t)); + * If the assertion fails, it will be a wakeup call that the errlEventType_t + * enum has grown larger than a byte in size. The mechanism to abend the + * compile when the expression is false is to cause a typedef of a char array + * that is -1 bytes in size. + * + * Similar: #define CHECK_SIZE(DATA, EXPECTED_SIZE)\ + * typedef char CHECKSIZEVAR[(EXPECTED_SIZE == sizeof(DATA)) -1] + * + */ +#define CPPASSERT(exp) typedef char compile_time_assert_failed[2*((exp)!=0)-1] + + #ifdef __cplusplus }; #endif diff --git a/src/include/usr/errl/errlentry.H b/src/include/usr/errl/errlentry.H index 71d2102ae..7e9d91a50 100644 --- a/src/include/usr/errl/errlentry.H +++ b/src/include/usr/errl/errlentry.H @@ -29,7 +29,7 @@ class ErrlSctn; class ErrlFFDC; /** - * @brief Host Boot Error log entry class. + * @brief Host Boot Error log entry class. * This class contains all of the entry management logic and necessary * information to create a PEL or IPMI event type logs. * A pointer to this class is known as an errlHndl_t (the error log handle) @@ -43,7 +43,7 @@ class ErrlEntry public: /** - * @brief ErrlEntry constructor. Builds an error log with info + * @brief ErrlEntry constructor. Builds an error log with info * constructed from the input. * Event type, Sub System, SRC type, and Terminate state are defaulted * to the most common values for Host Boot environment. These values @@ -66,7 +66,7 @@ public: * in the primary SRC * @param[in] i_user2 64 bits of user data which are placed * in the primary SRC - * @return None + * @return None */ ErrlEntry(const errlSeverity_t i_sev, const uint8_t i_modId, @@ -79,7 +79,9 @@ public: * * Releases all resources owned by the handle. If the log has not * been committed, it effectively aborts the log. - * All logs (committed or not) must be deleted to avoid a resource leak. + * All logs not committed must be deleted to avoid a resource leak. + * Committing an error log via ErrlManager will cause ErrlManager + * to delete the log after saving it. * * @return None * @@ -92,6 +94,7 @@ public: * problem is perceived to be. The severity is * initially set by the parameter in the constructor * and can be changed at any point thereafter. + * See errl/errltypes.H * * @return Current Log Severity * @@ -105,37 +108,70 @@ public: * initially set by the parameter in the constructor * and can be changed at any point thereafter. * - * @return void + * @param[in] i_sev Severity. See errl/errltypes.H * + * @return void */ void setSev(const errlSeverity_t i_sev); + /** - * @brief Returns the log's reason code - * - * @return uint16_t + * @brief Get reason code. See errl/errlreasoncodes.H * + * @return reason code */ uint16_t reasonCode() const; /** - * @brief Returns the log's event type + * @brief Set reason code + * + * @param[in] i_reasonCode The reason code. The upper byte + * of a reason code is the component ID. + * See errl/errlreasoncodes.H + * + * @return void + */ + void setReasonCode( const uint16_t i_reasonCode ); + + /** + * @brief Get module id. See errl/errlreasoncodes.H + * + * @return module id + */ + uint8_t moduleId() const; + + + + /** + * @brief Set module id * + * @param[in] i_moduleId The module ID. See errl/errlreasoncodes.H + * + * @return void + */ + void setModuleId( const uint8_t i_moduleId ); + + + /** + * @brief Get the event type of the error log. + * See errl/errltypes.H * @return errlEventType_t * */ errlEventType_t eventType() const; /** - * @brief Set the log's event type - * - * @return void - * - */ + * @brief Set the log's event type + * + * @param[in] i_eventType Event type. See errl/errltypes.H + * + * @return void + * + */ void setEventType(const errlEventType_t i_eventType); /** - * @brief Returns the log's sub system + * @brief Returns the log's sub system. See errl/errltypes.H * * @return epubSubSystem_t * @@ -143,15 +179,17 @@ public: epubSubSystem_t subSys() const; /** - * @brief Set the log's sub system + * @brief Set the log's ePub sub system type. * - * @return void + * @param[in] i_subSys Subsystem type. See errl/errltypes.H * + * @return void */ void setSubSys(const epubSubSystem_t i_subSys); + /** - * @brief Returns the log's SRC type + * @brief Returns the log's SRC type. See errl/errltypes.H * * @return srcType_t * @@ -161,13 +199,16 @@ public: /** * @brief Set the log's SRC type * - * @return void + * @param[in] i_srcType The SRC type for this error log. See + * errl/errltypes.H * + * @return void */ void setSrcType(const srcType_t i_srcType); /** - * @brief Returns the log's terminate state type + * @brief Returns the log's terminate state type. See + * errl/errltypes.H * * @return errlTermState_t * @@ -177,6 +218,8 @@ public: /** * @brief Set the log's Terminating state * + * @param[in] i_termState See errl/errltypes.H + * * @return void * */ @@ -194,6 +237,7 @@ public: * which classifies the data. This in * conjunction with the version can be used * to decode the data. + * * @return Pointer to FFDC section if successfully added. * NULL if fails */ @@ -211,35 +255,48 @@ public: * function is called earlier. * @param[in] i_dataPtr Points to data block to be added * @param[in] i_dataLen Length of data in bytes + * * @return void */ void appendToFFDC(ErrlFFDC* i_ffdcSctnPtr, const void *i_dataPtr, const uint32_t i_dataLen); -private: + + + + /** - * @brief Disabled copy constructor and assignment operator - */ - ErrlEntry(const ErrlEntry& i_right); - ErrlEntry& operator=(const ErrlEntry& i_right); + * @brief Compute the flattened size of an error log. + * + * @return size in bytes of the flattened data. + */ + uint64_t flattenedSize(); + /** - * @brief Add a data section to error log object + * @brief Flatten the data to caller's buffer. * - * @param[in] i_sctn Pointer to data section to be added + * @param[in,out] io_buffer Points to data block to be filled + * @param[in] i_cbBuffer Count of bytes in buffer supplied * - * @return void + * @return Count of bytes copied to caller's + * buffer or else zero if it does not fit. */ - void addSection(ErrlSctn* i_sctn); + uint64_t flatten( void * io_buffer, const uint64_t i_cbBuffer ); + + + + +private: /** - * @brief Returns the unique Error Entry Id. This ID is assigned to - * the entry when it's created. - * This is to be called by ErrlManager only. - * @return 32 bit unsigned identifier - */ - uint32_t logId() const; + * @brief Disabled copy constructor and assignment operator + */ + ErrlEntry(const ErrlEntry& i_right); + ErrlEntry& operator=(const ErrlEntry& i_right); + + /** * @brief Set the log's id @@ -247,14 +304,17 @@ private: * set this log's ID to a unique input number. * This is to be called by ErrlManager only. * + * There is no call to get the log id because it + * would just be zero until the log is committed. + * + * @param[in] i_val Log ID as assigned by ErrlManager + * * @return void */ void setLogId(const uint32_t i_val); - //@todo - Need to add serialization interfaces for ErrlSctn object. - // Serialization method (boost serialization?) is for HostBoot - // is currently not yet determined. - // Note: stream is currently not supported + + #if 0 @@ -334,21 +394,19 @@ private: #endif private: - // Data Members - uint16_t iv_reasonCode; // Component ID and reason code, 2 nibbles each - errlSeverity_t iv_sev; // Log severity - errlEventType_t iv_eventType; // Event type - epubSubSystem_t iv_subSys; // Sub system - srcType_t iv_srcType; // SRC type - errlTermState_t iv_termState; // Terminate state - uint8_t iv_modId; // Module ID - uint64_t iv_user1; // Optional user data 1 - uint64_t iv_user2; // Optional user data 2 - uint32_t iv_logId; // This log's unique ID - - // Sections in this log object - std::vector<ErrlSctn*> iv_sections; + uint16_t iv_reasonCode; // Comp ID and reason code, 2 nibbles ea + errlSeverity_t iv_sev; // Log severity + errlEventType_t iv_eventType; // Event type + epubSubSystem_t iv_subSys; // Sub system + srcType_t iv_srcType; // SRC type + errlTermState_t iv_termState; // Terminate state + uint8_t iv_modId; // Module ID + uint64_t iv_user1; // Optional user data 1 + uint64_t iv_user2; // Optional user data 2 + uint64_t iv_CreationTime; // Time of instantiation + uint32_t iv_logId; // This log's unique ID + std::vector<ErrlSctn*> iv_SectionVector; // list of user sections }; @@ -360,48 +418,65 @@ private: //////////////////////////////////////////////////////////////////////////// inline errlSeverity_t ErrlEntry::sev() const { - return (iv_sev); + return iv_sev; } -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// inline void ErrlEntry::setSev(const errlSeverity_t i_sev) { iv_sev = i_sev; return; } + //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// inline uint16_t ErrlEntry::reasonCode() const { - return (iv_reasonCode); + return iv_reasonCode; +} + +inline void ErrlEntry::setReasonCode( const uint16_t i_reasonCode ) +{ + iv_reasonCode = i_reasonCode; + return; } + //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// -inline errlEventType_t ErrlEntry::eventType() const +inline uint8_t ErrlEntry::moduleId() const +{ + return iv_modId; +} + +inline void ErrlEntry::setModuleId( const uint8_t i_moduleId ) { - return (iv_eventType); + iv_modId = i_moduleId; + return; } + //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// +inline errlEventType_t ErrlEntry::eventType() const +{ + return iv_eventType; +} + inline void ErrlEntry::setEventType(const errlEventType_t i_eventType) { iv_eventType = i_eventType; return; } + //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// inline epubSubSystem_t ErrlEntry::subSys() const { - return (iv_subSys); + return iv_subSys; } -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// inline void ErrlEntry::setSubSys(const epubSubSystem_t i_subSys) { iv_subSys = i_subSys; @@ -413,11 +488,9 @@ inline void ErrlEntry::setSubSys(const epubSubSystem_t i_subSys) //////////////////////////////////////////////////////////////////////////// inline srcType_t ErrlEntry::srcType() const { - return (iv_srcType); + return iv_srcType; } -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// inline void ErrlEntry::setSrcType(const srcType_t i_srcType) { iv_srcType = i_srcType; @@ -428,11 +501,9 @@ inline void ErrlEntry::setSrcType(const srcType_t i_srcType) //////////////////////////////////////////////////////////////////////////// inline errlTermState_t ErrlEntry::termState() const { - return (iv_termState); + return iv_termState; } -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// inline void ErrlEntry::setTermState(const errlTermState_t i_termState) { iv_termState = i_termState; @@ -440,18 +511,10 @@ inline void ErrlEntry::setTermState(const errlTermState_t i_termState) } //////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// -inline uint32_t ErrlEntry::logId() const -{ - return (iv_logId); -} - -//////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// +// Called by errlmanager at log commit time. inline void ErrlEntry::setLogId(const uint32_t i_val) { iv_logId = i_val; - return; } } // End namespace diff --git a/src/include/usr/errl/errlmanager.H b/src/include/usr/errl/errlmanager.H index 559353d87..445188f5a 100644 --- a/src/include/usr/errl/errlmanager.H +++ b/src/include/usr/errl/errlmanager.H @@ -14,10 +14,15 @@ #include <stdlib.h> #include <util/singleton.H> #include <errl/errltypes.H> +#include <sys/sync.h> +#include <vector> +#include <kernel/timemgr.H> namespace ERRORLOG { + + /** * @brief Global function to log an error * Writes the log to PNOR where committed logs are kept. @@ -79,7 +84,7 @@ public: * @brief Returns a unique error log ID * * This routine generates a unique Error ID and assign it to - * the input error log + * the input error log. Mutates iv_currLogId. * * @return Unique generated error log ID */ @@ -112,9 +117,28 @@ private: ErrlManager(const ErrlManager& i_right); ErrlManager& operator=(const ErrlManager& i_right); - + /** + * @brief + * Current log ID: increment this when assigning log ID to a new errlog + * as it is being committed. + */ uint32_t iv_currLogId; + + /** + * @brief + * Pointer to the header that preceeds the error log storage buffer + * in L3 RAM. This may go away when we adopt PNOR, or else become + * instance variables instead of a pointer pointing within the + * storage buffer. + */ + storage_header_t * iv_pStorage; + + /** + * @brief Serialization for error log commits. + */ + mutex_t iv_mutex; + }; } // End namespace diff --git a/src/include/usr/errl/errltypes.H b/src/include/usr/errl/errltypes.H index ca1deef9f..94f630f72 100644 --- a/src/include/usr/errl/errltypes.H +++ b/src/include/usr/errl/errltypes.H @@ -8,6 +8,9 @@ * This header file contains the definition of ErrlEntry related * parameters. * + * This file will be included by error log parsers that run + * on pool machines, so the stuff in here needs to be generic. + * */ /** @@ -55,7 +58,8 @@ namespace ERRORLOG { /** - * @brief Enumeration of error log severity + * @brief Enumeration of error log severity. + * Needs to fit into 1 byte for flattening purposes. */ enum errlSeverity_t { @@ -67,11 +71,12 @@ enum errlSeverity_t /** * @brief Event (error) type + * Needs to fit into 1 byte for flattening purposes. */ enum errlEventType_t { - ERRL_ETYPE_NOT_APPLICABLE = 0, - ERRL_ETYPE_DUMP_NOTIFICATION = 8, + ERRL_ETYPE_NOT_APPLICABLE = 0x00, + ERRL_ETYPE_DUMP_NOTIFICATION = 0x08, ERRL_ETYPE_USER_DECONFIG = 0x20, ERRL_ETYPE_SYS_DECONFIG = 0x21, ERRL_ETYPE_CONCURRENT_MAINTENANCE = 0x40, @@ -80,6 +85,7 @@ enum errlEventType_t /** * @brief Error log call out priority + * Needs to fit into 1 byte for flattening purposes. */ enum callOutPriority_t { @@ -90,6 +96,7 @@ enum callOutPriority_t /** * @brief Error log procedure Id + * Needs to fit into 1 byte for flattening purposes. */ enum epubProcedureId_t { @@ -98,6 +105,7 @@ enum epubProcedureId_t /** * @brief Sub system definitions + * Needs to fit into 1 byte for flattening purposes. */ enum epubSubSystem_t { @@ -107,6 +115,7 @@ enum epubSubSystem_t /** * @brief Terminating flag definitions + * Needs to fit into 1 word (32-bits) for flattening purposes. */ enum errlTermState_t { @@ -117,6 +126,7 @@ enum errlTermState_t /** * @brief SRC type definitions + * Needs to fit into 1 byte for flattening purposes. */ enum srcType_t { @@ -127,6 +137,89 @@ enum srcType_t }; +/** + * @brief This is the size of the storage buffer, presently + * in L3 RAM. When this storage is filled, no more error logs + * will be committed. The L3 RAM storage is g_ErrlStorage[] + * declared in errlmanager.C in BSS data. This will change + * when switching to PNOR. + */ +const uint32_t ERRL_STORAGE_SIZE = 65536; + + + +/** + * @brief Flattened error log header structure contains the basic + * instance variables of the ErrlEntry class. Note the + * alignment of the fields, and that the structure is packed. + */ +typedef struct errl_header +{ + uint32_t cbytes; // count of bytes in this struct + uint32_t csections; // count of sections in this error log + uint16_t reasonCode; // reason code + uint8_t unused1; // need this for alignment + uint8_t modId; // module id + uint8_t sev; // severity + uint8_t eventType; // event type + uint8_t subSys; // subsystem + uint8_t srcType; // SRC type + uint32_t termState; // Terminate state + uint32_t logId; // This log's unique ID + uint64_t user1; // Optional user data 1 + uint64_t user2; // Optional user data 2 + uint64_t CreationTime; // time error log was created +} __attribute__((packed)) errl_header_t; + + + +/** + * @brief Error logs may have a number of sections/FFDC sections added. + * This is a section header that preceeds the user-defined + * data that follows this header. Note the alignment of the fields, + * and that this structure is packed. + */ +typedef struct section_header +{ + uint32_t cbHeader; // count of bytes in this struct (flattening) + uint32_t cbSection; // count of bytes in the user-added data + uint16_t compId; // component id + uint8_t sctnVer; // section version + uint8_t subSect; // subsection +} __attribute__((packed)) section_header_t; + + +/** + * @brief The RAM storage for committed error logs starts with this + * header. This structure is org'ed at &g_ErrlStorage[0]. All + * offsets are based from &g_achErrlStorage[0], so the first + * marker will appear at offset sizeof( storage_header_t ) + */ +typedef struct storage_header +{ + uint32_t cbStorage; // count of bytes in buffer + uint32_t cInserted; // count of logs ever commited + uint32_t offsetStart; // start-of-list marker + uint32_t offsetMarker; // next-insertion marker +} __attribute__((packed)) storage_header_t; + + + + +/** + * @brief The storage buffer is a series of flattened error logs + * interspersed with markers. + * A typical marker will give the offset to the next marker and also + * the length of the flattened error log data. + */ +typedef struct marker +{ + uint32_t offsetNext; + uint32_t length; +} __attribute__((packed)) marker_t; + + + } // End namespace #endif // ERRLTYPES_H diff --git a/src/usr/errl/errlentry.C b/src/usr/errl/errlentry.C index 40138051c..f25d0cd29 100644 --- a/src/usr/errl/errlentry.C +++ b/src/usr/errl/errlentry.C @@ -9,12 +9,13 @@ /*****************************************************************************/ #include <stdio.h> #include <stdlib.h> +#include <hbotcompid.H> #include <errl/errlentry.H> #include <errl/errlmanager.H> -#include <trace/interface.H> -#include <hbotcompid.H> #include "errlsctn.H" #include "errlffdc.H" +#include <trace/interface.H> +#include <arch/ppc.H> namespace ERRORLOG { @@ -29,20 +30,21 @@ ErrlEntry::ErrlEntry(const errlSeverity_t i_sev, const uint8_t i_modId, const uint16_t i_reasonCode, const uint64_t i_user1, - const uint64_t i_user2) -:iv_reasonCode(i_reasonCode), -iv_sev(i_sev), -iv_eventType(ERRL_ETYPE_NOT_APPLICABLE), -iv_subSys(EPUB_RESERVED_0), -iv_srcType(SRC_ERR_INFO), -iv_termState(TERM_STATE_UNKNOWN), -iv_modId(i_modId), -iv_user1(i_user1), -iv_user2(i_user2), -iv_sections(NULL) + const uint64_t i_user2) : + iv_reasonCode(i_reasonCode), + iv_sev(i_sev), + iv_eventType(ERRL_ETYPE_NOT_APPLICABLE), + iv_subSys(EPUB_RESERVED_0), + iv_srcType(SRC_ERR_INFO), + iv_termState(TERM_STATE_UNKNOWN), + iv_modId(i_modId), + iv_user1(i_user1), + iv_user2(i_user2), + iv_logId(0) { - iv_logId = theErrlManager::instance().getUniqueErrId(); - TRACFCOMP(ERRORLOG::g_trac_errl, "Error %d created : modid=%X, rc=%X", iv_logId, iv_modId, iv_reasonCode); + + // record time of creation + iv_CreationTime = getTB(); } /////////////////////////////////////////////////////////////////////////////// @@ -50,8 +52,8 @@ iv_sections(NULL) ErrlEntry::~ErrlEntry() { // Free memory of all sections - for (std::vector<ErrlSctn*>::iterator l_itr = iv_sections.begin(); - l_itr != iv_sections.end(); ++l_itr) + for (std::vector<ErrlSctn*>::iterator l_itr = iv_SectionVector.begin(); + l_itr != iv_SectionVector.end(); ++l_itr) { delete (*l_itr); } @@ -69,15 +71,17 @@ ErrlFFDC* ErrlEntry::addFFDC(const compId_t i_compId, if ( (i_dataPtr == NULL) || (i_ffdcLen == 0) ) { - TRACFCOMP(ERRORLOG::g_trac_errl, "Invalid FFDC data pointer or size, no add"); + TRACFCOMP( ERRORLOG::g_trac_errl, + "Invalid FFDC data pointer or size, no add"); } else { // Create l_ffdcSection = new ErrlFFDC(i_compId, i_dataPtr, i_ffdcLen, i_ffdcVer, i_ffdcSubSect); - // Add to error log - addSection(l_ffdcSection); + + // Add to the end of the vector of sections for this error log. + iv_SectionVector.push_back( l_ffdcSection ); } return l_ffdcSection; @@ -89,20 +93,109 @@ void ErrlEntry::appendToFFDC(ErrlFFDC* i_ffdcPtr, const void *i_dataPtr, const uint32_t i_dataLen) { - //@todo Need to support append data to an existing FFDC data block + // class ErrlFFDC inherits addData() from its parent class ErrlSctn + i_ffdcPtr->addData( i_dataPtr, i_dataLen ); return; } + + + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -void ErrlEntry::addSection(ErrlSctn* i_sctn) + +uint64_t ErrlEntry::flattenedSize() { - // Add pointer - iv_sections.push_back(i_sctn); - return; + uint64_t l_bytecount = sizeof( errl_header_t ); + + // add the bytes in the sections, if any + std::vector<ErrlSctn*>::iterator it; + for( it = iv_SectionVector.begin(); it != iv_SectionVector.end(); it++ ) + { + l_bytecount += (*it)->flattenedSize(); + } + + return l_bytecount; +} + + + + +/////////////////////////////////////////////////////////////////////////////// +// Flatten object instance data into a packed structure. +// See errl/erltypes.H and the errl_header_t struct. + +uint64_t ErrlEntry::flatten( void * io_pBuffer, uint64_t i_bufsize ) +{ + uint64_t l_flatCount = 0; + + do + { + l_flatCount = flattenedSize(); + if ( i_bufsize < l_flatCount ) + { + // error path; return zero + TRACFCOMP( ERRORLOG::g_trac_errl, "Invalid buffer size"); + l_flatCount = 0; + break; + } + + // The CPPASSERT() macro will cause the compile to abend + // when the expression given evaluates to false. If ever + // these cause the compile to fail, then perhaps the size + // of enum'ed types has grown unexpectedly. At any rate, + // errl_header_t defined in errl/errltypes.H will need to + // be adjusted for the changes in size of these instance + // variables. Monte + CPPASSERT( 1 == sizeof(iv_sev)); + CPPASSERT( 1 == sizeof(iv_eventType)); + CPPASSERT( 1 == sizeof(iv_subSys)); + CPPASSERT( 1 == sizeof(iv_srcType)); + CPPASSERT( 2 == sizeof(iv_reasonCode)); + CPPASSERT( 2 == sizeof(compId_t)); + CPPASSERT( 1 == sizeof(iv_modId)); + CPPASSERT( 0 == (sizeof(errl_header_t) % sizeof(uint32_t))); + + + // Marshall the instance var data into a struct. + errl_header_t l_hdr; + memset( &l_hdr, 0, sizeof( l_hdr )); + l_hdr.cbytes = sizeof( l_hdr ); + l_hdr.csections = iv_SectionVector.size(); + l_hdr.reasonCode = iv_reasonCode; + l_hdr.modId = iv_modId; + l_hdr.sev = iv_sev; + l_hdr.eventType = iv_eventType; + l_hdr.subSys = iv_subSys; + l_hdr.srcType = iv_srcType; + l_hdr.termState = iv_termState; + l_hdr.logId = iv_logId; + l_hdr.user1 = iv_user1; + l_hdr.user2 = iv_user2; + l_hdr.CreationTime = iv_CreationTime; + + + // Write the flat data. + char * l_pchar = reinterpret_cast<char*>(io_pBuffer); + memcpy( l_pchar, &l_hdr, sizeof( l_hdr )); + l_pchar += sizeof( l_hdr ); + + // Append all the sections. + std::vector<ErrlSctn*>::iterator it; + for(it=iv_SectionVector.begin(); it != iv_SectionVector.end(); it++ ) + { + uint64_t l_countofbytes = (*it)->flattenedSize(); + (*it)->flatten( l_pchar, l_countofbytes ); + l_pchar += l_countofbytes; + } + } + while( 0 ); + + return l_flatCount; } + } // End namespace diff --git a/src/usr/errl/errlffdc.C b/src/usr/errl/errlffdc.C index 6fc4388fa..7e0204d12 100644 --- a/src/usr/errl/errlffdc.C +++ b/src/usr/errl/errlffdc.C @@ -12,7 +12,7 @@ #include <string.h> #include <trace/interface.H> #include "errlffdc.H" -#include "errlsctn.H" + namespace ERRORLOG { @@ -26,10 +26,10 @@ ErrlFFDC::ErrlFFDC(const compId_t i_compId, const uint32_t i_ffdcLen, const uint8_t i_ffdcVer, const uint8_t i_ffdcSubSect) -: ErrlSctn(i_compId, i_ffdcVer, i_ffdcSubSect), - iv_data( NULL ), - iv_size( 0 ) +: ErrlSctn(i_compId, i_ffdcVer, i_ffdcSubSect) { + + // addData is inherited from parent class ErrlSctn addData(i_ffdcPtr, i_ffdcLen); } @@ -37,32 +37,8 @@ ErrlFFDC::ErrlFFDC(const compId_t i_compId, /////////////////////////////////////////////////////////////////////////////// ErrlFFDC::~ErrlFFDC() { - // Free FFDC data memory - delete iv_data; } -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -void ErrlFFDC::addData(const void *i_data, - const uint32_t i_size) -{ - // Resize memory block - iv_data = (uint8_t*)realloc(iv_data, iv_size + i_size); - - // Make sure reallocate call successes - if (iv_data != NULL) - { - // Copy data to new area - memcpy(iv_data + iv_size, i_data, i_size); - - // Total extra data - iv_size += i_size; - } - else - { - TRACFCOMP(g_trac_errl, "ErrlFFDC::addData() - Reallocate memory failed!"); - } -} } // End namespace diff --git a/src/usr/errl/errlffdc.H b/src/usr/errl/errlffdc.H index 7e945527e..bbeea96a4 100644 --- a/src/usr/errl/errlffdc.H +++ b/src/usr/errl/errlffdc.H @@ -58,17 +58,6 @@ public: */ ~ErrlFFDC(); - /** - * @brief Appends data to the section - * Grows the section by the given amount - * - * @param[in] i_data Pointer to data source - * @param[in] i_size Data size (bytes) - * - * @return None - */ - void addData(const void *i_data, - const uint32_t i_size); private: /** @@ -77,8 +66,6 @@ private: ErrlFFDC(const ErrlFFDC& i_right); ErrlFFDC& operator=(const ErrlFFDC& i_right); - uint8_t* iv_data; // Data Pointer - uint32_t iv_size; // Data Length }; diff --git a/src/usr/errl/errlmanager.C b/src/usr/errl/errlmanager.C index 10eccbc66..166fbe6c9 100644 --- a/src/usr/errl/errlmanager.C +++ b/src/usr/errl/errlmanager.C @@ -10,28 +10,79 @@ #include <errl/errlmanager.H> #include <trace/interface.H> #include <errl/errlentry.H> +#include <stdlib.h> +#include <string.h> + + + + namespace ERRORLOG { extern trace_desc_t* g_trac_errl; + + +// Scaffolding +// Store error logs in this memory buffer in L3 RAM. +char g_ErrlStorage[ ERRL_STORAGE_SIZE ]; + + +/** +* @brief +* In storage, the flattened error logs are interspersed with "markers." +* CBMARKER is the count of bytes in one marker. +* CB2MARKERS is the count of bytes in two markers. +*/ +#define CBMARKER (sizeof(marker_t)) +#define CB2MARKERS (2*sizeof(marker_t)) + +/** +* @brief OFFSET2MARKER() +* Convert an offset within the buffer to a marker_t pointer. +*/ +#define OFFSET2MARKER(off) (reinterpret_cast<marker_t*>(&g_ErrlStorage[off])) + +/** +* @brief POINTER2OFFSET() +* Convert a marker_t pointer to its offset within the buffer. +*/ +#define POINTER2OFFSET(p) ((reinterpret_cast<char*>(p))-(g_ErrlStorage)) + + + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ErrlManager::ErrlManager() -:iv_currLogId(0) { - //@todo - // This is done in order to avoid reading logID from PNOR for every - // error log created. - // When ErrlManager singleton instantiated: - // 1. Parse the last committed error from PNOR - // 2. Get the logID from that error - // 3. Load iv_currLogId with that value. - // 4. When next error is committed, assign the next ID value to it - // before writing to PNOR. + // PNOR will be reinitialized every time hostboot runs + iv_currLogId = 0; + + mutex_init(&iv_mutex); + + // Scaffolding. + // For now, put error logs in a 64KB buffer in L3 RAM + // This buffer has a header (storage_header_t) followed by + // storage. + iv_pStorage = reinterpret_cast<storage_header_t*>(g_ErrlStorage); + + // g_ErrlStorage is in BSS segment, therefore already zeroed. + // memset( iv_pStorage, 0, sizeof(storage_header_t)); + // Storage size is placed here for benefit of downstream parsers. + iv_pStorage->cbStorage = sizeof( g_ErrlStorage ); + // Offsets are zero-based at &g_ErrlStorage[0], + // so the first usable offset is just past the header. + iv_pStorage->offsetMarker = sizeof(storage_header_t); + iv_pStorage->offsetStart = sizeof(storage_header_t); + + // g_ErrlStorage is in BSS segment, therefore already zeroed. + // Thus, the prime marker in storage is already zero. + // marker_t* l_pMarker = OFFSET2MARKER( iv_pStorage->offsetStart ); + // l_pMarker->offsetNext = 0; + // l_pMarker->length = 0; } /////////////////////////////////////////////////////////////////////////////// @@ -41,41 +92,88 @@ ErrlManager::~ErrlManager() } /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// +// +// Save and delete this error log. On output, io_err will be nul. +// void ErrlManager::commitErrLog(errlHndl_t& io_err) { - // If NULL, put out warning trace - if (io_err == NULL) + do { - TRACFCOMP(g_trac_errl, "commitErrLog() - NULL pointer"); - } - else - { - TRACFCOMP( g_trac_errl, "commitErrLog()> Reasoncode=%X, Id=%d", io_err->reasonCode(), io_err->logId() ); + if (io_err == NULL) + { + // put out warning trace + TRACFCOMP(g_trac_errl, "commitErrLog() - NULL pointer"); + break; + } + + + // lock sem + mutex_lock(&iv_mutex); + + // Assign a unique error ID to the committed log + uint32_t l_errId = getUniqueErrId(); + io_err->setLogId(l_errId); + + // Get flattened count of bytes. + uint32_t l_cbActualFlat = io_err->flattenedSize(); + + // Round this copy up to next nearest word (32-bit) boundary. + uint32_t l_cbflat = ((l_cbActualFlat+3) & ~3); + + // Save/flatten the error log to the storage buffer. + uint32_t l_extent = iv_pStorage->offsetMarker + CB2MARKERS + l_cbflat; - //@fixme - an id is already assigned in the constructor, which one do we want? - // Assign a unique error ID to the committed log - //uint32_t l_errId = getUniqueErrId(); - //io_err->setLogId(l_errId); + if( l_extent < ERRL_STORAGE_SIZE) + { + // New data and its surrounding markers can fit between + // the insertion point and the end of the storage buffer. + // Flatten the data at the insertion point. + marker_t * l_pMarker = OFFSET2MARKER( iv_pStorage->offsetMarker ); + io_err->flatten( l_pMarker+1, l_cbflat ); + l_pMarker->length = l_cbActualFlat; - // @todo: - // - Flatten error into PNOR + // Assign offset to next marker to this marker. + l_pMarker->offsetNext=iv_pStorage->offsetMarker+CBMARKER+l_cbflat; + + // Save new insertion point in header. + iv_pStorage->offsetMarker = l_pMarker->offsetNext; + + // Initialize the marker at the new insertion point. + marker_t * pNew = OFFSET2MARKER( iv_pStorage->offsetMarker ); + pNew->offsetNext = 0; + pNew->length = 0; + } + + + // Count of error logs called to commit, regardless if there was + // room to commit them or not. + iv_pStorage->cInserted++; + + + // unlock sem + mutex_unlock(&iv_mutex); delete io_err; io_err = NULL; } + while( 0 ); return; } + + /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// +// This operation is protected by the callers use of a mutex. uint32_t ErrlManager::getUniqueErrId() { - return (__sync_add_and_fetch(&iv_currLogId, 1)); + /* return (__sync_add_and_fetch(&iv_currLogId, 1)); */ + iv_currLogId++; + return iv_currLogId; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// +// Global function (not a method on an object) to commit the error log. void errlCommit(errlHndl_t& io_err) { ERRORLOG::theErrlManager::instance().commitErrLog(io_err); diff --git a/src/usr/errl/errlsctn.C b/src/usr/errl/errlsctn.C index 75d06c5bb..707bbf14b 100644 --- a/src/usr/errl/errlsctn.C +++ b/src/usr/errl/errlsctn.C @@ -7,26 +7,122 @@ /*****************************************************************************/ // I n c l u d e s /*****************************************************************************/ +#include <trace/interface.H> #include "errlsctn.H" +#include <assert.h> namespace ERRORLOG { +extern trace_desc_t* g_trac_errl; + + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ErrlSctn::ErrlSctn(const compId_t i_compId, const uint8_t i_sctnVer, const uint8_t i_subSect) -:iv_header(i_compId, i_sctnVer, i_subSect) +:iv_ErrlSctnHdr(i_compId, i_sctnVer, i_subSect),iv_pData(NULL),iv_cbData(0) { - } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ErrlSctn::~ErrlSctn() { + delete iv_pData; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +uint64_t ErrlSctn::addData(const void *i_data, const uint64_t i_size) +{ + uint64_t l_rc = 0; + + // Expected new size of user data. + uint64_t l_newsize = iv_cbData + i_size; + + // Resize memory block + iv_pData = static_cast<uint8_t*>(realloc(iv_pData, l_newsize)); + + // Make sure reallocate call succeeds + if (iv_pData != NULL) + { + // Copy new data to new area, past existing data (if any) + memcpy( iv_pData+iv_cbData, i_data, i_size ); + + // Save new size of the user-provided data. + l_rc = iv_cbData = l_newsize; + } + else + { + TRACFCOMP( g_trac_errl, + "ErrlFFDC::addData() - Reallocate memory failed!"); + } + return l_rc; +} + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +uint64_t ErrlSctn::flattenedSize() +{ + return sizeof(section_header_t) + iv_cbData; +} + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +uint64_t ErrlSctn::flatten( void* io_pBuffer, uint64_t i_bufsize ) +{ + uint64_t l_flatCount = 0; + + do + { + l_flatCount = flattenedSize(); + if( i_bufsize < l_flatCount ) + { + // error path, return 0 + TRACFCOMP( g_trac_errl, "Invalid buffer size" ); + l_flatCount = 0; + break; + } + + // CPPASSERT() makes an assertion to the compiler, and if the + // expression is false, the compile will end in error. If these + // compiler asserts should fail, then the packed structures + // defined in errl/errltypes.H will need to be adjusted. + CPPASSERT( 2 == sizeof(iv_ErrlSctnHdr.iv_compId)); + CPPASSERT( 1 == sizeof(iv_ErrlSctnHdr.iv_sctnVer)); + CPPASSERT( 1 == sizeof(iv_ErrlSctnHdr.iv_subSect)); + CPPASSERT( 0 == sizeof( section_header_t ) % sizeof( uint32_t )); + + // Marshall the data into a section_header_t + section_header_t l_Header; + memset( &l_Header, 0, sizeof( l_Header )); + l_Header.cbHeader = sizeof( l_Header ); + l_Header.cbSection = iv_cbData; + l_Header.compId = iv_ErrlSctnHdr.iv_compId; + l_Header.sctnVer = iv_ErrlSctnHdr.iv_sctnVer; + l_Header.subSect = iv_ErrlSctnHdr.iv_subSect; + + + // Write data to caller's memory. + char * l_pchar = static_cast<char *>(io_pBuffer); + memcpy( l_pchar, &l_Header, sizeof( l_Header )); + l_pchar += sizeof( l_Header ); + + // Write any user-defined data. + if( iv_cbData ) + { + memcpy( l_pchar, iv_pData, iv_cbData ); + } + } + while( 0 ); + + return l_flatCount; } + + } // end namespace diff --git a/src/usr/errl/errlsctn.H b/src/usr/errl/errlsctn.H index 800665d48..682d59033 100644 --- a/src/usr/errl/errlsctn.H +++ b/src/usr/errl/errlsctn.H @@ -82,6 +82,46 @@ public: */ compId_t compId() const; + + /** + * @brief Appends data to the section + * Grows the section by the given amount + * + * @param[in] i_data Pointer to data source + * @param[in] i_size Data size (bytes) + * + * @return Size of new data or else zero on error. + */ + uint64_t addData(const void *i_data, const uint64_t i_size); + + + /** + * @brief Get flattened size. Typically called prior to flatten(). + * Allocate space for the flat data, then call flatten(). These + * functions commonly used by ErrlManager when committing error + * logs. + * + * @return size + * + */ + uint64_t flattenedSize(); + + /** + * @brief Get flattened data. + * + * @param[in,out] io_pBuffer Pointer to memory where flattened + * error log will go. + * @param[in] i_cbBuffer Count of bytes of memory available + * at io_pBuffer. Caller should ensure there is enough memory + * available by calling flattenedSize() first. + * + * @return Count of bytes flattened. + * + */ + uint64_t flatten( void * io_pBuffer, const uint64_t i_cbBuffer ); + + + private: /** @@ -90,8 +130,14 @@ private: ErrlSctn(const ErrlSctn& i_right); ErrlSctn& operator=(const ErrlSctn& i_right); - // Section header - ErrlSctnHdr iv_header; + // A section header object for this section. + ErrlSctnHdr iv_ErrlSctnHdr; + + // Pointer to user-added data + uint8_t* iv_pData; + + // Count of bytes of user-added data + uint64_t iv_cbData; }; @@ -103,25 +149,28 @@ private: //////////////////////////////////////////////////////////////////////////// inline uint8_t ErrlSctn::sctnVer() const { - return iv_header.iv_sctnVer; + return iv_ErrlSctnHdr.iv_sctnVer; } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// inline uint8_t ErrlSctn::subSect() const { - return iv_header.iv_subSect; + return iv_ErrlSctnHdr.iv_subSect; } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// inline compId_t ErrlSctn::compId() const { - return iv_header.iv_compId; + return iv_ErrlSctnHdr.iv_compId; } + + } // End namespace + #endif //ERRLSCTN_H diff --git a/src/usr/errl/errlsctnhdr.C b/src/usr/errl/errlsctnhdr.C index a663b34b9..3d2a15841 100644 --- a/src/usr/errl/errlsctnhdr.C +++ b/src/usr/errl/errlsctnhdr.C @@ -28,6 +28,7 @@ iv_subSect(i_subSect) } + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ErrlSctnHdr::~ErrlSctnHdr() diff --git a/src/usr/errl/errlsctnhdr.H b/src/usr/errl/errlsctnhdr.H index cd741f42f..18dd75110 100644 --- a/src/usr/errl/errlsctnhdr.H +++ b/src/usr/errl/errlsctnhdr.H @@ -15,6 +15,7 @@ #include <stdlib.h> #include <errl/errltypes.H> #include <hbotcompid.H> +#include <string.h> namespace ERRORLOG { @@ -24,7 +25,7 @@ namespace ERRORLOG */ class ErrlSctnHdr { - // ErrlSctn needs to set the header's parameters + // ErrlSctn accesses ErrlSctnHdr directly. friend class ErrlSctn; /** @@ -55,6 +56,8 @@ class ErrlSctnHdr // is currently not yet determined. // Note: stream is currently not supported + + private: /** @@ -64,6 +67,7 @@ private: ErrlSctnHdr& operator=(const ErrlSctnHdr& i_right); // Data + // Can/will be accessed by friend class ErrlSctn compId_t iv_compId; uint8_t iv_sctnVer; uint8_t iv_subSect; diff --git a/src/usr/errl/makefile b/src/usr/errl/makefile index 22cd0ce00..eb826436a 100644 --- a/src/usr/errl/makefile +++ b/src/usr/errl/makefile @@ -3,6 +3,6 @@ MODULE = errl OBJS = errlentry.o errlmanager.o errlsctn.o errlffdc.o errlsctnhdr.o -SUBDIRS = test.d +SUBDIRS = test.d parser.d include ${ROOTPATH}/config.mk diff --git a/src/usr/errl/parser/errlparser.C b/src/usr/errl/parser/errlparser.C new file mode 100644 index 000000000..739e65558 --- /dev/null +++ b/src/usr/errl/parser/errlparser.C @@ -0,0 +1,701 @@ +/** + * @file errlparser.C + * + * @brief Parse and display committed error logs. Enter + * errlparser ? (or -? or -h or --help) to print help. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <string> +using namespace std; + + +#include <errl/errltypes.H> +#include <hbotcompid.H> +using namespace ERRORLOG; + + +#define USAGE "\ +Usage:\n\ +\n\ +errlparser <imagefile> <symsfile> [-l | -d <logid>]\n\ +\n\ +Provide L3 memory image file and its hbicore*.syms file.\n\ + -l summarize all error logs (default)\n\ + -d id print detail from specific error log\n\ +\n\ +Contact: Monte Copeland\n\ +" + +//------------------------------------------------------------------------ +// Stop the program with a message. This message is often USAGE. Since +// this program will be spawned from traceHB.py, I think we're better +// served sending the error message to stdout, not stderr. I don't +// think Simics is piping stderr to its console. +void halt( char * msg ) +{ + fprintf( stdout, "%s", msg ); + + // exit the process with a non-zero process exit level. + exit(2); +} + + + + +//------------------------------------------------------------------------- +// The file src/include/usr/hbotcompid.H provide a mapping from compId_t +// to component name. +// that maps comp id to a string label for it. +struct _errlcompname +{ + char * pszName; + uint32_t value; +}; +typedef _errlcompname ERRLCOMPNAME_t; + +ERRLCOMPNAME_t g_errlcompnames[] = { +// comps.C generated at build time by a script +// that parses data from src/include/usr/hbotcompid.H. +// Refer to src/usr/errl/parser/makefile +#include <comps.C> +}; + +// Given a reason code which has a comp id mangled into +// it, return a char* to the component name. Return +// null if not found, which printf seems to handle +// OK by printing (null). +char * FindComp( uint16_t reasoncode ) +{ + char * pch = NULL; + uint32_t id = (reasoncode & 0xFF00 ); + int c = sizeof( g_errlcompnames ) / sizeof( g_errlcompnames[0] ); + for( int i = 0; i < c; i++ ) + { + if( id == g_errlcompnames[i].value ) + { + pch = g_errlcompnames[i].pszName; + break; + } + } + return pch; +} + + + +//------------------------------------------------------------ +// Print a hex dump of the input buffer to the output file +// given, probably stdout. + +int FormatBytes( FILE * f, char * pchInput, int count, int indent ) +{ + char szChars[ 80 ]; + char szHex[ 80 ]; + char szOffset[ 64 ]; + char szWork[ 256 ]; + int i; + unsigned int ul; + char * pch; + char * pchLine; + int cb; + char * pszIndent = NULL; + + + + pszIndent = static_cast<char*>(malloc( indent+1 )); + memset( pszIndent, 0, indent+1 ); + memset( pszIndent, ' ', indent ); + + + + pchLine = pchInput; + + + while( pchLine < pchInput + count ) + { + /* current offset */ + ul = pchLine - pchInput; + + sprintf( szOffset, "%08X", ul ); + + memset( szHex, ' ', sizeof( szHex )); + pch = szHex; + + cb = ((pchInput+count)-pchLine) > 16 ? 16 : ((pchInput+count)-pchLine); + + for( i = 0; i < cb; i++ ) + { + ul = (unsigned char) pchLine[ i ]; + + sprintf( szWork, "%02x", ul ); + memcpy( pch, szWork, 2 ); + + pch += 3; + } + + szHex[ 23 ] = '-'; + szHex[ 48 ] = 0; + + memset( szChars, 0, sizeof( szChars )); + for( i = 0; i < cb; i++ ) + { + szChars[i] = '.'; + + int t = pchLine[i]; + + if( t > 31 ) + { + szChars[i] = pchLine[ i ]; + } + } + + sprintf( szWork, "%s %s %s", szOffset, szHex, szChars ); + fprintf( f, "%s%s\n", pszIndent, szWork ); + fflush( f ); + pchLine += 16; + } + + return 0; +} + + + +//------------------------------------------------------------- +// endian stuff +section_header_t* ConvertSectionHeader( section_header_t* p) +{ + p->cbHeader = ntohl( p->cbHeader ); + p->cbSection = ntohl( p->cbSection ); + p->compId = ntohs( p->compId ); + // sctnVer is byte long + // subSect is byte long + return p; +} + + +//------------------------------------------------------------- +// endian stuff +marker_t* ConvertMarker( marker_t* p) +{ + p->offsetNext = ntohl( p->offsetNext ); + p->length = ntohl( p->length ); + return p; +} + + + +//------------------------------------------------------------- +// endian switch a uint64 +uint64_t ntohll( uint64_t i ) +{ + uint64_t hi; + uint64_t lo; + uint32_t * pword = reinterpret_cast<uint32_t*>(&i); + + hi = ntohl( *pword ); + lo = ntohl( *(pword+1) ); + + return (hi<<32)|lo; +} + + +//------------------------------------------------------------- +// endian stuff +errl_header_t* ConvertErrlHeader( errl_header_t* p ) +{ + p->cbytes = ntohl( p->cbytes ); + p->csections = ntohl( p->csections ); + p->reasonCode = ntohs( p->reasonCode ); + // p->modId is a byte + // p->sev is a byte + // p->eventType is a byte + // p->subSys is a byte + // p->srcType is a byte + p->termState = ntohl( p->termState ); + p->logId = ntohl( p->logId ); + p->user1 = ntohll( p->user1 ); + p->user2 = ntohll( p->user2 ); + p->CreationTime = ntohll( p->CreationTime ); + return p; +} + + + +//------------------------------------------------------------- +// endian stuff +storage_header_t * ConvertStorageHeader( storage_header_t * p ) +{ + p->cbStorage = ntohl( p->cbStorage ); + p->cInserted = ntohl( p->cInserted ); + p->offsetMarker = ntohl( p->offsetMarker ); + p->offsetStart = ntohl( p->offsetStart ); + return p; +} + + + +//----------------------------------------------------------------------- +// Given the binary image file name, return the errl storage part of the file. +// Caller must endian convert anything/everything in the output buffer. +// This function will allocate (malloc) the buffer and return a pointer to it. +// On fatal error, this function will print a diagnostic and end the process. +// Return how many bytes allocated for the buffer in io_cbBuffer. +char* ReadStorageBuffer(char* i_Image, uint32_t i_ulAddr, uint32_t &io_cbBuffer) +{ + int fd; + int rc; + int cb; + off_t offsetEnd; + char * l_pchBuffer = NULL; // pointer to return + storage_header_t header; + + // open the binary image of L3 RAM and read the errl log buffer + fd = open( i_Image, O_RDONLY ); + if ( fd == -1 ) + { + // write the error to stdout because more likely to be seen in Simics + fprintf(stdout, "Unable to open %s for reading.\n", i_Image); + fprintf(stdout, "Failed with errno %s\n", strerror(errno) ); + exit(2); + } + + offsetEnd = lseek( fd, 0, SEEK_END ); + if( i_ulAddr >= offsetEnd ) + { + fprintf( stdout, "Image file %s appears to be truncated. " + "Offset 0x%X exceeds size of image file.\n", + i_Image, i_ulAddr ); + exit(2); + } + + rc = lseek( fd, i_ulAddr, SEEK_SET ); + assert( -1 != rc ); + + + // Read just the header for the size of the buffer is + // stored in the header. + cb = read( fd, &header, sizeof( header )); + assert( -1 != cb ); + + // endian convert this copy of the header + ConvertStorageHeader( &header ); + + // io_cbBuffer is a count of bytes in storage + io_cbBuffer = header.cbStorage; + + if( ( i_ulAddr + io_cbBuffer ) > offsetEnd ) + { + fprintf( stdout, "Image file %s appears to be truncated. " + "Offset 0x%X exceeds size of image file.\n", + i_Image, i_ulAddr+io_cbBuffer ); + exit(2); + } + + // re-seek and re-read entire buffer this time. + rc = lseek( fd, i_ulAddr, SEEK_SET ); + assert( -1 != rc ); + + l_pchBuffer = static_cast<char *>(malloc( io_cbBuffer )); + assert( l_pchBuffer ); + + cb = read( fd, l_pchBuffer, io_cbBuffer ); + assert( -1 != cb ); + + close( fd ); +#if 0 + { + // Write the error log storage buffer to its own file. + // Offsets stored in the buffer are relative to the + // start of the buffer. When this file is saved in + // its own file, the same offsets are relative to the + // start of the file. This is convenient when debugging. + fd = open( "storagebuffer.bin", O_CREAT | O_RDWR, 0666 ); + if( -1 != fd ) + { + write( fd, l_pchBuffer, io_cbBuffer ); + close( fd ); + } + } +#endif + return l_pchBuffer; +} + + + + + + +//---------------------------------------------------------------------------- +// Open the given symbols file name, a text file, and find the storage address +// of error logs given by the symbol in pszSearch. +uint32_t FindSymbol( char * pszSymbolFile, char * pszSearch ) +{ + char * pszAddr = NULL; + char * pch; + char szWork[ 1024 ]; + uint32_t ulAddr = 0; + FILE * f; + + f = fopen( pszSymbolFile, "r" ); + if ( !f ) + { + fprintf(stdout, "Unable to open file %s for reading.\n", pszSymbolFile); + fprintf(stdout, "Failed with errno %s\n", strerror(errno) ); + exit(2); + } + + while( fgets( szWork, sizeof( szWork ), f )) + { + pch = strstr( szWork, pszSearch ); + if( pch ) + { + pszAddr = szWork + 2; + pch = strchr( pszAddr, ',' ); + assert( pch ); + *pch = 0; + break; + } + } + fclose(f); + + if( NULL == pszAddr ) + { + fprintf( stdout, "Cannot find %s in syms file.\n", pszSearch ); + exit(2); + } + + int c = sscanf( pszAddr, "%x", &ulAddr ); + if( 1 != c ) + { + fprintf( stdout, + "Error, expecting '%s' to convert to hexidecimal.\n", + pszAddr ); + exit(2); + } + return ulAddr; +} + + + +// -------------------------------------------------------------------------- +// Print a summary of the error log, no user-defined data nor detail. +// perrlog is already endian converted + +void PrintErrlSummary( errl_header_t * perrlog ) +{ + + // print headline + // comp id sev rc mod evt u1 u2 csec + printf( "%-7s %10s %4s %-6s %-4s %-4s %-18s %-18s %5s\n", + "comp", + "logid", + "sev", + "reason", + "mod", + "evnt", + "user1", + "user2", + "csect" ); + + + // comp id sev reason mod event user1 user2 csec + // code + printf( "%-7s %10d 0x%02x 0x%04x 0x%02x 0x%02x 0x%016llx 0x%016llx %5d\n", + FindComp( perrlog->reasonCode ), + perrlog->logId, + perrlog->sev, + perrlog->reasonCode, + perrlog->modId, + perrlog->eventType, + perrlog->user1, + perrlog->user2, + perrlog->csections // count of sections + ); +} + + +//--------------------------------------------------------------------------- +// +// +void PrintErrlDetail( errl_header_t * perrlog ) +{ + + // print the summary line + PrintErrlSummary( perrlog ); + + // print sections if any + if( perrlog->csections ) + { + int i; + section_header_t* psect; + + // first section header resides just past the errl_header_t + psect = reinterpret_cast<section_header_t*>(perrlog+1); + + // Endian convert it + ConvertSectionHeader( psect ); + + i = 0; + do + { + printf( + "\nSection %d: %-8s len=0x%04x, ver=0x%04x, subsection=0x%04x\n", + i, + FindComp( psect->compId ), + psect->cbSection, + psect->sctnVer, + psect->subSect + ); + + // The user-provided data resides just past the section header. + char * pUserData = reinterpret_cast<char*>(psect+1); + + // Print a hex dump (for now) of the user-provided data. + FormatBytes( stdout, pUserData, (int)psect->cbSection, 4 ); + + i++; + if( i >= perrlog->csections ) + { + // Leave the loop, and do not ConvertSectionHeader(). + break; + } + + // There's more; point to the next section. + int cb = psect->cbHeader + psect->cbSection; + char * p = (reinterpret_cast<char*>(psect)) + cb; + psect = reinterpret_cast<section_header_t*>(p); + + // Endian convert it. + ConvertSectionHeader( psect ); + } + while( 1 ); + } +} + + + + + + +//------------------------------------------------------------- +int main( int argc, char *argv[] ) +{ + char * pch; + char * pszImageFile = NULL; + char * pszSymbolFile = NULL; + char szWork[ 1024 ]; + unsigned char * puch; + char * pszSearch; + char * pszAddr = NULL; + char * pchBuffer; + uint32_t ulAddr; + char szDivider[ 256 ]; + uint32_t ulLogId = 0; + int c; + int cb; + int cbSearch; + int fd; + int i; + int k; + int item; + int fOK; + int rc; + int exitcode = 0; + uint32_t cbBuffer = 0; + off_t offset; + off_t offsetEnd; + int fVerbose = 0; + int fList = 1; + int fDetail = 0; + int fFound = 0; + + + // build a =========== divider for printfing + cb = 84; + assert( cb < sizeof( szDivider )); + memset( szDivider, '=', sizeof( szDivider )); + szDivider[ cb ] = 0; + + + // Examine args. + i = 1; + while ( i < argc ) + { + if( 0 == strcmp( "-v", argv[i] )) + { + fVerbose = 1; + } + else if( 0 == strcmp( "-d", argv[i] )) + { + i++; + if( i >= argc ) + { + fprintf( stdout, "Provide -d <logid>\n" ); + exit( 2 ); + } + int c = sscanf( argv[i], "%d", &ulLogId ); + if( c != 1 ) + { + fprintf( stdout, "Provide -d <decimal log ID>\n" ); + exit( 2 ); + } + fList = 0; + fDetail = 1; + } + else if( 0 == strcmp( "-l", argv[i] )) + { + fList = 1; + fDetail = 0; + } + else if( 0 == strcmp("?", argv[i]) || + 0 == strcmp("-?", argv[i]) || + 0 == strcmp("-h", argv[i]) || + 0 == strcmp("--help", argv[i])) + { + // help + halt( USAGE ); + } + else if( 0 == strcmp( "-", argv[i] )) + { + // unrecognized switch + halt( USAGE ); + } + else + { + // must be a file name + pch = strstr( argv[i], "syms" ); + if( pch ) + { + pszSymbolFile = strdup( argv[i] ); + } + else + { + pszImageFile = strdup( argv[i] ); + } + } + + i++; + } + + + // Check args. + if((!pszImageFile) || (!pszSymbolFile)) + { + halt( USAGE ); + } + + + + // Given the symbols file, locate the address/offset of the errl storage + // buffer. + ulAddr = FindSymbol( pszSymbolFile, "g_ErrlStorage" ); + if( fVerbose ) + { + printf( "Error log storage buffer offset: 0x%08x\n", ulAddr ); + } + + + // Given the image file, read the portion that contains the + // error logs. + pchBuffer = ReadStorageBuffer( pszImageFile, ulAddr, cbBuffer ); + assert( pchBuffer ); + assert( cbBuffer ); + if( fVerbose ) + { + printf("Errlog storage buffer size: %d (decimal) bytes\n", cbBuffer ); + } + + + // Convert the endianess of the storage header. + storage_header_t* pHeader = reinterpret_cast<storage_header_t*>(pchBuffer); + ConvertStorageHeader( pHeader ); + if( fVerbose ) + { + printf( "%d error logs were committed.\n", pHeader->cInserted ); + printf( "Start offset: 0x%08x\n", pHeader->offsetStart ); + printf( "Ending offset: 0x%08x\n", pHeader->offsetMarker ); + } + + +/** @brief Convert an offset to a marker_t pointer. */ +#define OFFSET2MARKER(offset) (reinterpret_cast<marker_t*>(pchBuffer+offset)) + + +/** @brief Convert a marker_t pointer to an offset within the buffer. */ +#define MARKER2OFFSET(p) ((reinterpret_cast<char*>(p))-pchBuffer) + + + + // Count how many error logs found + int logcount = 0; + + // Traverse the list of error logs in the buffer. At this time, the + // buffer does not wrap. It is a straight shot from start to finish. + // Follow the markers. The start-of-list marker: + marker_t* pMarker = ConvertMarker( OFFSET2MARKER(pHeader->offsetStart)); + + while( 1 ) + { + if( fVerbose ) + { + cb = printf( "Marker at 0x%06x: next 0x%06x, length 0x%06x\n", + MARKER2OFFSET(pMarker), + pMarker->offsetNext, + pMarker->length ); + } + + if( pMarker->offsetNext == 0 ) + { + // This is the list-ending marker. + printf( "%s\n", szDivider ); + break; + } + + assert( pMarker->length ); + + logcount++; + + // Flattened struct of an error log resides just past marker. + errl_header_t* perr = reinterpret_cast<errl_header_t*>(pMarker+1); + ConvertErrlHeader( perr ); + + if( fList ) + { + // Just list the error log headers. + printf( "%s\n", szDivider ); + PrintErrlSummary( perr ); + } + else if(( fDetail ) && ( perr->logId == ulLogId )) + { + // Print the detail for the one error log. + printf( "%s\n", szDivider ); + PrintErrlDetail( perr ); + fFound = 1; + } + + // next marker/error log + pMarker = ConvertMarker( OFFSET2MARKER(pMarker->offsetNext) ); + } + + + if( fVerbose ) + { + printf( "%d error logs found.\n", logcount ); + } + + if( fDetail && !fFound ) + { + printf( "Error log %d not found.\n", ulLogId ); + exitcode = 2; + } + return exitcode; +} + diff --git a/src/usr/errl/parser/makefile b/src/usr/errl/parser/makefile new file mode 100644 index 000000000..f0d8e180b --- /dev/null +++ b/src/usr/errl/parser/makefile @@ -0,0 +1,35 @@ +# makefile for errlparser, +# a 32-bit x86 linux binary suitable for running on GFW pool machines. + + +ROOTPATH=../../../.. + +CC=g++ -m32 +CFLAGS:=-g -O0 -I $(ROOTPATH)/src/include/usr +BIN:=bin + + +all: code_pass + +gen_pass: + +code_pass: bindir $(BIN)/errlparser + +clean: + rm -fr $(BIN) + +beam: + +bindir: + mkdir -p $(BIN) + +$(BIN)/comps.C: $(ROOTPATH)/src/include/usr/hbotcompid.H readcomps.rex + rexx readcomps.rex $(ROOTPATH)/src/include/usr/hbotcompid.H >$(BIN)/comps.C + +$(BIN)/errlparser.o: errlparser.C $(ROOTPATH)/src/include/usr/errl/errltypes.H $(BIN)/comps.C + $(CC) -c $(CFLAGS) -I bin -o $(BIN)/errlparser.o errlparser.C + +$(BIN)/errlparser: $(BIN)/errlparser.o + $(CC) -o $(BIN)/errlparser $(BIN)/errlparser.o + + diff --git a/src/usr/errl/parser/readcomps.rex b/src/usr/errl/parser/readcomps.rex new file mode 100644 index 000000000..9aad554d8 --- /dev/null +++ b/src/usr/errl/parser/readcomps.rex @@ -0,0 +1,58 @@ +/* + * @file readcomps.rex + * + * Input file name is expected to be hbotcompid.H + * Output to stdout a snippet of C code that can + * be included by errlparser.C + */ + +parse arg szInput . + +if length( szInput ) = 0 then do + say 'Give filename on command line.' + signal halt +end + +szRC = stream( szInput, 'C', 'OPEN READ' ) +if left( szRC, 5 ) <> 'READY' then do + say 'File' szInput 'not found.' + signal halt +end + +do while lines( szInput ) + szCompName = '' + szCompID = '' + + szLine = linein( szInput ) + p1 = pos( "compId_t", szLine ); + p2 = pos( "_COMP_ID", szLine ); + p3 = pos( "MY_COMP_", szLine ); + if p1 > 0 & p2 > p1 & p3=0 then do + + /* interesting COMP_ID line */ + do i = 1 to words( szLine ) + w = translate( word( szLine, i )) + if pos( "_COMP_ID", w ) > 0 then szCompName = w + if pos( "0X", w ) > 0 then szCompID = w + end + + /* clean them up */ + szCompName = left( szCompName, pos( "_", szCompName )-1 ) + szCompID = strip( szCompID, 'B', ';' ) + + /* This output will be included by errlparser.C */ + say " {" '"'szCompName'",' szCompID "}," + + end +end + + +szRC = stream( szInput, 'C', 'CLOSE' ) +if left( szRC, 5 ) <> 'READY' then signal halt + +return 0 + + +halt: +say 'Error: readcomps.rex problem' +exit 2 diff --git a/src/usr/errl/test/errltest.H b/src/usr/errl/test/errltest.H index 7d10c3a34..40e58a266 100644 --- a/src/usr/errl/test/errltest.H +++ b/src/usr/errl/test/errltest.H @@ -10,9 +10,9 @@ #include <cxxtest/TestSuite.H> #include <errl/errlmanager.H> #include <errl/errlentry.H> -#include <errl/errltypes.H> +#include <hbotcompid.H> -#define TEST_REASON_CODE 0x0F0F +#define TEST_REASON_CODE (ERRL_COMP_ID | 0x0F) #define TEST_SEVERITY ERRORLOG::ERRL_SEV_INFORMATIONAL #define TEST_MOD_ID 0x0022 @@ -29,7 +29,6 @@ #define TEST_USR_64BIT_2 0x9000000000000003 -#define TEST_RETURN_CODE 0xF0F0 class ErrlTest: public CxxTest::TestSuite { @@ -45,37 +44,93 @@ public: */ void testErrl1(void) { + ERRORLOG::ErrlFFDC * pffdc; // An example that shows how to use macros to stuff data into // the two 64-bit user data parameters in the error log. // l_userData1 = 16bit(0):l_bit8_1:l_bit8_2:l_32bit_1 - uint8_t l_8bit_1 = TEST_USR_8BIT_1; - uint8_t l_8bit_2 = TEST_USR_8BIT_2; - uint32_t l_32bit_1 = TEST_USR_32BIT_1; - uint64_t l_userData1 = - TWO_UINT32_TO_UINT64( - TO_UINT32(TWO_UINT8_TO_UINT16(l_8bit_1, l_8bit_2)), l_32bit_1); + uint8_t l_8bit_1 = TEST_USR_8BIT_1; // 0x80 + uint8_t l_8bit_2 = TEST_USR_8BIT_2; // 0x93 + uint32_t l_32bit_1 = TEST_USR_32BIT_1; // 0x80000001 + uint64_t l_userData1 = + TWO_UINT32_TO_UINT64( TO_UINT32(TWO_UINT8_TO_UINT16(l_8bit_1, l_8bit_2)), l_32bit_1); + // yields 0x0000809380000001 + + // l_userData2 = l_16bit_1:l_16bit_2:l_32bit_2 - uint16_t l_16bit_1 = TEST_USR_16BIT_1; - uint16_t l_16bit_2 = TEST_USR_16BIT_2; - uint32_t l_32bit_2 = TEST_USR_32BIT_2; - uint64_t l_userData2 = - TWO_UINT16_ONE_UINT32_TO_UINT64(l_16bit_1, l_16bit_2, l_32bit_2); + uint16_t l_16bit_1 = TEST_USR_16BIT_1; // 0x8000 + uint16_t l_16bit_2 = TEST_USR_16BIT_2; // 0x9003 + uint32_t l_32bit_2 = TEST_USR_32BIT_2; // 0x90000003 + uint64_t l_userData2 = TWO_UINT16_ONE_UINT32_TO_UINT64(l_16bit_1, l_16bit_2, l_32bit_2); + // yields 0x8000900390000003 // Create an error log errlHndl_t l_err = new ERRORLOG::ErrlEntry( - TEST_SEVERITY, + ERRORLOG::ERRL_SEV_INFORMATIONAL, TEST_MOD_ID, TEST_REASON_CODE, l_userData1, l_userData2); + // Make sure log is created if (l_err == NULL) { TS_FAIL("testErrl1: createErrlLog() outputs NULL pointer!"); } + + // These addFFDC() calls return a pointer to class ERRORLOG::ErrlFFDC + // but errlffdc.H is not publicly includable to give me the definition + // for it. addFFDC() should return a Boolean indication of success. + + const char * pch = "martha washington"; + pffdc = l_err->addFFDC( ERRL_COMP_ID, pch, strlen( pch ), 1, 2 ); + if ( NULL == pffdc ) + { + TS_FAIL("testErrl1: addFFDC() output NULL pointer"); + } + + pch = "george washington"; + pffdc = l_err->addFFDC( DEVFW_COMP_ID, pch, strlen( pch ), 3, 4 ); + if ( NULL == pffdc ) + { + TS_FAIL("testErrl1: addFFDC() output NULL pointer"); + } + + pch = "dwight eisenhour"; + pffdc = l_err->addFFDC( SCOM_COMP_ID, pch, strlen( pch ), 5, 6 ); + if ( NULL == pffdc ) + { + TS_FAIL("testErrl1: addFFDC() output NULL pointer"); + } + + pch = "ronald "; + pffdc = l_err->addFFDC( ERRL_COMP_ID, pch, strlen( pch ), 7, 8 ); + if ( NULL == pffdc ) + { + TS_FAIL("testErrl1: addFFDC() output NULL pointer"); + } + + // Append data to something already added. + pch = "reagan"; + l_err->appendToFFDC( pffdc, pch, strlen(pch) ); + + + // Add null data. + pffdc = l_err->addFFDC( ERRL_COMP_ID, NULL, 0, 9, 10 ); + if ( NULL != pffdc ) + { + TS_FAIL("testErrl1: addFFDC() returned non null"); + } + + + + + + + + // Verify log data else if (l_err->sev() != ERRORLOG::ERRL_SEV_INFORMATIONAL) { @@ -133,7 +188,7 @@ public: // Create an error log errlHndl_t l_err = new ERRORLOG::ErrlEntry( - TEST_SEVERITY, + ERRORLOG::ERRL_SEV_UNRECOVERABLE, TEST_MOD_ID, TEST_REASON_CODE, l_userData1, |