diff options
Diffstat (limited to 'src')
22 files changed, 1478 insertions, 42 deletions
diff --git a/src/include/usr/initservice/mboxRegs.H b/src/include/usr/initservice/mboxRegs.H index 716311385..2f0314c54 100644 --- a/src/include/usr/initservice/mboxRegs.H +++ b/src/include/usr/initservice/mboxRegs.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -99,6 +99,16 @@ namespace SPLESS } PACKED; }; + // Mailbox Scratch Register 7 + union MboxScratch7_t + { + uint32_t data32; + struct + { + uint32_t drtmPayloadAddrMb :32; //0 + } PACKED; + }; + // Mailbox Scratch Register 8 union MboxScratch8_t { diff --git a/src/include/usr/secureboot/drtm.H b/src/include/usr/secureboot/drtm.H new file mode 100644 index 000000000..e061502ae --- /dev/null +++ b/src/include/usr/secureboot/drtm.H @@ -0,0 +1,156 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/secureboot/drtm.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2013,2017 */ +/* [+] 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 */ + +#ifndef __SECUREBOOT_DRTM_H +#define __SECUREBOOT_DRTM_H + +#include <initservice/mboxRegs.H> +#include <config.h> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <vector> +#include <secureboot/settings.H> +#include <targeting/common/targetservice.H> + +namespace SECUREBOOT +{ + +namespace DRTM +{ + +/** + * @brief Determine HW DRTM state and cache for code to use + * + * @par Detailed Description: + * Reads DRTM related scratch registers, attributes, and proc chip security + * settings to determine the DRTM state, and caches DRTM settings in + * attributes for use by the code. It will return an error log if a DRTM + * consistency violation is detected. + * + * @param[in] i_scratchReg7 Value of scratch register 7 + * @param[in] i_scratchReg8 Value of scratch register 8 + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Discovered/configured DRTM state successfully + * @retval !nullptr Error log providing failure details + */ +errlHndl_t discoverDrtmState( + const INITSERVICE::SPLESS::MboxScratch7_t& i_scratchReg7, + const INITSERVICE::SPLESS::MboxScratch8_t& i_scratchReg8); + +/** + * @brief Returns whether this is a DRTM MPIPL or not + * + * @param[out] o_isDrtmMpipl Returns whether this is a DRTM MPIPL or not + */ +void isDrtmMpipl(bool& o_isDrtmMpipl); + +/** + * @brief Determines whether DRTM HW settings are consistent across all + * processors in a node + * + * @par Detailed Description: + * Ensures that, when coming up in a DRTM MPIPL, the L4A, LQA, and SUL bits + * are set + LLP and LLS are clear in the processor security register for + * all processors in a node. If this is not the case, it returns an error + * log. Must only be called after FSI path is established and presence + * detect has been confirmed. + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr All processors in node have correct DRTM HW signature + * @retval !nullptr Error log providing failure details + */ +errlHndl_t validateDrtmHwSignature(); + +/** + * @brief Validates and extends the DRTM payload + * + * @par Detailed Description: + * When coming up in a DRTM MPIPL, locates the DRTM payload preserved in + * memory, validates its secure signature, and extends its measurement to + * TPM dynamic PCR range / dynamic log. + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Validated/extended the DRTM payload + * @retval !nullptr Error log providing failure details + */ +errlHndl_t validateDrtmPayload(); + +/** + * @brief Completes the DRTM sequence + * + * @par Detailed Description: + * Completes the DRTM sequence by clearing the LQA and L4A security switch + * register bits on all the functional processors + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Completed DRTM HW sequencing + * @retval !nullptr Error log providing failure details + */ +errlHndl_t completeDrtm(); + +#ifdef CONFIG_DRTM_TRIGGERING +/** + * @brief Initiates a DRTM sequence + * + * @par Detailed Description: + * Initiates a DRTM sequence. This pins the task running this code to the + * master processor and sets the LLP bit (for master proc chip) and LLS bit + * (for non-masters) on every processor, setting the LL bit for the + * processor this task is running on last, so that it doesn't get clobbered + * by the SBE core quiesce logic. It also sets up the master processor + * scratch registers to indicate presence and address of the DRTM payload. + * If successful, the function will never return becaue the core it's + * running on will be quiesced by SBE. + * + * @note: Only valid for RIT protection + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Not possible; on success the function never returns. + * @retval !nullptr Error log providing failure details + */ +errlHndl_t initiateDrtm(); + +/** + * @brief Updates DRTM related scratch registers with DRTM payload details + * + * @par Detailed Description: + * Updates scratch register 7+8 to record details of the DRTM payload + * preserved in memory. This should be called prior to initiating the + * DRTM late launch sequence. + * + * @note: Only valid for RIT protection + * + * @param[in] i_drtmPayloadAddrMb DRTM payload physical address in MB + */ +void setDrtmPayloadPhysAddrMb(uint32_t i_drtmPayloadPhysAddrMb); +#endif + +} // End DRTM namespace + +} // End SECUREBOOT namespace + +#endif // End __SECUREBOOT_DRTM_H + diff --git a/src/include/usr/secureboot/secure_reasoncodes.H b/src/include/usr/secureboot/secure_reasoncodes.H index 2bbed2b23..1609e1a5f 100644 --- a/src/include/usr/secureboot/secure_reasoncodes.H +++ b/src/include/usr/secureboot/secure_reasoncodes.H @@ -38,6 +38,7 @@ namespace SECUREBOOT MOD_SECURE_ROM_CLEANUP = 0x04, MOD_SECURE_ROM_SHA512 = 0x05, MOD_SECURE_READ_REG = 0x06, + MOD_SECURE_WRITE_REG = 0x07, }; enum SECUREReasonCode diff --git a/src/include/usr/secureboot/service.H b/src/include/usr/secureboot/service.H index afb3ed934..a328b7337 100644 --- a/src/include/usr/secureboot/service.H +++ b/src/include/usr/secureboot/service.H @@ -48,20 +48,6 @@ typedef uint8_t PAGE_TABLE_ENTRY_t[HASH_PAGE_TABLE_ENTRY_SIZE]; namespace SECUREBOOT { - // these constants represent the scom addresses and masks we need - // to obtain secure boot settings from the system - enum class ProcSecurity : uint64_t - { - SabBit = 0x8000000000000000ull, - SwitchRegister = 0x00010005ull, - }; - - enum class ProcCbsControl : uint64_t - { - JumperStateBit = 0x0400000000000000ull, - StatusRegister = 0x00050001ull, - }; - /** @brief Perform initialization of Secureboot for the Base image. * * - Copy secure header from original location. @@ -107,6 +93,47 @@ namespace SECUREBOOT TARGETING::Target* i_targ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); + /** + * @brief Clear specified bits in the processor security switch register + * + * @par Detailed Description: + * Clears the specified bits in the processor security switch register. + * + * @param[in] i_bits Vector of ProcSecurity (bit) enums + * @param[in] i_pTarget Processor target to write. Must be either + * the master processor target sentinel or valid processor target. + * Must not be NULL. + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Cleared specified security switch register bits + * successfully + * @retval !nullptr Error log providing failure details + */ + errlHndl_t clearSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* i_pTarget = + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); + + /** + * @brief Set specified bits in the processor security switch register + * + * @par Detailed Description: + * Sets the specified bits in the processor security switch register. + * + * @param[in] i_bits Vector of ProcSecurity (bit) enums + * @param[in] i_pTarget Processor target to write. Must be either + * the master processor target sentinel or valid processor target. + * Must not be NULL. + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Set specified security switch register bits + * successfully + * @retval !nullptr Error log providing failure details + */ + errlHndl_t setSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* i_pTarget = + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); /** @brief Returns the state of the secure jumper as reported by the * given processor. diff --git a/src/include/usr/secureboot/settings.H b/src/include/usr/secureboot/settings.H index d6f83126d..08681e08e 100644 --- a/src/include/usr/secureboot/settings.H +++ b/src/include/usr/secureboot/settings.H @@ -29,6 +29,7 @@ #include <targeting/common/target.H> #include <targeting/common/targetservice.H> #include <cstdint> +#include <vector> namespace SECUREBOOT { @@ -38,6 +39,39 @@ namespace SECUREBOOT SECURITY_ASSERTED = 0b1, }; + // these constants represent the scom addresses and masks we need + // to obtain secure boot settings from the system + enum class ProcSecurity : uint64_t + { + SabBit = 0x8000000000000000ull, // Secure access (mirrored) + LLPBit = 0x4000000000000000ull, // Late launch primary + LLSBit = 0x2000000000000000ull, // Late launch secondary + LQABit = 0x1000000000000000ull, // Local quiesce achieved + SULBit = 0x0800000000000000ull, // Security update lock + L4ABit = 0x0400000000000000ull, // Locality 4 access + SDBBit = 0x0200000000000000ull, // Secure chip debug mode + CMFSIBit = 0x0100000000000000ull, // cMFSI access protection + ABUSBit = 0x0080000000000000ull, // Abus mailbox protection + RNGBit = 0x0040000000000000ull, // Random number generator lock + // Spare = 0x0020000000000000ull, + // Spare = 0x0010000000000000ull, + TDPBit = 0x0008000000000000ull, // TPM deconfig protection + // Spare = 0x0004000000000000ull, + // Spare = 0x0002000000000000ull, + // Spare = 0x0001000000000000ull, + + SwitchRegister = 0x00010005ull, + SwitchRegisterClear = 0x00010006ull, + }; + + enum class ProcCbsControl : uint64_t + { + SabBit = 0x0800000000000000ull, // Secure access + JumperStateBit = 0x0400000000000000ull, // Secure jumper + + StatusRegister = 0x00050001ull, + }; + /** @class Settings * * @brief Caches and parses the hardware settings for Secureboot. @@ -58,6 +92,23 @@ namespace SECUREBOOT TARGETING::Target* i_targ = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) const; + /** + * @brief Clear bits in the processor security swith register. See + * full documentation in service.H. + */ + errlHndl_t clearSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* i_pTarget = + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) const; + /** + * @brief Set bits in the processor security swith register. See + * full documentation in service.H. + */ + errlHndl_t setSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* i_pTarget = + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) const; + /** @brief Returns the state of the secure jumper as reported by the * given processor. See wrapper in Secureboot's service.H * for documenation. @@ -91,6 +142,28 @@ namespace SECUREBOOT const uint64_t i_scomAddress, uint64_t& o_regValue) const; + /** + * @brief Write a generic security related register + * + * @par Detailed Description: + * Writes a given security register given a proc target, SCOM + * address, and value. + * + * @param[in] i_pTarget Processor target to write. Must be either + * the master processor target sentinel or valid processor + * target. Must not be NULL. + * @param[in] i_scomAddress SCOM address to write + * @param[in] i_data Data to write to given SCOM address + * + * @return errHndl_t Error log handle indicating success or failure + * @retval nullptr Wrote data to SCOM address successfully + * @retval !nullptr Error log providing failure details + */ + errlHndl_t writeSecurityRegister( + TARGETING::Target* i_pTarget, + uint64_t i_scomAddress, + uint64_t i_data) const; + /** Cached secure boot enabled value */ bool iv_enabled; }; diff --git a/src/makefile b/src/makefile index 6a1040291..de74f6420 100644 --- a/src/makefile +++ b/src/makefile @@ -198,7 +198,7 @@ EXTENDED_MODULES += p9_stop_util EXTENDED_MODULES += isteps_mss EXTENDED_MODULES += p9_cpuWkup EXTENDED_MODULES += $(if $(CONFIG_ENABLE_HDAT_IN_HOSTBOOT),hdat) - +EXTENDED_MODULES += $(if $(CONFIG_SECUREBOOT),secureboot_ext) #*************************************** # Working test modules diff --git a/src/usr/i2c/tpmdd.C b/src/usr/i2c/tpmdd.C index 3e34a357b..fc67ff59c 100755 --- a/src/usr/i2c/tpmdd.C +++ b/src/usr/i2c/tpmdd.C @@ -795,7 +795,7 @@ errlHndl_t tpmWrite ( void * i_buffer, { TRACFCOMP(g_trac_tpmdd, ERR_MRK"tpmWrite(): I2C Write-Offset! " - "p/e/dA=%d/%d/0x%X, OP=%d, ", + "p/e/dA=%d/%d/0x%X, OP=%d, " "offset=0x%X, aS=%d, len=%d", i_tpmInfo.port, i_tpmInfo.engine, i_tpmInfo.devAddr, diff --git a/src/usr/initservice/extinitsvc/extinitsvctasks.H b/src/usr/initservice/extinitsvc/extinitsvctasks.H index 02050f6b6..4b326e2fc 100644 --- a/src/usr/initservice/extinitsvc/extinitsvctasks.H +++ b/src/usr/initservice/extinitsvc/extinitsvctasks.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2011,2016 */ +/* Contributors Listed Below - COPYRIGHT 2011,2017 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -70,6 +70,20 @@ const TaskInfo g_exttaskinfolist[] = { }, #endif +#ifdef CONFIG_SECUREBOOT + /** + * @brief Secureboot extended + */ + { + "libsecureboot_ext.so", // taskname + NULL, // no pointer to fn + { + INIT_TASK, // task type + EXT_IMAGE, // Extended Module + } + }, +#endif + /** * @brief targeting task, */ diff --git a/src/usr/isteps/istep06/host_gard.C b/src/usr/isteps/istep06/host_gard.C index 0b6464d2c..f8dc30f1b 100644 --- a/src/usr/isteps/istep06/host_gard.C +++ b/src/usr/isteps/istep06/host_gard.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -53,6 +53,10 @@ // Custom compile configs #include <config.h> +#ifdef CONFIG_DRTM +#include <secureboot/drtm.H> +#endif + #ifdef CONFIG_ENABLE_CHECKSTOP_ANALYSIS #include <hwpf/hwp/occ/occ.H> #include <hwpf/hwp/occ/occ_common.H> @@ -203,6 +207,22 @@ void* host_gard( void *io_pArgs ) msg_free(core_msg); break; } + +#ifdef CONFIG_DRTM + bool drtmMpipl = false; + SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(drtmMpipl) + { + l_err = SECUREBOOT::DRTM::validateDrtmHwSignature(); + if(l_err) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK + "host_gard: Failed in call to validateDrtmHwSignature"); + break; + } + } +#endif + } while (0); if (l_err) diff --git a/src/usr/isteps/istep14/call_host_mpipl_service.C b/src/usr/isteps/istep14/call_host_mpipl_service.C index af29cb5be..6be572e45 100644 --- a/src/usr/isteps/istep14/call_host_mpipl_service.C +++ b/src/usr/isteps/istep14/call_host_mpipl_service.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* Contributors Listed Below - COPYRIGHT 2015,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -40,6 +40,12 @@ #include <vfs/vfs.H> #include <dump/dumpif.H> +#include <config.h> + +#ifdef CONFIG_DRTM +#include <secureboot/drtm.H> +#endif + using namespace ISTEP; using namespace ISTEP_ERROR; using namespace ERRORLOG; @@ -88,6 +94,40 @@ void* call_host_mpipl_service (void *io_pArgs) } +#ifdef CONFIG_DRTM + + if(!l_err) + { + do { + + bool drtmMpipl = false; + SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(drtmMpipl) + { + l_err = SECUREBOOT::DRTM::validateDrtmPayload(); + if(l_err) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK + "call_host_mpipl_service: Failed in call to " + "validateDrtmPayload()"); + break; + } + + l_err = SECUREBOOT::DRTM::completeDrtm(); + if(l_err) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK + "call_host_mpipl_service: Failed in call to " + "completeDrtm()" ); + break; + } + } + + } while(0); + } + +#endif + //Determine if we should perform dump ops //Note that this is only called in MPIPL context, so don't //have to check MPIPL diff --git a/src/usr/isteps/istep21/call_host_start_payload.C b/src/usr/isteps/istep21/call_host_start_payload.C index 776159ca5..3dcdd83b0 100644 --- a/src/usr/isteps/istep21/call_host_start_payload.C +++ b/src/usr/isteps/istep21/call_host_start_payload.C @@ -52,6 +52,11 @@ #include <fapi2/plat_hwp_invoker.H> #include <p9_cpu_special_wakeup.H> #include <ipmi/ipmiwatchdog.H> +#include <config.h> + +#ifdef CONFIG_DRTM_TRIGGERING +#include <secureboot/drtm.H> +#endif using namespace ERRORLOG; @@ -195,6 +200,40 @@ void* call_host_start_payload (void *io_pArgs) l_errl = INITSERVICE::executeUnitTests(); } +#ifdef CONFIG_DRTM_TRIGGERING + + if(l_errl == nullptr) + { + bool drtmMpipl = false; + SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(!drtmMpipl) + { + TARGETING::Target* pSysTarget = nullptr; + TARGETING::targetService().getTopLevelTarget(pSysTarget); + if(pSysTarget == nullptr) + { + assert(false,"call_host_start_payload: BUG! System target was " + "nullptr."); + } + + auto forceDrtm = pSysTarget->getAttr< + TARGETING::ATTR_FORCE_PRE_PAYLOAD_DRTM>(); + + if(forceDrtm) + { + l_errl = SECUREBOOT::DRTM::initiateDrtm(); + if(l_errl) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK + "call_host_start_payload: Failed in call to " + "initiateDrtm()"); + } + } + } + } + +#endif + if( l_errl == NULL ) { l_errl = disableSpecialWakeup(); diff --git a/src/usr/secureboot/HBconfig b/src/usr/secureboot/HBconfig index ac092ad73..0ef8bc748 100644 --- a/src/usr/secureboot/HBconfig +++ b/src/usr/secureboot/HBconfig @@ -3,3 +3,17 @@ config SECUREBOOT default y help Enable secure boot + +config DRTM #TODO RTC: 170487 Disable for relevant platforms + default y if (SECUREBOOT && TPMDD) + depends on (SECUREBOOT && TPMDD) + help + Enable DRTM support + +config DRTM_TRIGGERING #TODO RTC: 170487 Disable for relevant platforms + default y if DRTM + depends on DRTM + help + Enable triggering DRTM from Hostboot when the + ATTR_FORCE_PRE_PAYLOAD_DRTM attribute is overridden + diff --git a/src/usr/secureboot/base/service.C b/src/usr/secureboot/base/service.C index a381c4fd2..54b7d7fb7 100644 --- a/src/usr/secureboot/base/service.C +++ b/src/usr/secureboot/base/service.C @@ -109,6 +109,22 @@ errlHndl_t getJumperState(SecureJumperState& o_state, TARGETING::Target* i_targ) return Singleton<Settings>::instance().getJumperState(o_state, i_targ); } +errlHndl_t clearSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* const i_pTarget) +{ + return Singleton<Settings>::instance().clearSecuritySwitchBits( + i_bits, i_pTarget); +} + +errlHndl_t setSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* const i_pTarget) +{ + return Singleton<Settings>::instance().setSecuritySwitchBits( + i_bits, i_pTarget); +} + void handleSecurebootFailure(errlHndl_t &io_err, bool i_waitForShutdown) { TRACFCOMP( g_trac_secure, ENTER_MRK"handleSecurebootFailure()"); diff --git a/src/usr/secureboot/base/settings.C b/src/usr/secureboot/base/settings.C index bd8f129f0..83e5365e3 100644 --- a/src/usr/secureboot/base/settings.C +++ b/src/usr/secureboot/base/settings.C @@ -129,6 +129,141 @@ namespace SECUREBOOT return l_errl; } + errlHndl_t Settings::clearSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* const i_pTarget) const + { + uint64_t bitsToClear = 0; + for(const auto &bit : i_bits) + { + bitsToClear |= static_cast<uint64_t>(bit); + } + + auto pError = writeSecurityRegister( + i_pTarget, + static_cast<uint64_t>(ProcSecurity::SwitchRegisterClear), + bitsToClear); + + if(pError) + { + SB_ERR("clearSecuritySwitchBits: writeSecurityRegister " + "(SwitchRegisterClear) failed. Target HUID = 0x%08X, data = " + "0x%016llX.", + get_huid(i_pTarget),bitsToClear); + SB_ERR("clearSecuritySwitchBits: plid=0x%08X, eid=0x%08X, " + "reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + return pError; + } + + errlHndl_t Settings::setSecuritySwitchBits( + const std::vector<SECUREBOOT::ProcSecurity>& i_bits, + TARGETING::Target* const i_pTarget) const + { + uint64_t bitsToSet = 0; + for(const auto &bit : i_bits) + { + bitsToSet |= static_cast<uint64_t>(bit); + } + + auto pError = writeSecurityRegister( + i_pTarget, + static_cast<uint64_t>(ProcSecurity::SwitchRegister), + bitsToSet); + + if(pError) + { + SB_ERR("setSecuritySwitchBits: writeSecurityRegister " + "(SwitchRegister) failed. Target HUID = 0x%08X, data = " + "0x%016llX.", + get_huid(i_pTarget),bitsToSet); + SB_ERR("setSecuritySwitchBits: plid=0x%08X, eid=0x%08X, " + "reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + return pError; + } + + errlHndl_t Settings::writeSecurityRegister( + TARGETING::Target* const i_pTarget, + const uint64_t i_scomAddress, + const uint64_t i_data) const + { + errlHndl_t pError = nullptr; + + do + { + + // Target must be the sentinel or some other non-NULL proc value + if ( (i_pTarget != TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) + && ( (i_pTarget == nullptr) + || ( (i_pTarget->getAttr<TARGETING::ATTR_TYPE>()) + != (TARGETING::TYPE_PROC) ) ) ) + { + SB_ERR("writeSecurityRegister: Caller invoked API with bad target; " + "Target HUID = 0x%08X.",get_huid(i_pTarget)); + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid SECUREBOOT::MOD_SECURE_WRITE_REG + * @reasoncode SECUREBOOT::RC_SECURE_BAD_TARGET + * @userdata1 Target pointer value + * @userdata2 Target's HUID or 0 if NULL target pointer + * @devdesc Invalid target used to write security + * register. + * @custdesc Unexpected internal firmware error. + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + SECUREBOOT::MOD_SECURE_WRITE_REG, + SECUREBOOT::RC_SECURE_BAD_TARGET, + reinterpret_cast<uint64_t>(i_pTarget), + TO_UINT64(get_huid(i_pTarget)), + true); + pError->collectTrace(SECURE_COMP_NAME, ERROR_TRACE_SIZE); + break; + } + + // Write security switch settings to processor + const size_t expSize = sizeof(i_data); + size_t actSize = expSize; + pError = deviceWrite( + i_pTarget, + const_cast<uint64_t*>(&i_data), actSize, + DEVICE_SCOM_ADDRESS(i_scomAddress)); + if (nullptr != pError) + { + SB_ERR("writeSecurityRegister: deviceWrite failed; target HUID = " + "0x%08X, SCOM addr = 0x%016llX, data = 0x%016llX.", + get_huid(i_pTarget),i_scomAddress,i_data); + break; + } + + assert(actSize == expSize, + "writeSecurityRegister: BUG! size returned from device write (%d) " + "is not the expected size of %d",actSize,expSize); + + } while(0); + + if(pError) + { + SB_ERR("writeSecurityRegister: plid=0x%08X, eid=0x%08X, " + "reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + return pError; + } + errlHndl_t Settings::readSecurityRegister(Target* i_targ, const uint64_t i_scomAddress, uint64_t& o_regValue) const diff --git a/src/usr/secureboot/common/securetrace.H b/src/usr/secureboot/common/securetrace.H index 17c6988c7..06d3bc6b5 100644 --- a/src/usr/secureboot/common/securetrace.H +++ b/src/usr/secureboot/common/securetrace.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016 */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -61,4 +61,10 @@ extern trace_desc_t* g_trac_secure; #define SB_DBG_BIN(args...) \ TRACDBIN(SECUREBOOT::g_trac_secure,args) +#define SB_UNIT(args...) \ + TRACUCOMP(SECUREBOOT::g_trac_secure,"U> " args) + +#define SB_UNIT_BIN(args...) \ + TRACUBIN(SECUREBOOT::g_trac_secure,args) + #endif diff --git a/src/usr/secureboot/ext/drtm.C b/src/usr/secureboot/ext/drtm.C new file mode 100644 index 000000000..1497e35e3 --- /dev/null +++ b/src/usr/secureboot/ext/drtm.C @@ -0,0 +1,723 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/secureboot/ext/drtm.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2013,2017 */ +/* [+] 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 <stdint.h> +#include <config.h> +#include <builtins.h> +#include <limits.h> +#include <string.h> +#include <vector> +#include <algorithm> + +#include <sys/mm.h> +#include <sys/task.h> +#include <util/align.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <targeting/common/util.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/commontargeting.H> +#include <arch/pirformat.H> +#include <initservice/mboxRegs.H> +#include <util/utilmbox_scratch.H> +#include <secureboot/settings.H> +#include <secureboot/service.H> +#include <secureboot/secure_reasoncodes.H> +#include <secureboot/trustedbootif.H> +#include <secureboot/drtm.H> + +#include "../common/securetrace.H" + +// Set to "1" to enable unit tracing +#if 0 + // Enable SB_UNIT + #define TRACUCOMP(args...) TRACFCOMP(args) + // Enable SB_UNIT_BIN + #define TRACUBIN(args...) TRACFBIN(args) +#else + #define TRACUCOMP(args...) + #define TRACUBIN(args...) +#endif + +// Makes the math more intuitive +#define BYTES_PER_MEGABYTE MEGABYTE + +namespace SECUREBOOT +{ + +namespace DRTM +{ + +#ifdef CONFIG_DRTM_TRIGGERING + +// RIT protection DRTM payload address in megabytes +// Use reserved area immediately before payload base +const uint32_t DRTM_RIT_PAYLOAD_PHYS_ADDR_MB = 256-1; + +// RIT protection payload +const char DRTM_RIT_PAYLOAD[] = {'D','R','T','M'}; + +const char* const DRTM_RIT_LOG_TEXT = "DrtmPayload"; + +#endif + +errlHndl_t discoverDrtmState( + const INITSERVICE::SPLESS::MboxScratch7_t& i_scratchReg7, + const INITSERVICE::SPLESS::MboxScratch8_t& i_scratchReg8) +{ + SB_ENTER("discoverDrtmState: i_scratchReg7=0x%08X, " + "i_scratchReg8 = 0x%08X", + i_scratchReg7.data32,i_scratchReg8.data32); + + errlHndl_t pError = nullptr; + + do + { + + TARGETING::Target* pSysTarget = nullptr; + TARGETING::targetService().getTopLevelTarget(pSysTarget); + + if(pSysTarget == nullptr) + { + // TODO: RTC 167205: GA error handling + assert(false,"discoverDrtmState: BUG! nullptr system target detected."); + break; + } + + TARGETING::Target* pMasterProc = nullptr; + pError = TARGETING::targetService().queryMasterProcChipTargetHandle( + pMasterProc); + if(pError) + { + SB_ERR("discoverDrtmState: Failed in call to " + "queryMasterProcChipTargetHandle()."); + break; + } + + uint64_t securitySwitches = 0; + pError = SECUREBOOT::getSecuritySwitch(securitySwitches, + pMasterProc); + if(pError) + { + SB_ERR("discoverDrtmState: Failed in call to getSecuritySwitch() for " + "proc = 0x%08X.", + get_huid(pMasterProc)); + break; + } + + const bool masterProcL4A = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::L4ABit); + const bool masterProcLQA = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::LQABit); + const bool masterProcLLP = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::LLPBit); + + const bool drtmPayloadValid = i_scratchReg8.validDrtmPayloadAddr; + const bool isMpiplBoot = pSysTarget->getAttr<TARGETING::ATTR_IS_MPIPL_HB>(); + const bool securebootEnabled = SECUREBOOT::enabled(); + + SB_INF("discoverDrtmState: masterProcL4A = %d, drtmPayloadValid = %d, " + "isMpiplBoot = %d, securebootEnabled = %d, " + "masterProcLQA = %d, i_scratchReg7 = 0x%08X, " + "masterProcLLP = %d.", + masterProcL4A,drtmPayloadValid,isMpiplBoot, + securebootEnabled,masterProcLQA,i_scratchReg7.drtmPayloadAddrMb, + masterProcLLP); + + TARGETING::ATTR_IS_DRTM_MPIPL_HB_type drtmMpIpl = false; + if(masterProcL4A || drtmPayloadValid) + { + // Note: We don't care if trusted boot is not enabled, if not, the + // measurement will simply be ignored later + if( !masterProcL4A + || !drtmPayloadValid + || !isMpiplBoot + || !securebootEnabled + || !masterProcLQA + || masterProcLLP) + { + // TODO: RTC 167205: GA error handling + assert(false,"discoverDrtmState: BUG! Inconsistent DRTM state " + "detected. masterProcL4A = %d, drtmPayloadValid = %d, " + "isMpiplBoot = %d, securebootEnabled = %d, " + "masterProcLQA = %d, masterProcLLP = %d.", + masterProcL4A,drtmPayloadValid,isMpiplBoot, + securebootEnabled,masterProcLQA,masterProcLLP); + break; + } + else + { + drtmMpIpl = true; + } + } + + if( drtmMpIpl + && (i_scratchReg7.drtmPayloadAddrMb == 0)) + { + // TODO: RTC 167205: GA error handling + assert(false,"discoverDrtmState: BUG! DRTM payload address " + "should not be 0 on a DRTM boot."); + break; + } + + const auto drtmPayloadAddrMb = drtmMpIpl ? + i_scratchReg7.drtmPayloadAddrMb : 0; + + pSysTarget->setAttr<TARGETING::ATTR_IS_DRTM_MPIPL_HB>(drtmMpIpl); + pSysTarget->setAttr<TARGETING::ATTR_DRTM_PAYLOAD_ADDR_MB_HB>( + drtmPayloadAddrMb); + + // NOTE: It should be SBE job to clear the DRTM scratch regs + // on any given non-DRTM boot flow, hence Hostboot never has to clear them. + + } while(0); + + if(pError) + { + SB_ERR("discoverDrtmState: plid=0x%08X, eid=0x%08X, reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + SB_EXIT("discoverDrtmState"); + + return pError; +} + +void isDrtmMpipl(bool& o_isDrtmMpipl) +{ + TARGETING::Target* pSysTarget = nullptr; + TARGETING::targetService().getTopLevelTarget(pSysTarget); + + if(pSysTarget == nullptr) + { + // TODO: RTC 167205: GA error handling + assert(false,"isDrtmMpipl: BUG! nullptr system target detected"); + } + + o_isDrtmMpipl = pSysTarget->getAttr<TARGETING::ATTR_IS_DRTM_MPIPL_HB>(); +} + +errlHndl_t validateDrtmHwSignature() +{ + SB_ENTER("validateDrtmHwSignature"); + + errlHndl_t pError = nullptr; + + do + { + bool drtmMpIpl = false; + isDrtmMpipl(drtmMpIpl); + + if(drtmMpIpl) + { + SB_DBG("validateDrtmHwSignature: DRTM active, checking L4A, LQA, " + "SUL, LLS and LLP on node's functional proc chips."); + + TARGETING::TargetHandleList funcProcChips; + TARGETING::getAllChips(funcProcChips, + TARGETING::TYPE_PROC); + for(auto &pFuncProc :funcProcChips) + { + uint64_t securitySwitches = 0; + pError = SECUREBOOT::getSecuritySwitch(securitySwitches, + pFuncProc); + if(pError) + { + SB_ERR("validateDrtmHwSignature: getSecuritySwitch() " + "failed for proc = 0x%08X.", + get_huid(pFuncProc)); + break; + } + + const bool L4A = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::L4ABit); + const bool LQA = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::LQABit); + const bool SUL = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::SULBit); + const bool LLP = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::LLPBit); + const bool LLS = securitySwitches + & static_cast<uint64_t>(SECUREBOOT::ProcSecurity::LLSBit); + + SB_INF("validateDrtmHwSignature: Proc 0x%08X has L4A = %d, " + "LQA = %d, SUL = %d, LLP = %d, LLS = %d.", + get_huid(pFuncProc),L4A,LQA,SUL,LLP,LLS); + + if(!L4A || !LQA || !SUL || LLP || LLS) + { + // TODO: RTC 167205: GA error handling, including whether + // to attempt on every processor + assert(false,"validateDrtmHwSignature: BUG! In DRTM flow, " + "all functional proc chips should have L4A, LQA, and " + "SUL set + LLP and LLS clear, however proc 0x%08X has " + "L4A = %d, LQA = %d, SUL = %d, LLP = %d, LLS = %d.", + get_huid(pFuncProc),L4A,LQA,SUL,LLP,LLS); + break; + } + } + + if(pError) + { + break; + } + } + else + { + SB_INF("validateDrtmHwSignature: DRTM not active, skipping check " + "for L4A, LQA, SUL, LLP and LLS on node's functional procs"); + } + + } while(0); + + if(pError) + { + SB_ERR("validateDrtmHwSignature: plid=0x%08X, eid=0x%08X, " + "reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + SB_EXIT("validateDrtmHwSignature"); + + return pError; +} + +errlHndl_t validateDrtmPayload() +{ + SB_ENTER("validateDrtmPayload"); + + errlHndl_t pError = nullptr; + const void* drtmPayloadVirtAddr = nullptr; + + do + { + bool drtmMpIpl = false; + isDrtmMpipl(drtmMpIpl); + + if(drtmMpIpl) + { + SB_DBG("validateDrtmPayload: DRTM active, validating DRTM payload." + "proc chips."); + + TARGETING::Target* pSysTarget = nullptr; + TARGETING::targetService().getTopLevelTarget(pSysTarget); + + if(pSysTarget == nullptr) + { + // TODO: RTC 167205: GA error handling + assert(false,"validateDrtmPayload: BUG! nullptr system target " + "detected"); + break; + } + + const auto drtmPayloadPhysAddrMb = pSysTarget->getAttr< + TARGETING::ATTR_DRTM_PAYLOAD_ADDR_MB_HB>(); + + if(drtmPayloadPhysAddrMb == 0) + { + assert(false,"validateDrtmPayload: BUG! DRTM payload physical " + "address should not be 0."); + break; + } + + const uint64_t drtmPayloadPhysAddr = + drtmPayloadPhysAddrMb*BYTES_PER_MEGABYTE; + + SB_INF("validateDrtmPayload: DRTM payload available at physical " + "address of %d MB (0x%16llX).", + drtmPayloadPhysAddrMb,drtmPayloadPhysAddr); + + // Compute DRTM payload size + // TODO: RTC 167205: Once the DRTM save area is known/defined, + // need to figure out a better initial size to map. For example, + // perhaps we map just one page to begin with, in order to read out + // the actual total size. Also, a size is available, assert if the + // size is 0. + uint64_t drtmPayloadSize = 0; + #ifdef CONFIG_DRTM_TRIGGERING + drtmPayloadSize = ALIGN_PAGE(sizeof(DRTM_RIT_PAYLOAD)); + #endif + + // Map in the physical memory to virtual memory + drtmPayloadVirtAddr = mm_block_map ( + reinterpret_cast<void*>(drtmPayloadPhysAddr),drtmPayloadSize); + if(drtmPayloadVirtAddr == nullptr) + { + // TODO: RTC 167205: GA error handling + assert(false,"validateDrtmPayload: BUG! mm_block_map returned " + "nullptr for physical address 0x%016llX and size " + "0x%016llX.", + drtmPayloadPhysAddr,drtmPayloadSize); + break; + } + + #ifdef CONFIG_DRTM_TRIGGERING + + // Verify the payload matches expected result + if(memcmp(drtmPayloadVirtAddr,DRTM_RIT_PAYLOAD, + sizeof(DRTM_RIT_PAYLOAD) != 0)) + { + const uint32_t* pAddrAct = reinterpret_cast<const uint32_t*>( + drtmPayloadVirtAddr); + const uint32_t* pAddrExp = reinterpret_cast<const uint32_t*>( + &DRTM_RIT_PAYLOAD); + + SB_ERR("validateDrtmPayload: DRTM RIT: payload content at " + "0x%16llX was not as expected. Expected value = 0x%08X, " + "actual = 0x%08X", + drtmPayloadVirtAddr, + *pAddrAct, + *pAddrExp); + + // TODO: RTC 167205: GA error handling + assert(false,"validateDrtmPayload: BUG: DRTM payload content " + "at 0x%16llX was not as expected. Expected value = " + "0x%08X, actual = 0x%08X", + drtmPayloadVirtAddr, + *pAddrAct, + *pAddrExp); + break; + } + + // Extend (arbitrary) measurement to PCR17 + SHA512_t hash = {0}; + memcpy(hash,DRTM_RIT_PAYLOAD,sizeof(DRTM_RIT_PAYLOAD)); + pError = TRUSTEDBOOT::pcrExtend(TRUSTEDBOOT::PCR_DRTM_17, hash, + sizeof(SHA512_t),DRTM_RIT_LOG_TEXT); + if(pError) + { + SB_ERR("validateDrtmPayload: Failed in pcrExtend() for PCR 17"); + break; + } + + #else + + // TODO: RTC 167205: Securely verify the measured launch environment + // TODO: RTC 167205: Really measure+extend the payload + + #endif + } + else + { + SB_INF("validateDrtmPayload: DRTM not active, skipping DRTM " + "payload verification "); + } + + } while(0); + + if(drtmPayloadVirtAddr) + { + auto rc = mm_block_unmap(const_cast<void*>(drtmPayloadVirtAddr)); + if(rc != 0) + { + // TODO: RTC 167205: GA error handling + assert(false,"validateDrtmPayload: BUG! mm_block_unmap failed for " + "virtual address 0x%16llX.", + drtmPayloadVirtAddr); + + } + } + + if(pError) + { + SB_ERR("validateDrtmPayload: plid=0x%08X, eid=0x%08X, reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + SB_EXIT("validateDrtmPayload"); + + return pError; +} + +errlHndl_t completeDrtm() +{ + SB_ENTER("completeDrtm"); + + errlHndl_t pError = nullptr; + + do + { + bool drtmMpIpl = false; + isDrtmMpipl(drtmMpIpl); + + if(drtmMpIpl) + { + SB_INF("completeDrtm: Clearing L4A and LQA on node's functional " + "proc chips."); + + const std::vector<SECUREBOOT::ProcSecurity> bitsToClear { + SECUREBOOT::ProcSecurity::L4ABit, + SECUREBOOT::ProcSecurity::LQABit + }; + + TARGETING::TargetHandleList funcProcChips; + TARGETING::getAllChips(funcProcChips, + TARGETING::TYPE_PROC); + + for(auto &pFuncProc :funcProcChips) + { + pError = SECUREBOOT::clearSecuritySwitchBits(bitsToClear, + pFuncProc); + if(pError) + { + // TODO: RTC 167205: GA error handling to attempt on every + // processor + SB_ERR("completeDrtm: clearSecuritySwitchBits() failed for " + "proc = 0x%08X. Tried to clear LQA + L4A.", + get_huid(pFuncProc)); + break; + } + } + + if(pError) + { + break; + } + + } + else + { + SB_INF("completeDrtm: DRTM not active, not clearing LQA or L4A " + "bits."); + } + + } while(0); + + if(pError) + { + SB_ERR("completeDrtm: plid=0x%08X, eid=0x%08X, reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + SB_EXIT("completeDrtm"); + + return pError; +} + +#ifdef CONFIG_DRTM_TRIGGERING + +errlHndl_t initiateDrtm() +{ + SB_ENTER("initiateDrtm"); + + errlHndl_t pError = nullptr; + + // For DRTM, the thread has to be pinned to a core (and therefore pinned to + // a chip) + task_affinity_pin(); + + void* drtmPayloadVirtAddr = nullptr; + + do + { + const std::vector<SECUREBOOT::ProcSecurity> LLP { + SECUREBOOT::ProcSecurity::LLPBit, + }; + + const std::vector<SECUREBOOT::ProcSecurity> LLS { + SECUREBOOT::ProcSecurity::LLSBit, + }; + + // Determine which fabric group and chip this task is executing on and + // create a filter to find the matching chip target + auto cpuId = task_getcpuid(); + auto groupId = PIR_t::groupFromPir(cpuId); + auto chipId = PIR_t::chipFromPir(cpuId); + TARGETING::PredicateAttrVal<TARGETING::ATTR_FABRIC_GROUP_ID> + matchesGroup(groupId); + TARGETING::PredicateAttrVal<TARGETING::ATTR_FABRIC_CHIP_ID> + matchesChip(chipId); + TARGETING::PredicatePostfixExpr matchesGroupAndChip; + matchesGroupAndChip.push(&matchesGroup).push(&matchesChip).And(); + + // Get all the functional proc chips and find the chip we're running on + TARGETING::TargetHandleList funcProcChips; + TARGETING::getAllChips(funcProcChips, + TARGETING::TYPE_PROC); + if(funcProcChips.empty()) + { + // TODO: RTC 167205: GA error handling + assert(false,"initiateDrtm: BUG! Functional proc chips is empty, " + "yet this code is running on a functional chip!"); + break; + } + + // NOTE: std::find_if requires predicates to be copy constructable, but + // predicates are not; hence use a wrapper lambda function to bypass + // that limitation + auto pMatch = + std::find_if(funcProcChips.begin(),funcProcChips.end(), + [&matchesGroupAndChip] ( TARGETING::Target* pTarget ) + { + return matchesGroupAndChip(pTarget); + } ); + + if(pMatch == funcProcChips.end()) + { + // TODO: RTC 167205: GA error handling + assert(false, "initiateDrtm: BUG! No functional chip found " + "to be running this code"); + break; + } + + // Move the matching target to the end of the list. + // NOTE: If reverse iterators were supported, we could have verified the + // last element of the container is not the match, and done a + // std::iter_swap of the match and the last element + TARGETING::Target* const pMatchTarget = *pMatch; + funcProcChips.erase(pMatch); + funcProcChips.push_back(pMatchTarget); + + // Map to the DRTM payload area in mainstore + const uint32_t drtmPayloadPhysAddrMb = DRTM_RIT_PAYLOAD_PHYS_ADDR_MB; + drtmPayloadVirtAddr = mm_block_map( + reinterpret_cast<void*>(drtmPayloadPhysAddrMb*BYTES_PER_MEGABYTE), + PAGESIZE); + if(drtmPayloadVirtAddr == nullptr) + { + // TODO: RTC 167205: GA error handling + assert(false, "initiateDrtm: BUG! Failed in call to mm_block_map " + "to map the DRTM payload."); + break; + } + + // Copy the DRTM payload to the DRTM payload area + memcpy( + reinterpret_cast<uint32_t*>(drtmPayloadVirtAddr), + DRTM_RIT_PAYLOAD, + sizeof(DRTM_RIT_PAYLOAD)); + + // The required generic sequencing to initiate DRTM is as follows: + // 1) Initiating task must pin itself to a core (to ensure it + // will not be accidentally queisced by SBE) + // 2) It must set the DRTM payload information in the master processor + // mailbox scratch registers (registers 7 and 8) before it goes + // offline + // 3) It must determine the processor it's currently running on + // 4) It must set the late launch bit (LL) on all other processors + // 4a) If the given processor is an active master, it must set + // late launch primary (LLP) bit + // 4b) Otherwise it must set late launch secondary (LLS) bit + // 5) Finally, it must its own processor's LL bit last, according to the + // rules of step 4. + for(auto &pFuncProc :funcProcChips) + { + const auto procMasterType = pFuncProc->getAttr< + TARGETING::ATTR_PROC_MASTER_TYPE>(); + + // If master chip, set the DRTM payload address and validity + if(procMasterType == TARGETING::PROC_MASTER_TYPE_ACTING_MASTER) + { + (void)setDrtmPayloadPhysAddrMb(drtmPayloadPhysAddrMb); + } + + pError = SECUREBOOT::setSecuritySwitchBits(procMasterType == + TARGETING::PROC_MASTER_TYPE_ACTING_MASTER ? + LLP : LLS, + pFuncProc); + if(pError) + { + SB_ERR("initiateDrtm: setSecuritySwitchBits() failed for proc " + "= 0x%08X. Tried to set LLP or LLS.", + get_huid(pFuncProc)); + break; + } + } + + if(pError) + { + break; + } + + + SB_INF("initiateDrtm: SBE should eventually quiesce all cores; until " + "then, endlessly yield the task"); + while(1) + { + task_yield(); + } + + } while(0); + + // If we -do- come back from this function (on error path only), then we + // should unpin + task_affinity_unpin(); + + if(drtmPayloadVirtAddr) + { + auto rc = mm_block_unmap(const_cast<void*>(drtmPayloadVirtAddr)); + if(rc != 0) + { + // TODO: RTC 167205: GA error handling + assert(false,"initiateDrtm: BUG! mm_block_unmap failed for virtual " + "address 0x%16llX.", + drtmPayloadVirtAddr); + } + } + + if(pError) + { + SB_ERR("initiateDrtm: plid=0x%08X, eid=0x%08X, reason=0x%04X", + ERRL_GETPLID_SAFE(pError), + ERRL_GETEID_SAFE(pError), + ERRL_GETRC_SAFE(pError)); + } + + SB_EXIT("initiateDrtm"); + + return pError; +} + +void setDrtmPayloadPhysAddrMb( + const uint32_t i_drtmPayloadPhysAddrMb) +{ + // Set the address + Util::writeScratchReg( + INITSERVICE::SPLESS::MBOX_SCRATCH_REG7,i_drtmPayloadPhysAddrMb); + + // Mark as valid if non-0, else invalid + INITSERVICE::SPLESS::MboxScratch8_t scratch8 = + { .data32 = Util::readScratchReg( + INITSERVICE::SPLESS::MBOX_SCRATCH_REG8) }; + scratch8.validDrtmPayloadAddr = + i_drtmPayloadPhysAddrMb ? true : false; + Util::writeScratchReg( + INITSERVICE::SPLESS::MBOX_SCRATCH_REG8,scratch8.data32); +} + +#endif // CONFIG_DRTM_TRIGGERING + +} // End DRTM namespace + +} // End SECUREBOOT namespace + diff --git a/src/usr/secureboot/ext/makefile b/src/usr/secureboot/ext/makefile index ddc0261cc..952a8cc56 100644 --- a/src/usr/secureboot/ext/makefile +++ b/src/usr/secureboot/ext/makefile @@ -5,7 +5,9 @@ # # OpenPOWER HostBoot Project # -# COPYRIGHT International Business Machines Corp. 2013,2014 +# Contributors Listed Below - COPYRIGHT 2013,2017 +# [+] 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. @@ -24,7 +26,7 @@ ROOTPATH = ../../../.. MODULE = secureboot_ext SUBDIRS += -OBJS += +OBJS += $(if $(CONFIG_DRTM),drtm.o) CFLAGS += -iquote ../ include ${ROOTPATH}/config.mk diff --git a/src/usr/secureboot/trusted/trustedboot.C b/src/usr/secureboot/trusted/trustedboot.C index b6bbd313b..2009ab07a 100644 --- a/src/usr/secureboot/trusted/trustedboot.C +++ b/src/usr/secureboot/trusted/trustedboot.C @@ -56,6 +56,9 @@ #include "tpmLogMgr.H" #include "base/trustedbootMsg.H" #include <secureboot/settings.H> +#ifdef CONFIG_DRTM +#include <secureboot/drtm.H> +#endif namespace TRUSTEDBOOT { @@ -375,10 +378,18 @@ void tpmInitialize(TRUSTEDBOOT::TpmTarget & io_target) io_target.initAttempted = true; io_target.failed = false; - bool drtm = false; - /// @todo #157140 Add ability to check for DRTM + bool sendStartup = true; + +#ifdef CONFIG_DRTM + bool drtmMpipl = false; + (void)SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(drtmMpipl) + { + sendStartup = false; + } +#endif // Don't run STARTUP during DRTM - if (!drtm) + if (sendStartup) { // TPM_STARTUP err = tpmCmdStartup(&io_target); @@ -395,11 +406,13 @@ void tpmInitialize(TRUSTEDBOOT::TpmTarget & io_target) break; } +#ifdef CONFIG_DRTM // For a DRTM we need to reset PCRs 17-22 - if (drtm) + if (drtmMpipl) { - /// @todo Implement PCR reset + /// @TODO RTC 167667 Implement PCR reset } +#endif } while ( 0 ); @@ -596,7 +609,7 @@ errlHndl_t tpmLogConfigEntries(TRUSTEDBOOT::TpmTarget & io_target) } void pcrExtendSingleTpm(TpmTarget & io_target, - TPM_Pcr i_pcr, + const TPM_Pcr i_pcr, TPM_Alg_Id i_algId, const uint8_t* i_digest, size_t i_digestSize, @@ -606,6 +619,26 @@ void pcrExtendSingleTpm(TpmTarget & io_target, TCG_PCR_EVENT2 eventLog; bool unlock = false; + TPM_Pcr pcr = i_pcr; + bool useStaticLog = true; + +#ifdef CONFIG_DRTM + // In a DRTM flow, all extensions must be re-rerouted to PCR 17 + // (which will end up using locality 2). + bool drtmMpipl = false; + (void)SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(drtmMpipl) + { + TRACFCOMP(g_trac_trustedboot, + INFO_MRK " pcrExtendSingleTpm(): DRTM active; re-routing PCR %d " + "extend to PCR 17", + i_pcr); + + pcr = PCR_DRTM_17; + useStaticLog = false; + } +#endif + memset(&eventLog, 0, sizeof(eventLog)); do { @@ -617,22 +650,29 @@ void pcrExtendSingleTpm(TpmTarget & io_target, !io_target.failed) { // Fill in TCG_PCR_EVENT2 and add to log - eventLog = TpmLogMgr_genLogEventPcrExtend(i_pcr, + eventLog = TpmLogMgr_genLogEventPcrExtend(pcr, i_algId, i_digest, i_digestSize, TPM_ALG_SHA1, i_digest, i_digestSize, i_logMsg); - err = TpmLogMgr_addEvent(io_target.logMgr,&eventLog); - if (NULL != err) + if(useStaticLog) { - break; + err = TpmLogMgr_addEvent(io_target.logMgr,&eventLog); + if (NULL != err) + { + break; + } } + // TODO: RTC 145689: Add DRTM support for using dynamic + // log instead of static log; until then, inhibit DRTM logging + // entirely + // Perform the requested extension and also force into the // SHA1 bank err = tpmCmdPcrExtend2Hash(&io_target, - i_pcr, + pcr, i_algId, i_digest, i_digestSize, @@ -685,16 +725,34 @@ void pcrExtendSeparator(TpmTarget & io_target) mutex_lock( &io_target.tpmMutex ); unlock = true; - for (TPM_Pcr curPcr = PCR_0; curPcr <= PCR_7; - curPcr = static_cast<TPM_Pcr>(curPcr + 1)) + std::vector<TPM_Pcr> pcrs = + {PCR_0,PCR_1,PCR_2,PCR_3,PCR_4,PCR_5,PCR_6,PCR_7}; + bool useStaticLog = true; + +#ifdef CONFIG_DRTM + // In a DRTM flow, all extensions must be re-rerouted to PCR 17 + // (which will end up using locality 2). + bool drtmMpipl = false; + (void)SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(drtmMpipl) { + TRACFCOMP(g_trac_trustedboot, + INFO_MRK " pcrExtendSeparator(): DRTM active; extending " + "separator to PCR 17 instead of PCR 0..7."); + + pcrs = { PCR_DRTM_17 }; + useStaticLog = false; + } +#endif + for (const auto &pcr : pcrs) + { // Log the separator if (io_target.available && !io_target.failed) { // Fill in TCG_PCR_EVENT2 and add to log - eventLog = TpmLogMgr_genLogEventPcrExtend(curPcr, + eventLog = TpmLogMgr_genLogEventPcrExtend(pcr, TPM_ALG_SHA1, sha1_digest, sizeof(sha1_digest), @@ -702,15 +760,24 @@ void pcrExtendSeparator(TpmTarget & io_target) sha256_digest, sizeof(sha256_digest), logMsg); - err = TpmLogMgr_addEvent(io_target.logMgr,&eventLog); - if (NULL != err) + + if(useStaticLog) { - break; + err = TpmLogMgr_addEvent(io_target.logMgr,&eventLog); + if (NULL != err) + { + break; + } } + // TODO: RTC 145689: Add DRTM support for using dynamic + // log (which will happen any time useStaticLog is false). + // Until then, we cannot log DRTM events, since they are only + // allowed to go to the dynamic log + // Perform the requested extension err = tpmCmdPcrExtend2Hash(&io_target, - curPcr, + pcr, TPM_ALG_SHA1, sha1_digest, sizeof(sha1_digest), diff --git a/src/usr/secureboot/trusted/trustedbootCmds.C b/src/usr/secureboot/trusted/trustedbootCmds.C index 9e5875933..a052c0571 100644 --- a/src/usr/secureboot/trusted/trustedbootCmds.C +++ b/src/usr/secureboot/trusted/trustedbootCmds.C @@ -37,6 +37,8 @@ // ---------------------------------------------- #include <string.h> #include <stdlib.h> +#include <config.h> + #ifdef __HOSTBOOT_MODULE #include <secureboot/trustedboot_reasoncodes.H> #else @@ -47,6 +49,10 @@ #include "trustedboot.H" #include "trustedTypes.H" +#ifdef CONFIG_DRTM +#include <secureboot/drtm.H> +#endif + #ifdef __cplusplus namespace TRUSTEDBOOT { @@ -844,10 +850,26 @@ errlHndl_t tpmCmdPcrExtend2Hash(TpmTarget * io_target, i_digestSize_2 : fullDigestSize_2)); } + tpm_locality_t tpmLocality = TPM_LOCALITY_0; +#ifdef CONFIG_DRTM + bool drtmMpipl = false; + SECUREBOOT::DRTM::isDrtmMpipl(drtmMpipl); + if(drtmMpipl) + { + assert(i_pcr == TRUSTEDBOOT::PCR_DRTM_17, + "BUG! All DRTM extensions must be to PCR 17 (instead of %d)", + i_pcr); + + TRACFCOMP(g_trac_trustedboot, + INFO_MRK " tpmCmdPcrExtend2Hash(): DRTM active, redirecting " + "PCR extend request from locality 0 to locality 2."); + tpmLocality = TPM_LOCALITY_2; + } +#endif err = tpmTransmitCommand(io_target, dataBuf, sizeof(dataBuf), - TPM_LOCALITY_0); + tpmLocality); if (TB_SUCCESS != err) { diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml index 8888fff33..94b571b17 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml @@ -1705,6 +1705,53 @@ ID for the sensor number returned with the elog. --> </attribute> <attribute> + <id>IS_DRTM_MPIPL_HB</id> + <description> + Indicates if this is a DRTM MPIPL flow or not. + 0x00 = Not a DRTM MPIPL + 0x01 = DRTM MPIPL + </description> + <simpleType> + <uint8_t><default>0</default></uint8_t> + </simpleType> + <persistency>volatile-zeroed</persistency> + <readable/> + <writeable/> +</attribute> + +<attribute> + <id>DRTM_PAYLOAD_ADDR_MB_HB</id> + <description> + Physical address of DRTM payload in megabytes. 0 MB is not considered to + be a valid DRTM payload address + </description> + <simpleType> + <uint32_t><default>0</default></uint32_t> + </simpleType> + <persistency>volatile-zeroed</persistency> + <readable/> + <writeable/> +</attribute> + +<attribute> + <id>FORCE_PRE_PAYLOAD_DRTM</id> + <description> + If Hostboot is compiled with CONFIG_DRTM_TRIGGERING, controls + whether Hostboot will initiate a DRTM late launch sequence in place of + loading the payload. This attribute should always be compiled in not to + force the late launch sequence; it is designed to be changed via + attribute overrides only, to facilitate testing. + 0x00: Do not force a DRTM late launch sequence + 0x01: Force a DRTM late launch sequence (if not a DRTM boot) + </description> + <simpleType> + <uint8_t><default>0</default></uint8_t> + </simpleType> + <persistency>volatile-zeroed</persistency> + <readable/> +</attribute> + +<attribute> <id>ATTN_CHK_ALL_PROCS</id> <description> Used to tell ATTN code whether to chk MASTER(0) OR all PROCs(1) diff --git a/src/usr/targeting/common/xmltohb/target_types_hb.xml b/src/usr/targeting/common/xmltohb/target_types_hb.xml index 486b2c40a..811edd5fa 100755 --- a/src/usr/targeting/common/xmltohb/target_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/target_types_hb.xml @@ -81,6 +81,9 @@ <attribute><id>OCC_COMMON_AREA_PHYS_ADDR</id> </attribute> <attribute><id>ATTN_CHK_ALL_PROCS</id> </attribute> <attribute><id>MASTER_MBOX_SCRATCH</id> </attribute> + <attribute><id>IS_DRTM_MPIPL_HB</id></attribute> + <attribute><id>DRTM_PAYLOAD_ADDR_MB_HB</id></attribute> + <attribute><id>FORCE_PRE_PAYLOAD_DRTM</id></attribute> </targetTypeExtension> <targetTypeExtension> diff --git a/src/usr/targeting/targetservicestart.C b/src/usr/targeting/targetservicestart.C index 575d22e3d..62edd569c 100755 --- a/src/usr/targeting/targetservicestart.C +++ b/src/usr/targeting/targetservicestart.C @@ -55,7 +55,11 @@ #include <errl/errlmanager.H> #include <devicefw/userif.H> #include <config.h> +#include <initservice/initserviceif.H> +#ifdef CONFIG_DRTM +#include <secureboot/drtm.H> +#endif using namespace INITSERVICE::SPLESS; //****************************************************************************** @@ -151,6 +155,23 @@ static void initTargeting(errlHndl_t& io_pError) l_pTopLevel->getAttrAsString<ATTR_MODEL>()); } +#ifdef CONFIG_DRTM + const INITSERVICE::SPLESS::MboxScratch7_t scratch7 = + {.data32 = l_scratch[SCRATCH_7] }; + const INITSERVICE::SPLESS::MboxScratch8_t scratch8 = + {.data32 = l_scratch[SCRATCH_8] }; + + errlHndl_t pError = SECUREBOOT::DRTM::discoverDrtmState( + scratch7,scratch8); + if(pError) + { + auto plid = pError->plid(); + errlCommit(pError,SECURE_COMP_ID); + // TODO: RTC 167205: Better GA error handling + INITSERVICE::doShutdown(plid, true); + } +#endif + // No error module loaded in VPO to save load time #ifndef CONFIG_VPO_COMPILE // call ErrlManager function - tell him that TARG is ready! |