/** * @brief Constructor */ MvpdFacade::MvpdFacade() : IpVpdFacade(MVPD::SECTION_SIZE, MVPD::MAX_SECTIONS, MVPD::mvpdRecords, (sizeof(MVPD::mvpdRecords)/sizeof(MVPD::mvpdRecords[0])), MVPD::mvpdKeywords, (sizeof(MVPD::mvpdKeywords)/sizeof(MVPD::mvpdKeywords[0])), PNOR::MODULE_VPD, MVPD::g_mutex, VPD::VPD_WRITE_PROC) { TRACUCOMP(g_trac_vpd, "MvpdFacade::MvpdFacade> " ); #ifdef CONFIG_MVPD_READ_FROM_PNOR iv_configInfo.vpdReadPNOR = true; #else iv_configInfo.vpdReadPNOR = false; #endif #ifdef CONFIG_MVPD_READ_FROM_HW iv_configInfo.vpdReadHW = true; #else iv_configInfo.vpdReadHW = false; #endif #ifdef CONFIG_MVPD_WRITE_TO_PNOR iv_configInfo.vpdWritePNOR = true; #else iv_configInfo.vpdWritePNOR = false; #endif #ifdef CONFIG_MVPD_WRITE_TO_HW iv_configInfo.vpdWriteHW = true; #else iv_configInfo.vpdWriteHW = false; #endif }
/** * @brief Constructor */ CvpdFacade::CvpdFacade() : IpVpdFacade(CVPD::SECTION_SIZE, CVPD::MAX_SECTIONS, CVPD::cvpdRecords, (sizeof(CVPD::cvpdRecords)/sizeof(CVPD::cvpdRecords[0])), CVPD::cvpdKeywords, (sizeof(CVPD::cvpdKeywords)/sizeof(CVPD::cvpdKeywords[0])), PNOR::CENTAUR_VPD, CVPD::g_mutex, VPD::VPD_WRITE_MEMBUF) { TRACUCOMP(g_trac_vpd, "CvpdFacade::CvpdFacade> " ); #ifdef CONFIG_MEMVPD_READ_FROM_PNOR iv_configInfo.vpdReadPNOR = true; #else iv_configInfo.vpdReadPNOR = false; #endif #ifdef CONFIG_MEMVPD_READ_FROM_HW iv_configInfo.vpdReadHW = true; #else iv_configInfo.vpdReadHW = false; #endif #ifdef CONFIG_MEMVPD_WRITE_TO_PNOR iv_configInfo.vpdWritePNOR = true; #else iv_configInfo.vpdWritePNOR = false; #endif #ifdef CONFIG_MEMVPD_WRITE_TO_HW iv_configInfo.vpdWriteHW = true; #else iv_configInfo.vpdWriteHW = false; #endif }
/** * @brief Constructor * Planar VPD is included in the Centaur PNOR section. * Including with Centaur vpd minimizes the number of PNOR sections. */ DvpdFacade::DvpdFacade() : IpVpdFacade(DVPD::dvpdRecords, (sizeof(DVPD::dvpdRecords)/sizeof(DVPD::dvpdRecords[0])), DVPD::dvpdKeywords, (sizeof(DVPD::dvpdKeywords)/sizeof(DVPD::dvpdKeywords[0])), PNOR::CENTAUR_VPD, // note use of CVPD DVPD::g_mutex, VPD::VPD_WRITE_MCS) // Direct access memory { TRACUCOMP(g_trac_vpd, "DvpdFacade::DvpdFacade> " ); #ifdef CONFIG_MEMVPD_READ_FROM_PNOR iv_configInfo.vpdReadPNOR = true; #else iv_configInfo.vpdReadPNOR = false; #endif #ifdef CONFIG_MEMVPD_READ_FROM_HW iv_configInfo.vpdReadHW = true; #else iv_configInfo.vpdReadHW = false; #endif #ifdef CONFIG_MEMVPD_WRITE_TO_PNOR iv_configInfo.vpdWritePNOR = true; #else iv_configInfo.vpdWritePNOR = false; #endif #ifdef CONFIG_MEMVPD_WRITE_TO_HW iv_configInfo.vpdWriteHW = true; #else iv_configInfo.vpdWriteHW = false; #endif iv_vpdSectionSize = DVPD::SECTION_SIZE; iv_vpdMaxSections = DVPD::MAX_SECTIONS; }
/** * STATIC * @brief Static Initializer */ void PnorRP::init( errlHndl_t &io_rtaskRetErrl ) { TRACUCOMP(g_trac_pnor, "PnorRP::init> " ); uint64_t rc = 0; errlHndl_t l_errl = NULL; if( Singleton<PnorRP>::instance().didStartupFail(rc) ) { /*@ * @errortype ERRL_SEV_CRITICAL_SYS_TERM * @moduleid PNOR::MOD_PNORRP_DIDSTARTUPFAIL * @reasoncode PNOR::RC_BAD_STARTUP_RC * @userdata1 return code * @userdata2 0 * * @devdesc PNOR startup task returned an error. * @custdesc A problem occurred while accessing the boot flash. */ l_errl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_CRITICAL_SYS_TERM, PNOR::MOD_PNORRP_DIDSTARTUPFAIL, PNOR::RC_BAD_STARTUP_RC, rc, 0, true /*Add HB SW Callout*/ ); l_errl->collectTrace(PNOR_COMP_NAME); } io_rtaskRetErrl=l_errl; }
/** * @brief Convert a virtual address into the PNOR device address */ errlHndl_t PnorRP::computeDeviceAddr( void* i_vaddr, uint64_t& o_offset, uint64_t& o_chip, bool& o_ecc ) { errlHndl_t l_errhdl = NULL; o_offset = 0; o_chip = 99; uint64_t l_vaddr = (uint64_t)i_vaddr; // make sure this is one of our addresses if( !((l_vaddr >= BASE_VADDR) && (l_vaddr < LAST_VADDR)) ) { TRACFCOMP( g_trac_pnor, "PnorRP::computeDeviceAddr> Virtual Address outside known PNOR range : i_vaddr=%p", i_vaddr ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE * @reasoncode PNOR::RC_INVALID_ADDRESS * @userdata1 Virtual Address * @userdata2 Base PNOR Address * @devdesc PnorRP::computeDeviceAddr> Virtual Address outside * known PNOR range * @custdesc A problem occurred while accessing the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_COMPUTEDEVICEADDR, PNOR::RC_INVALID_ADDRESS, l_vaddr, BASE_VADDR, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); return l_errhdl; } // find the matching section PNOR::SectionId id = PNOR::INVALID_SECTION; l_errhdl = computeSection( l_vaddr, id ); if( l_errhdl ) { return l_errhdl; } // pull out the information we need to return from our global copy o_chip = iv_TOC[id].chip; o_ecc = (bool)(iv_TOC[id].integrity & FFS_INTEG_ECC_PROTECT); o_offset = l_vaddr - iv_TOC[id].virtAddr; //offset into section // for ECC we need to figure out where the ECC-enhanced offset is // before tacking on the offset to the section if( o_ecc ) { o_offset = (o_offset * 9) / 8; } // add on the offset of the section itself o_offset += iv_TOC[id].flashAddr; TRACUCOMP( g_trac_pnor, "< PnorRP::computeDeviceAddr: i_vaddr=%X, o_offset=0x%X, o_chip=%d", l_vaddr, o_offset, o_chip ); return l_errhdl; }
// ------------------------------------------------------------------ // Fake readPNOR - image is in memory // ------------------------------------------------------------------ errlHndl_t readPNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * readAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"RT fake readPNOR()" ); do { // fake getPnorAddr gets memory address of VPD err = getPnorAddr(i_pnorInfo, io_cachedAddr, i_mutex ); if(err) { break; } addr = io_cachedAddr; err = getVpdLocation( vpdLocation, i_target); if(err) { break; } // Add Offset for target vpd location addr += (vpdLocation * i_pnorInfo.segmentSize); // Add keyword offset addr += i_byteAddr; TRACUCOMP( g_trac_vpd, INFO_MRK"Address to read: 0x%08x", addr ); readAddr = reinterpret_cast<const char *>( addr ); memcpy( o_data, readAddr, i_numBytes ); } while(0); TRACSSCOMP( g_trac_vpd, EXIT_MRK"RT fake readPNOR()" ); return err; }
/** * @brief Sets up OCC Host data * * @param[in] i_occHostDataVirtAddr Virtual * address of current * proc's Host data area. * * @return errlHndl_t Error log Host data setup failed */ errlHndl_t loadHostDataToHomer(void* i_occHostDataVirtAddr) { TRACUCOMP( g_fapiTd, ENTER_MRK"loadHostDataToHomer(%p)", i_occHostDataVirtAddr); errlHndl_t l_errl = NULL; //Treat virtual address as starting pointer //for config struct HBOCC::occHostConfigDataArea_t * config_data = reinterpret_cast<HBOCC::occHostConfigDataArea_t *> (i_occHostDataVirtAddr); // Get top level system target TARGETING::TargetService & tS = TARGETING::targetService(); TARGETING::Target * sysTarget = NULL; tS.getTopLevelTarget( sysTarget ); assert( sysTarget != NULL ); uint32_t nestFreq = sysTarget->getAttr<ATTR_FREQ_PB>(); config_data->version = HBOCC::OccHostDataVersion; config_data->nestFrequency = nestFreq; // Figure out the interrupt type if( INITSERVICE::spBaseServicesEnabled() ) { config_data->interruptType = USE_FSI2HOST_MAILBOX; } else { config_data->interruptType = USE_PSIHB_COMPLEX; } TRACUCOMP( g_fapiTd, EXIT_MRK"loadHostDataToHomer"); return l_errl; }
/** * @brief Fetches OCC image from FSP and writes to * specified offset. * * @param[in] i_occVirtAddr Virtual * address where OCC image * should be loaded. * * @return errlHndl_t Error log image load failed */ errlHndl_t loadOCCImageToHomer(void* i_occVirtAddr) { TRACUCOMP( g_fapiTd, ENTER_MRK"loadOCCImageToHomer(%p)", i_occVirtAddr); errlHndl_t l_errl = NULL; size_t lidSize = 0; do { UtilLidMgr lidMgr(HBOCC::OCC_LIDID); l_errl = lidMgr.getLidSize(lidSize); if(l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadOCCImageToHomer: Error getting lid size. lidId=0x%.8x", OCC_LIDID); break; } l_errl = lidMgr.getLid(i_occVirtAddr, lidSize); if(l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadOCCImageToHomer: Error getting lid.. lidId=0x%.8x", OCC_LIDID); break; } }while(0); TRACUCOMP( g_fapiTd, EXIT_MRK"loadOCCImageToHomer"); return l_errl; }
// ------------------------------------------------------------------ // getVpdLocation // ------------------------------------------------------------------ errlHndl_t getVpdLocation ( int64_t & o_vpdLocation, TARGETING::Target * i_target ) { errlHndl_t err = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"getVpdLocation()" ); o_vpdLocation = i_target->getAttr<TARGETING::ATTR_VPD_REC_NUM>(); TRACUCOMP( g_trac_vpd, INFO_MRK"Using VPD location: %d", o_vpdLocation ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"getVpdLocation()" ); return err; }
const uint8_t* TPM2B_DIGEST_unmarshal(TPM2B_DIGEST* val, const uint8_t* i_tpmBuf, size_t* io_tpmBufSize) { i_tpmBuf = unmarshalChunk(i_tpmBuf, io_tpmBufSize, &val->size, sizeof(val->size)); if (NULL != i_tpmBuf && sizeof(TPMU_HA) < val->size) { TRACUCOMP( g_trac_trustedboot, "TPM2B_DIGEST::unmarshal invalid size (%d)", val->size); return NULL; } i_tpmBuf = unmarshalChunk(i_tpmBuf, io_tpmBufSize, val->buffer, val->size); return i_tpmBuf; }
/** * @brief Starts OCCs on all Processors in the node * This is intended to be used for AVP testing. * * @param[out] o_failedOccTarget: Pointer to the target failing * loadnStartAllOccs * @param[in] i_useSRAM: bool - use SRAM for OCC image, ie during IPL * true if during IPL, false if at end of IPL (default) * @return errlHndl_t Error log if OCC load failed */ errlHndl_t loadnStartAllOccs(TARGETING::Target *& o_failedOccTarget, bool i_useSRAM) { errlHndl_t l_errl = NULL; void* homerVirtAddrBase = NULL; uint64_t homerPhysAddrBase = VMM_HOMER_REGION_START_ADDR; bool winkle_loaded = false; TRACUCOMP( g_fapiTd, ENTER_MRK"loadnStartAllOccs(%d)", i_useSRAM); do { #ifndef __HOSTBOOT_RUNTIME //OCC requires the build_winkle_images library if ( !VFS::module_is_loaded( "libbuild_winkle_images.so" ) ) { l_errl = VFS::module_load( "libbuild_winkle_images.so" ); if ( l_errl ) { // load module returned with errl set TRACFCOMP( g_fapiTd,ERR_MRK"loadnStartAllOccs: Could not load build_winkle module" ); // break from do loop if error occured break; } winkle_loaded = true; } assert(VMM_HOMER_REGION_SIZE <= THIRTYTWO_GB, "loadnStartAllOccs: Unsupported HOMER Region size"); if (!i_useSRAM) { //If running Sapphire need to place this at the top of memory if(TARGETING::is_sapphire_load()) { homerPhysAddrBase = TARGETING::get_top_mem_addr(); assert (homerPhysAddrBase != 0, "loadnStartAllOccs: Top of memory was 0!"); homerPhysAddrBase -= VMM_ALL_HOMER_OCC_MEMORY_SIZE; } TRACFCOMP( g_fapiTd, "HOMER is at %.16X", homerPhysAddrBase ); //Map entire homer region into virtual memory homerVirtAddrBase = mm_block_map(reinterpret_cast<void*>(homerPhysAddrBase), VMM_HOMER_REGION_SIZE); TRACFCOMP( g_fapiTd, "HOMER virtaddrbase %.16X", homerVirtAddrBase ); } else { // malloc space big enough for all of OCC homerVirtAddrBase = (void *)malloc(1 * MEGABYTE); homerPhysAddrBase = mm_virt_to_phys(homerVirtAddrBase); } #endif if (i_useSRAM) { // OCC is going into L3 and SRAM so only need 1 prime and load // into the Master Proc TargetService & tS = targetService(); Target * sysTarget = NULL; tS.getTopLevelTarget( sysTarget ); assert( sysTarget != NULL ); Target* masterproc = NULL; tS.masterProcChipTargetHandle( masterproc ); /******* SETUP AND LOAD **************/ l_errl = primeAndLoadOcc (masterproc, homerVirtAddrBase, homerPhysAddrBase, i_useSRAM); if(l_errl) { o_failedOccTarget = masterproc; TRACFCOMP( g_fapiImpTd, ERR_MRK "loadnStartAllOccs:primeAndLoadOcc failed"); free(homerVirtAddrBase); break; } /********* START OCC *************/ l_errl = HBOCC::startOCC (masterproc, NULL, o_failedOccTarget); // it either started or errored; either way, free the memory free(homerVirtAddrBase); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadnStartAllOccs: startOCC failed"); break; } } else { TargetHandleList procChips; getAllChips(procChips, TYPE_PROC, true); if(procChips.size() == 0) { TRACFCOMP( g_fapiTd,INFO_MRK"loadnStartAllOccs: No processors found" ); //We'll never get this far in the IPL without any processors, // so just exit. break; } TRACUCOMP( g_fapiTd, INFO_MRK"loadnStartAllOccs: %d procs found", procChips.size()); TargetHandleList::iterator itr1 = procChips.begin(); //The OCC Procedures require processors within a DCM be //setup together. So, first checking if any proc has //DCM installed attribute set. If not, we can iterate //over the list in any order. //If DCM installed is set, we work under the assumption //that each nodeID is a DCM. So sort the list by NodeID //then call OCC Procedures on NodeID pairs. if(0 == (*itr1)->getAttr<ATTR_PROC_DCM_INSTALLED>()) { TRACUCOMP( g_fapiTd, INFO_MRK"loadnStartAllOccs: non-dcm path entered"); for (TargetHandleList::iterator itr = procChips.begin(); itr != procChips.end(); ++itr) { /******* SETUP AND LOAD **************/ l_errl = primeAndLoadOcc (*itr, homerVirtAddrBase, homerPhysAddrBase, i_useSRAM); if(l_errl) { o_failedOccTarget = *itr; TRACFCOMP( g_fapiImpTd, ERR_MRK "loadnStartAllOccs:primeAndLoadOcc failed"); break; } /********* START OCC *************/ l_errl = HBOCC::startOCC (*itr, NULL, o_failedOccTarget); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadnStartAllOccs: startOCC failed"); break; } } if (l_errl) { break; } } else { TRACUCOMP( g_fapiTd, INFO_MRK"loadnStartAllOccs: Following DCM Path"); std::sort(procChips.begin(), procChips.end(), orderByNodeAndPosition); TRACUCOMP( g_fapiTd, INFO_MRK"loadnStartAllOccs: procChips list sorted"); for (TargetHandleList::iterator itr = procChips.begin(); itr != procChips.end(); ++itr) { TRACUCOMP( g_fapiImpTd, INFO_MRK"loadnStartAllOccs: Insepcting first target" ); Target* targ0 = *itr; Target* targ1 = NULL; TRACUCOMP( g_fapiImpTd, INFO_MRK "loadnStartAllOccs: Cur target nodeID=%d", targ0->getAttr<ATTR_FABRIC_NODE_ID>()); //if the next target in the list is in the same node // they are on the same DCM, so bump itr forward // and update targ1 pointer if((itr+1) != procChips.end()) { TRACUCOMP( g_fapiImpTd, INFO_MRK "loadnStartAllOccs: n+1 target nodeID=%d", ((*(itr+1))->getAttr<ATTR_FABRIC_NODE_ID>()) ); if((targ0->getAttr<ATTR_FABRIC_NODE_ID>()) == ((*(itr+1))->getAttr<ATTR_FABRIC_NODE_ID>())) { itr++; targ1 = *itr; } } /********** Setup and load targ0 ***********/ l_errl = primeAndLoadOcc (targ0, homerVirtAddrBase, homerPhysAddrBase, i_useSRAM); if(l_errl) { o_failedOccTarget = targ0; TRACFCOMP( g_fapiImpTd, ERR_MRK "loadnStartAllOccs: " "primeAndLoadOcc failed on targ0"); break; } /*********** Setup and load targ1 **********/ l_errl = primeAndLoadOcc (targ1, homerVirtAddrBase, homerPhysAddrBase, i_useSRAM); if(l_errl) { o_failedOccTarget = targ1; TRACFCOMP( g_fapiImpTd, ERR_MRK "loadnStartAllOccs: " "primeAndLoadOcc failed on targ1"); break; } /*********** Start OCC *******************/ l_errl = HBOCC::startOCC (targ0, targ1, o_failedOccTarget); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK "loadnStartAllOccs: start failed"); break; } } if (l_errl) { break; } } } } while(0); errlHndl_t l_tmpErrl = NULL; //Unless HTMGT is in use, there are no further accesses to HOMER memory //required during the IPL #ifndef CONFIG_HTMGT if(homerVirtAddrBase) { int rc = 0; rc = mm_block_unmap(homerVirtAddrBase); if (rc != 0) { /*@ * @errortype * @moduleid fapi::MOD_OCC_LOAD_START_ALL_OCCS * @reasoncode fapi::RC_MM_UNMAP_ERR * @userdata1 Return Code * @userdata2 Unmap address * @devdesc mm_block_unmap() returns error * @custdesc A problem occurred during the IPL * of the system. */ l_tmpErrl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi::MOD_OCC_LOAD_START_ALL_OCCS, fapi::RC_MM_UNMAP_ERR, rc, reinterpret_cast<uint64_t> (homerVirtAddrBase)); if(l_tmpErrl) { if(l_errl) { errlCommit( l_tmpErrl, HWPF_COMP_ID ); } else { l_errl = l_tmpErrl; } } } } #endif //make sure we always unload the module if (winkle_loaded) { l_tmpErrl = VFS::module_unload( "libbuild_winkle_images.so" ); if ( l_tmpErrl ) { TRACFCOMP ( g_fapiTd,ERR_MRK "loadnStartAllOccs: Error unloading build_winkle module" ); if(l_errl) { errlCommit( l_tmpErrl, HWPF_COMP_ID ); } else { l_errl = l_tmpErrl; } } } TRACUCOMP( g_fapiTd, EXIT_MRK"loadnStartAllOccs" ); return l_errl; }
// ------------------------------------------------------------------ // writePNOR // ------------------------------------------------------------------ errlHndl_t writePNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * i_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * writeAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"writePNOR()" ); do { // Check if we have the PNOR addr cached. if( 0x0 == io_cachedAddr ) { err = getPnorAddr( i_pnorInfo, io_cachedAddr, i_mutex ); if( err ) { break; } } addr = io_cachedAddr; // Find vpd location of the target err = getVpdLocation( vpdLocation, i_target ); if( err ) { break; } // Offset cached address by vpd location multiplier addr += (vpdLocation * i_pnorInfo.segmentSize); // Now offset into that chunk of data by i_byteAddr addr += i_byteAddr; //TODO: Validate write is within bounds of appropriate PNOR // partition/section. RTC: 51807 TRACUCOMP( g_trac_vpd, INFO_MRK"Address to write: 0x%08x", addr ); // Write the data writeAddr = reinterpret_cast<const char*>( addr ); memcpy( (void*)(writeAddr), i_data, i_numBytes ); // @todo RTC:117042 - enable flush once PNOR writes supported // Flush the page to make sure it gets to the PNOR #if 0 int rc = mm_remove_pages( FLUSH, (void*)addr, i_numBytes ); if( rc ) { TRACFCOMP(g_trac_vpd,ERR_MRK"writePNOR() Error from mm_remove_pages, rc=%d",rc); /*@ * @errortype * @moduleid VPD_WRITE_PNOR * @reasoncode VPD_REMOVE_PAGES_FAIL * @userdata1 Requested Address * @userdata2 rc from mm_remove_pages * @devdesc writePNOR mm_remove_pages FLUSH failed */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD_WRITE_PNOR, VPD_REMOVE_PAGES_FAIL, addr, TO_UINT64(rc), true /*Add HB Software Callout*/ ); } #endif } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"writePNOR()" ); return err; }
// ------------------------------------------------------------------ // readPNOR // ------------------------------------------------------------------ errlHndl_t readPNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * o_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * readAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"readPNOR()" ); do { // Check if we have the PNOR addr cached. if( 0x0 == io_cachedAddr ) { err = getPnorAddr( i_pnorInfo, io_cachedAddr, i_mutex ); if( err ) { break; } } addr = io_cachedAddr; // Find vpd location of the target err = getVpdLocation( vpdLocation, i_target ); if( err ) { break; } // Offset cached address by vpd location multiplier addr += (vpdLocation * i_pnorInfo.segmentSize); // Now offset into that chunk of data by i_byteAddr addr += i_byteAddr; TRACUCOMP( g_trac_vpd, INFO_MRK"Address to read: 0x%08x", addr ); //TODO: Validate write is within bounds of appropriate PNOR // partition/section. RTC: 51807 // Pull the data readAddr = reinterpret_cast<const char*>( addr ); memcpy( o_data, readAddr, i_numBytes ); } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"readPNOR()" ); return err; }
/** * @brief Retrieve 1 page of data from the PNOR device */ errlHndl_t PnorRP::readFromDevice( uint64_t i_offset, uint64_t i_chip, bool i_ecc, void* o_dest, uint64_t& o_fatalError ) { TRACUCOMP(g_trac_pnor, "PnorRP::readFromDevice> i_offset=0x%X, i_chip=%d", i_offset, i_chip ); errlHndl_t l_errhdl = NULL; uint8_t* ecc_buffer = NULL; o_fatalError = 0; do { TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; // assume a single page void* data_to_read = o_dest; size_t read_size = PAGESIZE; // if we need to handle ECC we need to read more than 1 page if( i_ecc ) { ecc_buffer = new uint8_t[PAGESIZE_PLUS_ECC](); data_to_read = ecc_buffer; read_size = PAGESIZE_PLUS_ECC; } // get the data from the PNOR DD l_errhdl = DeviceFW::deviceRead(pnor_target, data_to_read, read_size, DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); if( l_errhdl ) { TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error from device : RC=%X", l_errhdl->reasonCode() ); break; } // remove the ECC data if( i_ecc ) { // remove the ECC and fix the original data if it is broken PNOR::ECC::eccStatus ecc_stat = PNOR::ECC::removeECC( reinterpret_cast<uint8_t*>(data_to_read), reinterpret_cast<uint8_t*>(o_dest), PAGESIZE ); // create an error if we couldn't correct things if( ecc_stat == PNOR::ECC::UNCORRECTABLE ) { TRACFCOMP( g_trac_pnor, "PnorRP::readFromDevice> Uncorrectable ECC error : chip=%d,offset=0x%.X", i_chip, i_offset ); // Need to shutdown here instead of creating an error log // because the bad page could be critical to the regular // error handling path and cause an infinite loop. // Also need to spawn a separate task to do the shutdown // so that the regular PNOR task can service the writes // that happen during shutdown. o_fatalError = PNOR::RC_ECC_UE; INITSERVICE::doShutdown( PNOR::RC_ECC_UE, true ); } // found an error so we need to fix something else if( ecc_stat != PNOR::ECC::CLEAN ) { TRACFCOMP( g_trac_pnor, "PnorRP::readFromDevice> Correctable ECC error : chip=%d, offset=0x%.X", i_chip, i_offset ); // need to write good data back to PNOR l_errhdl = DeviceFW::deviceWrite(pnor_target, data_to_read,//corrected data read_size, DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); if( l_errhdl ) { TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error writing corrected data back to device : RC=%X", l_errhdl->reasonCode() ); // we don't need to fail here since we can correct // it the next time we read it again, instead just // commit the log here errlCommit(l_errhdl,PNOR_COMP_ID); } // keep some stats here in case we want them someday //no need for mutex since only ever 1 thread accessing this iv_stats[i_offset/PAGESIZE].numCEs++; } } } while(0); if( ecc_buffer ) { delete[] ecc_buffer; } TRACUCOMP(g_trac_pnor, "< PnorRP::readFromDevice" ); return l_errhdl; }
/** * @brief Message receiver */ void PnorRP::waitForMessage() { TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage>" ); errlHndl_t l_errhdl = NULL; msg_t* message = NULL; uint8_t* user_addr = NULL; uint8_t* eff_addr = NULL; uint64_t dev_offset = 0; uint64_t chip_select = 0xF; bool needs_ecc = false; int rc = 0; uint64_t status_rc = 0; uint64_t fatal_error = 0; while(1) { status_rc = 0; TRACUCOMP(g_trac_pnor, "PnorRP::waitForMessage> waiting for message" ); message = msg_wait( iv_msgQ ); if( message ) { /* data[0] = virtual address requested * data[1] = address to place contents */ eff_addr = (uint8_t*)message->data[0]; user_addr = (uint8_t*)message->data[1]; //figure out the real pnor offset l_errhdl = computeDeviceAddr( eff_addr, dev_offset, chip_select, needs_ecc ); if( l_errhdl ) { status_rc = -EFAULT; /* Bad address */ } else { switch(message->type) { case( MSG_MM_RP_READ ): l_errhdl = readFromDevice( dev_offset, chip_select, needs_ecc, user_addr, fatal_error ); if( l_errhdl || ( 0 != fatal_error ) ) { status_rc = -EIO; /* I/O error */ } break; case( MSG_MM_RP_WRITE ): l_errhdl = writeToDevice( dev_offset, chip_select, needs_ecc, user_addr ); if( l_errhdl ) { status_rc = -EIO; /* I/O error */ } break; default: TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unrecognized message type : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE * @reasoncode PNOR::RC_INVALID_MESSAGE_TYPE * @userdata1 Message type * @userdata2 Requested Virtual Address * @devdesc PnorRP::waitForMessage> Unrecognized * message type * @custdesc A problem occurred while accessing * the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_WAITFORMESSAGE, PNOR::RC_INVALID_MESSAGE_TYPE, TO_UINT64(message->type), (uint64_t)eff_addr, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); status_rc = -EINVAL; /* Invalid argument */ } } if( !l_errhdl && msg_is_async(message) ) { TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unsupported Asynchronous Message : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE * @reasoncode PNOR::RC_INVALID_ASYNC_MESSAGE * @userdata1 Message type * @userdata2 Requested Virtual Address * @devdesc PnorRP::waitForMessage> Unrecognized message * type * @custdesc A problem occurred while accessing the boot * flash. */ l_errhdl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_WAITFORMESSAGE, PNOR::RC_INVALID_ASYNC_MESSAGE, TO_UINT64(message->type), (uint64_t)eff_addr, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); status_rc = -EINVAL; /* Invalid argument */ } if( l_errhdl ) { errlCommit(l_errhdl,PNOR_COMP_ID); } /* Expected Response: * data[0] = virtual address requested * data[1] = rc (0 or negative errno value) * extra_data = Specific reason code. */ message->data[1] = status_rc; message->extra_data = reinterpret_cast<void*>(fatal_error); rc = msg_respond( iv_msgQ, message ); if( rc ) { TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage> Error from msg_respond, giving up : rc=%d", rc ); break; } } } TRACFCOMP(g_trac_pnor, "< PnorRP::waitForMessage" ); }
/** * @brief Read the TOC and store section information */ errlHndl_t PnorRP::readTOC() { TRACUCOMP(g_trac_pnor, "PnorRP::readTOC>" ); errlHndl_t l_errhdl = NULL; uint8_t* tocBuffer = NULL; uint64_t fatal_error = 0; bool TOC_0_failed = false; do{ iv_TOC_used = 0; for (uint32_t cur_TOC = 0; cur_TOC < NUM_TOCS; ++cur_TOC) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC verifying TOC: %d",cur_TOC); uint64_t nextVAddr = BASE_VADDR; // Zero out my table for( size_t id = PNOR::FIRST_SECTION; id <= PNOR::NUM_SECTIONS; //include extra entry for error paths ++id ) { iv_TOC[id].id = (PNOR::SectionId)id; //everything else should default to zero } // Read TOC information from TOC 0 and then TOC 1 tocBuffer = new uint8_t[PAGESIZE]; if (cur_TOC == 0) { l_errhdl = readFromDevice( TOC_0_OFFSET, 0, false, tocBuffer, fatal_error ); } else if (cur_TOC == 1) { l_errhdl = readFromDevice( TOC_1_OFFSET, 0, false, tocBuffer, fatal_error ); } if( l_errhdl ) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC readFromDevice Failed."); break; } ffs_hdr* l_ffs_hdr = (ffs_hdr*) tocBuffer; // ffs entry check, 0 if checksums match if( PNOR::pnor_ffs_checksum(l_ffs_hdr, FFS_HDR_SIZE) != 0) { //@TODO - RTC:90780 - May need to handle this differently in SP-less config TRACFCOMP(g_trac_pnor, "PnorRP::readTOC pnor_ffs_checksum header checksums do not match."); if (cur_TOC == 0) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC TOC 0 failed header checksum"); TOC_0_failed = true; iv_TOC_used = 1; continue; } else if (cur_TOC == 1 && TOC_0_failed) { // Both TOC's failed TRACFCOMP(g_trac_pnor, "PnorRP::readTOC both TOC's are corrupted"); INITSERVICE::doShutdown( PNOR::RC_PARTITION_TABLE_INVALID); } else { // TOC 1 failed TRACFCOMP(g_trac_pnor, "PnorRP::readTOC TOC 1 failed header checksum"); break; } } // Only check header if on first TOC or the first TOC failed if (cur_TOC == 0 || TOC_0_failed) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC: FFS Block size = 0x%.8X, Partition Table Size = 0x%.8x, entry_count=%d", l_ffs_hdr->block_size, l_ffs_hdr->size, l_ffs_hdr->entry_count); uint64_t spaceUsed = (sizeof(ffs_entry))*l_ffs_hdr->entry_count; /* Checking FFS Header to make sure it looks valid */ bool header_good = true; if(l_ffs_hdr->magic != FFS_MAGIC) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: Invalid magic number in FFS header: 0x%.4X", l_ffs_hdr->magic); header_good = false; } else if(l_ffs_hdr->version != SUPPORTED_FFS_VERSION) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: Unsupported FFS Header version: 0x%.4X", l_ffs_hdr->version); header_good = false; } else if(l_ffs_hdr->entry_size != sizeof(ffs_entry)) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: Unexpected entry_size(0x%.8x) in FFS header: 0x%.4X", l_ffs_hdr->entry_size); header_good = false; } else if(l_ffs_hdr->entries == NULL) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: FFS Header pointer to entries is NULL."); header_good = false; } else if(l_ffs_hdr->block_size != PAGESIZE) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: Unsupported Block Size(0x%.4X). PNOR Blocks must be 4k", l_ffs_hdr->block_size); header_good = false; } else if(l_ffs_hdr->block_count == 0) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: Unsupported BLock COunt(0x%.4X). Device cannot be zero blocks in length.", l_ffs_hdr->block_count); header_good = false; } //Make sure all the entries fit in specified partition table size. else if(spaceUsed > ((l_ffs_hdr->block_size * l_ffs_hdr->size) - sizeof(ffs_hdr))) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: FFS Entries (0x%.16X) go past end of FFS Table.", spaceUsed); header_good = false; } if(!header_good) { //Shutdown if we detected a partition table issue for any reason if (TOC_0_failed) { INITSERVICE::doShutdown( PNOR::RC_PARTITION_TABLE_INVALID); } else { TOC_0_failed = true; } //Try TOC1 continue; } } ffs_hb_user_t* ffsUserData = NULL; //Walk through all the entries in the table and parse the data. for(uint32_t i=0; i<l_ffs_hdr->entry_count; i++) { ffs_entry* cur_entry = (&l_ffs_hdr->entries[i]); TRACUCOMP(g_trac_pnor, "PnorRP::readTOC: Entry %d, name=%s, pointer=0x%X", i, cur_entry->name, (uint64_t)cur_entry); uint32_t secId = PNOR::INVALID_SECTION; // ffs entry check, 0 if checksums match if( PNOR::pnor_ffs_checksum(cur_entry, FFS_ENTRY_SIZE) != 0) { //@TODO - RTC:90780 - May need to handle this differently in SP-less config TRACFCOMP(g_trac_pnor, "PnorRP::readTOC pnor_ffs_checksum entry checksums do not match."); if (cur_TOC == 0) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC TOC 0 entry checksum failed"); TOC_0_failed = true; iv_TOC_used = 1; break; } else if (cur_TOC == 1 && TOC_0_failed) { // Both TOC's failed TRACFCOMP(g_trac_pnor, "PnorRP::readTOC both TOC's are corrupted"); INITSERVICE::doShutdown( PNOR::RC_PARTITION_TABLE_INVALID); } else { // TOC 1 failed TRACFCOMP(g_trac_pnor, "PnorRP::readTOC TOC 1 entry checksum failed"); break; } } // Only set data if on first TOC or the first TOC failed if (cur_TOC == 0 || TOC_0_failed) { //Figure out section enum for(uint32_t eyeIndex=PNOR::TOC; eyeIndex < PNOR::NUM_SECTIONS; eyeIndex++) { if(strcmp(cv_EYECATCHER[eyeIndex], cur_entry->name) == 0) { secId = eyeIndex; TRACUCOMP(g_trac_pnor, "PnorRP::readTOC: sectionId=%d", secId); break; } } if(secId == PNOR::INVALID_SECTION) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC: Unrecognized Section name(%s), skipping", cur_entry->name); continue; } ffsUserData = (ffs_hb_user_t*)&(cur_entry->user); //size iv_TOC[secId].size = ((uint64_t)cur_entry->size)*PAGESIZE; //virtAddr iv_TOC[secId].virtAddr = nextVAddr; nextVAddr += iv_TOC[secId].size; //flashAddr iv_TOC[secId].flashAddr = ((uint64_t)cur_entry->base)*PAGESIZE; //chipSelect iv_TOC[secId].chip = ffsUserData->chip; //user data iv_TOC[secId].integrity = ffsUserData->dataInteg; iv_TOC[secId].version = ffsUserData->verCheck; iv_TOC[secId].misc = ffsUserData->miscFlags; TRACFCOMP(g_trac_pnor, "PnorRp::readTOC: User Data %s", cur_entry->name); if (iv_TOC[secId].integrity == FFS_INTEG_ECC_PROTECT) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC: ECC enabled for %s", cur_entry->name); iv_TOC[secId].size = ALIGN_PAGE_DOWN((iv_TOC[secId].size * 8 ) / 9); } // TODO RTC:96009 handle version header w/secureboot if (iv_TOC[secId].version == FFS_VERS_SHA512) { TRACFCOMP(g_trac_pnor, "PnorRP::readTOC: Incrementing Flash Address for SHA Header"); if (iv_TOC[secId].integrity == FFS_INTEG_ECC_PROTECT) { iv_TOC[secId].flashAddr += PAGESIZE_PLUS_ECC; } else { iv_TOC[secId].flashAddr += PAGESIZE; } } if((iv_TOC[secId].flashAddr + iv_TOC[secId].size) > (l_ffs_hdr->block_count*PAGESIZE)) { TRACFCOMP(g_trac_pnor, "E>PnorRP::readTOC: Partition(%s) at base address (0x%.8x) extends past end of flash device", cur_entry->name, iv_TOC[secId].flashAddr); INITSERVICE::doShutdown( PNOR::RC_PARTITION_TABLE_INVALID); } } } //keep these traces here until PNOR is rock-solid for(PNOR::SectionId tmpId = PNOR::FIRST_SECTION; tmpId < PNOR::NUM_SECTIONS; tmpId = (PNOR::SectionId) (tmpId + 1) ) { TRACFCOMP(g_trac_pnor, "%s: size=0x%.8X flash=0x%.8X virt=0x%.16X", cv_EYECATCHER[tmpId], iv_TOC[tmpId].size, iv_TOC[tmpId].flashAddr, iv_TOC[tmpId].virtAddr ); } } }while(0); if(tocBuffer != NULL) { TRACUCOMP(g_trac_pnor, "Deleting tocBuffer"); delete[] tocBuffer; } TRACUCOMP(g_trac_pnor, "< PnorRP::readTOC" ); return l_errhdl; }
/** * @brief Initialize the daemon */ void PnorRP::initDaemon() { TRACUCOMP(g_trac_pnor, "PnorRP::initDaemon> " ); errlHndl_t l_errhdl = NULL; do { // read the TOC in the PNOR to compute the sections l_errhdl = readTOC(); if( l_errhdl ) { break; } // create a message queue iv_msgQ = msg_q_create(); // create a Block, passing in the message queue int rc = mm_alloc_block( iv_msgQ, (void*) BASE_VADDR, TOTAL_SIZE ); if( rc ) { TRACFCOMP( g_trac_pnor, "PnorRP::initDaemon> Error from mm_alloc_block : rc=%d", rc ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_INITDAEMON * @reasoncode PNOR::RC_EXTERNAL_ERROR * @userdata1 Requested Address * @userdata2 rc from mm_alloc_block * @devdesc PnorRP::initDaemon> Error from mm_alloc_block * @custdesc A problem occurred while accessing the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_INITDAEMON, PNOR::RC_EXTERNAL_ERROR, TO_UINT64(BASE_VADDR), TO_UINT64(rc), true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); break; } //Register this memory range to be FLUSHed during a shutdown. INITSERVICE::registerBlock(reinterpret_cast<void*>(BASE_VADDR), TOTAL_SIZE,PNOR_PRIORITY); // Need to set permissions to R/W rc = mm_set_permission((void*) BASE_VADDR,TOTAL_SIZE, WRITABLE | WRITE_TRACKED); // start task to wait on the queue task_create( wait_for_message, NULL ); } while(0); if( l_errhdl ) { iv_startupRC = l_errhdl->reasonCode(); errlCommit(l_errhdl,PNOR_COMP_ID); } // call ErrlManager function - tell him that PNOR is ready! ERRORLOG::ErrlManager::errlResourceReady(ERRORLOG::PNOR); TRACUCOMP(g_trac_pnor, "< PnorRP::initDaemon" ); }
/** * @brief Static function wrapper to pass into task_create */ void* wait_for_message( void* unused ) { TRACUCOMP(g_trac_pnor, "wait_for_message> " ); Singleton<PnorRP>::instance().waitForMessage(); return NULL; }
// ------------------------------------------------------------------ // dimmPresenceDetect // ------------------------------------------------------------------ errlHndl_t dimmPresenceDetect( 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 err = NULL; bool present = false; size_t presentSz = sizeof(present); TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect() " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); do { // Check to be sure that the buffer is big enough. if( !(io_buflen >= sizeof(bool)) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Invalid Data Length: %d", io_buflen ); /*@ * @errortype * @reasoncode VPD::VPD_INSUFFICIENT_BUFFER_SIZE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> * @devdesc Buffer for checking Presence Detect * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, VPD::VPD_INSUFFICIENT_BUFFER_SIZE, TO_UINT64(io_buflen), 0x0, true /*Add HB Software Callout*/); err->collectTrace( "SPD", 256); break; } // Is the target present? #ifdef CONFIG_DJVPD_READ_FROM_HW // Check if the i2c master is present. // If it is not then no reason to check the DIMM which would // otherwise generate tons of FSI errors. // We can't just check if parent MCA or MBA // is functional because DIMM presence detect is called before // the parent MCS/MCA or MBA/MEMBUF is set as present/functional. bool l_i2cMasterPresent = false; do { // get eeprom vpd primary info TARGETING::EepromVpdPrimaryInfo eepromData; if( !(i_target-> tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> ( eepromData ) ) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error: no eeprom vpd primary info" ); break; } // find i2c master target TARGETING::TargetService& tS = TARGETING::targetService(); bool exists = false; tS.exists( eepromData.i2cMasterPath, exists ); if( !exists ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "i2cMasterPath attribute path doesn't exist"); break; } // Since it exists, convert to a target TARGETING::Target * l_i2cMasterTarget = tS.toTarget( eepromData.i2cMasterPath ); if( NULL == l_i2cMasterTarget ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "i2cMasterPath target is NULL"); break; } TRACSSCOMP( g_trac_spd, "dimmPresenceDetect() " "i2c master HUID 0x%X", TARGETING::get_huid(l_i2cMasterTarget)); // Check if present TARGETING::Target* masterProcTarget = NULL; TARGETING::targetService().masterProcChipTargetHandle( masterProcTarget ); // Master proc is taken as always present. Validate other targets. if (l_i2cMasterTarget != masterProcTarget) { l_i2cMasterPresent = FSI::isSlavePresent(l_i2cMasterTarget); if( !l_i2cMasterPresent ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "isSlavePresent failed"); break; } } l_i2cMasterPresent = true; } while (0); if (!l_i2cMasterPresent) { present = false; // Invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error invalidating SPD in PNOR" ); } break; } #endif present = spdPresent( i_target ); if( present == false ) { TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() " "Dimm was found to be NOT present." ); } else { TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() " "Dimm was found to be present." ); } #if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR) if( present ) { // Check if the VPD data in the PNOR matches the SEEPROM err = VPD::ensureCacheIsInSync( i_target ); if( err ) { present = false; TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error during ensureCacheIsInSync (SPD)" ); break; } } else { // SPD is not present, invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error invalidating SPD in PNOR" ); } } #endif if( present && !err ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { //populate serial and part number attributes SPD::setPartAndSerialNumberAttributes( i_target ); } // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute TARGETING::Target* l_sys = NULL; TARGETING::targetService().getTopLevelTarget(l_sys); TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD = l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>(); // If SPD clear is enabled then write 0's into magic word for // DIMM_BAD_DQ_DATA keyword // Note: If there's an error from performing the clearing, // just log the error and continue. if (l_clearSPD) { size_t l_size = 0; // Do a read to get the DIMM_BAD_DQ_DATA keyword size err = deviceRead(i_target, NULL, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error reading DIMM_BAD_DQ_DATA keyword size"); errlCommit( err, VPD_COMP_ID ); } else { // Clear the data TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size )); memset(l_data, 0, l_size); err = deviceWrite(i_target, l_data, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP(g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error trying to clear SPD on DIMM HUID 0x%X", TARGETING::get_huid(i_target)); errlCommit( err, VPD_COMP_ID ); } // Free the memory if (NULL != l_data) { free(l_data); } } } } // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; } while( 0 ); TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" ); return err; } // end dimmPresenceDetect
errlHndl_t fsiScomPerformOp(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; uint64_t l_scomAddr = va_arg(i_args,uint64_t); ioData6432 scratchData; uint32_t l_command = 0; uint32_t l_status = 0; bool need_unlock = false; size_t op_size = sizeof(uint32_t); mutex_t* l_mutex = NULL; do{ if( io_buflen != sizeof(uint64_t) ) { TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Invalid data length : io_buflen=%d", io_buflen ); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_LENGTH * @userdata1 SCOM Address * @userdata2 Data Length * @devdesc fsiScomPerformOp> Invalid data length (!= 8 bytes) * @custdesc A problem occurred during the IPL of the system: * Invalid data length for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_LENGTH, l_scomAddr, TO_UINT64(io_buflen)); l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_LOW ); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } if( (l_scomAddr & 0xFFFFFFFF80000000) != 0) { TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Address contains more than 31 bits : l_scomAddr=0x%.16X", l_scomAddr ); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_ADDRESS * @userdata1 SCOM Address * @userdata2 Target HUID * @devdesc fsiScomPerformOp> Address contains * more than 31 bits. * @custdesc A problem occurred during the IPL of the system: * Invalid address on a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_ADDRESS, l_scomAddr, TARGETING::get_huid(i_target)); l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_LOW ); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } l_command = static_cast<uint32_t>(l_scomAddr & 0x000000007FFFFFFF); // use the chip-specific mutex attribute l_mutex = i_target->getHbMutexAttr<TARGETING::ATTR_FSI_SCOM_MUTEX>(); if(i_opType == DeviceFW::WRITE) { memcpy(&(scratchData.data64), io_buffer, 8); TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp> Write(l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X)", l_scomAddr, scratchData.data32_0, scratchData.data32_1); // atomic section >> mutex_lock(l_mutex); need_unlock = true; //write bits 0-31 to data0 l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &scratchData.data32_0, op_size, DEVICE_FSI_ADDRESS(DATA0_REG)); if(l_err) { break; } //write bits 32-63 to data1 l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &scratchData.data32_1, op_size, DEVICE_FSI_ADDRESS(DATA1_REG)); if(l_err) { break; } //write to FSI2PIB command reg starts write operation //bit 0 high => write command l_command = 0x80000000 | l_command; l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(COMMAND_REG)); if(l_err) { break; } //check status reg to see result l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &l_status, op_size, DEVICE_FSI_ADDRESS(STATUS_REG)); if(l_err) { break; } // Check the status reg for errors if( (l_status & PIB_ERROR_BITS) // PCB/PIB Errors || (l_status & PIB_ABORT_BIT) ) // PIB Abort { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Write: PCB/PIB error received: l_status=0x%X)", l_status); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_WRITE_ERROR * @userdata1 SCOM Addr * @userdata2[00:31] Target HUID * @userdata2[32:63] SCOM Status Reg * @devdesc fsiScomPerformOp> Error returned * from SCOM Engine after write * @custdesc A problem occurred during the IPL of the system: * Error returned from SCOM engine after write. */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_WRITE_ERROR, l_scomAddr, TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), l_status)); // call common error handler to do callouts and recovery pib_error_handler( i_target, l_err, l_status, l_scomAddr ); //Grab the PIB2OPB Status reg for a XSCOM Block error if( (l_status & 0x00007000) == 0x00001000 ) //piberr=001 { //@todo: Switch to external FSI FFDC interfaces RTC:35064 TARGETING::Target* l_master = NULL; TARGETING::targetService(). masterProcChipTargetHandle(l_master); uint64_t scomdata = 0; size_t scomsize = sizeof(uint64_t); errlHndl_t l_err2 = DeviceFW::deviceOp( DeviceFW::READ, l_master, &scomdata, scomsize, DEVICE_XSCOM_ADDRESS(0x00020001)); if( l_err2 ) { delete l_err2; } else { TRACFCOMP( g_trac_fsiscom, "PIB2OPB Status = %.16X", scomdata ); } } break; } // atomic section << need_unlock = false; mutex_unlock(l_mutex); } else if(i_opType == DeviceFW::READ) { TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read(l_scomAddr=0x%.8X)", l_scomAddr); // atomic section >> mutex_lock(l_mutex); need_unlock = true; //write to FSI2PIB command reg starts read operation // bit 0 low -> read command l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(COMMAND_REG)); if(l_err) { break; } //check ststus reg to see result l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &l_status, op_size, DEVICE_FSI_ADDRESS(STATUS_REG)); if(l_err) { break; } // Check the status reg for errors if( (l_status & PIB_ERROR_BITS) // PCB/PIB Errors || (l_status & PIB_ABORT_BIT) ) // PIB Abort { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Read: PCB/PIB error received: l_status=0x%0.8X)", l_status); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_READ_ERROR * @userdata1 SCOM Addr * @userdata2[00:31] Target HUID * @userdata2[32:63] SCOM Status Reg * @devdesc fsiScomPerformOp> Error returned from SCOM Engine after read. * @custdesc A problem occurred during the IPL of the system: * Error returned from SCOM engine after read. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_READ_ERROR, l_scomAddr, TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), l_status)); // call common error handler to do callouts and recovery pib_error_handler( i_target, l_err, l_status, l_scomAddr ); break; } //read bits 0-31 to data0 l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &scratchData.data32_0, op_size, DEVICE_FSI_ADDRESS(DATA0_REG)); if(l_err) { break; } //read bits 32-63 to data1 l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &scratchData.data32_1, op_size, DEVICE_FSI_ADDRESS(DATA1_REG)); if(l_err) { break; } // atomic section << need_unlock = false; mutex_unlock(l_mutex); TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read: l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X", l_scomAddr, scratchData.data32_0, scratchData.data32_1); memcpy(io_buffer, &(scratchData.data64), 8); } else { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Unsupported Operation Type: i_opType=%d)", i_opType); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_OPTYPE * @userdata1[0:31] Operation Type (i_opType) : 0=READ, 1=WRITE * @userdata1[32:64] Input scom address * @userdata2 Target HUID * @devdesc fsiScomPerformOp> Unsupported Operation Type specified * @custdesc A problem occurred during the IPL of the system: * Unsupported SCOM operation type. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_OPTYPE, TWO_UINT32_TO_UINT64(i_opType, l_scomAddr), TARGETING::get_huid(i_target), true /*SW error*/); //Add this target to the FFDC ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } }while(0); if( need_unlock && l_mutex ) { mutex_unlock(l_mutex); } return l_err; }
/** * @brief Sets up OCC Host data */ errlHndl_t loadHostDataToHomer( TARGETING::Target* i_proc, void* i_occHostDataVirtAddr) { TRACUCOMP( g_fapiTd, ENTER_MRK"loadHostDataToHomer(%p)", i_occHostDataVirtAddr); errlHndl_t l_errl = NULL; //Treat virtual address as starting pointer //for config struct HBOCC::occHostConfigDataArea_t * config_data = reinterpret_cast<HBOCC::occHostConfigDataArea_t *> (i_occHostDataVirtAddr); // Get top level system target TARGETING::TargetService & tS = TARGETING::targetService(); TARGETING::Target * sysTarget = NULL; tS.getTopLevelTarget( sysTarget ); assert( sysTarget != NULL ); uint32_t nestFreq = sysTarget->getAttr<ATTR_FREQ_PB>(); config_data->version = HBOCC::OccHostDataVersion; config_data->nestFrequency = nestFreq; // Figure out the interrupt type if( INITSERVICE::spBaseServicesEnabled() ) { config_data->interruptType = USE_FSI2HOST_MAILBOX; } else { config_data->interruptType = USE_PSIHB_COMPLEX; } #ifdef CONFIG_ENABLE_CHECKSTOP_ANALYSIS // Figure out the FIR master TARGETING::Target* masterproc = NULL; tS.masterProcChipTargetHandle( masterproc ); if( masterproc == i_proc ) { config_data->firMaster = IS_FIR_MASTER; // TODO: RTC 124683 The ability to write the HOMER data // is currently not available at runtime. #ifndef __HOSTBOOT_RUNTIME l_errl = PRDF::writeHomerFirData( config_data->firdataConfig, sizeof(config_data->firdataConfig) ); #endif } else { config_data->firMaster = NOT_FIR_MASTER; } #else config_data->firMaster = 0; //force to an older version so we can support // older levels of OCC config_data->version = PRE_FIR_MASTER_VERSION; #endif TRACUCOMP( g_fapiTd, EXIT_MRK"loadHostDataToHomer"); return l_errl; }
// ------------------------------------------------------------------ // dimmPresenceDetect // ------------------------------------------------------------------ errlHndl_t dimmPresenceDetect( 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 err = NULL; bool present = false; size_t presentSz = sizeof(present); TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect()" ); do { // Check to be sure that the buffer is big enough. if( !(io_buflen >= sizeof(bool)) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() - Invalid Data Length: %d", io_buflen ); /*@ * @errortype * @reasoncode VPD::VPD_INSUFFICIENT_BUFFER_SIZE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> * @devdesc Buffer for checking Presence Detect * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, VPD::VPD_INSUFFICIENT_BUFFER_SIZE, TO_UINT64(io_buflen), 0x0, true /*Add HB Software Callout*/); err->collectTrace( "SPD", 256); break; } // Is the target present #ifdef CONFIG_DJVPD_READ_FROM_HW // Check if the parent MBA/MEMBUF is present. If it is not then // no reason to check the DIMM which would otherwise generate // tons of FSI errors. We can't just check if parent MBA // is functional because DIMM presence detect is called before // the parent MBA/MEMBUF is set as present/functional. TARGETING::TargetHandleList membufList; TARGETING::PredicateCTM membufPred( TARGETING::CLASS_CHIP, TARGETING::TYPE_MEMBUF ); TARGETING::targetService().getAssociated( membufList, i_target, TARGETING::TargetService::PARENT_BY_AFFINITY, TARGETING::TargetService::ALL, &membufPred); bool parentPresent = false; const TARGETING::TargetHandle_t membufTarget = *(membufList.begin()); err = deviceRead(membufTarget, &parentPresent, presentSz, DEVICE_PRESENT_ADDRESS()); if (err) { TRACFCOMP( g_trac_spd, "Error reading parent MEMBUF present: huid 0x%X DIMM huid 0x%X", TARGETING::get_huid(membufTarget), TARGETING::get_huid(i_target) ); break; } if (!parentPresent) { present = false; // Invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" ); } break; } #endif present = spdPresent( i_target ); if( present == false ) { TRACUCOMP( g_trac_spd, INFO_MRK"Dimm was found to be NOT present." ); } else { TRACUCOMP( g_trac_spd, INFO_MRK"Dimm was found to be present." ); } #if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR) if( present ) { // Check if the VPD data in the PNOR matches the SEEPROM err = VPD::ensureCacheIsInSync( i_target ); if( err ) { present = false; TRACFCOMP(g_trac_spd,ERR_MRK "dimmPresenceDetectt> Error during ensureCacheIsInSync (SPD)" ); break; } } else { // SPD is not present, invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" ); } } #endif if( present && !err ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { //populate serial and part number attributes SPD::setPartAndSerialNumberAttributes( i_target ); } // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute TARGETING::Target* l_sys = NULL; TARGETING::targetService().getTopLevelTarget(l_sys); TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD = l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>(); // If SPD clear is enabled then write 0's into magic word for // DIMM_BAD_DQ_DATA keyword // Note: If there's an error from performing the clearing, // just log the error and continue. if (l_clearSPD) { size_t l_size = 0; // Do a read to get the DIMM_BAD_DQ_DATA keyword size err = deviceRead(i_target, NULL, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP(g_trac_spd, "dimmPresenceDetect - " "Error reading DIMM_BAD_DQ_DATA keyword size"); errlCommit( err, VPD_COMP_ID ); } else { // Clear the data TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size )); memset(l_data, 0, l_size); err = deviceWrite(i_target, l_data, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP( g_trac_spd, "Error trying to clear SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); errlCommit( err, VPD_COMP_ID ); } // Free the memory if (NULL != l_data) { free(l_data); } } } } // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; } while( 0 ); TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" ); return err; } // end dimmPresenceDetect
/** * @brief Stops OCCs on all Processors in the node */ errlHndl_t stopAllOCCs() { TRACFCOMP( g_fapiTd,ENTER_MRK"stopAllOCCs" ); errlHndl_t l_errl = NULL; bool winkle_loaded = false; do { #ifndef __HOSTBOOT_RUNTIME //OCC requires the build_winkle_images library if ( !VFS::module_is_loaded( "libbuild_winkle_images.so" ) ) { l_errl = VFS::module_load( "libbuild_winkle_images.so" ); if ( l_errl ) { // load module returned with errl set TRACFCOMP( g_fapiTd,ERR_MRK"loadnStartAllOccs: Could not load build_winkle module" ); // break from do loop if error occured break; } winkle_loaded = true; } #endif TargetHandleList procChips; getAllChips(procChips, TYPE_PROC, true); if(procChips.size() == 0) { TRACFCOMP( g_fapiTd,INFO_MRK"loadnStartAllOccs: No processors found" ); //We'll never get this far in the IPL without any processors, // so just exit. break; } TRACFCOMP( g_fapiTd, INFO_MRK"loadnStartAllOccs: %d procs found", procChips.size()); //The OCC Procedures require processors within a DCM be //setup together. If DCM installed is set, we work under //the assumption that each nodeID is a DCM. So sort the //list by NodeID then call OCC Procedures on NodeID pairs. std::sort(procChips.begin(), procChips.end(), orderByNodeAndPosition); //The OCC master for the node must be reset last. For all //OP systems there is only a single OCC that can be the //master so it is safe to look at the MASTER_CAPABLE flag. Target* masterProc0 = NULL; Target* masterProc1 = NULL; TargetHandleList::iterator itr1 = procChips.begin(); if(0 == (*itr1)->getAttr<ATTR_PROC_DCM_INSTALLED>()) { TRACUCOMP( g_fapiTd, INFO_MRK"stopAllOCCs: non-dcm path entered"); for (TargetHandleList::iterator itr = procChips.begin(); itr != procChips.end(); ++itr) { TargetHandleList pOccs; getChildChiplets(pOccs, *itr, TYPE_OCC); if (pOccs.size() > 0) { if( pOccs[0]->getAttr<ATTR_OCC_MASTER_CAPABLE>() ) { masterProc0 = *itr; continue; } } l_errl = HBOCC::stopOCC( *itr, NULL ); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"stopAllOCCs: stop failed"); errlCommit (l_errl, HWPF_COMP_ID); // just commit and try the next chip } } if (l_errl) { break; } } else { TRACFCOMP( g_fapiTd, INFO_MRK"stopAllOCCs: Following DCM Path"); for (TargetHandleList::iterator itr = procChips.begin(); itr != procChips.end(); ++itr) { Target* targ0 = *itr; Target* targ1 = NULL; TRACFCOMP( g_fapiImpTd, INFO_MRK"stopAllOCCs: Cur target nodeID=%d", targ0->getAttr<ATTR_FABRIC_NODE_ID>()); //if the next target in the list is in the same node // they are on the same DCM, so bump itr forward // and update targ0 pointer if((itr+1) != procChips.end()) { TRACFCOMP( g_fapiImpTd, INFO_MRK"stopAllOCCs: n+1 target nodeID=%d", ((*(itr+1))->getAttr<ATTR_FABRIC_NODE_ID>())); if((targ0->getAttr<ATTR_FABRIC_NODE_ID>()) == ((*(itr+1))->getAttr<ATTR_FABRIC_NODE_ID>())) { //need to flip the numbers because we were reversed targ1 = targ0; itr++; targ0 = *itr; } } TargetHandleList pOccs; getChildChiplets(pOccs, targ0, TYPE_OCC); if (pOccs.size() > 0) { if( pOccs[0]->getAttr<ATTR_OCC_MASTER_CAPABLE>() ) { masterProc0 = targ0; masterProc1 = targ1; continue; } } l_errl = HBOCC::stopOCC( targ0, targ1 ); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"stopAllOCCs: stop failed"); errlCommit (l_errl, HWPF_COMP_ID); // just commit and try the next module } } if (l_errl) { break; } } //now do the master OCC if( masterProc0 ) { l_errl = HBOCC::stopOCC( masterProc0, masterProc1 ); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"stopAllOCCs: stop failed on master"); break; } } } while(0); //make sure we always unload the module if we loaded it if (winkle_loaded) { #ifndef __HOSTBOOT_RUNTIME errlHndl_t l_tmpErrl = VFS::module_unload( "libbuild_winkle_images.so" ); if ( l_tmpErrl ) { TRACFCOMP( g_fapiTd,ERR_MRK"stopAllOCCs: Error unloading build_winkle module" ); if(l_errl) { errlCommit( l_tmpErrl, HWPF_COMP_ID ); } else { l_errl = l_tmpErrl; } } #endif } TRACFCOMP( g_fapiTd,EXIT_MRK"stopAllOCCs" ); return l_errl; }
/** * @brief Execute procedures and steps necessary * to load OCC data in specified processor * * @param[in] i_target Target proc to load * @param[in] i_homerVirtAddrBase Virtual * address of current * proc's HOMER * @param[in] i_homerPhysAddrBase Physical * address of current * proc's HOMER * * @return errlHndl_t Error log image load failed */ errlHndl_t loadOCC(TARGETING::Target* i_target, uint64_t i_homerPhysAddr, uint64_t i_homerVirtAddr, uint64_t i_commonPhysAddr) { errlHndl_t l_errl = NULL; TRACFCOMP( g_fapiTd, ENTER_MRK"loadOCC" ); do{ // Remember where we put things if( i_target ) { i_target->setAttr<ATTR_HOMER_PHYS_ADDR>(i_homerPhysAddr); i_target->setAttr<ATTR_HOMER_VIRT_ADDR>(i_homerVirtAddr); } // cast OUR type of target to a FAPI type of target. const fapi::Target l_fapiTarg(fapi::TARGET_TYPE_PROC_CHIP, (const_cast<Target*>(i_target))); TRACFCOMP( g_fapiTd, "FapiTarget: %s",l_fapiTarg.toEcmdString()); //============================== //Setup for OCC Load //============================== // BAR0 is the Entire HOMER (start of HOMER contains OCC base Image) // Bar size is in MB, obtained value of 4MB from Greg Still TRACUCOMP( g_fapiImpTd, INFO_MRK"loadOCC: OCC Address: 0x%.8X, size=0x%.8X", i_homerPhysAddr, VMM_HOMER_INSTANCE_SIZE_IN_MB); FAPI_INVOKE_HWP( l_errl, p8_pba_bar_config, l_fapiTarg, 0, i_homerPhysAddr, VMM_HOMER_INSTANCE_SIZE_IN_MB, PBA_CMD_SCOPE_NODAL ); if (l_errl) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadOCC: Bar0 config failed!" ); l_errl->collectTrace(FAPI_TRACE_NAME,256); l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256); break; } // BAR1 is what OCC uses to talk to the Centaur // Bar size is in MB uint64_t centaur_addr = i_target->getAttr<ATTR_IBSCOM_PROC_BASE_ADDR>(); FAPI_INVOKE_HWP( l_errl, p8_pba_bar_config, l_fapiTarg, 1, //i_index centaur_addr, //i_pba_bar_addr (uint64_t)OCC_IBSCOM_RANGE_IN_MB, //i_pba_bar_size PBA_CMD_SCOPE_NODAL ); //i_pba_cmd_scope if ( l_errl ) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadOCC: Bar1 config failed!" ); l_errl->collectTrace(FAPI_TRACE_NAME,256); l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256); break; } // BAR3 is the OCC Common Area // Bar size is in MB, obtained value of 8MB from Tim Hallett TRACUCOMP( g_fapiImpTd, INFO_MRK"loadOCC: OCC Common Addr: 0x%.8X,size=0x%.8X", i_commonPhysAddr,VMM_OCC_COMMON_SIZE_IN_MB); FAPI_INVOKE_HWP( l_errl, p8_pba_bar_config, l_fapiTarg, 3, i_commonPhysAddr, VMM_OCC_COMMON_SIZE_IN_MB, PBA_CMD_SCOPE_NODAL ); if ( l_errl != NULL ) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loadOCC: Bar3 config failed!" ); l_errl->collectTrace(FAPI_TRACE_NAME,256); l_errl->collectTrace(FAPI_IMP_TRACE_NAME,256); break; } //============================== //Load the OCC HOMER image //============================== void* occVirt = reinterpret_cast<void *>(i_homerVirtAddr); l_errl = loadOCCImageToHomer( occVirt ); if( l_errl != NULL ) { TRACFCOMP(g_fapiImpTd, ERR_MRK"loadOCC: loadOCCImageToHomer failed!"); break; } }while(0); TRACFCOMP( g_fapiTd, EXIT_MRK"loadOCC"); return l_errl; }
const uint8_t* TCG_PCR_EVENT2_logUnmarshal(TCG_PCR_EVENT2* val, const uint8_t* i_tpmBuf, size_t i_bufSize, bool* o_err) { size_t size = 0; uint32_t* field32 = NULL; do { *o_err = false; // Ensure enough space for unmarshalled data if (sizeof(TCG_PCR_EVENT2) > i_bufSize) { *o_err = true; i_tpmBuf = NULL; break; } // pcrIndex size = sizeof(val->pcrIndex); field32 = (uint32_t*)(i_tpmBuf); val->pcrIndex = le32toh(*field32); // Ensure a valid pcr index if (val->pcrIndex > IMPLEMENTATION_PCR) { *o_err = true; i_tpmBuf = NULL; TRACUCOMP(g_trac_trustedboot,"ERROR> TCG_PCR_EVENT2:" "logUnmarshal() invalid pcrIndex %d", val->pcrIndex); break; } i_tpmBuf += size; // eventType size = sizeof(val->eventType); field32 = (uint32_t*)(i_tpmBuf); val->eventType = le32toh(*field32); // Ensure a valid event type if (val->eventType == 0 || val->eventType >= EV_INVALID) { *o_err = true; i_tpmBuf = NULL; TRACUCOMP(g_trac_trustedboot,"ERROR> TCG_PCR_EVENT2:" "logUnmarshal() invalid eventType %d", val->eventType); break; } i_tpmBuf += size; // TPML_DIGEST_VALUES i_tpmBuf = TPML_DIGEST_VALUES_logUnmarshal(&(val->digests), i_tpmBuf, o_err); if (i_tpmBuf == NULL) { break; } // TPM EVENT FIELD i_tpmBuf = TPM_EVENT_FIELD_logUnmarshal(&(val->event), i_tpmBuf, o_err); if (i_tpmBuf == NULL) { break; } } while(0); return i_tpmBuf; }
errlHndl_t primeAndLoadOcc (Target* i_target, void* i_homerVirtAddrBase, uint64_t i_homerPhysAddrBase, bool i_useSRAM) { errlHndl_t l_errl = NULL; TRACUCOMP( g_fapiTd, ENTER_MRK"primeAndLoadOcc(%d)", i_useSRAM); do { //============================== //Setup Addresses //============================== uint64_t occImgPaddr, occImgVaddr; uint64_t commonPhysAddr, homerHostVirtAddr; #ifndef __HOSTBOOT_RUNTIME const uint8_t procPos = i_target->getAttr<ATTR_POSITION>(); const uint64_t procOffset = (procPos * VMM_HOMER_INSTANCE_SIZE); if (i_useSRAM) { occImgVaddr = reinterpret_cast<uint64_t>(i_homerVirtAddrBase); } else { occImgVaddr = reinterpret_cast<uint64_t>(i_homerVirtAddrBase) + procOffset + HOMER_OFFSET_TO_OCC_IMG; } occImgPaddr = i_homerPhysAddrBase + procOffset + HOMER_OFFSET_TO_OCC_IMG; commonPhysAddr = i_homerPhysAddrBase + VMM_HOMER_REGION_SIZE; homerHostVirtAddr = reinterpret_cast<uint64_t> (i_homerVirtAddrBase) + procOffset + HOMER_OFFSET_TO_OCC_HOST_DATA; #else uint64_t homerPaddr = i_target->getAttr<ATTR_HOMER_PHYS_ADDR>(); uint64_t homerVaddr = i_target->getAttr<ATTR_HOMER_VIRT_ADDR>(); occImgPaddr = homerPaddr + HOMER_OFFSET_TO_OCC_IMG; occImgVaddr = homerVaddr + HOMER_OFFSET_TO_OCC_IMG; TARGETING::Target* sys = NULL; TARGETING::targetService().getTopLevelTarget(sys); commonPhysAddr = sys->getAttr<ATTR_OCC_COMMON_AREA_PHYS_ADDR>(); homerHostVirtAddr = homerVaddr + HOMER_OFFSET_TO_OCC_HOST_DATA; #endif //============================== // Load OCC //============================== l_errl = HBOCC::loadOCC(i_target, occImgPaddr, occImgVaddr, commonPhysAddr, i_useSRAM); if(l_errl != NULL) { TRACFCOMP( g_fapiImpTd, ERR_MRK"primeAndLoadOcc: loadOCC failed" ); break; } #ifdef CONFIG_ENABLE_CHECKSTOP_ANALYSIS #ifndef __HOSTBOOT_RUNTIME if (i_useSRAM) { //============================== //Setup host data area in SRAM //============================== l_errl = HBOCC::loadHostDataToSRAM(i_target, PRDF::MASTER_PROC_CORE); if( l_errl != NULL ) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loading Host Data Area failed!" ); break; } } else #endif #endif { //============================== //Setup host data area of HOMER; //============================== void* occHostVirt = reinterpret_cast<void*>(homerHostVirtAddr); l_errl = HBOCC::loadHostDataToHomer(i_target,occHostVirt); if( l_errl != NULL ) { TRACFCOMP( g_fapiImpTd, ERR_MRK"loading Host Data Area failed!" ); break; } } } while (0); TRACUCOMP( g_fapiTd, EXIT_MRK"primeAndLoadOcc" ); return l_errl; }