summaryrefslogtreecommitdiffstats
path: root/src/usr/pnor
diff options
context:
space:
mode:
authorStephen Cprek <smcprek@us.ibm.com>2017-04-20 16:55:27 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-04-28 15:42:23 -0400
commite53a2e5cd5b152d6e565f56867f1f8cd435e7556 (patch)
tree9586a89a945da5b2f684688a9a421dadb494ee8b /src/usr/pnor
parentf30075299ce2c078705192b1835b70eff4f08fc1 (diff)
downloadtalos-hostboot-e53a2e5cd5b152d6e565f56867f1f8cd435e7556.tar.gz
talos-hostboot-e53a2e5cd5b152d6e565f56867f1f8cd435e7556.zip
Implement Best Effort Secureboot Policy for Hostboot Runtime
Optimized getting the master proc id in rt_pnor Change-Id: Iab5c194553dddfbb642cfc9dec6398a93ab56d4a Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/39520 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/pnor')
-rw-r--r--src/usr/pnor/pnor_common.C7
-rw-r--r--src/usr/pnor/pnor_utils.C4
-rw-r--r--src/usr/pnor/pnor_utils.H2
-rw-r--r--src/usr/pnor/runtime/rt_pnor.C199
-rw-r--r--src/usr/pnor/runtime/rt_pnor.H29
5 files changed, 181 insertions, 60 deletions
diff --git a/src/usr/pnor/pnor_common.C b/src/usr/pnor/pnor_common.C
index e6e7bd2a1..b3bc54c35 100644
--- a/src/usr/pnor/pnor_common.C
+++ b/src/usr/pnor/pnor_common.C
@@ -388,6 +388,7 @@ bool PNOR::isInhibitedSection(const uint32_t i_section)
#endif
}
+// @TODO RTC:155374 Remove this in the future
errlHndl_t PNOR::setSecure(const uint32_t i_secId,
PNOR::SectionData_t* io_TOC)
{
@@ -407,9 +408,9 @@ errlHndl_t PNOR::setSecure(const uint32_t i_secId,
// Apply best effort policy by checking if the section appears to have a
// secure header
size_t l_size = sizeof(ROM_MAGIC_NUMBER);
- auto l_buf = new uint8_t[l_size]();
+ uint8_t l_buf[l_size] = {0};
auto l_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;
- // Read first 8 bytes of section data from the PNOR DD
+ // Read first 4 bytes of section data from the PNOR DD
// Note: Do not need to worry about ECC as the 9th byte is the first
// ECC byte.
l_errhdl = DeviceFW::deviceRead(l_target, l_buf, l_size,
@@ -419,7 +420,7 @@ errlHndl_t PNOR::setSecure(const uint32_t i_secId,
break;
}
- // Check if first 8 bytes match the Secureboot Magic Number
+ // Check if first 4 bytes match the Secureboot Magic Number
io_TOC[i_secId].secure &= PNOR::cmpSecurebootMagicNumber(l_buf);
}
#endif
diff --git a/src/usr/pnor/pnor_utils.C b/src/usr/pnor/pnor_utils.C
index 979b1cb1f..a5950bc20 100644
--- a/src/usr/pnor/pnor_utils.C
+++ b/src/usr/pnor/pnor_utils.C
@@ -212,7 +212,7 @@ void PNOR::checkHeader (ffs_hdr* i_ffs_hdr,
* @brief Takes in an ffs_entry and returns the enum version of the section
* title.
*/
-void PNOR::getSectionEnum (ffs_entry* i_entry,
+void PNOR::getSectionEnum (const ffs_entry* i_entry,
uint32_t* o_secId)
{
*o_secId = PNOR::INVALID_SECTION;
@@ -321,7 +321,7 @@ PNOR::parseEntries (ffs_hdr* i_ffs_hdr,
#ifdef BOOTLOADER
io_TOC[secId].secure = PNOR::isEnforcedSecureSection(secId);
-#else
+#elif !defined(__HOSTBOOT_RUNTIME) // runtime is handled by rt_pnor code
// Check if PNOR section has a secureHeader or not.
l_errhdl = PNOR::setSecure(secId, io_TOC);
if (l_errhdl)
diff --git a/src/usr/pnor/pnor_utils.H b/src/usr/pnor/pnor_utils.H
index 6007b3492..700820644 100644
--- a/src/usr/pnor/pnor_utils.H
+++ b/src/usr/pnor/pnor_utils.H
@@ -183,7 +183,7 @@ void checkHeader (ffs_hdr* i_ffs_hdr,
* enums found in include/usr/pnor/pnor_const.H
*
*/
-void getSectionEnum (ffs_entry* i_entry,
+void getSectionEnum (const ffs_entry* i_entry,
uint32_t* o_secId);
/**
* @brief Iterate through the entries, each which represent a section in pnor.
diff --git a/src/usr/pnor/runtime/rt_pnor.C b/src/usr/pnor/runtime/rt_pnor.C
index 484d47e7d..a614ae274 100644
--- a/src/usr/pnor/runtime/rt_pnor.C
+++ b/src/usr/pnor/runtime/rt_pnor.C
@@ -38,6 +38,8 @@
#include "../ffs.h"
#include "../common/ffs_hb.H"
#include <util/align.H>
+#include <runtime/customize_attrs_for_payload.H>
+#include <securerom/ROM.H>
// Trace definition
extern trace_desc_t* g_trac_pnor;
@@ -47,6 +49,8 @@ extern trace_desc_t* g_trac_pnor;
*/
TASK_ENTRY_MACRO( RtPnor::init );
+// @TODO RTC:155374 Remove this in the future
+const size_t BEST_EFFORT_NUM_BYTES = 32;
/**
* @brief Return the size and address of a given section of PNOR data
@@ -103,6 +107,9 @@ void PNOR::getPnorInfo( PnorInfo_t& o_pnorInfo )
}
/****************Public Methods***************************/
+
+uint64_t RtPnor::iv_masterProcId = RUNTIME::HBRT_HYP_ID_UNKNOWN;
+
/**
* STATIC
* @brief Static Initializer
@@ -110,7 +117,18 @@ void PNOR::getPnorInfo( PnorInfo_t& o_pnorInfo )
void RtPnor::init(errlHndl_t &io_taskRetErrl)
{
TRACFCOMP(g_trac_pnor, "RtPnor::init> " );
+ do {
+ io_taskRetErrl = Singleton<RtPnor>::instance().getMasterProcId();
+ if (io_taskRetErrl)
+ {
+ break;
+ }
io_taskRetErrl = Singleton<RtPnor>::instance().readTOC();
+ if (io_taskRetErrl)
+ {
+ break;
+ }
+ }while (0);
TRACFCOMP(g_trac_pnor, "<RtPnor::init" );
}
/**************************************************************/
@@ -158,16 +176,6 @@ errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section,
i_section, 0,true);
break;
}
- //find proc id
- uint64_t l_procId;
- TARGETING::Target* l_masterProc = NULL;
- TARGETING::targetService().masterProcChipTargetHandle( l_masterProc );
- l_err = RT_TARG::getRtTarget (l_masterProc, l_procId);
- if (l_err)
- {
- TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo: getRtTarget failed");
- break;
- }
//ecc
bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ?
@@ -192,8 +200,8 @@ errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section,
l_pClean = malloc(l_sizeBytes);
//offset = 0 : read the entire section
- l_err = readFromDevice(l_procId, i_section, 0, l_sizeBytes, l_ecc,
- l_pWorking);
+ l_err = readFromDevice(iv_masterProcId, i_section, 0, l_sizeBytes,
+ l_ecc, l_pWorking);
if(l_err)
{
TRACFCOMP(g_trac_pnor, "RtPnor::getSectionInfo:readFromDevice"
@@ -218,6 +226,15 @@ errlHndl_t RtPnor::getSectionInfo(PNOR::SectionId i_section,
(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;
+#ifdef CONFIG_SECUREBOOT
+ // We don't verify PNOR sections at runtime, but we
+ // still have to bypass the secure header
+ if(iv_TOC[i_section].secure)
+ {
+ o_info.vaddr += PAGESIZE;
+ o_info.size -= PAGESIZE;
+ }
+#endif
} while (0);
TRACFCOMP(g_trac_pnor, EXIT_MRK"RtPnor::getSectionInfo");
@@ -283,16 +300,6 @@ errlHndl_t RtPnor::flush( PNOR::SectionId i_section)
//ecc
bool l_ecc = (iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT) ?
true : false;
- //find proc id
- uint64_t l_procId;
- TARGETING::Target* l_masterProc = NULL;
- TARGETING::targetService().masterProcChipTargetHandle( l_masterProc );
- l_err = RT_TARG::getRtTarget (l_masterProc, l_procId);
- if (l_err)
- {
- TRACFCOMP(g_trac_pnor, "RtPnor::flush: getRtTarget failed");
- break;
- }
//find the diff between each pointer
//write back to pnor what doesn't match
@@ -303,8 +310,8 @@ errlHndl_t RtPnor::flush( PNOR::SectionId i_section)
{
TRACFCOMP(g_trac_pnor, "RtPnor::flush: page %d is different,"
" writing back to pnor", i);
- l_err = writeToDevice(l_procId, i_section, i*PAGESIZE,PAGESIZE,
- l_ecc,l_pWorking);
+ l_err = writeToDevice(iv_masterProcId, i_section,
+ i*PAGESIZE,PAGESIZE, l_ecc, l_pWorking);
if (l_err)
{
TRACFCOMP(g_trac_pnor, "RtPnor::flush: writeToDevice failed");
@@ -331,12 +338,20 @@ errlHndl_t RtPnor::flush( PNOR::SectionId i_section)
/*******Protected Methods**************/
RtPnor::RtPnor()
{
- errlHndl_t l_err = readTOC();
+ do {
+ errlHndl_t l_err = getMasterProcId();
if (l_err)
{
errlCommit(l_err, PNOR_COMP_ID);
+ break;
}
-
+ l_err = readTOC();
+ if (l_err)
+ {
+ errlCommit(l_err, PNOR_COMP_ID);
+ break;
+ }
+ } while (0);
}
/*************************/
@@ -350,7 +365,7 @@ errlHndl_t RtPnor::readFromDevice (uint64_t i_procId,
uint64_t i_offset,
size_t i_size,
bool i_ecc,
- void* o_data)
+ 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,
@@ -648,26 +663,16 @@ errlHndl_t RtPnor::writeToDevice( uint64_t i_procId,
errlHndl_t RtPnor::readTOC ()
{
TRACFCOMP(g_trac_pnor, ENTER_MRK"RtPnor::readTOC" );
- errlHndl_t l_err = NULL;
+ errlHndl_t l_err = nullptr;
uint8_t* l_toc0Buffer = new uint8_t[PNOR::TOC_SIZE];
do {
if (g_hostInterfaces && g_hostInterfaces->pnor_read)
{
- //find proc id
- uint64_t l_procId;
- TARGETING::Target* l_masterProc = NULL;
- TARGETING::targetService().masterProcChipTargetHandle(l_masterProc);
- l_err = RT_TARG::getRtTarget (l_masterProc, l_procId);
- if (l_err)
- {
- TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: getRtTarget failed");
- break;
- }
// offset = 0 means read the entire PNOR::TOC partition
// This offset is offset into the partition, not offset from the
// beginning of the flash
- l_err = readFromDevice (l_procId, PNOR::TOC, 0,
- PNOR::TOC_SIZE, false, l_toc0Buffer);
+ l_err = readFromDevice (iv_masterProcId, PNOR::TOC, 0,
+ PNOR::TOC_SIZE, false, l_toc0Buffer);
if (l_err)
{
TRACFCOMP(g_trac_pnor,"RtPnor::readTOC:readFromDevice failed"
@@ -684,10 +689,19 @@ errlHndl_t RtPnor::readTOC ()
TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: parseTOC failed");
break;
}
+
+ // Check if PNOR section has a secureHeader or not.
+ // Cannot do a device read during parseTOC in Runtime, so do after.
+ l_err = setSecure(l_toc0Buffer, iv_TOC);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_pnor, "RtPnor::readTOC: setSecure failed");
+ break;
+ }
}
} while (0);
- if(l_toc0Buffer != NULL)
+ if(l_toc0Buffer != nullptr)
{
delete[] l_toc0Buffer;
}
@@ -696,6 +710,73 @@ errlHndl_t RtPnor::readTOC ()
return l_err;
}
+// @TODO RTC:155374 Remove this in the future
+errlHndl_t RtPnor::setSecure(const uint8_t* i_tocBuffer,
+ PNOR::SectionData_t* io_TOC) const
+{
+ errlHndl_t l_errhdl = nullptr;
+
+ assert(i_tocBuffer != nullptr, "RtPnor::setSecure received a NULL tocBuffer to read");
+ assert(io_TOC != nullptr, "RtPnor::setSecure received a NULL toc to modify");
+
+ do {
+ // Set secure flag for each section after the TOC
+ // Walk through all the entries in the table and parse the data.
+ auto const l_ffs_hdr = reinterpret_cast<const ffs_hdr*>(i_tocBuffer);
+ for(uint32_t i=0; i<l_ffs_hdr->entry_count; ++i)
+ {
+ uint32_t l_secId = PNOR::INVALID_SECTION;
+
+ // Get current entry section id
+ auto cur_entry = &(l_ffs_hdr->entries[i]);
+ PNOR::getSectionEnum(cur_entry, &l_secId);
+ if(l_secId == PNOR::INVALID_SECTION)
+ {
+ TRACFCOMP(g_trac_pnor, "RtPnor::setSecure Unrecognized Section name(%s), skipping",cur_entry->name);
+ continue;
+ }
+
+ // Set secure field based on enforced policy
+ io_TOC[l_secId].secure = PNOR::isEnforcedSecureSection(l_secId);
+
+#ifdef CONFIG_SECUREBOOT_BEST_EFFORT
+ if (io_TOC[l_secId].secure)
+ {
+ // Apply best effort policy by checking if the section appears to have a
+ // secure header
+ // Need to read first 4 bytes of data to check version header
+ // Note: For OPAL and PHYP need to read 8 bytes for ECC checking
+ // In CXX test a pnorDD read is called and requires a
+ // multiple of 4 bytes. If the section as ECC then it
+ // needs to be a multiple of 4 bytes after ECC.
+ // 32 Bytes fulfills both requirements.
+ size_t l_size = BEST_EFFORT_NUM_BYTES;
+ uint8_t l_buf[l_size] = {0};
+
+ bool l_ecc = io_TOC[l_secId].integrity & FFS_INTEG_ECC_PROTECT;
+ // Read first 8 bytes of section data from PNOR
+ l_errhdl = readFromDevice(iv_masterProcId,
+ static_cast<PNOR::SectionId>(l_secId),
+ 0, l_size, l_ecc, l_buf);
+ if (l_errhdl)
+ {
+ break;
+ }
+
+ // Check if first 4 bytes match the Secureboot Magic Number
+ io_TOC[l_secId].secure &= PNOR::cmpSecurebootMagicNumber(l_buf);
+ }
+#endif
+ }
+ if (l_errhdl)
+ {
+ break;
+ }
+ } while(0);
+
+ return l_errhdl;
+}
+
/***********************************************************/
RtPnor& RtPnor::getInstance()
{
@@ -797,17 +878,6 @@ errlHndl_t RtPnor::clearSection(PNOR::SectionId i_section)
l_size = (l_size*9)/8;
}
- //find proc id
- uint64_t l_procId;
- TARGETING::Target* l_masterProc = NULL;
- TARGETING::targetService().masterProcChipTargetHandle( l_masterProc );
- l_errl = RT_TARG::getRtTarget (l_masterProc, l_procId);
- if (l_errl)
- {
- TRACFCOMP(g_trac_pnor, "RtPnor::clearSection: getRtTarget failed");
- break;
- }
-
// Write clear section page to PNOR
for (uint64_t i = 0; i < l_size; i+=PAGESIZE)
{
@@ -821,7 +891,7 @@ errlHndl_t RtPnor::clearSection(PNOR::SectionId i_section)
// Set ecc parameter to false to avoid double writes will only write
// 4k at a time, even if the section is ecc protected.
- l_errl = writeToDevice( l_procId,i_section,
+ l_errl = writeToDevice( iv_masterProcId, i_section,
(l_address + i), l_chipSelect,
false, l_buf);
if (l_errl)
@@ -847,4 +917,27 @@ errlHndl_t RtPnor::clearSection(PNOR::SectionId i_section)
return l_errl;
}
+errlHndl_t RtPnor::getMasterProcId()
+{
+ errlHndl_t l_err = nullptr;
+
+ do {
+ TARGETING::Target* l_masterProc = nullptr;
+ l_err = TARGETING::targetService().queryMasterProcChipTargetHandle(l_masterProc);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_pnor, "RtPnor::getMasterProcId: queryMasterProcChipTargetHandle failed");
+ break;
+ }
+ l_err = RT_TARG::getRtTarget(l_masterProc, iv_masterProcId);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_pnor, "RtPnor::getMasterProcId: getRtTarget failed for master proc");
+ break;
+ }
+ } while(0);
+
+ return l_err;
+}
+
diff --git a/src/usr/pnor/runtime/rt_pnor.H b/src/usr/pnor/runtime/rt_pnor.H
index 7425adda6..61ec8a02f 100644
--- a/src/usr/pnor/runtime/rt_pnor.H
+++ b/src/usr/pnor/runtime/rt_pnor.H
@@ -134,7 +134,7 @@ class RtPnor
uint64_t i_offset,
size_t i_size,
bool i_ecc,
- void* o_data);
+ void* o_data) const;
/**
* @brief Write data back to the PNOR device
@@ -164,6 +164,33 @@ class RtPnor
*/
errlHndl_t readTOC();
+ // @TODO RTC:155374 Remove this in the future
+ /**
+ * @brief Check if PNOR sections appear to be secure and sets the
+ * internal TOC of PnorRp accordingly.
+ * Note: The setting of the flag is based on the Secureboot policy.
+ * Note: Done separately from pnor common code to prevent PNOR
+ * deadlock when reading section bytes.
+ *
+ * @param[in] io_TOC Pointer to internal array of section data that
+ * represents the TOC of pnor flash
+ * Asserts if nullptr
+ *
+ * @return errlHndl_t Error log if request was invalid
+ */
+ errlHndl_t setSecure(const uint8_t* i_tocBuffer,
+ PNOR::SectionData_t* io_TOC) const;
+
+ /**
+ * @brief Get processor id of master proc and cache in internal variable
+ *
+ * @return errlHndl_t - Error from runtime targeting call
+ */
+ errlHndl_t getMasterProcId();
+
+ // Cached master Proc Id
+ static uint64_t iv_masterProcId;
+
//allow testcases to see inside the class
friend class PnorRtTest;
OpenPOWER on IntegriCloud