diff options
Diffstat (limited to 'src/usr/util')
-rw-r--r-- | src/usr/util/runtime/rt_cmds.C | 164 | ||||
-rw-r--r-- | src/usr/util/runtime/rt_fwnotify.C | 767 | ||||
-rw-r--r-- | src/usr/util/runtime/rt_fwreq_helper.C | 283 | ||||
-rw-r--r-- | src/usr/util/runtime/test/testlidmgr_rt.H | 3 | ||||
-rw-r--r-- | src/usr/util/runtime/test/testruncommand.H | 3 | ||||
-rw-r--r-- | src/usr/util/runtime/utillidmgr_rt.C | 23 | ||||
-rw-r--r-- | src/usr/util/test/threadpool.H | 134 | ||||
-rw-r--r-- | src/usr/util/threadpool.C | 54 | ||||
-rw-r--r-- | src/usr/util/utillidmgr.C | 3 | ||||
-rw-r--r-- | src/usr/util/utillidpnor.C | 13 |
10 files changed, 1266 insertions, 181 deletions
diff --git a/src/usr/util/runtime/rt_cmds.C b/src/usr/util/runtime/rt_cmds.C index c015215b5..aa23ae7c0 100644 --- a/src/usr/util/runtime/rt_cmds.C +++ b/src/usr/util/runtime/rt_cmds.C @@ -48,6 +48,7 @@ // switchToFspScomAccess #ifdef CONFIG_NVDIMM #include <isteps/nvdimm/nvdimm.H> // notify NVDIMM protection change +#include <util/runtime/rt_fwnotify.H> #endif extern char hbi_ImageId; @@ -1162,42 +1163,101 @@ void cmd_nvdimm_protection_msg( char* &o_output, uint32_t i_huid, { errlHndl_t l_err = nullptr; o_output = new char[500]; - uint8_t l_notifyType = NVDIMM::NOT_PROTECTED; TARGETING::Target* l_targ{}; l_targ = getTargetFromHUID(i_huid); - if (l_targ != NULL) - { - if (protection == 1) - { - l_notifyType = NVDIMM::PROTECTED; - l_err = notifyNvdimmProtectionChange(l_targ, NVDIMM::PROTECTED); - } - else if (protection == 2) - { - l_notifyType = NVDIMM::UNPROTECTED_BECAUSE_ERROR; - l_err = notifyNvdimmProtectionChange(l_targ, NVDIMM::UNPROTECTED_BECAUSE_ERROR); - } - else - { - l_err = notifyNvdimmProtectionChange(l_targ, NVDIMM::NOT_PROTECTED); - } - if (l_err) - { - sprintf( o_output, "Error on call to notifyNvdimmProtectionChange" - "(0x%.8X, %d), rc=0x%.8X, plid=0x%.8X", - i_huid, l_notifyType, ERRL_GETRC_SAFE(l_err), l_err->plid() ); - errlCommit(l_err, UTIL_COMP_ID); - return; - } + + // protection should match enum from nvdimm_protection_t + // No match will just return, no error generated + l_err = notifyNvdimmProtectionChange( l_targ, + (NVDIMM::nvdimm_protection_t)protection); + if (l_err) + { + sprintf( o_output, "Error on call to notifyNvdimmProtectionChange" + "(0x%.8X, %d), rc=0x%.8X, plid=0x%.8X", + i_huid, protection, ERRL_GETRC_SAFE(l_err), l_err->plid() ); + errlCommit(l_err, UTIL_COMP_ID); + } +} + +/** + * @brief Check the ES (energy source) health status of all NVDIMMs in the + * system. If check fails, see HBRT traces for further details. + * @param[out] o_output Output display buffer, memory allocated here. + * Will inform caller if ES health check passes or fails. + */ +void cmd_nvDimmEsCheckHealthStatus( char* &o_output) +{ + o_output = new char[500]; + if (NVDIMM::nvDimmEsCheckHealthStatusOnSystem()) + { + sprintf( o_output, "cmd_nvDimmEsCheckHealthStatus: " + "ES (energy source) health status check passed."); + } else { - sprintf( o_output, "cmd_nvdimm_protection_msg: HUID 0x%.8X not found", - i_huid ); - return; + sprintf( o_output, "cmd_nvDimmEsCheckHealthStatus: " + "ES (energy source) health status check failed. " + "Inspect HBRT traces for further details."); + + } + + return; +} // end cmd_nvDimmEsCheckHealthStatus + +/** + * @brief Check the NVM (non-volatile memory) health status of all NVDIMMs in + * the system. If check fails, see HBRT traces for further details. + * @param[out] o_output Output display buffer, memory allocated here. + * Will inform caller if NVM health check passes or fails. + */ + +void cmd_nvdDmmNvmCheckHealthStatus( char* &o_output) +{ + o_output = new char[500]; + if (NVDIMM::nvDimmNvmCheckHealthStatusOnSystem()) + { + sprintf( o_output, "cmd_nvdDmmNvmCheckHealthStatus: " + "NVM (non-volatile memory) health status check passed."); + + } + else + { + sprintf( o_output, "cmd_nvdDmmNvmCheckHealthStatus: " + "NVM (non-volatile memory) health status check failed. " + "Inspect HBRT traces for further details."); + + } + + return; +} // end cmd_nvdDmmNvmCheckHealthStatus + + +/** + * @brief Execute nvdimm operation, see interface.h for operation format + * @param[out] o_output Output display buffer, memory allocated here. + * Will inform caller if nvdimm op passes or fails. + * @param[in] i_op nvdimm operation to perform, see interface.h + */ +void cmd_nvdimm_op( char* &o_output, uint16_t i_op ) +{ + o_output = new char[500]; + + hostInterfaces::nvdimm_operation_t l_operation; + l_operation.procId = HBRT_NVDIMM_OPERATION_APPLY_TO_ALL_NVDIMMS; + l_operation.rsvd1 = 0x0; + l_operation.rsvd2 = 0x0; + l_operation.opType = (hostInterfaces::NVDIMM_Op_t)i_op; + + int rc = doNvDimmOperation(l_operation); + if (rc == -1) + { + sprintf( o_output, "Error on call doNvDimmOperation() op 0x%X",i_op); } } + + #endif /** @@ -1534,6 +1594,44 @@ int hbrtCommand( int argc, sprintf(*l_output, "ERROR: nvdimm_protection <huid> <0 or 1>"); } } + else if( !strcmp( argv[0], "nvdimm_es_check_status" ) ) + { + if (argc == 1) + { + cmd_nvDimmEsCheckHealthStatus( *l_output ); + } + else + { + *l_output = new char[100]; + sprintf(*l_output, "Usage: nvdimm_es_check_status"); + } + } + else if( !strcmp( argv[0], "nvdimm_nvm_check_status" ) ) + { + if (argc == 1) + { + cmd_nvdDmmNvmCheckHealthStatus( *l_output ); + } + else + { + *l_output = new char[100]; + sprintf(*l_output, "Usage: nvdimm_nvm_check_status"); + } + } + else if( !strcmp( argv[0], "nvdimm_op" ) ) + { + if (argc == 2) + { + uint16_t op = strtou64(argv[1], NULL, 16); + cmd_nvdimm_op( *l_output, op ); + } + else + { + *l_output = new char[100]; + sprintf(*l_output, "ERROR: nvdimm_op <op>"); + } + } + #endif else { @@ -1574,6 +1672,16 @@ int hbrtCommand( int argc, #ifdef CONFIG_NVDIMM sprintf( l_tmpstr, "nvdimm_protection <huid> <0 or 1>\n"); strcat( *l_output, l_tmpstr ); + sprintf( l_tmpstr, "nvdimm_es_check_status\n"); + strcat( *l_output, l_tmpstr ); + sprintf( l_tmpstr, "nvdimm_nvm_check_status\n"); + strcat( *l_output, l_tmpstr ); + sprintf( l_tmpstr, "nvdimm_op <op>\n" + " 0x1=disarm 0x2=disable_encryption 0x4=remove_keys\n" + " 0x8=enable_encryption 0x10=arm 0x20=es_healthcheck\n" + " 0x40=nvm_healthcheck\n"); + strcat( *l_output, l_tmpstr ); + #endif } diff --git a/src/usr/util/runtime/rt_fwnotify.C b/src/usr/util/runtime/rt_fwnotify.C index dae81e7d6..556a1c31f 100644 --- a/src/usr/util/runtime/rt_fwnotify.C +++ b/src/usr/util/runtime/rt_fwnotify.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2017,2019 */ +/* Contributors Listed Below - COPYRIGHT 2017,2020 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -31,10 +31,14 @@ #include <errl/errlmanager.H> // errlCommit #include <errl/hberrltypes.H> // TWO_UINT32_TO_UINT64 #include <targeting/common/target.H> // TargetHandle_t, getTargetFromHuid +#include <targeting/runtime/rt_targeting.H> // RT_TARG::getHbTarget #include <attributeenums.H> // ATTRIBUTE_ID #ifdef CONFIG_NVDIMM -#include <isteps/nvdimm/nvdimm.H> // notify NVDIMM protection change +#include <isteps/nvdimm/nvdimm.H> // NVDIMM related activities +#include <targeting/common/targetUtil.H> // makeAttribute +#include <runtime/hbrt_utilities.H> +using namespace NVDIMM; #endif using namespace TARGETING; @@ -43,6 +47,7 @@ using namespace ERRORLOG; using namespace MBOX; using namespace SBEIO; + // Trace definition extern trace_desc_t* g_trac_runtime; extern trace_desc_t* g_trac_hbrt; @@ -51,7 +56,7 @@ extern trace_desc_t* g_trac_hbrt; * @brief The lower and upper bounds for the sequence ID. **/ const uint16_t SEQ_ID_MIN = 0x0000; -const uint16_t SEQ_ID_MAX = 0x7FFF; +const uint16_t SEQ_ID_MAX = 0x7FFF; /** * @brief Set the sequence ID to the minimum value @@ -85,7 +90,7 @@ uint16_t SeqId_t::getNextSeqId() **/ uint16_t SeqId_t::getCurrentSeqId() { - return SeqId_t::SEQ_ID; + return SeqId_t::SEQ_ID; } /** @@ -96,12 +101,12 @@ uint16_t SeqId_t::getCurrentSeqId() **/ void sbeAttemptRecovery(uint64_t i_data) { - // Create a useful struct to get to the data - // The data is expected to be a HUID (in the first 4 bytes) - // followed by a PLID (in the last 4 bytes). - SbeRetryReqData_t *l_sbeRetryData = reinterpret_cast<SbeRetryReqData_t*>(&i_data); + // Create a useful struct to get to the data + // The data is expected to be a HUID (in the first 4 bytes) + // followed by a PLID (in the last 4 bytes). + SbeRetryReqData_t *l_sbeRetryData = reinterpret_cast<SbeRetryReqData_t*>(&i_data); - TRACFCOMP(g_trac_runtime, ENTER_MRK"sbeAttemptRecovery: plid:0x%X, " + TRACFCOMP(g_trac_runtime, ENTER_MRK"sbeAttemptRecovery: plid:0x%X, " "HUID:0x%X", l_sbeRetryData->plid, l_sbeRetryData->huid); errlHndl_t l_err = nullptr; @@ -115,7 +120,7 @@ void sbeAttemptRecovery(uint64_t i_data) // If HUID invalid, log error and quit if (nullptr == l_target) { - TRACFCOMP(g_trac_runtime, ERR_MRK"sbeAttemptRecovery: " + TRACFCOMP(g_trac_runtime, ERR_MRK"sbeAttemptRecovery: " "No target associated with HUID:0x%.8X", l_sbeRetryData->huid); @@ -149,7 +154,7 @@ void sbeAttemptRecovery(uint64_t i_data) if (nullptr == g_hostInterfaces || nullptr == g_hostInterfaces->firmware_request) { - TRACFCOMP(g_trac_runtime, ERR_MRK"sbeAttemptRecovery: " + TRACFCOMP(g_trac_runtime, ERR_MRK"sbeAttemptRecovery: " "Hypervisor firmware_request interface not linked"); /*@ @@ -260,12 +265,12 @@ void occActiveNotification( void * i_data ) if (*l_active) { l_err = NVDIMM::notifyNvdimmProtectionChange(l_proc, - NVDIMM::PROTECTED); + NVDIMM::OCC_ACTIVE); } else { l_err = NVDIMM::notifyNvdimmProtectionChange(l_proc, - NVDIMM::NOT_PROTECTED); + NVDIMM::OCC_INACTIVE); } // commit error if it exists @@ -294,12 +299,12 @@ void attrSyncRequest( void * i_data) HbrtAttrSyncData_t * l_hbrtAttrData = reinterpret_cast<HbrtAttrSyncData_t*>(i_data); TRACFCOMP(g_trac_runtime, ENTER_MRK"attrSyncRequest: Target HUID 0x%0X " - "for AttrID: 0x%0X with AttrSize: %lld", l_hbrtAttrData->huid, - l_hbrtAttrData->attrID, l_hbrtAttrData->sizeOfAttrData); + "for AttrID: 0x%0X with AttrSize: %lld", l_hbrtAttrData->huid, + l_hbrtAttrData->attrID, l_hbrtAttrData->sizeOfAttrData); TRACFBIN(g_trac_runtime, "Attribute data: ", - &(l_hbrtAttrData->attrDataStart), - l_hbrtAttrData->sizeOfAttrData); + &(l_hbrtAttrData->attrDataStart), + l_hbrtAttrData->sizeOfAttrData); // extract the target from the given HUID TargetHandle_t l_target = Target::getTargetFromHuid(l_hbrtAttrData->huid); @@ -325,36 +330,496 @@ void attrSyncRequest( void * i_data) memcpy(&l_attrData, &(l_hbrtAttrData->attrDataStart), l_attrSize); /*@ - * @errortype - * @severity ERRL_SEV_PREDICTIVE - * @moduleid MOD_RT_ATTR_SYNC_REQUEST - * @reasoncode RC_ATTR_UPDATE_FAILED - * @userdata1[0:31] Target HUID - * @userdata1[32:63] Attribute ID - * @userdata2[0:31] Data Size - * @userdata2[32:63] Up to 4 bytes of attribute data - * @devdesc Attribute failed to update on HBRT side - */ - errlHndl_t l_err = new ErrlEntry(ERRL_SEV_PREDICTIVE, - MOD_RT_ATTR_SYNC_REQUEST, - RC_ATTR_UPDATE_FAILED, - TWO_UINT32_TO_UINT64( + * @errortype + * @severity ERRL_SEV_PREDICTIVE + * @moduleid MOD_RT_ATTR_SYNC_REQUEST + * @reasoncode RC_ATTR_UPDATE_FAILED + * @userdata1[0:31] Target HUID + * @userdata1[32:63] Attribute ID + * @userdata2[0:31] Data Size + * @userdata2[32:63] Up to 4 bytes of attribute data + * @devdesc Attribute failed to update on HBRT side + */ + errlHndl_t l_err = new ErrlEntry(ERRL_SEV_PREDICTIVE, + MOD_RT_ATTR_SYNC_REQUEST, + RC_ATTR_UPDATE_FAILED, + TWO_UINT32_TO_UINT64( l_hbrtAttrData->huid, l_hbrtAttrData->attrID), - TWO_UINT32_TO_UINT64( + TWO_UINT32_TO_UINT64( l_hbrtAttrData->sizeOfAttrData, l_attrData), - true); + true); - l_err->collectTrace(RUNTIME_COMP_NAME, 256); + l_err->collectTrace(RUNTIME_COMP_NAME, 256); - //Commit the error - errlCommit(l_err, RUNTIME_COMP_ID); + //Commit the error + errlCommit(l_err, RUNTIME_COMP_ID); } TRACFCOMP(g_trac_runtime, EXIT_MRK"attrSyncRequest"); } +#ifdef CONFIG_NVDIMM +/** + * @brief Utility function to set ATTR_NVDIMM_ENCRYPTION_ENABLE + * and send the value to the FSP + */ +void set_ATTR_NVDIMM_ENCRYPTION_ENABLE( + ATTR_NVDIMM_ENCRYPTION_ENABLE_type i_val ) +{ + errlHndl_t l_err = nullptr; + + Target* l_sys = nullptr; + targetService().getTopLevelTarget( l_sys ); + assert(l_sys, "set_ATTR_NVDIMM_ENCRYPTION_ENABLE: no TopLevelTarget"); + l_sys->setAttr<ATTR_NVDIMM_ENCRYPTION_ENABLE>(i_val); + + // Send it down to the FSP + AttributeTank::Attribute l_attr = {}; + if( !makeAttribute<ATTR_NVDIMM_ENCRYPTION_ENABLE> + (l_sys, l_attr) ) + { + TRACFCOMP(g_trac_runtime, ERR_MRK"set_ATTR_NVDIMM_ENCRYPTION_ENABLE() Could not create Attribute"); + /*@ + *@errortype + *@reasoncode RC_CANNOT_MAKE_ATTRIBUTE + *@severity ERRORLOG_SEV_PREDICTIVE + *@moduleid SET_ATTR_NVDIMM_ENCRYPTION_ENABLE + *@devdesc Couldn't create an Attribute to send the data + * to the FSP + *@custdesc NVDIMM encryption error + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_PREDICTIVE, + SET_ATTR_NVDIMM_ENCRYPTION_ENABLE, + RC_CANNOT_MAKE_ATTRIBUTE, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT ); + l_err->collectTrace(NVDIMM_COMP_NAME); + errlCommit( l_err, NVDIMM_COMP_ID ); + } + else + { + std::vector<TARGETING::AttributeTank::Attribute> l_attrList; + l_attrList.push_back(l_attr); + l_err = sendAttributes( l_attrList ); + if (l_err) + { + TRACFCOMP(g_trac_runtime, ERR_MRK"set_ATTR_NVDIMM_ENCRYPTION_ENABLE() Error sending ATTR_NVDIMM_ENCRYPTION_ENABLE down to FSP"); + l_err->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE); + l_err->collectTrace(NVDIMM_COMP_NAME); + errlCommit( l_err, NVDIMM_COMP_ID ); + } + } +} +#endif //CONFIG_NVDIMM + +/** + * @brief Perform an NVDIMM operation + * @param[in] i_nvDimmOp - A struct that contains the operation(s) to perform + * and a flag indicating whether to perform operation + * on all processors or a given single processor. + * + * @Note The arming/disarming operations below are in the order of which they + * should be performed. If a new sequence is added to the + * arming/disarming sequence, make sure it is inserted in the + * correct order. + * The current order is: disarm -> disable encryption -> remove keys -> + * enable encryption -> arm + **/ +int doNvDimmOperation(const hostInterfaces::nvdimm_operation_t& i_nvDimmOp) +{ + int rc = 0; +#ifndef CONFIG_NVDIMM + TRACFCOMP(g_trac_runtime, ENTER_MRK"doNvDimmOperation: not an " + "NVDIMM configuration, this call becomes a noop."); + +#else + TRACFCOMP(g_trac_runtime, ENTER_MRK"doNvDimmOperation: Operation(s) " + "0x%0X, processor ID 0x%0X", + i_nvDimmOp.opType, + i_nvDimmOp.procId); + + // Error log handle for capturing any errors + errlHndl_t l_err{nullptr}; + // List of NVDIMM Targets to execute NVDIMM operation on + TargetHandleList l_nvDimmTargetList; + + // Perform the operations requested + do + { + /// Populate the NVDIMM target list + // If requesting to perform operation on all NVDIMMs, then + // retrieve all NVDIMMs from system + if (HBRT_NVDIMM_OPERATION_APPLY_TO_ALL_NVDIMMS == i_nvDimmOp.procId) + { + nvdimm_getNvdimmList(l_nvDimmTargetList); + } + // Else retrieve only the NVDIMMs from given processor ID + else + { + /// Get the NVDIMMs associated with procId + // Convert the procId to a real boy, uh, I mean target + TARGETING::TargetHandle_t l_procTarget; + l_err = RT_TARG::getHbTarget(i_nvDimmOp.procId, l_procTarget); + if (l_err) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: Error getting " + "HB Target from processor ID 0x%0X, " + "exiting ...", + i_nvDimmOp.procId); + rc = -1; + break; + } + + // Get the list of NVDIMMs associated with processor target + l_nvDimmTargetList = TARGETING::getProcNVDIMMs(l_procTarget); + } + + // No point in continuing if the list of NVDIMM Targets is empty + if (!l_nvDimmTargetList.size()) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: No NVDIMMs found, " + "exiting ..."); + rc = -1; + break; + } + + // Perform the arming/disarming operations. If anyone fails in the + // sequence, no point in calling the next, if there is a next operation. + do + { + // Disarm the NV logic + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_DISARM) + { + // Make call to disarm + if (!nvdimmDisarm(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to disarm failed. Will not perform any " + "more arming/disarming calls, if they exist"); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to disarm succeeded"); + } + } + + // Disable encryption on the NVDIMM and clear saved values from FW + if (i_nvDimmOp.opType & + hostInterfaces::HBRT_FW_NVDIMM_DISABLE_ENCRYPTION) + { + // Make call to disable encryption + if (!nvdimm_crypto_erase(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to disable encryption failed. Will not " + "perform any more arming/disarming calls, if " + "they exist"); + + // Clear the encryption enable attribute + set_ATTR_NVDIMM_ENCRYPTION_ENABLE(0); + + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to disable encryption succeeded."); + } + + // Clear the encryption enable attribute + set_ATTR_NVDIMM_ENCRYPTION_ENABLE(0); + } + + // Remove keys + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_REMOVE_KEYS) + { + // Make call to remove keys + if (!nvdimm_remove_keys()) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to remove keys failed. Will not perform " + "any more arming/disarming calls, if they exist"); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to remove keys succeeded."); + } + } + + // Enable encryption on the NVDIMM + if (i_nvDimmOp.opType & + hostInterfaces::HBRT_FW_NVDIMM_ENABLE_ENCRYPTION) + { + // Set the encryption enable attribute + set_ATTR_NVDIMM_ENCRYPTION_ENABLE(1); + + // Make call to generate keys before enabling encryption + if(!nvdimm_gen_keys()) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to generate keys failed, unable to enable " + "encryption. Will not perform any more " + "arming/disarming calls, if they exist"); + rc = -1; + break; + } + else + { + // Make call to enable encryption + if (!nvdimm_encrypt_enable(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to enable encryption failed. " + "Will not perform any more arming/disarming " + "calls, if they exist"); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to enable encryption succeeded."); + } + } // end if(!nvdimm_gen_keys()) ... else ... + } + + // Arm the NV logic + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_ARM) + { + // Make call to arm + if (!nvdimmArm(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to arm failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to arm succeeded."); + } + } // end if (nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_ARM) + } while (0); // end Perform the arming/disarming operations. + + // Perform the ES (energy source) health check operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_MNFG_ES_HEALTH_CHECK) + { + if (!nvDimmEsCheckHealthStatus(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do an ES (energy source) health check failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do an ES (energy source) health check succeeded."); + } + } + + // Perform the NVM (non-volatile memory) health check operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_MNFG_NVM_HEALTH_CHECK) + { + if (!nvDimmNvmCheckHealthStatus(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do a NVM (non-volatile memory) health check failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do a NVM (non-volatile memory) health check succeeded."); + } + } + + // Perform the factory default operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_FACTORY_DEFAULT) + { + if (!nvdimmFactoryDefault(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Factory Default operation failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Factory Default operation succeeded."); + } + } + + // Perform the secure erase verify start operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_SECURE_EV_START) + { + if (!nvdimmSecureEraseVerifyStart(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Start failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Start succeeded."); + } + } + + // Perform the secure erase verify status operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_SECURE_EV_STATUS) + { + if (!nvdimmSecureEraseVerifyStatus(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Status failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Status succeeded."); + } + } + + } while(0); // end Perform the operations requested + + if (l_err) + { + //Commit the error if it exists + errlCommit(l_err, RUNTIME_COMP_ID); + } + +#endif + + TRACFCOMP(g_trac_runtime, EXIT_MRK"doNvDimmOperation") + return rc; +} + +/** + * @brief Log the gard event from PHYP/OPAL + * + * @param[in] i_gardEvent - The details of the gard event + * @see hostInterfaces::gard_event_t for more info + * + **/ +void logGardEvent(const hostInterfaces::gard_event_t& i_gardEvent) +{ + // Trace input components + TRACFCOMP(g_trac_runtime, + ENTER_MRK"logGardEvent: Gard Event Data: " + "error type(0x%.8X), processor ID(0x%.8X), " + "PLID(0x%.8X), sub unit mask(0x.%4X), " + "recovery level(0x.%4X)", + i_gardEvent.i_error_type, + i_gardEvent.i_procId, + i_gardEvent.i_plid, + i_gardEvent.i_sub_unit_mask, + i_gardEvent.i_recovery_level); + + errlHndl_t l_err{nullptr}; + + do + { + // Make sure the error type is valid, if not, log it + if ((i_gardEvent.i_error_type == hostInterfaces::HBRT_GARD_ERROR_UNKNOWN ) || + (i_gardEvent.i_error_type >= hostInterfaces::HBRT_GARD_ERROR_LAST) ) + { + TRACFCOMP(g_trac_runtime, "logGardEvent: ERROR: unknown/invalid " + "error type 0x%.8X", + i_gardEvent.i_error_type); + + /* @ + * @errortype + * @severity ERRL_SEV_PREDICTIVE + * @moduleid MOD_RT_FIRMWARE_NOTIFY + * @reasoncode RC_LOG_GARD_EVENT_UNKNOWN_ERROR_TYPE + * @userdata1[0:31] GARD error type + * @userdata1[32:63] Processor ID + * @userdata2[0:31] Sub unit mask + * @userdata2[32:63] Recovery level + * @devdesc Unknown/invalid error type + * @custdesc Internal firmware error + */ + l_err = new ErrlEntry( ERRL_SEV_PREDICTIVE, + MOD_RT_FIRMWARE_NOTIFY, + RC_LOG_GARD_EVENT_UNKNOWN_ERROR_TYPE, + TWO_UINT32_TO_UINT64( + i_gardEvent.i_error_type, + i_gardEvent.i_procId), + TWO_UINT32_TO_UINT64( + i_gardEvent.i_sub_unit_mask, + i_gardEvent.i_recovery_level), + ErrlEntry::ADD_SW_CALLOUT); + break; + } + + + // Get the Target associated with processor ID + TARGETING::TargetHandle_t l_procTarget{nullptr}; + l_err = RT_TARG::getHbTarget(i_gardEvent.i_procId, l_procTarget); + if (l_err) + { + TRACFCOMP(g_trac_runtime, "logGardEvent: Error getting " + "HB Target from processor ID 0x%0X, " + "exiting ...", + i_gardEvent.i_procId); + break; + } + + // Log the GARD event + /* @ + * @errortype + * @severity ERRL_SEV_PREDICTIVE + * @moduleid MOD_RT_FIRMWARE_NOTIFY + * @reasoncode RC_LOG_GARD_EVENT + * @userdata1[0:31] GARD error type + * @userdata1[32:63] Processor ID + * @userdata2[0:31] Sub unit mask + * @userdata2[32:63] Recovery level + * @devdesc Gard event from Opal/Phyp + * @custdesc Hardware error detected at runtime + */ + l_err = new ErrlEntry( ERRL_SEV_PREDICTIVE, + MOD_RT_FIRMWARE_NOTIFY, + RC_LOG_GARD_EVENT, + TWO_UINT32_TO_UINT64( + i_gardEvent.i_error_type, + i_gardEvent.i_procId), + TWO_UINT32_TO_UINT64( + i_gardEvent.i_sub_unit_mask, + i_gardEvent.i_recovery_level)); + + // Set the PLID to the given gard event PLID if it exist + if (i_gardEvent.i_plid) + { + l_err->plid(i_gardEvent.i_plid); + } + + // Do the actual gard + l_err->addHwCallout( l_procTarget, HWAS::SRCI_PRIORITY_MED, + HWAS::NO_DECONFIG, HWAS::GARD_PHYP); + } while(0); + + // Commit any error log that occurred. + errlCommit(l_err, RUNTIME_COMP_ID); + + TRACFCOMP(g_trac_runtime, EXIT_MRK"logGardEvent") +} /** * @see src/include/runtime/interface.h for definition of call @@ -362,12 +827,12 @@ void attrSyncRequest( void * i_data) */ void firmware_notify( uint64_t i_len, void *i_data ) { - TRACFCOMP(g_trac_hbrt, ENTER_MRK"firmware_notify: " + TRACFCOMP(g_trac_hbrt, ENTER_MRK"firmware_notify: " "i_len:%d", i_len ); - TRACFBIN(g_trac_runtime, "firmware_notify: i_data", i_data, i_len); + TRACFBIN(g_trac_runtime, "firmware_notify: i_data", i_data, i_len); - errlHndl_t l_err = nullptr; + errlHndl_t l_err = nullptr; // Flag to detect an invalid/unknown/not used message bool l_badMessage = false; @@ -381,12 +846,12 @@ void firmware_notify( uint64_t i_len, void *i_data ) // data necessary to determine type of message if (i_len < hostInterfaces::HBRT_FW_MSG_BASE_SIZE) { - l_badMessage = true; + l_badMessage = true; - TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " - "Received a non hostInterfaces::hbrt_fw_msg data stream" ); + TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: Received " + "a non hostInterfaces::hbrt_fw_msg data stream" ); - break; + break; } // Cast the data to an hbrt_fw_msg to extract the input type @@ -394,68 +859,116 @@ void firmware_notify( uint64_t i_len, void *i_data ) static_cast<hostInterfaces::hbrt_fw_msg*>(i_data); switch (l_hbrt_fw_msg->io_type) { - case hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ: - { - // Distinguish based on msgType and msgq - if ( (l_hbrt_fw_msg->generic_msg.msgType == + case hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ: + { + // Distinguish based on msgType and msgq + if ( (l_hbrt_fw_msg->generic_msg.msgType == GenericFspMboxMessage_t::MSG_ATTR_SYNC_REQUEST) && (l_hbrt_fw_msg->generic_msg.msgq == MBOX::HB_ATTR_SYNC_MSGQ) ) - { - attrSyncRequest((void*)&(l_hbrt_fw_msg->generic_msg.data)); - } - else if ((l_hbrt_fw_msg->generic_msg.msgType == - GenericFspMboxMessage_t::MSG_OCC_ACTIVE) && - (l_hbrt_fw_msg->generic_msg.msgq == - MBOX::FSP_OCC_MSGQ_ID) ) - { - occActiveNotification((void*)&(l_hbrt_fw_msg->generic_msg.data)); - } - // Placing this at end as it does not have a msgq specified - // Want to match msgType & msgq combos first - else if (l_hbrt_fw_msg->generic_msg.msgType == - GenericFspMboxMessage_t::MSG_SBE_ERROR) - { - sbeAttemptRecovery(l_hbrt_fw_msg->generic_msg.data); - } - else - { - l_badMessage = true; - - TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " - "Unknown FSP message type:0x%.8X, " - "message queue id:0x%.8X, seqNum:%d ", - l_hbrt_fw_msg->generic_msg.msgType, - l_hbrt_fw_msg->generic_msg.msgq, - l_hbrt_fw_msg->generic_msg.seqnum); - - // Pack user data 1 with message input type and - // firmware request message sequence number - l_userData1 = TWO_UINT32_TO_UINT64( - l_hbrt_fw_msg->io_type, - l_hbrt_fw_msg->generic_msg.seqnum); - - // Pack user data 2 with message queue and message type - l_userData2 = TWO_UINT32_TO_UINT64( - l_hbrt_fw_msg->generic_msg.msgq, - l_hbrt_fw_msg->generic_msg.msgType); - } - } // END case HBRT_FW_MSG_HBRT_FSP_REQ: + { + attrSyncRequest((void*)&(l_hbrt_fw_msg->generic_msg.data)); + } + else if ((l_hbrt_fw_msg->generic_msg.msgType == + GenericFspMboxMessage_t::MSG_OCC_ACTIVE) && + (l_hbrt_fw_msg->generic_msg.msgq == + MBOX::FSP_OCC_MSGQ_ID) ) + { + occActiveNotification((void*)&(l_hbrt_fw_msg->generic_msg.data)); + } + // Placing this at end as it does not have a msgq specified + // Want to match msgType & msgq combos first + else if (l_hbrt_fw_msg->generic_msg.msgType == + GenericFspMboxMessage_t::MSG_SBE_ERROR) + { + sbeAttemptRecovery(l_hbrt_fw_msg->generic_msg.data); + } + else + { + l_badMessage = true; + + TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " + "Unknown FSP message type:0x%.8X, " + "message queue id:0x%.8X, seqNum:%d ", + l_hbrt_fw_msg->generic_msg.msgType, + l_hbrt_fw_msg->generic_msg.msgq, + l_hbrt_fw_msg->generic_msg.seqnum); + + // Pack user data 1 with message input type and + // firmware request message sequence number + l_userData1 = TWO_UINT32_TO_UINT64( + l_hbrt_fw_msg->io_type, + l_hbrt_fw_msg->generic_msg.seqnum); + + // Pack user data 2 with message queue and message type + l_userData2 = TWO_UINT32_TO_UINT64( + l_hbrt_fw_msg->generic_msg.msgq, + l_hbrt_fw_msg->generic_msg.msgType); + } // END if ( (l_hbrt_fw_msg->generic_msg.msgType ... else ... + } // END case hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ: + break; - break; + case hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_OPERATION: + { + uint64_t l_minMsgSize = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + + sizeof(hostInterfaces::hbrt_fw_msg::nvdimm_operation); + if (i_len < l_minMsgSize) + { + l_badMessage = true; + + TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " + "Received message HBRT_FW_MSG_TYPE_NVDIMM_OPERATION, " + "but size of message data(%d) is not adequate for a " + "complete message of this type, with size requirement of " + "%d", i_len, l_minMsgSize ); + + // Pack user data 1 with the message input type, the only + // data that can be safely retrieved + l_userData1 = l_hbrt_fw_msg->io_type; + + break; + } + + doNvDimmOperation(l_hbrt_fw_msg->nvdimm_operation); + } // END case hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_OPERATION: + break; - default: - { - l_badMessage = true; + case hostInterfaces::HBRT_FW_MSG_TYPE_GARD_EVENT: + { + uint64_t l_minMsgSize = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + + sizeof(hostInterfaces::hbrt_fw_msg::gard_event); + if (i_len < l_minMsgSize) + { + l_badMessage = true; + + TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " + "Received message HBRT_FW_MSG_TYPE_GARD_EVENT, " + "but size of message data(%d) is not adequate for a " + "complete message of this type, with size requirement of " + "%d", i_len, l_minMsgSize ); + + // Pack user data 1 with the message input type, the only + // data that can be safely retrieved + l_userData1 = l_hbrt_fw_msg->io_type; + + break; + } + + logGardEvent(l_hbrt_fw_msg->gard_event); + } // END case hostInterfaces::HBRT_FW_MSG_TYPE_GARD_EVENT: + break; - TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " - "Unknown firmware request input type:0x%.8X ", - l_hbrt_fw_msg->io_type); + default: + { + l_badMessage = true; - l_userData1 = l_hbrt_fw_msg->io_type; - } // END default + TRACFCOMP(g_trac_runtime, ERR_MRK"firmware_notify: " + "Unknown firmware request input type:0x%.8X ", + l_hbrt_fw_msg->io_type); - break; + l_userData1 = l_hbrt_fw_msg->io_type; + } // END default + break; }; // END switch (l_hbrt_fw_msg->io_type) @@ -463,42 +976,42 @@ void firmware_notify( uint64_t i_len, void *i_data ) if (l_badMessage) { - /*@ - * @errortype - * @severity ERRL_SEV_PREDICTIVE - * @moduleid MOD_RT_FIRMWARE_NOTIFY - * @reasoncode RC_FW_NOTIFY_RT_INVALID_MSG - * @userdata1[0:31] Firmware Request type - * @userdata1[32:63] Sequence number (FSP msg) - * @userdata2[0:31] MBOX message type (FSP msg) - * @userdata2[32:63] Message Type (FSP msg) - * @devdesc Error with Firmware Notify request - */ - l_err = new ErrlEntry(ERRL_SEV_PREDICTIVE, - MOD_RT_FIRMWARE_NOTIFY, - RC_FW_NOTIFY_RT_INVALID_MSG, - l_userData1, - l_userData2, - true); - - if (i_len > 0) - { - l_err->addFFDC(RUNTIME_COMP_ID, - i_data, - i_len, - 0, 0, false ); - } - - l_err->collectTrace( "FW_REQ", 256); + /*@ + * @errortype + * @severity ERRL_SEV_PREDICTIVE + * @moduleid MOD_RT_FIRMWARE_NOTIFY + * @reasoncode RC_FW_NOTIFY_RT_INVALID_MSG + * @userdata1[0:31] Firmware Request type + * @userdata1[32:63] Sequence number (FSP msg) + * @userdata2[0:31] MBOX message type (FSP msg) + * @userdata2[32:63] Message Type (FSP msg) + * @devdesc Error with Firmware Notify request + */ + l_err = new ErrlEntry(ERRL_SEV_PREDICTIVE, + MOD_RT_FIRMWARE_NOTIFY, + RC_FW_NOTIFY_RT_INVALID_MSG, + l_userData1, + l_userData2, + true); + + if (i_len > 0) + { + l_err->addFFDC(RUNTIME_COMP_ID, + i_data, + i_len, + 0, 0, false ); + } + + l_err->collectTrace(RUNTIME_COMP_NAME, 256); } if (l_err) { - //Commit the error if it exists - errlCommit(l_err, RUNTIME_COMP_ID); + //Commit the error if it exists + errlCommit(l_err, RUNTIME_COMP_ID); } - TRACFCOMP(g_trac_hbrt, EXIT_MRK"firmware_notify"); + TRACFCOMP(g_trac_hbrt, EXIT_MRK"firmware_notify"); }; struct registerFwNotify diff --git a/src/usr/util/runtime/rt_fwreq_helper.C b/src/usr/util/runtime/rt_fwreq_helper.C index f94dab238..ce2a1baf6 100644 --- a/src/usr/util/runtime/rt_fwreq_helper.C +++ b/src/usr/util/runtime/rt_fwreq_helper.C @@ -27,6 +27,7 @@ #include <runtime/interface.h> // hostInterfaces #include <runtime/runtime_reasoncodes.H> // MOD_RT_FIRMWARE_REQUEST, etc #include <errl/errlmanager.H> // errlCommit +#include <targeting/common/targetUtil.H> // makeAttribute using namespace ERRORLOG; using namespace RUNTIME; @@ -629,3 +630,285 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req, return l_err; }; + +/** + * @brief A handy utility to create the firmware request and response + * messages, for FSP, where the messages must be of equal size. + */ +bool createGenericFspMsg(uint32_t i_fspReqPayloadSize, + uint32_t &o_fspMsgSize, + uint64_t &o_requestMsgSize, + hostInterfaces::hbrt_fw_msg* &o_requestMsg, + uint64_t &o_responseMsgSize, + hostInterfaces::hbrt_fw_msg* &o_responseMsg) +{ + // Default the return value to true, assume things will go right + bool l_retVal(true); + + // Do some quick initialization of the output data + o_fspMsgSize = o_requestMsgSize = o_responseMsgSize = 0; + o_requestMsg = o_responseMsg = nullptr; + + // Calculate the total size of the Generic FSP Message. + o_fspMsgSize = GENERIC_FSP_MBOX_MESSAGE_BASE_SIZE + + i_fspReqPayloadSize; + + // The total Generic FSP Message size must be at a minimum the + // size of the FSP generic message (sizeof(GenericFspMboxMessage_t)) + if (o_fspMsgSize < sizeof(GenericFspMboxMessage_t)) + { + o_fspMsgSize = sizeof(GenericFspMboxMessage_t); + } + + // Calculate the total size of the hbrt_fw_msgs which + // means only adding hostInterfaces::HBRT_FW_MSG_BASE_SIZE to + // the previous calculated Generic FSP Message size. + o_requestMsgSize = o_responseMsgSize = + hostInterfaces::HBRT_FW_MSG_BASE_SIZE + o_fspMsgSize; + + // Create the hbrt_fw_msgs + o_responseMsg = reinterpret_cast<hostInterfaces::hbrt_fw_msg *> + (new uint8_t[o_responseMsgSize]); + o_requestMsg = reinterpret_cast<hostInterfaces::hbrt_fw_msg *> + (new uint8_t[o_requestMsgSize]); + + // If any one of these two message's memory can't be allocated, then + // delete both messages (in case one did allocate memory), set both + // messages to NULL pointers and set their respective sizes to zero. + if (!o_responseMsg || !o_requestMsg) + { + // OK to delete a NULL pointer if it happens + delete []o_responseMsg; + delete []o_requestMsg; + + // Return output data zeroed out + o_responseMsg = o_requestMsg = nullptr; + o_fspMsgSize = o_requestMsgSize = o_responseMsgSize = 0; + + // Return false, indicating that this function had an issue creating + // the request and/or response message + l_retVal = false; + } + else + { + // Initialize/zero out hbrt_fw_msgs + o_requestMsg->generic_msg.initialize(); + memset(o_responseMsg, 0, o_responseMsgSize); + + // We can at least set these parameters based on current usage + o_requestMsg->io_type = hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ; + o_requestMsg->generic_msg.dataSize = o_fspMsgSize; + o_requestMsg->generic_msg.__req = GenericFspMboxMessage_t::REQUEST; + } + + return l_retVal; +} // end createGenericFspMsg + + +/** + * @brief Serializes a list of Attributes to be sent to FSP + */ +errlHndl_t sendAttributes(const std::vector<TARGETING::AttributeTank::Attribute>& + i_attributeList) +{ + TRACFCOMP(g_trac_runtime, + ENTER_MRK"sendAttributes - number of attributes to send %d", + i_attributeList.size()); + + // Handle to error log + errlHndl_t l_err{nullptr}; + + // Handles to the firmware messages + hostInterfaces::hbrt_fw_msg *l_fwRequestMsg{nullptr}; // request message + hostInterfaces::hbrt_fw_msg *l_fwResponseMsg{nullptr}; // response message + + do + { + // If caller passes in an empty list, then nothing to do + if (!i_attributeList.size()) + { + TRACFCOMP(g_trac_runtime, "sendAttributes: attribute list is " + "empty,nothing to do ..."); + break; + } + + // Make sure we have all of our function pointers setup right + if ((nullptr == g_hostInterfaces) || + (nullptr == g_hostInterfaces->firmware_request)) + { + TRACFCOMP(g_trac_runtime, ERR_MRK"sendAttributes: " + "Hypervisor firmware_request interface not linked"); + + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_RT_FIRMWARE_REQUEST + * @reasoncode RC_FW_REQUEST_RT_NULL_PTR + * @userdata1 Number of Attributes to serialize and send + * @devdesc Hypervisor firmware request interface not linked + * @custdesc Internal firmware error + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + RUNTIME::MOD_RT_FIRMWARE_REQUEST, + RUNTIME::RC_FW_REQUEST_RT_NULL_PTR, + i_attributeList.size(), + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + break; + } + + /// Calculate the size requirements needed to serialize + /// the Attribute info + // Aggregate the size of the incoming Attributes + uint32_t l_aggregatedAttributeSize(0); + for (auto l_attribute: i_attributeList) + { + l_aggregatedAttributeSize += l_attribute.getSize(); + } + + // Combine the size of the AttributeSetter_t itself to the size of + // incoming Attributes to get the full size requirement needed + uint32_t l_dataSize(sizeof(AttributeSetter_t) + + l_aggregatedAttributeSize); + + // Create and initialize to zero a few needed variables + uint32_t l_fullFspDataSize(0); + uint64_t l_fwRequestMsgSize(0), l_fwResponseMsgSize(0); + + // Create the dynamic firmware messages + if (!createGenericFspMsg(l_dataSize, + l_fullFspDataSize, + l_fwRequestMsgSize, + l_fwRequestMsg, + l_fwResponseMsgSize, + l_fwResponseMsg) ) + { + TRACFCOMP(g_trac_runtime, ERR_MRK"sendAttributes: " + "Unable to allocate firmware request messages"); + + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_SEND_ATTRIBUTES_TO_FSP + * @reasoncode RC_NULL_FIRMWARE_MSG_PTR + * @userdata1 Number of Attributes to serialize and send + * @devdesc Unable to allocate firmware request messages + * @custdesc Internal firmware error + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + RUNTIME::MOD_SEND_ATTRIBUTES_TO_FSP, + RUNTIME::RC_NULL_FIRMWARE_MSG_PTR, + i_attributeList.size(), + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + break; + } + + // Populate the 'message queue' and 'message type' for this message + l_fwRequestMsg->generic_msg.msgq = MBOX::FSP_NVDIMM_KEYS_MSGQ_ID; + l_fwRequestMsg->generic_msg.msgType = + GenericFspMboxMessage_t::MSG_ATTR_WRITE_OP; + + // Create a useful struct to populate the generic_msg::data field + AttributeSetter_t* l_attributeSetter = + reinterpret_cast<AttributeSetter_t*> + (&(l_fwRequestMsg->generic_msg.data)); + + // Initialize the AttributeSetter to default values + l_attributeSetter->initialize(); + + // The number of attributes being copied can be obtained from + // size of the attrbute input list + l_attributeSetter->iv_numAttributes = i_attributeList.size(); + + // Retrieve the individual attributes (header and value) + // Create a useful struct to poulate attribute data + uint8_t* l_attributeData = l_attributeSetter->iv_attrData; + uint32_t l_sizeOfDataCopied(0); + + // Iterate thru the attribute list and serialize the attributes + for (const auto & l_attribute: i_attributeList) + { + if (l_aggregatedAttributeSize >= l_attribute.getSize()) + { + l_sizeOfDataCopied = l_attribute.serialize( + l_attributeData, l_aggregatedAttributeSize); + + if (!l_sizeOfDataCopied) + { + TRACFCOMP(g_trac_runtime, ERR_MRK"sendAttributes: " + "Serialization of an Attribute failed, " + "should never happen") + + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_SEND_ATTRIBUTES_TO_FSP + * @reasoncode RC_SERIALIZE_ATTRIBUTE_FAILED + * @userdata1 Number of Attributes to serialize and send + * @devdesc Serialization of an Attribute Failed + * @custdesc Internal firmware error + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + RUNTIME::MOD_SEND_ATTRIBUTES_TO_FSP, + RUNTIME::RC_SERIALIZE_ATTRIBUTE_FAILED, + i_attributeList.size(), + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + break; + } // end if (!l_sizeOfDataCopied) + } + else + { + TRACFCOMP(g_trac_runtime, ERR_MRK"sendAttributes: " + "Miscalculation of aggregated size of attributes, " + "should never happen") + + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid MOD_SEND_ATTRIBUTES_TO_FSP + * @reasoncode RC_NO_SPACE_FOR_ATTRIBUTE_SERIALIZATION + * @userdata1 Number of Attributes to serialize and send + * @devdesc Serialization data of Attribute to large + * for given buffer + * @custdesc Internal firmware error + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + RUNTIME::MOD_SEND_ATTRIBUTES_TO_FSP, + RUNTIME::RC_NO_SPACE_FOR_ATTRIBUTE_SERIALIZATION, + i_attributeList.size(), + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + break; + } + + // Decrement/increment our counters/pointers + l_aggregatedAttributeSize -= l_sizeOfDataCopied; + l_attributeData += l_sizeOfDataCopied; + } // end for (const auto & l_attribute: i_attributeList) + + // Make the firmware_request call + l_err = firmware_request_helper(l_fwRequestMsgSize, + l_fwRequestMsg, + &l_fwResponseMsgSize, + l_fwResponseMsg); + } while (0); + + // Release the firmware messages and set to NULL + delete []l_fwRequestMsg; + delete []l_fwResponseMsg; + l_fwRequestMsg = l_fwResponseMsg = nullptr; + + TRACFCOMP(g_trac_runtime, EXIT_MRK"sendAttributes - exit with %s", + (nullptr == l_err ? "no error" : "error")); + + + return l_err; +} diff --git a/src/usr/util/runtime/test/testlidmgr_rt.H b/src/usr/util/runtime/test/testlidmgr_rt.H index 36eb8bc64..a6681b37b 100644 --- a/src/usr/util/runtime/test/testlidmgr_rt.H +++ b/src/usr/util/runtime/test/testlidmgr_rt.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2014,2016 */ +/* Contributors Listed Below - COPYRIGHT 2014,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -26,7 +26,6 @@ #include <cxxtest/TestSuite.H> #include <errl/errlmanager.H> #include <utilbase.H> -#include <config.h> class LidMgrRtTest : public CxxTest::TestSuite { diff --git a/src/usr/util/runtime/test/testruncommand.H b/src/usr/util/runtime/test/testruncommand.H index 9dbb6b5c0..f6563819e 100644 --- a/src/usr/util/runtime/test/testruncommand.H +++ b/src/usr/util/runtime/test/testruncommand.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -24,7 +24,6 @@ /* IBM_PROLOG_END_TAG */ #include <cxxtest/TestSuite.H> #include <errl/errlmanager.H> -#include <config.h> #include <runtime/interface.h> #include <string.h> #include <stdio.h> diff --git a/src/usr/util/runtime/utillidmgr_rt.C b/src/usr/util/runtime/utillidmgr_rt.C index ad5a7cd48..55bebdeb3 100644 --- a/src/usr/util/runtime/utillidmgr_rt.C +++ b/src/usr/util/runtime/utillidmgr_rt.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -192,13 +192,24 @@ errlHndl_t UtilLidMgr::loadLid() UTIL_FT(ERR_MRK"UtilLidMgr::loadLid - setheader failed"); break; } - iv_lidSize = l_conHdr.payloadTextSize(); UTIL_FT("UtilLidMgr::loadLid - resv mem section has secure header"); - - // Increment by page size to not expose secure header - iv_lidBuffer = static_cast<uint8_t*>(iv_lidBuffer) + - PAGESIZE; + if (l_conHdr.sb_flags()->sw_hash) + { + // Size of lid has to be size of unprotected data. So we + // need to take out header and hash table sizes + iv_lidSize = l_conHdr.totalContainerSize() - PAGESIZE - + l_conHdr.payloadTextSize(); + iv_lidBuffer = static_cast<uint8_t*>(iv_lidBuffer) + + PAGESIZE + l_conHdr.payloadTextSize(); + } + else + { + iv_lidSize = l_conHdr.payloadTextSize(); + // Increment by page size to not expose secure header + iv_lidBuffer = static_cast<uint8_t*>(iv_lidBuffer) + + PAGESIZE; + } } } else if(iv_isLidInVFS) diff --git a/src/usr/util/test/threadpool.H b/src/usr/util/test/threadpool.H index 9784540a9..7e474b2c3 100644 --- a/src/usr/util/test/threadpool.H +++ b/src/usr/util/test/threadpool.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2012,2014 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ +/* [+] 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. */ @@ -25,6 +27,15 @@ #include <cxxtest/TestSuite.H> #include <util/threadpool.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <util/util_reasoncodes.H> +#include <hbotcompid.H> +#include <kernel/console.H> + +// Thread pool constructor flags +#define DISABLE_CHILD_RC_CHECKING false +#define CHECK_CHILD_RC true namespace __ThreadPoolTest { @@ -86,6 +97,17 @@ namespace __ThreadPoolTest uint64_t* iv_value; }; + /** A simple work item that causes the task to crash */ + struct CrashedTask + { + CrashedTask() {}; + void operator()() + { + uint8_t* l_ptr = nullptr; + *l_ptr = 1; + } + }; + }; @@ -96,7 +118,8 @@ class ThreadPoolTest: public CxxTest::TestSuite * ordered pools. */ void testSimpleWorkItem() { - Util::ThreadPool<__ThreadPoolTest::Simple> instance; + Util::ThreadPool<__ThreadPoolTest::Simple> + instance(DISABLE_CHILD_RC_CHECKING); uint64_t value = 0; instance.insert(new __ThreadPoolTest::Simple(&value)); @@ -108,7 +131,8 @@ class ThreadPoolTest: public CxxTest::TestSuite TS_FAIL("Value was not changed by Simple worker thread."); } - Util::ThreadPool<__ThreadPoolTest::SimpleOrdered> instance2; + Util::ThreadPool<__ThreadPoolTest::SimpleOrdered> + instance2(DISABLE_CHILD_RC_CHECKING); value = 0; instance2.insert(new __ThreadPoolTest::SimpleOrdered(&value)); @@ -127,7 +151,8 @@ class ThreadPoolTest: public CxxTest::TestSuite * threads as directed. */ void testThreadManager() { - Util::ThreadPool<__ThreadPoolTest::EnsureThreads> instance; + Util::ThreadPool<__ThreadPoolTest::EnsureThreads> + instance(DISABLE_CHILD_RC_CHECKING); barrier_t barrier; for (size_t count = 1; count < 5; count++) @@ -151,7 +176,8 @@ class ThreadPoolTest: public CxxTest::TestSuite /** Test that the order functions work on the thread pool. */ void testThreadOrder() { - Util::ThreadPool<__ThreadPoolTest::EnsureOrder> instance; + Util::ThreadPool<__ThreadPoolTest::EnsureOrder> + instance(DISABLE_CHILD_RC_CHECKING); uint64_t value = 0; // Ensure that adding work items in order works. @@ -191,6 +217,104 @@ class ThreadPoolTest: public CxxTest::TestSuite instance.start(); instance.shutdown(); } + + /** Test a good child task that doesn't return an error. */ + void testChildRCGoodTask() + { + TS_INFO(ENTER_MRK"testChildRCGoodTask"); + Util::ThreadPool<__ThreadPoolTest::Simple> + l_threadPool(CHECK_CHILD_RC); + uint64_t l_value = 0; + + do { + l_threadPool.insert(new __ThreadPoolTest::Simple(&l_value)); + l_threadPool.start(); + errlHndl_t l_errl = l_threadPool.shutdown(); + if(l_errl) + { + TS_FAIL("testChildRCGoodTask: an unexpected error log (EID 0x%.8%x) returned from the thread pool", l_errl->eid()); + errlCommit(l_errl, CXXTEST_COMP_ID); + break; + } + + if(l_value == 0) + { + TS_FAIL("testChildRCGoodTask: the test value was not changed by the child task"); + break; + } + + }while(0); + TS_INFO(EXIT_MRK"testChildRCGoodTask"); + } + + /** Test that the crashed task's error log is returned to thread pool + correctly */ + void testChildRCCrashedTask() + { + TS_INFO(ENTER_MRK"testChildRCCrashedTask"); + Util::ThreadPool<__ThreadPoolTest::CrashedTask> + l_threadPool(CHECK_CHILD_RC); + errlHndl_t l_errl = nullptr; + + do { + printk("testChildRCCrashedTask: Expect to see uncaught exception\n"); + l_threadPool.insert(new __ThreadPoolTest::CrashedTask()); + l_threadPool.start(); + l_errl = l_threadPool.shutdown(); + if(!l_errl) + { + TS_FAIL("testChildRCCrashedTask: the thread pool did not return an error log as was expected"); + break; + } + + if(l_errl->moduleId() != Util::UTIL_MOD_TP_SHUTDOWN) + { + TS_FAIL("testChildRCCrashedTask: unexpected moduleId returned from EID 0x%.8x; expected: 0x%x; actual: 0x%x", + l_errl->eid(), + Util::UTIL_MOD_TP_SHUTDOWN, + l_errl->moduleId()); + break; + } + + if(l_errl->reasonCode() != Util::UTIL_RC_CHILD_TASK_FAILED) + { + TS_FAIL("testChildRCCrashedTask: unexpected return code from EID 0x%.8x; expected: 0x%x; actual 0x%x", + l_errl->eid(), + Util::UTIL_RC_CHILD_TASK_FAILED, + l_errl->reasonCode()); + break; + } + }while(0); + + if(l_errl) + { + ERRORLOG::errlCommit(l_errl, CXXTEST_COMP_ID); + } + TS_INFO(EXIT_MRK"testChildRCCrashedTask"); + } + + /* Test that error is not returned by crashed task when explicitly + not requested by thread pool */ + void testChildNoRCCrashedTask() + { + TS_INFO(ENTER_MRK"testChildNoRCCrashedTask"); + Util::ThreadPool<__ThreadPoolTest::CrashedTask> + l_threadPool(DISABLE_CHILD_RC_CHECKING); + errlHndl_t l_errl = nullptr; + + printk("testChildNoRCCrashedTask: Expect to see uncaught exception\n"); + l_threadPool.insert(new __ThreadPoolTest::CrashedTask()); + l_threadPool.start(); + l_errl = l_threadPool.shutdown(); + + if(l_errl) + { + TS_FAIL("testChildNoRCCrashedTask: unexpected error returned from the thread pool (EID 0x%.8x)", l_errl->eid()); + ERRORLOG::errlCommit(l_errl, CXXTEST_COMP_ID); + } + + TS_INFO(EXIT_MRK"testChildNoRCCrashedTask"); + } }; #endif diff --git a/src/usr/util/threadpool.C b/src/usr/util/threadpool.C index d2b156839..b51cca642 100644 --- a/src/usr/util/threadpool.C +++ b/src/usr/util/threadpool.C @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2012,2014 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ +/* [+] 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. */ @@ -23,6 +25,9 @@ #include <util/threadpool.H> #include <sys/task.h> #include <sys/misc.h> +#include <util/util_reasoncodes.H> +#include <errl/errlmanager.H> +#include <hbotcompid.H> void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__init() { @@ -96,10 +101,15 @@ void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__start( mutex_unlock(&iv_mutex); } -void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__shutdown() +errlHndl_t Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__shutdown() { mutex_lock(&iv_mutex); + int l_childRc = 0; + void* l_childRetval = nullptr; + errlHndl_t l_origError = nullptr; + errlHndl_t l_errl = nullptr; + // Set shutdown status and signal all children to release from their // condition variable. iv_shutdown = true; @@ -109,14 +119,52 @@ void Util::__Util_ThreadPool_Impl::ThreadPoolImpl::__shutdown() while(!iv_children.empty()) { tid_t child = iv_children.front(); + tid_t l_returnedTid = 0; iv_children.pop_front(); mutex_unlock(&iv_mutex); - task_wait_tid(child, NULL, NULL); // Don't need status. + l_returnedTid = task_wait_tid(child, &l_childRc, &l_childRetval); + if(iv_checkChildRc && + ((l_returnedTid != child) || + (l_childRc != TASK_STATUS_EXITED_CLEAN))) + { + /** + * @errortype + * @moduleid UTIL_MOD_TP_SHUTDOWN + * @reasoncode UTIL_RC_CHILD_TASK_FAILED + * @userdata1 The return code of the child thread + * @userdata2[0:31] The returned task ID of the child thread + * @userdata2[32:63] The original task ID of the child thread + * @devdesc The child thread of a thread pool returned an + * error + * @custdesc A failure occurred during the IPL of the system + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UTIL_MOD_TP_SHUTDOWN, + UTIL_RC_CHILD_TASK_FAILED, + l_childRc, + TWO_UINT32_TO_UINT64(l_returnedTid, + child), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT + ); + l_errl->collectTrace(UTIL_COMP_NAME); + + if(!l_origError) + { + l_origError = l_errl; + l_errl = nullptr; + } + else + { + l_errl->plid(l_origError->plid()); + errlCommit(l_errl, UTIL_COMP_ID); + } + } mutex_lock(&iv_mutex); } mutex_unlock(&iv_mutex); + return l_origError; } // Default thread count of one per HW thread. diff --git a/src/usr/util/utillidmgr.C b/src/usr/util/utillidmgr.C index da9b26052..05c671fe4 100644 --- a/src/usr/util/utillidmgr.C +++ b/src/usr/util/utillidmgr.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -37,7 +37,6 @@ #include <sys/mm.h> #include <util/align.H> -#include <config.h> #ifdef CONFIG_SECUREBOOT #include <pnor/pnorif.H> #include <secureboot/service.H> diff --git a/src/usr/util/utillidpnor.C b/src/usr/util/utillidpnor.C index 7e910f6eb..89dc09711 100644 --- a/src/usr/util/utillidpnor.C +++ b/src/usr/util/utillidpnor.C @@ -25,7 +25,6 @@ #include <util/utillidmgr.H> #include <util/utillidpnor.H> -#include <config.h> #include <pnor/pnorif.H> #include <errl/errlmanager.H> @@ -53,10 +52,6 @@ static const PnorLidsMap PnorToLidsMap = { PNOR::OCC, LidAndContainerLid(OCC_LIDID, OCC_CONTAINER_LIDID)}, { PNOR::WOFDATA, LidAndContainerLid(WOF_LIDID, WOF_CONTAINER_LIDID)}, { PNOR::HCODE, LidAndContainerLid(NIMBUS_HCODE_LIDID, HCODE_CONTAINER_LIDID)}, - /* @TODO RTC:177927 - Figure out how to handle different Lids for the - same PNOR section based on chip. - { PNOR::HCODE, LidAndContainerLid(CUMULUS_HCODE_LIDID, HCODE_CONTAINER_LIDID)}, - */ { PNOR::RINGOVD, LidAndContainerLid(HWREFIMG_RINGOVD_LIDID,INVALID_LIDID)}, }; @@ -179,7 +174,13 @@ errlHndl_t UtilLidMgr::getLidPnorSectionInfo(const uint32_t i_lidId, // downstream logic from going past the end of the image. // NOTE: This assumes that any secure lid loaded from PNOR by // UtilLidMgr does not contain an unprotected section - iv_lidPnorInfo.size = iv_lidPnorInfo.secureProtectedPayloadSize; + // In this case of hash tables, we need to load the entire + // partition size because the user data is part of the + // unprotected payload + if (!iv_lidPnorInfo.hasHashTable) + { + iv_lidPnorInfo.size = iv_lidPnorInfo.secureProtectedPayloadSize; + } } #endif #endif |