errlHndl_t xscomPerformOp(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_err = NULL; HMER l_hmer; mutex_t* l_XSComMutex = NULL; uint64_t l_addr = va_arg(i_args,uint64_t); do { // XSCOM operation sanity check l_err = xscomOpSanityCheck(i_opType, i_target, io_buffer, io_buflen, i_args); if (l_err) { break; } // Set to buffer len to 0 until successfully access io_buflen = 0; // Get the target chip's virtual address uint64_t* l_virtAddr = NULL; l_err = getTargetVirtualAddress(i_target, l_virtAddr); if (l_err) { break; } // Pin this thread to current CPU task_affinity_pin(); // Lock other XSCom in this same thread from running l_XSComMutex = mmio_xscom_mutex(); mutex_lock(l_XSComMutex); // this function will return an errorlog if bad status is detected on // the read or write. l_err = xScomDoOp(i_opType, l_virtAddr, l_addr, io_buffer, io_buflen, l_hmer); // If we got a scom error. if (l_err) { // Call XscomCollectFFDC.. collectXscomFFDC(i_target, l_virtAddr, l_err); // reset the scomEngine. resetScomEngine(i_target, l_virtAddr); // Add traces to errorlog.. l_err->collectTrace("XSCOM",1024); } else { // No error, set output buffer size. // Always 8 bytes for XSCOM, but we want to make it consistent // with all other device drivers io_buflen = XSCOM_BUFFER_SIZE; } // Unlock mutex_unlock(l_XSComMutex); // Done, un-pin task_affinity_unpin(); // FRU callouts use targeting so this must be after the // mutex is unlocked // Add Callouts to the errorlog if( l_err ) { PIB::addFruCallouts(i_target, l_hmer.mXSComStatus, l_addr, l_err); } } while (0); return l_err; }
errlHndl_t initiateDrtm() { SB_ENTER("initiateDrtm"); errlHndl_t pError = nullptr; // For DRTM, the thread has to be pinned to a core (and therefore pinned to // a chip) task_affinity_pin(); void* drtmPayloadVirtAddr = nullptr; do { const std::vector<SECUREBOOT::ProcSecurity> LLP { SECUREBOOT::ProcSecurity::LLPBit, }; const std::vector<SECUREBOOT::ProcSecurity> LLS { SECUREBOOT::ProcSecurity::LLSBit, }; // Determine which fabric group and chip this task is executing on and // create a filter to find the matching chip target auto cpuId = task_getcpuid(); auto groupId = PIR_t::groupFromPir(cpuId); auto chipId = PIR_t::chipFromPir(cpuId); TARGETING::PredicateAttrVal<TARGETING::ATTR_FABRIC_GROUP_ID> matchesGroup(groupId); TARGETING::PredicateAttrVal<TARGETING::ATTR_FABRIC_CHIP_ID> matchesChip(chipId); TARGETING::PredicatePostfixExpr matchesGroupAndChip; matchesGroupAndChip.push(&matchesGroup).push(&matchesChip).And(); // Get all the functional proc chips and find the chip we're running on TARGETING::TargetHandleList funcProcChips; TARGETING::getAllChips(funcProcChips, TARGETING::TYPE_PROC); if(funcProcChips.empty()) { // TODO: RTC 167205: GA error handling assert(false,"initiateDrtm: BUG! Functional proc chips is empty, " "yet this code is running on a functional chip!"); break; } // NOTE: std::find_if requires predicates to be copy constructable, but // predicates are not; hence use a wrapper lambda function to bypass // that limitation auto pMatch = std::find_if(funcProcChips.begin(),funcProcChips.end(), [&matchesGroupAndChip] ( TARGETING::Target* pTarget ) { return matchesGroupAndChip(pTarget); } ); if(pMatch == funcProcChips.end()) { // TODO: RTC 167205: GA error handling assert(false, "initiateDrtm: BUG! No functional chip found " "to be running this code"); break; } // Move the matching target to the end of the list. // NOTE: If reverse iterators were supported, we could have verified the // last element of the container is not the match, and done a // std::iter_swap of the match and the last element TARGETING::Target* const pMatchTarget = *pMatch; funcProcChips.erase(pMatch); funcProcChips.push_back(pMatchTarget); // Map to the DRTM payload area in mainstore const uint32_t drtmPayloadPhysAddrMb = DRTM_RIT_PAYLOAD_PHYS_ADDR_MB; drtmPayloadVirtAddr = mm_block_map( reinterpret_cast<void*>(drtmPayloadPhysAddrMb*BYTES_PER_MEGABYTE), PAGESIZE); if(drtmPayloadVirtAddr == nullptr) { // TODO: RTC 167205: GA error handling assert(false, "initiateDrtm: BUG! Failed in call to mm_block_map " "to map the DRTM payload."); break; } // Copy the DRTM payload to the DRTM payload area memcpy( reinterpret_cast<uint32_t*>(drtmPayloadVirtAddr), DRTM_RIT_PAYLOAD, sizeof(DRTM_RIT_PAYLOAD)); // The required generic sequencing to initiate DRTM is as follows: // 1) Initiating task must pin itself to a core (to ensure it // will not be accidentally queisced by SBE) // 2) It must set the DRTM payload information in the master processor // mailbox scratch registers (registers 7 and 8) before it goes // offline // 3) It must determine the processor it's currently running on // 4) It must set the late launch bit (LL) on all other processors // 4a) If the given processor is an active master, it must set // late launch primary (LLP) bit // 4b) Otherwise it must set late launch secondary (LLS) bit // 5) Finally, it must its own processor's LL bit last, according to the // rules of step 4. for(auto &pFuncProc :funcProcChips) { const auto procMasterType = pFuncProc->getAttr< TARGETING::ATTR_PROC_MASTER_TYPE>(); // If master chip, set the DRTM payload address and validity if(procMasterType == TARGETING::PROC_MASTER_TYPE_ACTING_MASTER) { (void)setDrtmPayloadPhysAddrMb(drtmPayloadPhysAddrMb); } pError = SECUREBOOT::setSecuritySwitchBits(procMasterType == TARGETING::PROC_MASTER_TYPE_ACTING_MASTER ? LLP : LLS, pFuncProc); if(pError) { SB_ERR("initiateDrtm: setSecuritySwitchBits() failed for proc " "= 0x%08X. Tried to set LLP or LLS.", get_huid(pFuncProc)); break; } } if(pError) { break; } SB_INF("initiateDrtm: SBE should eventually quiesce all cores; until " "then, endlessly yield the task"); while(1) { task_yield(); } } while(0); // If we -do- come back from this function (on error path only), then we // should unpin task_affinity_unpin(); if(drtmPayloadVirtAddr) { auto rc = mm_block_unmap(const_cast<void*>(drtmPayloadVirtAddr)); if(rc != 0) { // TODO: RTC 167205: GA error handling assert(false,"initiateDrtm: BUG! mm_block_unmap failed for virtual " "address 0x%16llX.", drtmPayloadVirtAddr); } } if(pError) { SB_ERR("initiateDrtm: plid=0x%08X, eid=0x%08X, reason=0x%04X", ERRL_GETPLID_SAFE(pError), ERRL_GETEID_SAFE(pError), ERRL_GETRC_SAFE(pError)); } SB_EXIT("initiateDrtm"); return pError; }