errlHndl_t RtPnor::writeToDevice( uint64_t i_procId, PNOR::SectionId i_section, uint64_t i_offset, size_t i_size, bool i_ecc, void* i_src ) { TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::writeToDevice: i_offset=0x%X, " "i_procId=%d sec=%d size=0x%X ecc=%d", i_offset, i_procId, i_section, i_size, i_ecc); errlHndl_t l_err = nullptr; uint8_t* l_eccBuffer = nullptr; do { void* l_dataToWrite = i_src; size_t l_writeSize = i_size; size_t l_writeSizePlusECC = (i_size * 9)/8; uint64_t l_offset = i_offset; // apply ECC to data if needed if( i_ecc ) { l_eccBuffer = new uint8_t[l_writeSizePlusECC]; PNOR::ECC::injectECC( reinterpret_cast<uint8_t*>(i_src), l_writeSize, reinterpret_cast<uint8_t*>(l_eccBuffer) ); l_dataToWrite = reinterpret_cast<void*>(l_eccBuffer); l_writeSize = l_writeSizePlusECC; l_offset = (i_offset * 9)/8; } const char* l_partitionName = SectionIdToString(i_section); if (g_hostInterfaces && g_hostInterfaces->pnor_write) { //make call into opal to write the data int l_rc = g_hostInterfaces->pnor_write(i_procId, l_partitionName,l_offset,l_dataToWrite,l_writeSize); if (l_rc != static_cast<int>(l_writeSize)) { TRACFCOMP(g_trac_pnor, "RtPnor::writeToDevice: pnor_write failed " "proc:%d, part:%s, offset:0x%X, size:0x%X, dataPt:0x%X," " rc:%d", i_procId, l_partitionName, l_offset, l_writeSize, l_dataToWrite, l_rc); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_WRITETODEVICE * @reasoncode PNOR::RC_PNOR_WRITE_FAILED * @userdata1[00:31] rc returned from pnor_write * @userdata1[32:63] section ID * @userdata2[00:31] offset within the section * @userdata2[32:63] size of data written in bytes * @devdesc g_hostInterfaces->pnor_write failed * @custdesc Error accessing system firmware flash */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_WRITETODEVICE, PNOR::RC_PNOR_WRITE_FAILED, TWO_UINT32_TO_UINT64(l_rc, i_section), TWO_UINT32_TO_UINT64(l_offset, l_writeSize), true); break; } else if( l_rc != static_cast<int>(l_writeSize) ) { TRACFCOMP( g_trac_pnor, "RtPnor::writeToDevice: only read 0x%X bytes, expecting 0x%X", l_rc, l_writeSize ); } } else { TRACFCOMP(g_trac_pnor,"RtPnor::writeToDevice: This version of" " OPAL does not support pnor_write"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_WRITETODEVICE * @reasoncode PNOR::RC_PNOR_WRITE_NOT_SUPPORTED * @devdesc g_hostInterfaces->pnor_write not supported * @custdesc Error accessing system firmware flash */ //@todo Add PNOR callout RTC:116145 l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_WRITETODEVICE, PNOR::RC_PNOR_WRITE_NOT_SUPPORTED, 0,0,true); break; } } while(0); if( l_eccBuffer ) { delete[] l_eccBuffer; } TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::writeToDevice" ); return l_err; }
errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section, PNOR::SectionInfo_t& o_info) { TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::getSectionInfo %d, initialized = %d", i_section, iv_initialized?1:0); errlHndl_t l_err = nullptr; do { // Check if Section is invalid or inhibited from loading at runtime. bool l_inhibited = false; bool l_secure = PNOR::isEnforcedSecureSection(i_section); bool l_preVerified = RUNTIME::isPreVerifiedSection(i_section); #ifdef CONFIG_SECUREBOOT l_inhibited = PNOR::isInhibitedSection(i_section); #endif if (i_section == PNOR::INVALID_SECTION || l_inhibited || l_secure || l_preVerified) { TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo: Invalid Section %d", static_cast<int>(i_section)); if (l_preVerified) { TRACFCOMP(g_trac_pnor, ERR_MRK"RtPnor::getSectionInfo: pre-verified sections should be loaded via Hostboot Reserved Memory "); } #ifdef CONFIG_SECUREBOOT else if (l_inhibited) { TRACFCOMP(g_trac_pnor, ERR_MRK"RtPnor::getSectionInfo: attribute overrides inhibited by secureboot"); } else if (l_secure) { TRACFCOMP(g_trac_pnor, ERR_MRK"RtPnor::getSectionInfo: secure sections should be loaded via Hostboot Reserved Memory"); } #endif /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_GETSECTIONINFO * @reasoncode PNOR::RC_RTPNOR_INVALID_SECTION * @userdata1 PNOR::SectionId * @userdata2[0:15] Inhibited by secureboot * @userdata2[16:31] Indication of a secure section * @userdata2[32:47] Indication of a pre-verified section * @userdata2[48:63] 0 * @devdesc invalid section passed to getSectionInfo or * section prohibited by secureboot */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_GETSECTIONINFO, PNOR::RC_RTPNOR_INVALID_SECTION, i_section, FOUR_UINT16_TO_UINT64(l_inhibited, l_secure, l_preVerified, 0), true); break; } //size of the section uint64_t l_sizeBytes = iv_TOC[i_section].size; if (l_sizeBytes == 0) { TRACFCOMP(g_trac_pnor,"RtPnor::getSectionInfo: Section %d" " size is 0", static_cast<int>(i_section)); // prevent hang between ErrlManager and rt_pnor assert(iv_initialized, "RtPnor::getSectionInfo: Section size 0 returned" " before completing PNOR initialization"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_GETSECTIONINFO * @reasoncode PNOR::RC_SECTION_SIZE_IS_ZERO * @userdata1 PNOR::SectionId * @devdesc section size is zero */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_GETSECTIONINFO, PNOR::RC_SECTION_SIZE_IS_ZERO, i_section, 0,true); break; } //ecc bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ? true : false; void* l_pWorking = nullptr; void* l_pClean = nullptr; //find the section in the map first if(iv_pnorMap.find(i_section) != iv_pnorMap.end()) { //get the addresses from the map PnorAddrPair_t l_addrPair = iv_pnorMap[i_section]; l_pWorking = l_addrPair.first; l_pClean = l_addrPair.second; } else { //malloc twice -- one working copy and one clean copy //So, we can diff and write only the dirty bytes l_pWorking = malloc(l_sizeBytes); l_pClean = malloc(l_sizeBytes); //offset = 0 : read the entire section l_err = readFromDevice(iv_masterProcId, i_section, 0, l_sizeBytes, l_ecc, l_pWorking); if(l_err) { TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo:readFromDevice" " failed"); break; } //copy data to another pointer to save a clean copy of data memcpy(l_pClean, l_pWorking, l_sizeBytes); //save it in the map iv_pnorMap [i_section] = PnorAddrPair_t(l_pWorking, l_pClean); } //return the data in the struct o_info.id = i_section; o_info.name = SectionIdToString(i_section); o_info.vaddr = reinterpret_cast<uint64_t>(l_pWorking); o_info.flashAddr = iv_TOC[i_section].flashAddr; o_info.size = l_sizeBytes; o_info.eccProtected = l_ecc; o_info.sha512Version= (iv_TOC[i_section].version & FFS_VERS_SHA512) ? true : false; o_info.sha512perEC = (iv_TOC[i_section].version & FFS_VERS_SHA512_PER_EC) ? true : false; o_info.secure = iv_TOC[i_section].secure; } while (0); TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::getSectionInfo %d", i_section); return l_err; }
/*******************Private Methods*********************/ errlHndl_t RtPnor::readFromDevice (uint64_t i_procId, PNOR::SectionId i_section, uint64_t i_offset, size_t i_size, bool i_ecc, void* o_data) const { TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::readFromDevice: i_offset=0x%X, " "i_procId=%d sec=%d size=0x%X ecc=%d", i_offset, i_procId, i_section, i_size, i_ecc); errlHndl_t l_err = nullptr; uint8_t* l_eccBuffer = nullptr; do { const char* l_partitionName = SectionIdToString(i_section); void* l_dataToRead = o_data; size_t l_readSize = i_size; size_t l_readSizePlusECC = (i_size * 9)/8; uint64_t l_offset = i_offset; // if we need to handle ECC, we need to read more if( i_ecc ) { l_eccBuffer = new uint8_t[l_readSizePlusECC](); l_dataToRead = l_eccBuffer; l_readSize = l_readSizePlusECC; l_offset = (i_offset * 9)/8; } int l_rc = 0; if (g_hostInterfaces && g_hostInterfaces->pnor_read) { // get the data from OPAL l_rc = g_hostInterfaces->pnor_read(i_procId, l_partitionName, l_offset, l_dataToRead, l_readSize); if (l_rc < 0) { TRACFCOMP(g_trac_pnor, "RtPnor::readFromDevice: pnor_read" " failed proc:%d, part:%s, offset:0x%X, size:0x%X," " dataPt:0x%X, rc:%d", i_procId, l_partitionName, l_offset, l_readSize, l_dataToRead, l_rc); // prevent hang between ErrlManager and rt_pnor assert(iv_initialized, "RtPnor::readFromDevice: pnor_read returned an error" " during initialization"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE * @reasoncode PNOR::RC_PNOR_READ_FAILED * @userdata1[00:31] rc returned from pnor_read * @userdata1[32:63] section ID * @userdata2[00:31] offset within the section * @userdata2[32:63] size of data read in bytes * @devdesc g_hostInterfaces->pnor_read failed * @custdesc Error accessing system firmware flash */ //@todo Add PNOR callout RTC:116145 l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_READFROMDEVICE, PNOR::RC_PNOR_READ_FAILED, TWO_UINT32_TO_UINT64(l_rc, i_section), TWO_UINT32_TO_UINT64(l_offset, l_readSize), true); break; } else if( l_rc != static_cast<int>(l_readSize) ) { TRACFCOMP( g_trac_pnor, "RtPnor::readFromDevice: only read 0x%X bytes, expecting 0x%X", l_rc, l_readSize ); if( PNOR::TOC == i_section ) { // we can't know how big the TOC partition is without // reading it so we have to make a request for more // data and then handle a smaller amount getting returned TRACFCOMP( g_trac_pnor, "Ignoring mismatch for TOC" ); } else // everything else should have a known size { // prevent hang between ErrlManager and rt_pnor assert(iv_initialized, "RtPnor::readFromDevice: pnor_read failed to read " "expected amount before rt_pnor initialization"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE * @reasoncode PNOR::RC_WRONG_SIZE_FROM_READ * @userdata1[00:31] section ID * @userdata1[32:63] requested size of read * @userdata2[00:31] requested start offset into flash * @userdata2[32:63] actual amount read * @devdesc Amount of data read from pnor does * not match expected size * @custdesc Error accessing system firmware flash */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_READFROMDEVICE, PNOR::RC_WRONG_SIZE_FROM_READ, TWO_UINT32_TO_UINT64(i_section,l_readSize), TWO_UINT32_TO_UINT64(l_offset,l_rc), true); break; } } } else { TRACFCOMP(g_trac_pnor,"RtPnor::readFromDevice: This version of" " OPAL does not support pnor_read"); // prevent hang between ErrlManager and rt_pnor assert(iv_initialized, "RtPnor::readFromDevice: OPAL version does NOT support" "pnor_read during initialization"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE * @reasoncode PNOR::RC_PNOR_READ_NOT_SUPPORTED * @devdesc g_hostInterfaces->pnor_read not supported * @custdesc Error accessing system firmware flash */ //@todo Add PNOR callout RTC:116145 l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_READFROMDEVICE, PNOR::RC_PNOR_READ_NOT_SUPPORTED, 0,0,true); break; } // remove the ECC data if( i_ecc ) { TRACFCOMP(g_trac_pnor, "RtPnor::readFromDevice: removing ECC..."); // remove the ECC and fix the original data if it is broken size_t l_eccSize = (l_rc/9)*8; l_eccSize = std::min( l_eccSize, i_size ); PNOR::ECC::eccStatus ecc_stat = PNOR::ECC::removeECC(reinterpret_cast<uint8_t*>(l_dataToRead), reinterpret_cast<uint8_t*>(o_data), l_eccSize); //logical size of read data // create an error if we couldn't correct things if( ecc_stat == PNOR::ECC::UNCORRECTABLE ) { TRACFCOMP(g_trac_pnor,"RtPnor::readFromDevice>" " Uncorrectable ECC error : chip=%d,offset=0x%.X", i_procId, i_offset ); // prevent hang between ErrlManager and rt_pnor assert(iv_initialized, "RtPnor::readFromDevice: UNCORRECTABLE_ECC encountered" " during initialization"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE * @reasoncode PNOR::RC_UNCORRECTABLE_ECC * @devdesc UNCORRECTABLE ECC */ //@todo Add PNOR callout RTC:116145 l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_READFROMDEVICE, PNOR::RC_UNCORRECTABLE_ECC, 0, 0, true); break; } // found an error so we need to fix something else if( ecc_stat != PNOR::ECC::CLEAN ) { TRACFCOMP(g_trac_pnor,"RtPnor::readFromDevice>" "Correctable ECC error : chip=%d, offset=0x%.X", i_procId, i_offset ); if (g_hostInterfaces && g_hostInterfaces->pnor_write) { //need to write good data back to PNOR int l_rc = g_hostInterfaces->pnor_write(i_procId, l_partitionName,l_offset, l_dataToRead,l_readSize); if (l_rc != static_cast<int>(l_readSize)) { TRACFCOMP(g_trac_pnor, "RtPnor::readFromDevice> Error" " writing corrected data back to device"); // prevent hang between ErrlManager and rt_pnor assert(iv_initialized, "RtPnor::readFromDevice: pnor_write returned an" " error during initialization"); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_READFROMDEVICE * @reasoncode PNOR::RC_PNOR_WRITE_FAILED * @userdata1 rc returned from pnor_write * @userdata2 Expected size of write * @devdesc error writing corrected data back to PNOR * @custdesc Error accessing system firmware flash */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_READFROMDEVICE, PNOR::RC_PNOR_WRITE_FAILED, l_rc, l_readSize, true); errlCommit(l_err, PNOR_COMP_ID); } } } } } while(0); if( l_eccBuffer ) { delete[] l_eccBuffer; } TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::readFromDevice" ); return l_err; }
errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section, PNOR::SectionInfo_t& o_info) { TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::getSectionInfo"); errlHndl_t l_err = nullptr; do { // TODO: RTC:180063 change this to error out on secure sections as it // did previously in HB commit cefc4c // Check if Section is invalid or inhibited from loading at runtime. bool l_inhibited = false; #ifdef CONFIG_SECUREBOOT l_inhibited = PNOR::isInhibitedSection(i_section); #endif if (i_section == PNOR::INVALID_SECTION || l_inhibited) { TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo: Invalid Section %d", static_cast<int>(i_section)); #ifdef CONFIG_SECUREBOOT if (l_inhibited) { TRACFCOMP(g_trac_pnor, ERR_MRK"RtPnor::getSectionInfo: attribute overrides inhibited by secureboot"); } #endif /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_GETSECTIONINFO * @reasoncode PNOR::RC_RTPNOR_INVALID_SECTION * @userdata1 PNOR::SectionId * @userdata2[0:63] Inhibited by secureboot * @devdesc invalid section passed to getSectionInfo or * section prohibited by secureboot */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_GETSECTIONINFO, PNOR::RC_RTPNOR_INVALID_SECTION, i_section, l_inhibited, true); break; } //size of the section uint64_t l_sizeBytes = iv_TOC[i_section].size; if (l_sizeBytes == 0) { TRACFCOMP(g_trac_pnor,"RtPnor::getSectionInfo: Section %d" " size is 0", static_cast<int>(i_section)); /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_GETSECTIONINFO * @reasoncode PNOR::RC_SECTION_SIZE_IS_ZERO * @userdata1 PNOR::SectionId * @devdesc section size is zero */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_GETSECTIONINFO, PNOR::RC_SECTION_SIZE_IS_ZERO, i_section, 0,true); break; } //ecc bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ? true : false; // TODO: RTC:180063 change this to error out on secure sections as it // did previously in HB commit cefc4c // Only do mapping and read from device to set vaddr if not a secure // section. Secure sections should load from HB resv memory and will set // vaddr to 0 if (iv_TOC[i_section].secure) { TRACFCOMP(g_trac_pnor,"RtPnor::getSectionInfo: Warning> Section is secure, so must be loaded from Hb resv memory. vaddr will be set to 0"); o_info.vaddr = 0; } else { void* l_pWorking = nullptr; void* l_pClean = nullptr; //find the section in the map first if(iv_pnorMap.find(i_section) != iv_pnorMap.end()) { //get the addresses from the map PnorAddrPair_t l_addrPair = iv_pnorMap[i_section]; l_pWorking = l_addrPair.first; l_pClean = l_addrPair.second; } else { //malloc twice -- one working copy and one clean copy //So, we can diff and write only the dirty bytes l_pWorking = malloc(l_sizeBytes); l_pClean = malloc(l_sizeBytes); //offset = 0 : read the entire section l_err = readFromDevice(iv_masterProcId, i_section, 0, l_sizeBytes, l_ecc, l_pWorking); if(l_err) { TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo:readFromDevice" " failed"); break; } //copy data to another pointer to save a clean copy of data memcpy(l_pClean, l_pWorking, l_sizeBytes); //save it in the map iv_pnorMap [i_section] = PnorAddrPair_t(l_pWorking, l_pClean); } o_info.vaddr = reinterpret_cast<uint64_t>(l_pWorking); } //return the data in the struct o_info.id = i_section; o_info.name = SectionIdToString(i_section); o_info.flashAddr = iv_TOC[i_section].flashAddr; o_info.size = l_sizeBytes; o_info.eccProtected = l_ecc; o_info.sha512Version= (iv_TOC[i_section].version & FFS_VERS_SHA512) ? true : false; o_info.sha512perEC = (iv_TOC[i_section].version & FFS_VERS_SHA512_PER_EC) ? true : false; o_info.secure = iv_TOC[i_section].secure; } while (0); TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::getSectionInfo"); return l_err; }