void EntityPath::dump() const { #define TARG_FN "dump()" char l_pBuf[200]; memset(l_pBuf,'\0',200); char* l_pCursor = l_pBuf; l_pCursor+=sprintf(l_pCursor,"%s:",pathTypeAsString()); for(uint32_t i=0; i<size(); ++i) { l_pCursor+=sprintf(l_pCursor,"/%s%d", pathElementTypeAsString(operator[](i).type), operator[](i).instance); } TRACFBIN(g_trac_targeting, "EntityPath", l_pBuf, l_pCursor-l_pBuf); #undef TARG_FN }
//***************************************************************************** // resetBackupTopology //***************************************************************************** errlHndl_t resetBackupTopology( uint32_t i_oscPos, const TARGETING::TargetHandle_t& i_procOscTgt, const TARGETING::TargetHandleList& i_badChipList, bool i_informPhyp) { TOD_ENTER("resetBackupTopology"); errlHndl_t l_err = nullptr; // Put the handle to the firmware_request request struct // out here so it is easier to free later hostInterfaces::hbrt_fw_msg *l_req_fw_msg = nullptr; hostInterfaces::hbrt_fw_msg *l_resp_fw_msg = nullptr; do { if ((nullptr == g_hostInterfaces) || (nullptr == g_hostInterfaces->firmware_request)) { TOD_ERR("resetBackupTopology: " "Hypervisor firmware_request interface not linked"); /*@ * @errortype * @severity ERRL_SEV_UNRECOVERABLE * @moduleid TOD_RT_TOPOLOGY_RESET_BACKUP * @reasoncode TOD_RT_NULL_FIRMWARE_REQUEST_PTR * @userdata1 None * @userdata2 None * @devdesc Host interfaces are not initialized * @custdesc An internal error occurred. This will * force the Time of Day function to run * with complete redundancy. */ l_err = new ErrlEntry( ERRL_SEV_UNRECOVERABLE, TOD_RT_TOPOLOGY_RESET_BACKUP, TOD_RT_NULL_FIRMWARE_REQUEST_PTR, 0, 0, true); break; } // The format of the data to be sent, according to the document // "Handle PRD Request for resetting backup TOD topology" is as follows // All data members below are 4 bytes long (32 bits) // Ordinal ID - 0xFFFFFFFF means no OSC to be avoided // HUID of the node - This field should be considered only if Ordinal // ID is NOT set to 0xFFFFFFFF otherwise it is set // to 0 // HUID of the first processor // HUID of the second processor, etc // Check if we get conflicting data, if so send a Trace out if ((0xFFFFFFFF == i_oscPos) && (nullptr != i_procOscTgt)) { TOD_ERR("Conflicting input data, input oscillator position " "(i_oscPos) has value 0xFFFFFFFF, meaning no oscillator " "to be avoided but input oscillator target (i_procOscTgt) " "has a valid value" ); } else if ((0xFFFFFFFF != i_oscPos) && (nullptr == i_procOscTgt)) { TOD_ERR("Conflicting input data, input oscillator position " "(i_oscPos) has value 0x%X, meaning avoid oscillator " "but input oscillator target (i_procOscTgt) " "has a NULL value", i_oscPos); } // Flag to determine if the OSC data will be added to the data bool l_addOscData = (0xFFFFFFFF != i_oscPos) && (nullptr != i_procOscTgt); // Default the request data size to the size of the // GenericFspMboxMessage_t minus the size of the // GenericFspMboxMessage_t's data. The size of the // GenericFspMboxMessage_t's data will be added later uint32_t l_req_data_size = sizeof(GenericFspMboxMessage_t) - sizeof(GenericFspMboxMessage_t::data); // Add to the request data size iff there is data needing to be passed if (i_badChipList.size() > 0) { // if the bad chip list has any items then increase size to // accommodate for an ordinal ID and a HUID, regardless if // they have relevant data or not, because they are expected // before the HUID list. l_req_data_size += (MSG_OSC_SIZE_OF_DETAILS * sizeof(uint32_t)) + (i_badChipList.size() * sizeof(uint32_t)); } else if (l_addOscData) { // if there is a valid OSC then accommodate for an ordinal ID // and HUID of node, but don't need space for HUID list because, // if we are here, the list is empty l_req_data_size += (MSG_OSC_SIZE_OF_DETAILS * sizeof(uint32_t)); } // The request data size must be at a minimum the size of the // FSP generic message (sizeof(GenericFspMboxMessage_t)) if (l_req_data_size < sizeof(GenericFspMboxMessage_t)) { l_req_data_size = sizeof(GenericFspMboxMessage_t); } // Calculate the TOTAL size of hostInterfaces::hbrt_fw_msg which // means only adding hostInterfaces::HBRT_FW_MSG_BASE_SIZE to // the previous calculated request data size uint64_t l_req_fw_msg_size = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + l_req_data_size; // Create the firmware_request request struct to send data l_req_fw_msg = (hostInterfaces::hbrt_fw_msg *)malloc(l_req_fw_msg_size); // Initialize the firmware_request request struct l_req_fw_msg->generic_msg.initialize(); // Populate the firmware_request request struct with given data l_req_fw_msg->io_type = hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ; l_req_fw_msg->generic_msg.dataSize = l_req_data_size; l_req_fw_msg->generic_msg.msgq = MBOX::FSP_TOD_MSGQ; l_req_fw_msg->generic_msg.msgType = (false == i_informPhyp ? GenericFspMboxMessage_t::MSG_TOD_BACKUP_RESET: GenericFspMboxMessage_t::MSG_TOD_BACKUP_RESET_INFORM_PHYP); l_req_fw_msg->generic_msg.__req = GenericFspMboxMessage_t::REQUEST; // A convenient way to populate the data uint32_t* l_dataPtr = reinterpret_cast<uint32_t*>(&(l_req_fw_msg->generic_msg.data)); if (i_badChipList.size() > 0) { // set the ordinal ID l_dataPtr[MSG_OSC_ORDINAL_ID_LOC] = i_oscPos; // attach the HUIDs from bad chip list to end of struct size_t i = MSG_OSC_HUIDS_LOC; for (auto l_target : i_badChipList) { l_dataPtr[i++] = GETHUID(l_target); } } // Set the HUID of the ordinal node if need be if (l_addOscData) { // set the ordinal ID l_dataPtr[MSG_OSC_ORDINAL_ID_LOC] = i_oscPos; // Get the parent node target TARGETING::TargetHandleList l_list; TARGETING::targetService().getAssociated(l_list, i_procOscTgt, TARGETING::TargetService::PARENT, TARGETING::TargetService::IMMEDIATE); if (l_list.size() == 1) { l_dataPtr[MSG_OSC_ORDINAL_NODE_HUID_LOC] = GETHUID(l_list[0]); } else { /*@ * @errortype * @severity ERRL_SEV_UNRECOVERABLE * @moduleid TOD_RT_TOPOLOGY_RESET_BACKUP * @reasoncode TOD_INVALID_TARGET * @userdata1 The number of parents found osc target * @userdata2 None * @devdesc No/Multiple parent(s) found for * processor osc target * @custdesc An internal error occurred. This will * force the Time of Day function to run * with complete redundancy. */ l_err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, TOD_RT_TOPOLOGY_RESET_BACKUP, TOD_INVALID_TARGET, l_list.size(), 0, true); break; } } // Create the firmware_request response struct to receive data // NOTE: For messages to the FSP the response size must match // the request size uint64_t l_resp_fw_msg_size = l_req_fw_msg_size; l_resp_fw_msg = (hostInterfaces::hbrt_fw_msg *)malloc(l_resp_fw_msg_size); memset(l_resp_fw_msg, 0, l_resp_fw_msg_size); // Trace out the request structure TRACFBIN(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"TOD::Sending firmware_request", l_req_fw_msg, l_req_fw_msg_size); // Make the firmware_request call l_err = firmware_request_helper(l_req_fw_msg_size, l_req_fw_msg, &l_resp_fw_msg_size, l_resp_fw_msg); if (l_err) { break; } } while (0); // Release the firmware messages free(l_req_fw_msg); free(l_resp_fw_msg); l_req_fw_msg = l_resp_fw_msg = nullptr; TOD_EXIT("resetBackupTopology"); return l_err; } // end resetBackupTopology
//***************************************************************************** // readTodProcDataFromFile //***************************************************************************** errlHndl_t readTodProcDataFromFile(TodChipDataContainer& o_todChipData) { TOD_ENTER("readTodProcDataFromFile"); errlHndl_t l_err = nullptr; // Put the handle to the firmware messages out here // so it is easier to free later hostInterfaces::hbrt_fw_msg *l_req_fw_msg = nullptr; hostInterfaces::hbrt_fw_msg *l_resp_fw_msg = nullptr; // clear the out data, regardless of the code to follow o_todChipData.clear(); do { if ((nullptr == g_hostInterfaces) || (nullptr == g_hostInterfaces->firmware_request)) { TOD_ERR("readTodProcDataFromFile: " "Hypervisor firmware_request interface not linked"); /*@ * @errortype * @severity ERRL_SEV_UNRECOVERABLE * @moduleid TOD_RT_TOPOLOGY_DATA * @reasoncode TOD_RT_NULL_FIRMWARE_REQUEST_PTR * @devdesc Host interfaces are not initialized * @custdesc An internal error occurred. This will * force the Time of Day function to run * with complete redundancy. */ l_err = new ErrlEntry( ERRL_SEV_UNRECOVERABLE, TOD_RT_TOPOLOGY_DATA, TOD_RT_NULL_FIRMWARE_REQUEST_PTR, 0, 0, true); break; } // Default the response data size to the size of the // GenericFspMboxMessage_t minus the size of the // GenericFspMboxMessage_t's data. The size of the // GenericFspMboxMessage_t's data will be added later uint32_t l_resp_data_size = sizeof(GenericFspMboxMessage_t) - sizeof(GenericFspMboxMessage_t::data); // Get the number of TodChipData items that will be returned. uint32_t l_nTodChips = TodSvcUtil::getMaxProcsOnSystem(); // Add to the response data size iff there is data needing to be passed l_resp_data_size += (l_nTodChips * sizeof(TodChipData)); // The response data size must be at a minimum the size of the // FSP generic message (sizeof(GenericFspMboxMessage_t)) if (l_resp_data_size < sizeof(GenericFspMboxMessage_t)) { l_resp_data_size = sizeof(GenericFspMboxMessage_t); } // Calculate the TOTAL size of hostInterfaces::hbrt_fw_msg which // means only adding hostInterfaces::HBRT_FW_MSG_BASE_SIZE to // the previous calculated response data size uint64_t l_resp_fw_msg_size = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + l_resp_data_size; // Create the firmware_request response struct to receive data l_resp_fw_msg = (hostInterfaces::hbrt_fw_msg *)malloc(l_resp_fw_msg_size); memset(l_resp_fw_msg, 0, l_resp_fw_msg_size); // Create the firmware_request request struct to send data uint64_t l_req_fw_msg_size = l_resp_fw_msg_size; l_req_fw_msg = (hostInterfaces::hbrt_fw_msg *)malloc(l_req_fw_msg_size); // Initialize the firmware_request request struct l_req_fw_msg->generic_msg.initialize(); // Populate the firmware_request request struct with given data l_req_fw_msg->io_type = hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ; l_req_fw_msg->generic_msg.msgq = MBOX::FSP_TOD_MSGQ; l_req_fw_msg->generic_msg.msgType = GenericFspMboxMessage_t::MSG_TOD_TOPOLOGY_DATA; l_req_fw_msg->generic_msg.__req = GenericFspMboxMessage_t::REQUEST; // Trace out the request structure TRACFBIN(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK"TOD::Sending firmware_request", l_req_fw_msg, l_req_fw_msg_size); // Make the firmware_request call l_err = firmware_request_helper(l_req_fw_msg_size, l_req_fw_msg, &l_resp_fw_msg_size, l_resp_fw_msg); if (l_err) { break; } // If we are here, then this was no error retrieving the data. Now, // just get the data from the returned struct and pass back to caller // Get a pointer to the data TodChipData* l_todChipData = (TodChipData*)(&(l_resp_fw_msg->generic_msg.data)); // Gather the data into the container provided for (size_t i = 0; i < l_nTodChips; ++i) { o_todChipData.push_back(l_todChipData[i]); } } while (0); // Release the firmware messages free(l_req_fw_msg); free(l_resp_fw_msg); l_req_fw_msg = l_resp_fw_msg = nullptr; TOD_EXIT("readTodProcDataFromFile"); return l_err; } // end readTodProcDataFromFile
// ------------------------------------------------------------------ // sendMboxWriteMsg // ------------------------------------------------------------------ errlHndl_t sendMboxWriteMsg ( size_t i_numBytes, void * i_data, TARGETING::Target * i_target, VPD_MSG_TYPE i_type, VpdWriteMsg_t& i_record ) { errlHndl_t l_err = NULL; msg_t* msg = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"sendMboxWriteMsg()" ); do { //Create a mailbox message to send to FSP msg = msg_allocate(); msg->type = i_type; msg->data[0] = i_record.data0; msg->data[1] = i_numBytes; //Copy the data into the message msg->extra_data = malloc( i_numBytes ); memcpy( msg->extra_data, i_data, i_numBytes ); TRACFCOMP( g_trac_vpd, INFO_MRK"sendMboxWriteMsg: Send msg to FSP to write VPD type %.8X, record %d, offset 0x%X", i_type, i_record.rec_num, i_record.offset ); //We only send VPD update when we have SP Base Services if( !INITSERVICE::spBaseServicesEnabled() ) { TRACFCOMP(g_trac_vpd, INFO_MRK "No SP Base Services, skipping VPD write"); TRACFBIN( g_trac_vpd, "msg=", msg, sizeof(msg_t) ); TRACFBIN( g_trac_vpd, "extra=", msg->extra_data, i_numBytes ); free (msg->extra_data); msg_free( msg ); break; } l_err = MBOX::send( MBOX::FSP_VPD_MSGQ, msg ); if( l_err ) { TRACFCOMP(g_trac_vpd, ERR_MRK "Failed sending VPD to FSP for %.8X", TARGETING::get_huid(i_target)); ERRORLOG::ErrlUserDetailsTarget(i_target).addToLog(l_err); l_err->collectTrace("VPD",1024); if( VPD_WRITE_DIMM == i_type ) { l_err->collectTrace("SPD",1024); } // just commit the log and move on, nothing else to do errlCommit( l_err, VPD_COMP_ID ); l_err = NULL; free( msg->extra_data ); msg->extra_data = NULL; msg_free( msg ); } } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"sendMboxWriteMsg()" ); return l_err; }
//************************************************************************** // FREQVOLTSVC::setWofFrequencyUpliftSelected //************************************************************************** void setWofFrequencyUpliftSelected() { // get mrw data TARGETING::Target* l_pTopLevel = NULL; (void)TARGETING::targetService().getTopLevelTarget(l_pTopLevel); ATTR_WOF_FREQUENCY_UPLIFT_type l_upliftTable = {{{0}}}; ATTR_WOF_PROC_SORT_type l_procSortTable = {{0}}; ATTR_NOMINAL_FREQ_MHZ_type l_sysNomFreqMhz = l_pTopLevel->getAttr<ATTR_NOMINAL_FREQ_MHZ>(); ATTR_WOF_ENABLED_type l_wofEnabled = l_pTopLevel->getAttr < TARGETING::ATTR_WOF_ENABLED > (); // tryGetAttr used due to complex data type. Expected to always work. if (!l_pTopLevel->tryGetAttr<ATTR_WOF_FREQUENCY_UPLIFT>(l_upliftTable)) { // The zero initialized values will be used for the select array TRACFCOMP(g_fapiTd, "Failed to get ATTR_WOF_FREQUENCY_UPLIFT"); } // tryGetAttr used due to complex data type. Expected to always work. if ( !l_pTopLevel->tryGetAttr<ATTR_WOF_PROC_SORT>(l_procSortTable)) { // Not finding the sort table will result in not finding the index // which will result in a log later TRACFCOMP(g_fapiTd, "Failed to get ATTR_WOF_PROC_SORT"); } // get the list of procs TargetHandleList l_procTargetList; getAllChips(l_procTargetList, TYPE_PROC, true); // for each proc, fill in Wof Frequency Uplift Selected attribute for (TargetHandleList::const_iterator l_proc_iter = l_procTargetList.begin(); l_proc_iter != l_procTargetList.end(); ++l_proc_iter) { TARGETING::Target * l_pProcTarget = *l_proc_iter; // find number of active cores TARGETING::TargetHandleList l_presCoreList; getChildAffinityTargetsByState( l_presCoreList, const_cast<TARGETING::Target*>(l_pProcTarget), TARGETING::CLASS_UNIT, TARGETING::TYPE_CORE, TARGETING::UTIL_FILTER_PRESENT); uint8_t l_activeCores = l_presCoreList.size(); TRACDCOMP(g_fapiTd, "setWofFrequencyUpliftSelected:" " number of active cores is %d ", l_activeCores); // find WOF index. For example: // ATTR_WOF_PROC_SORT = // Cores/Nom Freq/Index // 8 3325 1 // 10 2926 2 // 12 2561 3 // 12 3093 4 // Use WOF index=3 for active cores=12 && nom freq=2561 uint8_t l_wofIndex = 0; for (uint8_t i=0;i<4;i++) { if ( (l_activeCores == l_procSortTable[i][0]) && (l_sysNomFreqMhz == l_procSortTable[i][1]) ) { l_wofIndex = l_procSortTable[i][2]; break; } } TRACDCOMP(g_fapiTd, "setWofFrequencyUpliftSelected:" " WOF index is %d ", l_wofIndex); // validate WOF index ATTR_WOF_FREQUENCY_UPLIFT_SELECTED_type l_selectedTable = {{0}}; if ( (!l_wofIndex) || (l_wofIndex > 4)) { if (l_wofEnabled) // log error if WOF enabled { TRACFCOMP(g_fapiTd, "setWofFrequencyUpliftSelected:" " No WOF table index match found HUID:0x%08X" " active cores=%d, nom freq=%d, index=%d", l_pProcTarget->getAttr<TARGETING::ATTR_HUID>(), l_activeCores, l_sysNomFreqMhz, l_wofIndex); errlHndl_t l_err = NULL; /*@ * @errortype * @moduleid fapi::MOD_GET_WOF_FREQ_UPLIFT_SELECTED * @reasoncode fapi::RC_INVALID_WOF_INDEX * @userdata1[0:31] Proc HUID * @userdata1[32:63] WOF Freq Uplift Index * @userdata2[0:31] Number of active cores * @userdata2[32:63] Nomimal Frequency * @devdesc When WOF is enabled, the WOF Freq * Uplift index should be 1,2,3, or 4 */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi::MOD_GET_WOF_FREQ_UPLIFT_SELECTED, fapi::RC_INVALID_WOF_INDEX, TWO_UINT32_TO_UINT64( l_pProcTarget->getAttr<TARGETING::ATTR_HUID>(), l_wofIndex), TWO_UINT32_TO_UINT64( l_activeCores, l_sysNomFreqMhz)); // Callout HW as WOF mrw data is incorrect l_err->addHwCallout(l_pProcTarget, HWAS::SRCI_PRIORITY_MED, HWAS::NO_DECONFIG, HWAS::GARD_NULL); // Include WOF processor sort table TRACFBIN (g_fapiTd, "WOF processor sort table", l_procSortTable, sizeof(l_procSortTable)); l_err->collectTrace(FAPI_TRACE_NAME); // log error and keep going errlCommit(l_err,HWPF_COMP_ID); } // make sure zeros are set in the selected table attribute memset(l_selectedTable, 0, sizeof(l_selectedTable)); } else { // use index to set Wof Frequency Uplift selected attribute // note: mrw index is 1 based memcpy(l_selectedTable, &l_upliftTable[l_wofIndex-1][0][0], sizeof(l_selectedTable)); } if (!l_pProcTarget->trySetAttr<ATTR_WOF_FREQUENCY_UPLIFT_SELECTED> (l_selectedTable)) { //unlikely, crash TRACFCOMP(g_fapiTd, "Failed to set ATTR_WOF_FREQUENCY_UPLIFT_SELECTED"); assert(0); } } return; }
/** * @brief Check flash image SHA512 hash value of each explorer chip * and update the flash if it does not match the SHA512 hash * of the image in PNOR. * * @param[out] o_stepError Error handle for logging istep failures * */ void updateAll(IStepError& o_stepError) { bool l_imageLoaded = false; errlHndl_t l_err = nullptr; bool l_rebootRequired = false; // Get a list of OCMB chips TARGETING::TargetHandleList l_ocmbTargetList; getAllChips(l_ocmbTargetList, TYPE_OCMB_CHIP); TRACFCOMP(g_trac_expupd, ENTER_MRK "updateAll: %d ocmb chips found", l_ocmbTargetList.size()); do { // If no OCMB chips exist, we're done. if(l_ocmbTargetList.size() == 0) { break; } // Read explorer fw image from pnor PNOR::SectionInfo_t l_pnorSectionInfo; rawImageInfo_t l_imageInfo; #ifdef CONFIG_SECUREBOOT l_err = PNOR::loadSecureSection(PNOR::OCMBFW); if(l_err) { TRACFCOMP(g_trac_expupd, ERR_MRK "updateAll: Failed to load OCMBFW section" " from PNOR!"); l_err->collectTrace(EXPUPD_COMP_NAME); // Create IStep error log and cross reference to error that occurred o_stepError.addErrorDetails( l_err ); // Commit Error errlCommit( l_err, EXPUPD_COMP_ID ); break; } #endif //CONFIG_SECUREBOOT l_imageLoaded = true; // get address and size of packaged image l_err = PNOR::getSectionInfo(PNOR::OCMBFW, l_pnorSectionInfo); if(l_err) { TRACFCOMP(g_trac_expupd, ERR_MRK "updateAll: Failure in getSectionInfo()"); l_err->collectTrace(EXPUPD_COMP_NAME); // Create IStep error log and cross reference to error that occurred o_stepError.addErrorDetails( l_err ); // Commit Error errlCommit( l_err, EXPUPD_COMP_ID ); break; } // Verify the header and retrieve address, size and // SHA512 hash of unpackaged image l_err = ocmbFwValidateImage( l_pnorSectionInfo.vaddr, l_pnorSectionInfo.secureProtectedPayloadSize, l_imageInfo); if(l_err) { TRACFCOMP(g_trac_expupd, ERR_MRK "updateAll: Failure in expupdValidateImage"); l_err->collectTrace(EXPUPD_COMP_NAME); // Create IStep error log and cross reference to error that occurred o_stepError.addErrorDetails( l_err ); // Commit Error errlCommit( l_err, EXPUPD_COMP_ID ); break; } // For each explorer chip, compare flash hash with PNOR hash and // create a list of explorer chips with differing hash values. TARGETING::TargetHandleList l_flashUpdateList; for(const auto & l_ocmbTarget : l_ocmbTargetList) { sha512regs_t l_regs; //skip all gemini ocmb chips (not updateable) if(l_ocmbTarget->getAttr<TARGETING::ATTR_CHIP_ID>() == POWER_CHIPID::GEMINI_16) { TRACFCOMP(g_trac_expupd, "updateAll: skipping update of gemini OCMB 0x%08x", TARGETING::get_huid(l_ocmbTarget)); continue; } //retrieve the SHA512 hash for the currently flashed image. l_err = getFlashedHash(l_ocmbTarget, l_regs); if(l_err) { TRACFCOMP(g_trac_expupd, ERR_MRK "updateAll: Failure in getFlashedHash(huid = 0x%08x)", TARGETING::get_huid(l_ocmbTarget)); l_err->collectTrace(EXPUPD_COMP_NAME); // Create IStep error log and cross reference to error // that occurred o_stepError.addErrorDetails(l_err); errlCommit(l_err, EXPUPD_COMP_ID); //Don't stop on error, go to next target. continue; } // Trace the hash and image ID values TRACFCOMP(g_trac_expupd, "updateAll: OCMB 0x%08x image ID=0x%08x", TARGETING::get_huid(l_ocmbTarget), l_regs.imageId); TRACFBIN(g_trac_expupd, "SHA512 HASH FROM EXPLORER", l_regs.sha512Hash, HEADER_SHA512_SIZE); //Compare hashes. If different, add to list for update. if(memcmp(l_regs.sha512Hash, l_imageInfo.imageSHA512HashPtr, HEADER_SHA512_SIZE)) { TRACFCOMP(g_trac_expupd, "updateAll: SHA512 hash mismatch on ocmb[0x%08x]", TARGETING::get_huid(l_ocmbTarget)); //add target to our list of targets needing an update l_flashUpdateList.push_back(l_ocmbTarget); } else { TRACFCOMP(g_trac_expupd, "updateAll: SHA512 hash for ocmb[0x%08x]" " matches SHA512 hash of PNOR image.", TARGETING::get_huid(l_ocmbTarget)); } } TRACFCOMP(g_trac_expupd, "updateAll: updating flash for %d OCMB chips", l_flashUpdateList.size()); // update each explorer in the list of chips needing updates for(const auto & l_ocmb : l_flashUpdateList) { TRACFCOMP(g_trac_expupd, "updateAll: updating OCMB 0x%08x", TARGETING::get_huid(l_ocmb)); fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>l_fapi2Target(l_ocmb); // reset watchdog for each ocmb as this function can be very slow INITSERVICE::sendProgressCode(); // Invoke procedure FAPI_INVOKE_HWP(l_err, exp_fw_update, l_fapi2Target, l_imageInfo.imagePtr, l_imageInfo.imageSize); if (l_err) { TRACFCOMP(g_trac_expupd, "Error from exp_fw_update for OCMB 0x%08x", TARGETING::get_huid(l_ocmb)); l_err->collectTrace(EXPUPD_COMP_NAME); // Create IStep error log and cross reference to error // that occurred o_stepError.addErrorDetails( l_err ); errlCommit(l_err, EXPUPD_COMP_ID); // Don't stop on error, go to next target. continue; } else { TRACFCOMP(g_trac_expupd, "updateAll: successfully updated OCMB 0x%08x", TARGETING::get_huid(l_ocmb)); // Request reboot for new firmware to be used l_rebootRequired = true; } } }while(0); // unload explorer fw image if(l_imageLoaded) { #ifdef CONFIG_SECUREBOOT l_err = PNOR::unloadSecureSection(PNOR::OCMBFW); if(l_err) { TRACFCOMP(g_trac_expupd, ERR_MRK "updateAll: Failed to unload OCMBFW"); l_err->collectTrace(EXPUPD_COMP_NAME); // Create IStep error log and cross reference to error that occurred o_stepError.addErrorDetails( l_err ); // Commit Error errlCommit( l_err, EXPUPD_COMP_ID ); } #endif //CONFIG_SECUREBOOT } // force reboot if any updates were successful if(l_rebootRequired) { TRACFCOMP(g_trac_expupd, "updateAll: OCMB chip(s) was updated. Requesting reboot..."); Target* l_pTopLevel = nullptr; targetService().getTopLevelTarget( l_pTopLevel ); assert(l_pTopLevel, "expupd::updateAll: no TopLevelTarget"); auto l_reconfigAttr = l_pTopLevel->getAttr<TARGETING::ATTR_RECONFIGURE_LOOP>(); l_reconfigAttr |= RECONFIGURE_LOOP_OCMB_FW_UPDATE; l_pTopLevel->setAttr<TARGETING::ATTR_RECONFIGURE_LOOP>(l_reconfigAttr); } else { TRACFCOMP(g_trac_expupd, "updateAll: No OCMB chips were updated"); } TRACFCOMP(g_trac_expupd, EXIT_MRK"updateAll()"); }
/* * @brief Send esel data to bmc */ void send_esel(eselInitData * i_data, errlHndl_t &o_err, IPMI::completion_code &o_cc) { IPMI_TRAC(ENTER_MRK "send_esel"); uint8_t* data = NULL; size_t len = 0; uint8_t esel_recordID[2] = {0,0}; uint8_t sel_recordID[2] = {0,0}; do{ const size_t l_eSELlen = i_data->dataSize; if (l_eSELlen == 0) { IPMI_TRAC(INFO_MRK "no eSEL data present, skipping to SEL"); // sending sensor SELs only, not the eSEL break; } uint8_t reserveID[2] = {0,0}; // we need to send down the extended sel data (eSEL), which is // longer than the protocol buffer, so we need to do a reservation and // call the AMI partial_add_esel command multiple times // put a reservation on the SEL Device since we're doing a partial_add len = 0; delete [] data; data = NULL; o_cc = IPMI::CC_UNKBAD; o_err = IPMI::sendrecv(IPMI::reserve_sel(),o_cc,len,data); if(o_err) { IPMI_TRAC(ERR_MRK "error from reserve_sel"); break; } if(o_cc != IPMI::CC_OK) { IPMI_TRAC(ERR_MRK "Failed to reserve_sel, o_cc %02x",o_cc); break; } storeReserveRecord(reserveID,data); // first send down the SEL Event Record data size_t eSELindex = 0; uint8_t l_lastEntry = 0; len = PARTIAL_ADD_ESEL_REQ + sizeof(selRecord); delete [] data; data = new uint8_t[len]; // fill in the partial_add_esel request (command) data createPartialAddHeader(reserveID,esel_recordID,eSELindex,l_lastEntry,data); // copy in the SEL event record data memcpy(&data[PARTIAL_ADD_ESEL_REQ], i_data->eSel, sizeof(selRecord)); // update to make this what AMI eSEL wants data[PARTIAL_ADD_ESEL_REQ + offsetof(selRecord,record_type)] = record_type_ami_esel; data[PARTIAL_ADD_ESEL_REQ + offsetof(selRecord,event_data1)] = event_data1_ami; o_cc = IPMI::CC_UNKBAD; TRACFBIN( g_trac_ipmi, INFO_MRK"1st partial_add_esel:", data, len); o_err = IPMI::sendrecv(IPMI::partial_add_esel(),o_cc,len,data); if(o_err) { IPMI_TRAC(ERR_MRK "error from first partial_add_esel"); break; } // as long as we continue to get CC_OK, the reserve sel is good. // if the reservation is lost (ie, because something else tried to // create a SEL) then the BMC just discards all this data. the // errorlog will still be in PNOR and won't get ACKed, so it'll get // resent on the next IPL. if (o_cc != IPMI::CC_OK) { IPMI_TRAC(ERR_MRK "failed first partial_add_esel, o_cc %02x, eSELindex %02x", o_cc, eSELindex); break; } // BMC returns the recordID, it's always the same (unless // there's a major BMC bug...) storeReserveRecord(esel_recordID,data); // now send down the eSEL data in chunks. const size_t l_maxBuffer = IPMI::max_buffer(); while(eSELindex<l_eSELlen) { //if the index + the maximum buffer is less than what we still //have left in the eSEL, this is not the last entry (data[6] = 0) //otherwise, it is and data[6] = 1 if(eSELindex + (l_maxBuffer - PARTIAL_ADD_ESEL_REQ) < l_eSELlen) { len = l_maxBuffer; l_lastEntry = 0x00; } else { len = l_eSELlen - eSELindex + PARTIAL_ADD_ESEL_REQ; l_lastEntry = 0x01; } delete [] data; data = new uint8_t[len]; // fill in the partial_add_esel request (command) data createPartialAddHeader(reserveID, esel_recordID, eSELindex + sizeof(selRecord), l_lastEntry, data); uint8_t dataCpyLen = len - PARTIAL_ADD_ESEL_REQ; memcpy(&data[PARTIAL_ADD_ESEL_REQ], &i_data->eSelExtra[eSELindex], dataCpyLen); // update the offset into the data eSELindex = eSELindex + dataCpyLen; o_cc = IPMI::CC_UNKBAD; TRACFBIN( g_trac_ipmi, INFO_MRK"partial_add_esel:", data, len); o_err = IPMI::sendrecv(IPMI::partial_add_esel(),o_cc,len,data); if(o_err) { IPMI_TRAC(ERR_MRK "error from partial_add_esel"); break; } // as long as we continue to get CC_OK, the reserve sel is good. // if the reservation is lost (ie, because something else tried to // create a SEL) then the BMC just discards all this data. the // errorlog will still be in PNOR and won't get ACKed, so it'll get // resent on the next IPL. if (o_cc != IPMI::CC_OK) { IPMI_TRAC(ERR_MRK "failed partial_add_esel, o_cc %02x, eSELindex %02x", o_cc, eSELindex); break; } // BMC returns the recordID, it's always the same (unless // there's a major BMC bug...) storeReserveRecord(esel_recordID,data); } // while eSELindex }while(0); // if eSEL wasn't created due to an error, we don't want to continue if (o_err == NULL) { // caller wants us to NOT create sensor SEL if ((i_data->eSel[offsetof(selRecord,sensor_type)] == SENSOR::INVALID_TYPE) && (i_data->eSel[offsetof(selRecord,sensor_number)] == TARGETING::UTIL::INVALID_IPMI_SENSOR) ) { IPMI_TRAC(INFO_MRK "Invalid sensor type/number - NOT sending sensor SELs"); } else { // if the eSEL wasn't created due to a bad completion code, we will // still try to send down a SEL that we create, which will contain // the eSEL recordID (if it was successful) if (data) { delete [] data; } len = sizeof(IPMISEL::selRecord); data = new uint8_t[len]; // copy in the SEL event record data memcpy(data, i_data->eSel, sizeof(IPMISEL::selRecord)); // copy the eSEL recordID (if it was created) into the extra data area // and mark the event_data1 to indicate this is OEM data data[offsetof(selRecord,event_data1)] |= 0xA0; data[offsetof(selRecord,event_data2)] = esel_recordID[1]; data[offsetof(selRecord,event_data3)] = esel_recordID[0]; // use local cc so that we don't corrupt the esel from above IPMI::completion_code l_cc = IPMI::CC_UNKBAD; TRACFBIN( g_trac_ipmi, INFO_MRK"add_sel:", data, len); o_err = IPMI::sendrecv(IPMI::add_sel(),l_cc,len,data); if(o_err) { IPMI_TRAC(ERR_MRK "error from add_sel"); } else if (l_cc != IPMI::CC_OK) { IPMI_TRAC(ERR_MRK "failed add_sel, l_cc %02x", l_cc); } else { // if CC_OK, then len=2 and data contains the recordID of the new SEL storeReserveRecord(sel_recordID,data); } } } if (data) { delete [] data; } IPMI_TRAC(EXIT_MRK "send_esel o_err=%.8X, o_cc=x%.2x, sel recID=x%x%x, esel recID=x%x%x", o_err ? o_err->plid() : NULL, o_cc, sel_recordID[1], sel_recordID[0], esel_recordID[1], esel_recordID[0]); return; } // send_esel