diff options
author | Prachi Gupta <pragupta@us.ibm.com> | 2014-10-28 15:41:49 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-01-16 12:34:43 -0600 |
commit | c068f50829ec46e4e5b056064dcbe9d786d549a4 (patch) | |
tree | 36c5fd8f2f6b5d420644ed83b877f6d0d8657f42 /src/usr/pnor/pnor_common.C | |
parent | 5412ba2270945edcfb23f60c34de01dccd44c098 (diff) | |
download | talos-hostboot-c068f50829ec46e4e5b056064dcbe9d786d549a4.tar.gz talos-hostboot-c068f50829ec46e4e5b056064dcbe9d786d549a4.zip |
hbrt interface for PNOR access
RTC:108836
Change-Id: I49e568e7f4fcad13fcd75dfdfa4aee8a263c5001
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/14307
Reviewed-by: STEPHEN M. CPREK <smcprek@us.ibm.com>
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/pnor/pnor_common.C')
-rw-r--r-- | src/usr/pnor/pnor_common.C | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/src/usr/pnor/pnor_common.C b/src/usr/pnor/pnor_common.C new file mode 100644 index 000000000..e92ce56c8 --- /dev/null +++ b/src/usr/pnor/pnor_common.C @@ -0,0 +1,417 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/pnor_common.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include "pnor_common.H" +#include <pnor/pnorif.H> +#include <pnor/pnor_reasoncodes.H> + +#include "ffs.h" //Common header file with BuildingBlock. +#include "common/ffs_hb.H" //Hostboot def of user data in ffs_entry struct + +#include <initservice/initserviceif.H> +#include <util/align.H> + +// Trace definition +trace_desc_t* g_trac_pnor = NULL; +TRAC_INIT(&g_trac_pnor, PNOR_COMP_NAME, 4*KILOBYTE, TRACE::BUFFER_SLOW); //4K + +// Easy macro replace for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + +/** + * Eyecatcher strings for PNOR TOC entries + */ +const char* cv_EYECATCHER[] = { + "part", /**< PNOR::TOC : Table of Contents */ + "HBI", /**< PNOR::HB_EXT_CODE : Hostboot Extended Image */ + "GLOBAL", /**< PNOR::GLOBAL_DATA : Global Data */ + "HBB", /**< PNOR::HB_BASE_CODE : Hostboot Base Image */ + "SBEC", /**< PNOR::CENTAUR_SBE : Centaur Self-Boot Engine image */ + "SBE", /**< PNOR::SBE_IPL : Self-Boot Enginer IPL image */ + "WINK", /**< PNOR::WINK : Sleep Winkle Reference image */ + "PAYLOAD", /**< PNOR::PAYLOAD : HAL/OPAL */ + "HBRT", /**< PNOR::HB_RUNTIME : Hostboot Runtime (for Sapphire) */ + "HBD", /**< PNOR::HB_DATA : Hostboot Data */ + "GUARD", /**< PNOR::GUARD_DATA : Hostboot Data */ + "HBEL", /**< PNOR::HB_ERRLOGS : Hostboot Error log Repository */ + "DJVPD", /**< PNOR::DIMM_JEDEC_VPD : Dimm JEDEC VPD */ + "MVPD", /**< PNOR::MODULE_VPD : Module VPD */ + "CVPD", /**< PNOR::CENTAUR_VPD : Centaur VPD */ + "NVRAM", /**< PNOR::NVRAM : OPAL Storage */ + "OCC", /**< PNOR::OCC : OCC LID */ + "FIRDATA", /**< PNOR::FIRDATA : FIRDATA */ + "ATTR_TMP", /**< PNOR::ATTR_TMP : Temporary Attribute Overrides */ + "ATTR_PERM", /**< PNOR::ATTR_PERM : Permanent Attribute Overrides */ + "TEST", /**< PNOR::TEST : Test space for PNOR*/ + //Not currently used +// "XXX", /**< NUM_SECTIONS : Used as invalid entry */ +}; + +/** + * @brief calculates the checksum on data(ffs header/entry) and will return + * 0 if the checksums match + */ +uint32_t PNOR::pnor_ffs_checksum(void* data, size_t size) +{ + uint32_t checksum = 0; + + for (size_t i = 0; i < (size/4); i++) + { + checksum ^= ((uint32_t*)data)[i]; + } + + checksum = htobe32(checksum); + return checksum; +} + +errlHndl_t PNOR::parseTOC(uint8_t* i_toc0Buffer, uint8_t* i_toc1Buffer, + uint32_t & o_TOC_used, SectionData_t * o_TOC, uint64_t i_baseVAddr) +{ + TRACUCOMP(g_trac_pnor,"PNOR::parseTOC>"); + errlHndl_t l_errhdl = NULL; + + bool TOC_0_failed = false; + + do{ + o_TOC_used = 0; + + for (uint32_t cur_TOC = 0; cur_TOC < NUM_TOCS; ++cur_TOC) + { + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC verifying TOC: %d",cur_TOC); + uint64_t nextVAddr = i_baseVAddr; + + // Zero out my table + for( size_t id = PNOR::FIRST_SECTION; + id <= PNOR::NUM_SECTIONS; //include extra entry for error paths + ++id ) + { + o_TOC[id].id = (PNOR::SectionId)id; + //everything else should default to zero + } + // Read TOC information from TOC 0 and then TOC 1 + ffs_hdr* l_ffs_hdr; + if (cur_TOC == 0) + { + l_ffs_hdr = (ffs_hdr*) i_toc0Buffer; + } + else if (cur_TOC == 1) + { + l_ffs_hdr = (ffs_hdr*) i_toc1Buffer; + } + + // 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,"PNOR::parseTOC pnor_ffs_checksum header" + " checksums do not match."); + if (cur_TOC == 0) + { + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC TOC 0 failed header checksum"); + TOC_0_failed = true; + o_TOC_used = 1; + continue; + } + else if (cur_TOC == 1 && TOC_0_failed) + { + // Both TOC's failed + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC both TOCs are corrupted"); + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORCOMMON_PARSETOC + * @reasoncode PNOR::RC_CORRUPTED_TOCS + * @devdesc Both TOCs are corruputed + */ + //@todo Add PNOR callout RTC:116145 + l_errhdl = new ERRORLOG::ErrlEntry + (ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORCOMMON_PARSETOC, + PNOR::RC_CORRUPTED_TOCS, + 0, 0, true); + break; + } + else + { + // TOC 1 failed + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC 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, "PNOR::parseTOC: 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>PNOR::parseTOC: 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>PNOR::parseTOC: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>PNOR::parseTOC: 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>PNOR::parseTOC:" + " FFS Header pointer to entries is NULL."); + header_good = false; + } + else if(l_ffs_hdr->block_size != PAGESIZE) + { + TRACFCOMP(g_trac_pnor, "E>PNOR::parseTOC: 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>PNOR::parseTOC: 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>PNOR::parseTOC: 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) + { + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORCOMMON_PARSETOC + * @reasoncode PNOR::RC_BAD_TOC_HEADER + * @devdesc TOC 0 doesn't have a good header + */ + l_errhdl = new ERRORLOG::ErrlEntry + (ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORCOMMON_PARSETOC, + PNOR::RC_BAD_TOC_HEADER, + 0, 0, true); + break; + } + 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, "PNOR::parseTOC: 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, "PNOR::parseTOC pnor_ffs_checksum" + " entry checksums do not match"); + if (cur_TOC == 0) + { + TRACFCOMP(g_trac_pnor,"PNOR::parseTOC TOC 0 entry" + " checksum failed"); + TOC_0_failed = true; + o_TOC_used = 1; + break; + } + else if (cur_TOC == 1 && TOC_0_failed) + { + // Both TOC's failed + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC both TOC's are" + " corrupted"); + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORCOMMON_PARSETOC + * @reasoncode PNOR::RC_PARTITION_TABLE_INVALID + * @devdesc Both TOCs are corrupted + */ + l_errhdl = new ERRORLOG::ErrlEntry + (ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORCOMMON_PARSETOC, + PNOR::RC_PARTITION_TABLE_INVALID, + 0, 0, true); + break; + } + else + { + // TOC 1 failed + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC 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, "PNOR::parseTOC: sectionId=%d", secId); + break; + } + } + + if(secId == PNOR::INVALID_SECTION) + { + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC: Unrecognized" + " Section name(%s), skipping",cur_entry->name); + continue; + } + + ffsUserData = (ffs_hb_user_t*)&(cur_entry->user); + + //size + o_TOC[secId].size = ((uint64_t)cur_entry->size)*PAGESIZE; + + //virtAddr + o_TOC[secId].virtAddr = nextVAddr; + nextVAddr += o_TOC[secId].size; + + //flashAddr + o_TOC[secId].flashAddr=((uint64_t)cur_entry->base)*PAGESIZE; + + //chipSelect + o_TOC[secId].chip = ffsUserData->chip; + + //user data + o_TOC[secId].integrity = ffsUserData->dataInteg; + o_TOC[secId].version = ffsUserData->verCheck; + o_TOC[secId].misc = ffsUserData->miscFlags; + + TRACFCOMP(g_trac_pnor,"PNOR::parseTOC: User Data %s", + cur_entry->name); + + if (o_TOC[secId].integrity == FFS_INTEG_ECC_PROTECT) + { + TRACFCOMP(g_trac_pnor, "PNOR::TOC: ECC enabled for %s", + cur_entry->name); + o_TOC[secId].size = ALIGN_PAGE_DOWN + ((o_TOC[secId].size * 8 ) / 9); + } + + // TODO RTC:96009 handle version header w/secureboot + if (o_TOC[secId].version == FFS_VERS_SHA512) + { + TRACFCOMP(g_trac_pnor, "PNOR::parseTOC: Incrementing" + " Flash Address for SHA Header"); + if (o_TOC[secId].integrity == FFS_INTEG_ECC_PROTECT) + { + o_TOC[secId].flashAddr += PAGESIZE_PLUS_ECC; + } + else + { + o_TOC[secId].flashAddr += PAGESIZE; + } + } + + if((o_TOC[secId].flashAddr + o_TOC[secId].size) > + (l_ffs_hdr->block_count*PAGESIZE)) + { + TRACFCOMP(g_trac_pnor, "E>PNOR::parseTOC:Partition(%s)" + " at base address (0x%.8x) extends past end of" + " flash device",cur_entry->name, + o_TOC[secId].flashAddr); + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORCOMMON_PARSETOC + * @reasoncode PNOR::RC_SECTION_SIZE_IS_BIG + * @devdesc Invalid partition table + */ + l_errhdl = new ERRORLOG::ErrlEntry + (ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORCOMMON_PARSETOC, + PNOR::RC_SECTION_SIZE_IS_BIG, + 0, 0, true); + break; + } + } + } + if (l_errhdl) + { + TRACFCOMP(g_trac_pnor, ERR_MRK"PNOR::parseTOC: error parsing"); + break; + } + + 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], o_TOC[tmpId].size, + o_TOC[tmpId].flashAddr, o_TOC[tmpId].virtAddr ); + } + } + } while(0); + + TRACUCOMP(g_trac_pnor, "< PNOR::parseTOC" ); + return l_errhdl; +} + |