summaryrefslogtreecommitdiffstats
path: root/src/usr/i2c
diff options
context:
space:
mode:
authorChris Engel <cjengel@us.ibm.com>2015-03-19 16:05:07 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2015-08-31 17:54:12 -0500
commit0795cc6781a4d937786b39c23b655397432ec90e (patch)
treec046357de087101de900b3958e18d60812462381 /src/usr/i2c
parentb9c64e6a1948009018490b3cd41bc8725a8a6050 (diff)
downloadtalos-hostboot-0795cc6781a4d937786b39c23b655397432ec90e.tar.gz
talos-hostboot-0795cc6781a4d937786b39c23b655397432ec90e.zip
Nuvoton TPM 1.2 Device Driver
This adds support for the Nuvoton TPM 1.2 in simics Change-Id: I24973cb9824e31967aae3fb97e86a631e514b2ff RTC: 125287 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/16535 Tested-by: Jenkins Server Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Tested-by: FSP CI Jenkins Reviewed-by: Michael Baiocchi <baiocchi@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/i2c')
-rw-r--r--src/usr/i2c/HBconfig22
-rwxr-xr-xsrc/usr/i2c/eepromdd.C2
-rwxr-xr-xsrc/usr/i2c/eepromdd.H6
-rw-r--r--src/usr/i2c/makefile1
-rw-r--r--src/usr/i2c/test/makefile8
-rwxr-xr-xsrc/usr/i2c/test/tpmddtest.H843
-rwxr-xr-xsrc/usr/i2c/tpmdd.C2036
-rwxr-xr-xsrc/usr/i2c/tpmdd.H509
8 files changed, 3422 insertions, 5 deletions
diff --git a/src/usr/i2c/HBconfig b/src/usr/i2c/HBconfig
new file mode 100644
index 000000000..f9377e524
--- /dev/null
+++ b/src/usr/i2c/HBconfig
@@ -0,0 +1,22 @@
+config TPMDD
+ default n
+ depends on TPM_NUVOTON && (TPMDD_1_2 || TPMDD_2_0)
+ help
+ Enable TPM support
+
+config TPMDD_1_2
+ default n
+ depends on !TPMDD_2_0
+ help
+ Enable TPM 1.2 Support
+
+config TPMDD_2_0
+ default n
+ depends on !TPMDD_1_2
+ help
+ Enable TPM 2.0 Support
+
+config TPM_NUVOTON
+ default n
+ help
+ Enable Nuvoton TPM I2C driver
diff --git a/src/usr/i2c/eepromdd.C b/src/usr/i2c/eepromdd.C
index a6178a61d..55b136cc1 100755
--- a/src/usr/i2c/eepromdd.C
+++ b/src/usr/i2c/eepromdd.C
@@ -599,7 +599,7 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
// ------------------------------------------------------------------
errlHndl_t eepromWrite ( TARGETING::Target * i_target,
void * io_buffer,
- size_t io_buflen,
+ size_t & io_buflen,
eeprom_addr_t i_i2cInfo )
{
errlHndl_t err = NULL;
diff --git a/src/usr/i2c/eepromdd.H b/src/usr/i2c/eepromdd.H
index 6e969cefb..234be5eb1 100755
--- a/src/usr/i2c/eepromdd.H
+++ b/src/usr/i2c/eepromdd.H
@@ -5,7 +5,9 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* COPYRIGHT International Business Machines Corp. 2011,2014 */
+/* Contributors Listed Below - COPYRIGHT 2011,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. */
@@ -150,7 +152,7 @@ errlHndl_t eepromRead ( TARGETING::Target * i_target,
*/
errlHndl_t eepromWrite ( TARGETING::Target * i_target,
void * io_buffer,
- size_t io_buflen,
+ size_t & io_buflen,
eeprom_addr_t i_i2cInfo );
/**
diff --git a/src/usr/i2c/makefile b/src/usr/i2c/makefile
index f3c47daec..a226d6754 100644
--- a/src/usr/i2c/makefile
+++ b/src/usr/i2c/makefile
@@ -30,6 +30,7 @@ include i2c.mk
#include unique objects
OBJS += i2c.o
+OBJS += $(if $(CONFIG_TPMDD),tpmdd.o,)
SUBDIRS += test.d
SUBDIRS += runtime.d
diff --git a/src/usr/i2c/test/makefile b/src/usr/i2c/test/makefile
index c244319e5..ef774e6e0 100644
--- a/src/usr/i2c/test/makefile
+++ b/src/usr/i2c/test/makefile
@@ -5,7 +5,9 @@
#
# OpenPOWER HostBoot Project
#
-# COPYRIGHT International Business Machines Corp. 2011,2014
+# Contributors Listed Below - COPYRIGHT 2011,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.
@@ -23,6 +25,8 @@
ROOTPATH = ../../../..
MODULE = testi2c
-TESTS = *.H
+TESTS = eepromddtest.H
+TESTS += i2ctest.H
+TESTS += $(if $(CONFIG_TPMDD),tpmddtest.H,)
include ${ROOTPATH}/config.mk
diff --git a/src/usr/i2c/test/tpmddtest.H b/src/usr/i2c/test/tpmddtest.H
new file mode 100755
index 000000000..578cd6b95
--- /dev/null
+++ b/src/usr/i2c/test/tpmddtest.H
@@ -0,0 +1,843 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/test/tpmddtest.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+#ifndef __TPMDDTEST_H
+#define __TPMDDTEST_H
+
+/**
+ * @file tpmddtest.H
+ *
+ * @brief Test cases for the tpm dd code
+ */
+
+#include <sys/time.h>
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <devicefw/driverif.H>
+#include <i2c/tpmddreasoncodes.H>
+#include <targeting/common/commontargeting.H>
+#include "i2ctest.H"
+#include "../tpmdd.H"
+#include "../../secureboot/trusted/trustedboot.H"
+
+extern trace_desc_t* g_trac_tpmdd;
+
+// NOTE: TRACUCOMP defined/controlled in i2ctest.H
+
+using namespace TARGETING;
+using namespace TPMDD;
+
+
+class TPMDDTest: public CxxTest::TestSuite
+{
+ public:
+
+ /**
+ * @brief Retrieve a node target to test with
+ */
+ TARGETING::Target* getTestTarget( tpm_chip_types_t i_chip )
+ {
+ TARGETING::TargetService& tS = TARGETING::targetService();
+ TARGETING::Target* testTarget = NULL;
+ tS.getMasterNodeTarget( testTarget );
+
+ assert(testTarget != NULL);
+
+ TRACFCOMP( g_trac_tpmdd,
+ "getTestTarget node tgt=0x%X chip=%d",
+ TARGETING::get_huid(testTarget),
+ i_chip);
+
+ // Let's see if the requested chip is functional
+ tpm_info_t tpmInfo;
+ tpmInfo.chip = i_chip;
+ errlHndl_t err = tpmReadAttributes (testTarget, tpmInfo);
+ if (NULL != err)
+ {
+ testTarget = NULL;
+ delete err;
+ }
+ else if (!tpmInfo.tpmEnabled)
+ {
+ TRACFCOMP(g_trac_tpmdd, "getTestTarget - "
+ "Chip %d not enabled",
+ i_chip);
+ testTarget = NULL;
+ }
+ else
+ {
+ TRACFCOMP(g_trac_tpmdd, "getTestTarget - "
+ "Chip %d enabled",
+ i_chip);
+ }
+
+ return testTarget;
+ }
+
+ /**
+ * @brief TPM Read VendorID Test
+ */
+ void testTPMReadVendorID ( void )
+ {
+ errlHndl_t err = NULL;
+ int64_t fails = 0, num_ops = 0;
+ uint32_t data = 0x0;
+ size_t dataSize = sizeof(data);
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMReadVendorID - Start" );
+
+ do
+ {
+ // Get a node Target
+ TARGETING::Target* testTarget = getTestTarget(TPM_PRIMARY);
+ if (NULL == testTarget)
+ {
+ continue;
+ }
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_READVENDORID,
+ 0) );
+
+ if( NULL != err )
+ {
+ fails++;
+ TS_FAIL( "testTPMReadVendorID - Error detected" );
+ errlCommit( err,
+ TPMDD_COMP_ID );
+ delete err;
+ err = NULL;
+ continue;
+ }
+ else if (data != TPMDD::TPM_VENDORID)
+ {
+ fails++;
+ TS_FAIL( "testTPMReadVendorID - Failed to read "
+ "correct vendor id ID=0x%X", data);
+ continue;
+
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMReadVendorID - "
+ "VendorID returned as expected. ID=0x%X",
+ data);
+ continue;
+ }
+ } while( 0 );
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMReadVendorID - End: %d/%d fails",
+ fails, num_ops );
+ }
+
+ /**
+ * @brief TPM Invalid Operation Test
+ * This test will pass in an invalid Operation type. It
+ * is expected that an error log is to be returned.
+ */
+ void testTPMInvalidOperation ( void )
+ {
+ errlHndl_t err = NULL;
+ int64_t fails = 0, num_ops = 0;
+ uint64_t data = 0x0ull;
+ size_t dataSize = 0;
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMInvalidOperation - Start" );
+
+ do
+ {
+
+ // Get a node Target
+ TARGETING::Target* testTarget = getTestTarget(TPM_PRIMARY);
+ if (NULL == testTarget)
+ {
+ continue;
+ }
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_LASTOP,
+ 0) );
+
+ if( NULL == err )
+ {
+ fails++;
+ TS_FAIL( "testTPMInvalidOperation - Error should've "
+ " resulted in Operation type of TPM_OP_LASTOP!" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMInvalidOperation - "
+ "TPM_OP_LASTOP : Error log returned as expected. "
+ "RC=0x%X",
+ err->reasonCode() );
+ delete err;
+ err = NULL;
+ }
+
+
+ num_ops++;
+ err = deviceOp( DeviceFW::LAST_OP_TYPE,
+ testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_READVENDORID,
+ 0) );
+
+ if( NULL == err )
+ {
+ fails++;
+ TS_FAIL( "testTPMInvalidOperation - Error should've "
+ " resulted in Operation type of LAST_OP_TYPE!" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMInvalidOperation - "
+ "DevFW::LastOp : Error log returned as expected. "
+ "RC=0x%X",
+ err->reasonCode() );
+ delete err;
+ err = NULL;
+ }
+
+
+ } while( 0 );
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMInvalidOperation - End: %d/%d fails",
+ fails, num_ops );
+ }
+
+ /**
+ * @brief TPM Overflow Test
+ * This test will pass in a read length too long for the
+ * device. It is expected that an error log is to be
+ * returned.
+ */
+ void testTPMOverflow ( void )
+ {
+ errlHndl_t err = NULL;
+ int64_t fails = 0, num_ops = 0;
+ uint64_t data = 0x0ull;
+ size_t dataSize = 0;
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMOverflow - Start" );
+
+ do
+ {
+ // Get a node Target
+ TARGETING::Target* testTarget = getTestTarget(TPM_PRIMARY);
+ if (NULL == testTarget)
+ {
+ continue;
+ }
+
+ // Set max length
+ dataSize = 0xFFFFFFFFFFFFFFFF;
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_READVENDORID,
+ 0) );
+
+ if( NULL == err ||
+ err->reasonCode() != TPM_OVERFLOW_ERROR)
+ {
+ fails++;
+ TS_FAIL( "testTPMOverflow - ReadVendorId: Error should've "
+ "resulted from overflow length: "
+ "length = 0x%x",
+ dataSize);
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMOverflow - "
+ "ReadVendorId: Error log returned as expected. "
+ "RC=0x%X",
+ err->reasonCode() );
+ delete err;
+ err = NULL;
+ }
+
+
+
+ } while( 0 );
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMOverflow - End: %d/%d fails",
+ fails, num_ops );
+ }
+
+
+ /**
+ * @brief TPM Invalid Chip Test
+ * This test will pass in an invalid chip identifier which should
+ * result in an error being returned.
+ */
+ void testTPMInvalidChip ( void )
+ {
+ errlHndl_t err = NULL;
+ int64_t fails = 0, num_ops = 0;
+ uint64_t data = 0x0ull;
+ size_t dataSize = sizeof(data);
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMInvalidChip - Start" );
+
+ do
+ {
+
+ // Get a processor Target instead of a node target
+ TARGETING::TargetService& tS = TARGETING::targetService();
+ TARGETING::Target* testTarget = NULL;
+ tS.masterProcChipTargetHandle( testTarget );
+ assert(testTarget != NULL);
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_READVENDORID,
+ 0) );
+
+ if( NULL == err )
+ {
+ fails++;
+ TS_FAIL( "testTPMInvalidChip - ProcTarget: Error should've "
+ "resulted in using processor target!" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMInvalidChip - "
+ "ProcTarget: Error log returned as expected. "
+ "RC=0x%x ",
+ err->reasonCode() );
+ delete err;
+ err = NULL;
+ }
+
+
+
+ // Attempt operation against the backup TPM
+ tS.getMasterNodeTarget( testTarget );
+ assert(testTarget != NULL);
+
+ // Skip this target if target is non-functional
+ if(!testTarget->getAttr<TARGETING::ATTR_HWAS_STATE>()
+ .functional)
+ {
+ continue;
+ }
+
+ // Many systems don't have a backup TPM, if not configured
+ // test TPM presence against it
+ if (getTestTarget(TPM_BACKUP) == NULL)
+ {
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_BACKUP,
+ TPM_OP_READVENDORID,
+ 0) );
+
+ if( NULL == err ||
+ err->reasonCode() != TPM_DEVICE_NOT_AVAILABLE)
+ {
+ fails++;
+ TS_FAIL( "testTPMInvalidChip - TpmBackup : Error "
+ "should've "
+ "resulted in using backup TPM target!" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMInvalidChip - "
+ "TpmBackup : Error log returned as expected. "
+ "RC=0x%X ",
+ err->reasonCode() );
+ delete err;
+ err = NULL;
+ }
+ }
+
+ } while( 0 );
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMInvalidChip - End: %d/%d fails",
+ fails, num_ops );
+ }
+
+ /**
+ * @brief TPM Presence Test
+ */
+ void testTPMPresence ( void )
+ {
+ int64_t fails = 0, num_ops = 0;
+ bool presence = false;
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMPresence - Start" );
+
+ do
+ {
+
+ // Get a processor Target instead of a node target
+ TARGETING::TargetService& tS = TARGETING::targetService();
+ TARGETING::Target* testTarget = NULL;
+ tS.masterProcChipTargetHandle( testTarget );
+ assert(testTarget != NULL);
+
+ // Skip this target if target is non-functional
+ if(!testTarget->getAttr<TARGETING::ATTR_HWAS_STATE>()
+ .functional)
+ {
+ continue;
+ }
+
+ num_ops++;
+
+ // Test with invalid proc target
+ presence = TPMDD::tpmPresence(testTarget,
+ TPM_PRIMARY);
+ if( presence == true )
+ {
+ fails++;
+ TS_FAIL( "testTPMPresence - ProcTarget: Error when "
+ "using processor target, false presence!" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMPresence - "
+ "ProcTarget: False returned as expected. ");
+ }
+
+
+ tS.getMasterNodeTarget( testTarget );
+ assert(testTarget != NULL);
+
+ // Skip this target if target is non-functional
+ if(!testTarget->getAttr<TARGETING::ATTR_HWAS_STATE>()
+ .functional)
+ {
+ continue;
+ }
+
+
+ // Many systems don't have a backup TPM, if not configured
+ // test TPM presence against it
+ if (getTestTarget(TPM_BACKUP) == NULL)
+ {
+
+ num_ops++;
+ // Attempt operation against the backup TPM
+ presence = TPMDD::tpmPresence(testTarget,
+ TPM_BACKUP);
+ if( presence == true )
+ {
+ fails++;
+ TS_FAIL( "testTPMPresence - TPMBackup: Error when "
+ "using backup TPM!, false presence" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMPresence - "
+ "TPMBackup: False returned as expected. ");
+ }
+ }
+
+
+ if (getTestTarget(TPM_PRIMARY) != NULL)
+ {
+ // Now test with valid primary target
+ num_ops++;
+ presence = TPMDD::tpmPresence(testTarget,
+ TPM_PRIMARY);
+ if( presence == false )
+ {
+ fails++;
+ TS_FAIL( "testTPMPresence - TPMPrimary: true should've "
+ "resulted in using backup TPM!" );
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMPresence - "
+ "TPMPrimary: true returned as expected. ");
+ }
+ }
+
+ } while( 0 );
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMPresence - End: %d/%d fails",
+ fails, num_ops );
+ }
+
+
+ /**
+ * @brief TPM Transmit Test
+ */
+ void testTPMTransmit ( void )
+ {
+ errlHndl_t err = NULL;
+ int64_t fails = 0, num_ops = 0;
+ uint8_t data[256];
+ size_t dataSize = sizeof(data);
+ uint32_t subCap = 0;
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMTransmit - Start" );
+
+ do
+ {
+
+ // Get a node Target
+ TARGETING::Target* testTarget = getTestTarget(TPM_PRIMARY);
+ if (NULL == testTarget)
+ {
+ continue;
+ }
+
+
+ // Build our command block for a startup
+ memset(data, 0xFE, sizeof(data));
+
+#ifdef CONFIG_TPMDD_1_2
+ TRUSTEDBOOT::TPM_2ByteIn* cmd =
+ reinterpret_cast<TRUSTEDBOOT::TPM_2ByteIn*>(data);
+ cmd->base.tag = TRUSTEDBOOT::TPM_TAG_RQU_COMMAND;
+ cmd->base.paramSize = sizeof (TRUSTEDBOOT::TPM_2ByteIn);
+ cmd->base.ordinal = TRUSTEDBOOT::TPM_ORD_Startup;
+ cmd->param = TRUSTEDBOOT::TPM_ST_CLEAR;
+#endif
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_TRANSMIT,
+ cmd->base.paramSize) );
+#ifdef CONFIG_TPMDD_1_2
+ TRUSTEDBOOT::TPM_BaseOut* resp =
+ reinterpret_cast<TRUSTEDBOOT::TPM_BaseOut*>(data);
+#endif
+
+
+ if( NULL != err )
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmit - Error detected" );
+ errlCommit( err,
+ TPMDD_COMP_ID );
+ delete err;
+ err = NULL;
+ continue;
+ }
+ else if (sizeof(TRUSTEDBOOT::TPM_BaseOut) != dataSize)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmit - TPM didn't return correct "
+ "response size");
+ continue;
+ }
+ else if (TRUSTEDBOOT::TPM_SUCCESS !=
+ resp->returnCode)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmit - TPM return non-success : %d",
+ resp->returnCode);
+ continue;
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMTransmit - "
+ "Transmit returned as expected. len=%d",
+ dataSize);
+ }
+
+
+
+ // Build our command block for a get capability
+ dataSize = sizeof(data);
+ memset(data, 0xFE, sizeof(data));
+
+#ifdef CONFIG_TPMDD_1_2
+ TRUSTEDBOOT::TPM_GetCapabilityIn* capCmd =
+ reinterpret_cast<TRUSTEDBOOT::TPM_GetCapabilityIn*>(data);
+ subCap = TRUSTEDBOOT::TPM_CAP_PROP_MANUFACTURER;
+
+ capCmd->base.tag = TRUSTEDBOOT::TPM_TAG_RQU_COMMAND;
+ capCmd->base.paramSize =
+ sizeof (TRUSTEDBOOT::TPM_GetCapabilityIn) + sizeof (subCap);
+ capCmd->base.ordinal = TRUSTEDBOOT::TPM_ORD_GetCapability;
+ capCmd->capArea = TRUSTEDBOOT::TPM_CAP_PROPERTY;
+ capCmd->subCapSize = sizeof (subCap);
+ memcpy(capCmd->subCap, &subCap, sizeof (subCap));
+#endif
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_TRANSMIT,
+ capCmd->base.paramSize) );
+#ifdef CONFIG_TPMDD_1_2
+ TRUSTEDBOOT::TPM_GetCapabilityOut* capResp =
+ reinterpret_cast<TRUSTEDBOOT::TPM_GetCapabilityOut*>(data);
+#endif
+
+
+ if( NULL != err )
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmit - GetCap : Error detected" );
+ errlCommit( err,
+ TPMDD_COMP_ID );
+ delete err;
+ err = NULL;
+ continue;
+ }
+ else if ((sizeof(TRUSTEDBOOT::TPM_GetCapabilityOut) +
+ capResp->respSize) != dataSize)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmit - GetCap : TPM didn't return "
+ "correct response size E:%d A:%d",
+ sizeof(TRUSTEDBOOT::TPM_GetCapabilityOut) +
+ capResp->respSize,
+ dataSize);
+ continue;
+ }
+ else if (TRUSTEDBOOT::TPM_SUCCESS !=
+ capResp->base.returnCode)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmit - GetCap : "
+ "TPM return non-success : %d",
+ resp->returnCode);
+ continue;
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMTransmit - GetCap : "
+ "Transmit returned as expected. len=%d",
+ dataSize);
+ }
+
+ } while( 0 );
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMTransmit - End: %d/%d fails",
+ fails, num_ops );
+ }
+
+
+ /**
+ * @brief TPM Transmit Over/Under flow Test
+ */
+ void testTPMTransmitOverUnder ( void )
+ {
+
+ // Unfortunately the simics 1.2 model doesn't handle the following
+ // over/under flow tests properly
+#ifndef CONFIG_TPMDD_1_2
+ errlHndl_t err = NULL;
+ int64_t fails = 0, num_ops = 0;
+ uint8_t data[256];
+ size_t dataSize = sizeof(data);
+ uint32_t subCap = 0;
+
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMTransmitOverUnder - Start" );
+
+ do
+ {
+
+ // Get a node Target
+ TARGETING::Target* testTarget = getTestTarget(TPM_PRIMARY);
+ if (NULL == testTarget)
+ {
+ continue;
+ }
+
+
+ // Build our command block for a startup
+ memset(data, 0xFE, sizeof(data));
+
+ // Test a TPM command underflow
+#ifdef CONFIG_TPMDD_1_2
+ TRUSTEDBOOT::TPM_GetCapabilityIn* capCmd =
+ reinterpret_cast<TRUSTEDBOOT::TPM_GetCapabilityIn*>(data);
+ subCap = TRUSTEDBOOT::TPM_CAP_PROP_MANUFACTURER;
+
+ capCmd->base.tag = TRUSTEDBOOT::TPM_TAG_RQU_COMMAND;
+ capCmd->base.paramSize =
+ sizeof (TRUSTEDBOOT::TPM_GetCapabilityIn) + sizeof (subCap);
+ capCmd->base.ordinal = TRUSTEDBOOT::TPM_ORD_GetCapability;
+ capCmd->capArea = TRUSTEDBOOT::TPM_CAP_PROPERTY;
+ capCmd->subCapSize = sizeof (subCap);
+ memcpy(capCmd->subCap, &subCap, sizeof (subCap));
+#endif
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_TRANSMIT,
+ capCmd->base.paramSize - 1) );
+
+ if( NULL == err ||
+ err->reasonCode() != TPM_UNDERFLOW_ERROR)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmitOverUnder - Error "
+ "command underflow not detected" );
+ errlCommit( err,
+ TPMDD_COMP_ID );
+ delete err;
+ err = NULL;
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMTransmitOverUnder - "
+ "CmdUnder Transmit returned as expected. len=%d",
+ dataSize);
+ }
+
+
+ // Build our command block for a startup
+ dataSize = sizeof(data);
+ memset(data, 0xFE, sizeof(data));
+
+ // Test a TPM command overflow
+#ifdef CONFIG_TPMDD_1_2
+ subCap = TRUSTEDBOOT::TPM_CAP_PROP_MANUFACTURER;
+
+ capCmd->base.tag = TRUSTEDBOOT::TPM_TAG_RQU_COMMAND;
+ capCmd->base.paramSize =
+ sizeof (TRUSTEDBOOT::TPM_GetCapabilityIn) + sizeof (subCap);
+ capCmd->base.ordinal = TRUSTEDBOOT::TPM_ORD_GetCapability;
+ capCmd->capArea = TRUSTEDBOOT::TPM_CAP_PROPERTY;
+ capCmd->subCapSize = sizeof (subCap);
+ memcpy(capCmd->subCap, &subCap, sizeof (subCap));
+#endif
+
+ num_ops++;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_TRANSMIT,
+ capCmd->base.paramSize + 1) );
+
+ if( NULL == err ||
+ err->reasonCode() != TPM_OVERFLOW_ERROR)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmitOverUnder - Error "
+ "command overflow not detected" );
+ errlCommit( err,
+ TPMDD_COMP_ID );
+ delete err;
+ err = NULL;
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMTransmitOverUnder - "
+ "CmdOver Transmit returned as expected. len=%d",
+ dataSize);
+ }
+
+ // Build our command block for a startup
+ dataSize = sizeof(data);
+ memset(data, 0xFE, sizeof(data));
+
+ // Test a TPM data overflow
+#ifdef CONFIG_TPMDD_1_2
+ subCap = TRUSTEDBOOT::TPM_CAP_PROP_MANUFACTURER;
+
+ capCmd->base.tag = TRUSTEDBOOT::TPM_TAG_RQU_COMMAND;
+ capCmd->base.paramSize =
+ sizeof (TRUSTEDBOOT::TPM_GetCapabilityIn) + sizeof (subCap);
+ capCmd->base.ordinal = TRUSTEDBOOT::TPM_ORD_GetCapability;
+ capCmd->capArea = TRUSTEDBOOT::TPM_CAP_PROPERTY;
+ capCmd->subCapSize = sizeof (subCap);
+ memcpy(capCmd->subCap, &subCap, sizeof (subCap));
+#endif
+
+ num_ops++;
+ // Force datasize to be too small
+ dataSize = sizeof(TRUSTEDBOOT::TPM_GetCapabilityOut) - 1;
+ err = deviceRead(testTarget,
+ &data,
+ dataSize,
+ DEVICE_TPM_ADDRESS( TPM_PRIMARY,
+ TPM_OP_TRANSMIT,
+ capCmd->base.paramSize) );
+
+ if( NULL == err ||
+ err->reasonCode() != TPM_OVERFLOW_ERROR)
+ {
+ fails++;
+ TS_FAIL( "testTPMTransmitOverUnder - Error "
+ "data overflow not detected" );
+ errlCommit( err,
+ TPMDD_COMP_ID );
+ delete err;
+ err = NULL;
+ }
+ else
+ {
+ TRACUCOMP(g_trac_tpmdd, "testTPMTransmitOverUnder - "
+ "DataOver Transmit returned as expected. len=%d",
+ dataSize);
+ }
+
+
+ } while( 0 );
+ TRACFCOMP( g_trac_tpmdd,
+ "testTPMTransmitOverUnder - End: %d/%d fails",
+ fails, num_ops );
+#endif // !defined CONFIG_TPMDD_1_2
+ }
+
+};
+
+#endif
diff --git a/src/usr/i2c/tpmdd.C b/src/usr/i2c/tpmdd.C
new file mode 100755
index 000000000..d493009d7
--- /dev/null
+++ b/src/usr/i2c/tpmdd.C
@@ -0,0 +1,2036 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/tpmdd.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2011,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 */
+/**
+ * @file tpmdd.C
+ *
+ * @brief Implementation of the TPM device driver,
+ * which will access the TPM within the
+ * system via the I2C device driver
+ *
+ */
+
+// ----------------------------------------------
+// Includes
+// ----------------------------------------------
+#include <string.h>
+#include <sys/time.h>
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <errl/errlmanager.H>
+#include <errl/errludtarget.H>
+#include <errl/errludstring.H>
+#include <targeting/common/targetservice.H>
+#include <devicefw/driverif.H>
+#include <i2c/tpmddif.H>
+#include <i2c/i2creasoncodes.H>
+#include <i2c/tpmddreasoncodes.H>
+#include <i2c/i2cif.H>
+#include "tpmdd.H"
+#include "errlud_i2c.H"
+
+// ----------------------------------------------
+// Globals
+// ----------------------------------------------
+mutex_t g_tpmMutex = MUTEX_INITIALIZER;
+
+// ----------------------------------------------
+// Trace definitions
+// ----------------------------------------------
+trace_desc_t* g_trac_tpmdd = NULL;
+TRAC_INIT( & g_trac_tpmdd, TPMDD_COMP_NAME, KILOBYTE );
+
+// Easy macro replace for unit testing
+//#define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+// ----------------------------------------------
+// Defines
+// ----------------------------------------------
+// ----------------------------------------------
+
+
+namespace TPMDD
+{
+
+static const size_t MAX_BYTE_ADDR = 2;
+static const size_t TPM_MAX_NACK_RETRIES = 2;
+
+// Register the perform Op with the routing code for Nodes.
+DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD,
+ DeviceFW::TPM,
+ TARGETING::TYPE_NODE,
+ tpmPerformOp );
+
+
+// ------------------------------------------------------------------
+// tpmPerformOp
+// ------------------------------------------------------------------
+errlHndl_t tpmPerformOp( DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & io_buflen,
+ int64_t i_accessType,
+ va_list i_args )
+{
+ errlHndl_t err = NULL;
+ tpm_info_t tpmInfo;
+ uint64_t commandSize = 0;
+ bool unlock = false;
+
+ tpmInfo.chip = va_arg( i_args, uint64_t );
+ tpmInfo.operation = ((TPMDD::tpm_op_types_t)va_arg( i_args, uint64_t ));
+ commandSize = va_arg( i_args, uint64_t );
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmPerformOp()" );
+
+ TRACUCOMP (g_trac_tpmdd, ENTER_MRK"tpmPerformOp(): "
+ "i_opType=%d, chip=%d, operation=%d, buflen=%d, cmdlen=%d",
+ (uint64_t) i_opType, tpmInfo.chip, tpmInfo.operation, io_buflen,
+ commandSize);
+
+ do
+ {
+ // Read Attributes needed to complete the operation
+ err = tpmReadAttributes( i_target,
+ tpmInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ // Ensure the TPM is enabled
+ if (!tpmInfo.tpmEnabled)
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmPerformOp(): TPM requested not enabled!"
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d",
+ tpmInfo.chip, tpmInfo.port,
+ tpmInfo.engine, tpmInfo.devAddr, tpmInfo.operation);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_DEVICE_NOT_AVAILABLE
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_PERFORM_OP
+ * @userdata1 Operation Type
+ * @userdata2 Chip to Access
+ * @devdesc Invalid operation type.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_PERFORM_OP,
+ TPM_DEVICE_NOT_AVAILABLE,
+ i_opType,
+ tpmInfo.chip,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ break;
+ }
+
+
+
+ // Get i2c master target
+ err = tpmGetI2CMasterTarget( i_target,
+ tpmInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+
+ // Lock to sequence operations
+ mutex_lock( &g_tpmMutex );
+ unlock = true;
+
+
+ // TPM_OP_READVENDORID operation
+ // Only supported with a DeviceFW::READ operation
+ if( TPMDD::TPM_OP_READVENDORID == tpmInfo.operation &&
+ DeviceFW::READ == i_opType)
+ {
+
+ if (io_buflen > 4)
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmPerformOp(): Operation Overflow! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "blen=%d",
+ tpmInfo.chip, tpmInfo.port,
+ tpmInfo.engine, tpmInfo.devAddr,
+ tpmInfo.operation, io_buflen);
+
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_OVERFLOW_ERROR
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_PERFORM_OP
+ * @userdata1 Operation
+ * @userdata2 Buffer Length (in Bytes)
+ * @devdesc TPM buffer length > 4 for read vendor op
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM buffer is too large.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_PERFORM_OP,
+ TPM_OVERFLOW_ERROR,
+ tpmInfo.operation,
+ io_buflen,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ break;
+ }
+
+
+
+ // Set the offset for the vendor reg
+ tpmInfo.offset = TPMDD::I2C_REG_VENDOR;
+
+
+ err = tpmRead( io_buffer,
+ io_buflen,
+ tpmInfo );
+
+ if ( err )
+ {
+ break;
+ }
+
+ }
+
+ // TPM_OP_TRANSMIT
+ // Ignoring read/write type since transmit really does both anyway
+ else if( TPMDD::TPM_OP_TRANSMIT == tpmInfo.operation )
+ {
+
+
+ err = tpmTransmit( io_buffer,
+ io_buflen,
+ commandSize,
+ tpmInfo );
+
+ if ( err )
+ {
+ break;
+ }
+
+ }
+ else
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmPerformOp(): Invalid TPM Operation!"
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, Type=%d",
+ tpmInfo.chip, tpmInfo.port,
+ tpmInfo.engine, tpmInfo.devAddr,
+ tpmInfo.operation, i_opType);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_INVALID_OPERATION
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_PERFORM_OP
+ * @userdata1 Operation Type
+ * @userdata2 Chip to Access
+ * @devdesc Invalid operation type.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_PERFORM_OP,
+ TPM_INVALID_OPERATION,
+ i_opType,
+ tpmInfo.chip,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ break;
+ }
+
+
+ } while( 0 );
+
+#if 0
+ // If there is an error, add parameter info to log
+ if ( err != NULL )
+ {
+ TPMDD::UdEepromParms( i_opType,
+ i_target,
+ io_buflen,
+ tpmInfo )
+ .addToLog(err);
+ }
+#endif
+ if( unlock )
+ {
+ mutex_unlock( & g_tpmMutex );
+ }
+
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmPerformOp() - %s",
+ ((NULL == err) ? "No Error" : "With Error") );
+
+ return err;
+} // end tpmPerformOp
+
+//-------------------------------------------------------------------
+//tpmPresence
+//-------------------------------------------------------------------
+bool tpmPresence ( TARGETING::Target * i_target,
+ tpm_chip_types_t i_chip)
+{
+
+ TRACDCOMP(g_trac_tpmdd, ENTER_MRK"tpmPresence()");
+
+ errlHndl_t err = NULL;
+ bool l_present = false;
+
+ tpm_info_t tpmInfo;
+
+ tpmInfo.chip = i_chip;
+ tpmInfo.offset = 0;
+ do
+ {
+
+ // Read Attributes needed to complete the operation
+ err = tpmReadAttributes( i_target,
+ tpmInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_tpmdd,
+ ERR_MRK"Error in tpmPresence::tpmReadAttributes() "
+ "RC 0x%X", err->reasonCode());
+ delete err;
+ err = NULL;
+ break;
+ }
+
+ // Get i2c master target
+ err = tpmGetI2CMasterTarget( i_target,
+ tpmInfo );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_tpmdd,
+ ERR_MRK"Error in tpmPresence::tpmGetI2Cmaster() "
+ "RC 0x%X", err->reasonCode());
+ delete err;
+ err = NULL;
+ break;
+ }
+
+ // Ensure the TPM is enabled
+ if (!tpmInfo.tpmEnabled)
+ {
+ TRACUCOMP(g_trac_tpmdd,
+ INFO_MRK"tpmPresence : Device not enabled");
+ break;
+ }
+
+ //Check for the target at the I2C level
+ l_present = I2C::i2cPresence(tpmInfo.i2cTarget,
+ tpmInfo.port,
+ tpmInfo.engine,
+ static_cast<uint64_t>(tpmInfo.devAddr)
+ );
+
+ if( !l_present )
+ {
+ TRACUCOMP(g_trac_tpmdd,
+ INFO_MRK"i2cPresence returned false! chip NOT present!");
+ break;
+ }
+
+ } while( 0 );
+
+ TRACDCOMP(g_trac_tpmdd, EXIT_MRK"tpmPresence() : presence : %d",
+ l_present);
+ return l_present;
+}
+
+// ------------------------------------------------------------------
+// tpmRead
+// ------------------------------------------------------------------
+errlHndl_t tpmRead ( void * o_buffer,
+ size_t i_buflen,
+ tpm_info_t i_tpmInfo )
+{
+ errlHndl_t err = NULL;
+ errlHndl_t err_NACK = NULL;
+ uint8_t byteAddr[MAX_BYTE_ADDR];
+ size_t byteAddrSize = 0;
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmRead()" );
+
+ do
+ {
+ TRACSCOMP( g_trac_tpmdd,
+ "TPM READ START : Chip: %02d : Offset %.2X : Len %d",
+ i_tpmInfo.chip, i_tpmInfo.offset, i_buflen );
+
+ err = tpmPrepareAddress( &byteAddr,
+ byteAddrSize,
+ i_tpmInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ /***********************************************************/
+ /* Attempt read multiple times ONLY on NACK fails */
+ /***********************************************************/
+ for (size_t retry = 0;
+ retry <= TPM_MAX_NACK_RETRIES;
+ retry++)
+ {
+
+ // Only write the byte address if we have data to write
+ if( 0 != byteAddrSize )
+ {
+ // Use the I2C OFFSET Interface for the READ
+ err = deviceOp( DeviceFW::READ,
+ i_tpmInfo.i2cTarget,
+ o_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS_OFFSET(
+ i_tpmInfo.port,
+ i_tpmInfo.engine,
+ i_tpmInfo.devAddr,
+ byteAddrSize,
+ reinterpret_cast<uint8_t*>(&byteAddr)));
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_tpmdd,
+ ERR_MRK"tpmRead(): I2C Read-Offset failed! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "offset=0x%X, aS=%d, len=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ i_tpmInfo.offset, byteAddrSize, i_buflen);
+ TRACFBIN(g_trac_tpmdd, "byteAddr[]",
+ &byteAddr, byteAddrSize);
+
+ // Don't break here -- error handled below
+ }
+ }
+ else
+ {
+ // Do the actual read via I2C
+ err = deviceOp( DeviceFW::READ,
+ i_tpmInfo.i2cTarget,
+ o_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS( i_tpmInfo.port,
+ i_tpmInfo.engine,
+ i_tpmInfo.devAddr ) );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_tpmdd,
+ ERR_MRK"tpmRead(): I2C Read failed! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "len=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ i_buflen);
+
+ // Don't break here -- error handled below
+ }
+ }
+
+ if ( err == NULL )
+ {
+ // Operation completed successfully
+ // break from retry loop
+ break;
+ }
+ else if ( err->reasonCode() != I2C::I2C_NACK_ONLY_FOUND )
+ {
+ // Only retry on NACK failures: break from retry loop
+ TRACFCOMP( g_trac_tpmdd, ERR_MRK"tpmRead(): Non-Nack! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "Error: rc=0x%X, No Retry (retry=%d)",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err->reasonCode(), retry);
+
+ err->collectTrace(TPMDD_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ else // Handle NACK error
+ {
+ // If op will be attempted again: save log and continue
+ if ( retry < TPM_MAX_NACK_RETRIES )
+ {
+ // Only save original NACK error
+ if ( err_NACK == NULL )
+ {
+ // Save original NACK error
+ err_NACK = err;
+
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmRead(): NACK Error! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "rc=0x%X, eid=0x%X, "
+ "retry/MAX=%d/%d. Save error and retry",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err_NACK->reasonCode(),
+ err_NACK->eid(),
+ retry, TPM_MAX_NACK_RETRIES);
+
+ err_NACK->collectTrace(TPMDD_COMP_NAME);
+ }
+ else
+ {
+ // Add data to original NACK error
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmRead(): Another NACK Error! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "rc=0x%X, eid=0x%X, "
+ "plid=0x%X, retry/MAX=%d/%d. "
+ "Delete error and retry",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err->reasonCode(), err->eid(), err->plid(),
+ retry, TPM_MAX_NACK_RETRIES);
+
+ ERRORLOG::ErrlUserDetailsString(
+ "Another NACK ERROR found")
+ .addToLog(err_NACK);
+
+ // Delete this new NACK error
+ delete err;
+ err = NULL;
+ }
+
+ // continue to retry
+ continue;
+ }
+ else // no more retries: trace and break
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmRead(): No More Retries! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "Error rc=0x%X, eid=%d, "
+ "retry/MAX=%d/%d. Returning Error",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err->reasonCode(), err->eid(),
+ retry, TPM_MAX_NACK_RETRIES);
+
+ err->collectTrace(TPMDD_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ }
+
+ } // end of retry loop
+
+ // Handle saved NACK error, if any
+ if (err_NACK)
+ {
+ if (err)
+ {
+ // commit original NACK error with new err PLID
+ err_NACK->plid(err->plid());
+ TRACFCOMP(g_trac_tpmdd, "tpmRead(): Committing saved NACK "
+ "err eid=0x%X with plid of returned err: 0x%X",
+ err_NACK->eid(), err_NACK->plid());
+
+ ERRORLOG::ErrlUserDetailsTarget(i_tpmInfo.i2cTarget)
+ .addToLog(err_NACK);
+
+ errlCommit(err_NACK, TPMDD_COMP_ID);
+ }
+ else
+ {
+ // Since we eventually succeeded, delete original NACK error
+ TRACFCOMP(g_trac_tpmdd, "tpmRead(): Op successful, "
+ "deleting saved NACK err eid=0x%X, plid=0x%X",
+ err_NACK->eid(), err_NACK->plid());
+
+ delete err_NACK;
+ err_NACK = NULL;
+ }
+ }
+
+
+ TRACUCOMP( g_trac_tpmdd,
+ "TPM READ END : Chip: %02d : "
+ "Offset %.2X : Len %d : %016llx",
+ i_tpmInfo.chip, i_tpmInfo.offset, i_buflen,
+ *(reinterpret_cast<uint64_t*>(o_buffer)) );
+
+ } while( 0 );
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmRead()" );
+
+ return err;
+} // end tpmRead
+
+// ------------------------------------------------------------------
+// tpmWrite
+// ------------------------------------------------------------------
+errlHndl_t tpmWrite ( void * i_buffer,
+ size_t i_buflen,
+ tpm_info_t i_tpmInfo )
+{
+ errlHndl_t err = NULL;
+ errlHndl_t err_NACK = NULL;
+ uint8_t byteAddr[MAX_BYTE_ADDR];
+ size_t byteAddrSize = 0;
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmWrite()" );
+
+ do
+ {
+ TRACUCOMP( g_trac_tpmdd,
+ "TPM WRITE START : Chip: %02d : "
+ "Offset %.2X : Len %d : %016llx",
+ i_tpmInfo.chip, i_tpmInfo.offset,
+ i_buflen,
+ *(reinterpret_cast<uint64_t*>(i_buffer)) );
+
+ err = tpmPrepareAddress( &byteAddr,
+ byteAddrSize,
+ i_tpmInfo );
+
+ if( err )
+ {
+ break;
+ }
+
+ /***********************************************************/
+ /* Attempt write multiple times ONLY on NACK fails */
+ /***********************************************************/
+ for (size_t retry = 0;
+ retry <= TPM_MAX_NACK_RETRIES;
+ retry++)
+ {
+
+ // Only write the byte address if we have data to write
+ if( 0 != byteAddrSize )
+ {
+ // Use the I2C OFFSET Interface for the WRITE
+ err = deviceOp( DeviceFW::WRITE,
+ i_tpmInfo.i2cTarget,
+ i_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS_OFFSET(
+ i_tpmInfo.port,
+ i_tpmInfo.engine,
+ i_tpmInfo.devAddr,
+ byteAddrSize,
+ reinterpret_cast<uint8_t*>(&byteAddr)));
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_tpmdd,
+ ERR_MRK"tpmWrite(): I2C Write-Offset! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, ",
+ "offset=0x%X, aS=%d, len=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ i_tpmInfo.offset, byteAddrSize, i_buflen);
+ TRACFBIN(g_trac_tpmdd, "byteAddr[]",
+ &byteAddr, byteAddrSize);
+
+ // Don't break here -- error handled below
+ }
+ }
+ else
+ {
+ // Do the actual write via I2C
+ err = deviceOp( DeviceFW::WRITE,
+ i_tpmInfo.i2cTarget,
+ i_buffer,
+ i_buflen,
+ DEVICE_I2C_ADDRESS( i_tpmInfo.port,
+ i_tpmInfo.engine,
+ i_tpmInfo.devAddr ) );
+
+ if( err )
+ {
+ TRACFCOMP(g_trac_tpmdd,
+ ERR_MRK"tpmWrite(): I2C Write failed! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "len=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ i_buflen);
+
+ // Don't break here -- error handled below
+ }
+ }
+
+ if ( err == NULL )
+ {
+ // Operation completed successfully
+ // break from retry loop
+ break;
+ }
+ else if ( err->reasonCode() != I2C::I2C_NACK_ONLY_FOUND )
+ {
+ // Only retry on NACK failures: break from retry loop
+ TRACFCOMP( g_trac_tpmdd, ERR_MRK"tpmWrite(): Non-Nack "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "Error: rc=0x%X, No Retry (retry=%d)",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err->reasonCode(), retry);
+
+ err->collectTrace(TPMDD_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ else // Handle NACK error
+ {
+ // If op will be attempted again: save log and continue
+ if ( retry < TPM_MAX_NACK_RETRIES )
+ {
+ // Only save original NACK error
+ if ( err_NACK == NULL )
+ {
+ // Save original NACK error
+ err_NACK = err;
+
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmWrite(): NACK Error! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "rc=0x%X, eid=0x%X, "
+ "retry/MAX=%d/%d. Save error and retry",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err_NACK->reasonCode(),
+ err_NACK->eid(),
+ retry, TPM_MAX_NACK_RETRIES);
+
+ err_NACK->collectTrace(TPMDD_COMP_NAME);
+ }
+ else
+ {
+ // Add data to original NACK error
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmWrite(): Another NACK Error! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "rc=0x%X, eid=0x%X "
+ "plid=0x%X, retry/MAX=%d/%d. "
+ "Delete error and retry",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err->reasonCode(), err->eid(), err->plid(),
+ retry, TPM_MAX_NACK_RETRIES);
+
+ ERRORLOG::ErrlUserDetailsString(
+ "Another NACK ERROR found")
+ .addToLog(err_NACK);
+
+ // Delete this new NACK error
+ delete err;
+ err = NULL;
+ }
+
+ // continue to retry
+ continue;
+ }
+ else // no more retries: trace and break
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmWrite(): No More Retries! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "Error rc=0x%X, eid=%d, "
+ "retry/MAX=%d/%d. Returning Error",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_tpmInfo.operation,
+ err->reasonCode(), err->eid(),
+ retry, TPM_MAX_NACK_RETRIES);
+
+ err->collectTrace(TPMDD_COMP_NAME);
+
+ // break from retry loop
+ break;
+ }
+ }
+
+ } // end of retry loop
+
+ // Handle saved NACK error, if any
+ if (err_NACK)
+ {
+ if (err)
+ {
+ // commit original NACK error with new err PLID
+ err_NACK->plid(err->plid());
+ TRACFCOMP(g_trac_tpmdd, "tpmWrite(): Committing saved NACK "
+ "err eid=0x%X with plid of returned err: 0x%X",
+ err_NACK->eid(), err_NACK->plid());
+
+ ERRORLOG::ErrlUserDetailsTarget(i_tpmInfo.i2cTarget)
+ .addToLog(err_NACK);
+
+ errlCommit(err_NACK, TPMDD_COMP_ID);
+ }
+ else
+ {
+ // Since we eventually succeeded, delete original NACK error
+ TRACFCOMP(g_trac_tpmdd, "tpmWrite(): Op successful, "
+ "deleting saved NACK err eid=0x%X, plid=0x%X",
+ err_NACK->eid(), err_NACK->plid());
+
+ delete err_NACK;
+ err_NACK = NULL;
+ }
+ }
+
+
+ TRACSCOMP( g_trac_tpmdd,
+ "TPM WRITE END : Chip: %02d : "
+ "Offset %.2X : Len %d",
+ i_tpmInfo.chip, i_tpmInfo.offset, i_buflen);
+
+ } while( 0 );
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmWrite()" );
+
+ return err;
+} // end tpmWrite
+
+// ------------------------------------------------------------------
+// tpmTransmit
+// ------------------------------------------------------------------
+errlHndl_t tpmTransmit ( void * io_buffer,
+ size_t & io_buflen,
+ size_t i_commandlen,
+ tpm_info_t i_tpmInfo )
+{
+ errlHndl_t err = NULL;
+ bool isReady = false;
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmTransmit()" );
+
+ do {
+
+ TRACUCOMP( g_trac_tpmdd,
+ "TPM TRANSMIT START : Chip: %02d : "
+ "BufLen %d : CmdLen %d : %016llx",
+ i_tpmInfo.chip,
+ io_buflen, i_commandlen,
+ *(reinterpret_cast<uint64_t*>(io_buffer)) );
+
+ err = tpmIsCommandReady(i_tpmInfo, isReady);
+ if( err )
+ {
+ break;
+ }
+
+ if (!isReady)
+ {
+ err = tpmWriteCommandReady(i_tpmInfo);
+ if( err )
+ {
+ break;
+ }
+ }
+
+ // Verify the TPM is ready to receive our command
+ err = tpmPollForCommandReady(i_tpmInfo);
+ if( err )
+ {
+ break;
+ }
+
+ // Write the command into the TPM FIFO
+ err = tpmWriteFifo(i_tpmInfo,
+ io_buffer, i_commandlen);
+ if( err )
+ {
+ break;
+ }
+
+ err = tpmWriteTpmGo(i_tpmInfo);
+ if( err )
+ {
+ break;
+ }
+
+ // Read the response from the TPM FIFO
+ err = tpmReadFifo(i_tpmInfo,
+ io_buffer, io_buflen);
+ if( err )
+ {
+ break;
+ }
+
+ err = tpmWriteCommandReady(i_tpmInfo);
+ if( err )
+ {
+ break;
+ }
+
+ } while( 0 );
+
+ TRACUCOMP( g_trac_tpmdd,
+ "TPM TRANSMIT END : Chip: %02d : "
+ "BufLen %d : CmdLen %d : %016llx",
+ i_tpmInfo.chip,
+ io_buflen, i_commandlen,
+ *(reinterpret_cast<uint64_t*>(io_buffer)) );
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmTransmit()" );
+
+ return err;
+
+} // end tpmTransmit
+
+
+// ------------------------------------------------------------------
+// tpmPrepareAddress
+// ------------------------------------------------------------------
+errlHndl_t tpmPrepareAddress ( void * io_buffer,
+ size_t & o_bufSize,
+ tpm_info_t i_tpmInfo )
+{
+ errlHndl_t err = NULL;
+
+ o_bufSize = 0;
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmPrepareAddress()" );
+ do
+ {
+
+ // --------------------------------------------------------------------
+ // Currently only supporting I2C devices and that use 0, 1, or 2 bytes
+ // to set the offset (ie, internal address) into the device.
+ // --------------------------------------------------------------------
+ switch( i_tpmInfo.addrSize )
+ {
+ case TWO_BYTE_ADDR:
+ o_bufSize = 2;
+ *((uint8_t*)io_buffer) = (i_tpmInfo.offset & 0xFF00ull) >> 8;
+ *((uint8_t*)io_buffer+1) = (i_tpmInfo.offset & 0x00FFull);
+ break;
+
+ case ONE_BYTE_ADDR:
+ o_bufSize = 1;
+ *((uint8_t*)io_buffer) = (i_tpmInfo.offset & 0xFFull);
+ break;
+
+ default:
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmPrepareAddress() - Invalid Device "
+ "Address Size: 0x%08x", i_tpmInfo.addrSize);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_INVALID_DEVICE_TYPE
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_PREPAREADDRESS
+ * @userdata1 Address Size (aka Device Type)
+ * @userdata2 TPM chip
+ * @devdesc The Device type not supported (addrSize)
+ * @custdesc A problem was detected during the IPL of
+ * the system: Device type not supported.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_PREPAREADDRESS,
+ TPM_INVALID_DEVICE_TYPE,
+ i_tpmInfo.addrSize,
+ i_tpmInfo.chip,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ break;
+ }
+
+ } while( 0 );
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmPrepareAddress()" );
+
+ return err;
+} // end tpmPrepareAddress
+
+
+// ------------------------------------------------------------------
+// tpmReadAttributes
+// ------------------------------------------------------------------
+errlHndl_t tpmReadAttributes ( TARGETING::Target * i_target,
+ tpm_info_t & io_tpmInfo )
+{
+ errlHndl_t err = NULL;
+ bool fail_reading_attribute = false;
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmReadAttributes()" );
+
+ // These variables will be used to hold the TPM attribute data
+ TARGETING::TpmPrimaryInfo tpmData;
+
+ do
+ {
+
+ switch (io_tpmInfo.chip )
+ {
+ case TPM_PRIMARY:
+ if( !( i_target->
+ tryGetAttr<TARGETING::ATTR_TPM_PRIMARY_INFO>
+ ( tpmData ) ) )
+
+ {
+ fail_reading_attribute = true;
+ }
+ break;
+
+ case TPM_BACKUP:
+
+ if( !(i_target->
+ tryGetAttr<TARGETING::ATTR_TPM_BACKUP_INFO>
+ ( reinterpret_cast<
+ TARGETING::ATTR_TPM_BACKUP_INFO_type&>
+ ( tpmData) ) ) )
+ {
+ fail_reading_attribute = true;
+ }
+ break;
+
+ default:
+ TRACFCOMP( g_trac_tpmdd,ERR_MRK"tpmReadAttributes() - "
+ "Invalid chip %d tgt=0x%X to read attributes from!",
+ io_tpmInfo.chip,
+ TARGETING::get_huid(i_target));
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_INVALID_CHIP
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_READATTRIBUTES
+ * @userdata1 TPM Chip
+ * @userdata2 HUID of target
+ * @devdesc Invalid TPM chip to access
+ */
+ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_READATTRIBUTES,
+ TPM_INVALID_CHIP,
+ io_tpmInfo.chip,
+ TARGETING::get_huid(i_target),
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ break;
+ }
+
+ // Check if Attribute Data was found
+ if( fail_reading_attribute == true )
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmReadAttributes() - ERROR reading "
+ "attributes for chip %d, tgt=0x%X!",
+ io_tpmInfo.chip,
+ TARGETING::get_huid(i_target));
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_ATTR_INFO_NOT_FOUND
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_READATTRIBUTES
+ * @userdata1 HUID of target
+ * @userdata2 TPM chip
+ * @devdesc TPM attribute was not found
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_READATTRIBUTES,
+ TPM_ATTR_INFO_NOT_FOUND,
+ TARGETING::get_huid(i_target),
+ io_tpmInfo.chip);
+
+ // Could be FSP or HB code's fault
+ err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE,
+ HWAS::SRCI_PRIORITY_MED);
+ err->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE,
+ HWAS::SRCI_PRIORITY_MED);
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ break;
+
+ }
+
+ // Successful reading of Attribute, so extract the data
+ io_tpmInfo.port = tpmData.port;
+ io_tpmInfo.devAddr = tpmData.devAddrLocality0;
+ /// @TODO RTC: 134415 Need to handle locality4
+ io_tpmInfo.engine = tpmData.engine;
+ io_tpmInfo.i2cMasterPath = tpmData.i2cMasterPath;
+ io_tpmInfo.tpmEnabled = tpmData.tpmEnabled;
+
+ // Convert attribute info to tpm_addr_size_t enum
+ if ( tpmData.byteAddrOffset == 0x2 )
+ {
+ io_tpmInfo.addrSize = TWO_BYTE_ADDR;
+ }
+ else if ( tpmData.byteAddrOffset == 0x1 )
+ {
+ io_tpmInfo.addrSize = ONE_BYTE_ADDR;
+ }
+ else
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmReadAttributes() - INVALID ADDRESS "
+ "OFFSET SIZE %d!",
+ tpmData.byteAddrOffset );
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_INVALID_ADDR_OFFSET_SIZE
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_READATTRIBUTES
+ * @userdata1 HUID of target
+ * @userdata2 Address Offset Size
+ * @devdesc Invalid address offset size
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_READATTRIBUTES,
+ TPM_INVALID_ADDR_OFFSET_SIZE,
+ TARGETING::get_huid(i_target),
+ tpmData.byteAddrOffset,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ break;
+
+ }
+
+ } while( 0 );
+
+ TRACUCOMP(g_trac_tpmdd,"tpmReadAttributes() tgt=0x%X, %d/%d/0x%X "
+ "En=%d, aS=%d, aS=%d (%d)",
+ TARGETING::get_huid(i_target),
+ io_tpmInfo.port, io_tpmInfo.engine, io_tpmInfo.devAddr,
+ io_tpmInfo.tpmEnabled,
+ io_tpmInfo.addrSize, tpmData.byteAddrOffset);
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmReadAttributes()" );
+
+ return err;
+} // end tpmReadAttributes
+
+
+// ------------------------------------------------------------------
+// tpmGetI2CMasterTarget
+// ------------------------------------------------------------------
+errlHndl_t tpmGetI2CMasterTarget ( TARGETING::Target * i_target,
+ tpm_info_t & io_tpmInfo )
+{
+ errlHndl_t err = NULL;
+
+ TRACDCOMP( g_trac_tpmdd,
+ ENTER_MRK"tpmGetI2CMasterTarget()" );
+
+ do
+ {
+ TARGETING::TargetService& tS = TARGETING::targetService();
+
+ // The path from i_target to its I2C Master was read from the
+ // attribute via tpmReadAttributes() and passed to this function
+ // in io_tpmInfo.i2cMasterPath
+
+ // check that the path exists
+ bool exists = false;
+ tS.exists( io_tpmInfo.i2cMasterPath,
+ exists );
+
+ if( !exists )
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmGetI2CMasterTarget() - "
+ "i2cMasterPath attribute path doesn't exist!" );
+
+ // Compress the i2cMasterPath entity path into a uint64_t value
+ // Format is up to 4 path elements defined like type:8 instance:8
+ uint64_t l_epCompressed = 0;
+ for( uint32_t i = 0; i < io_tpmInfo.i2cMasterPath.size(); i++ )
+ {
+ // Path element: type:8 instance:8
+ l_epCompressed |=
+ io_tpmInfo.i2cMasterPath[i].type << (16*(3-i));
+ l_epCompressed |=
+ io_tpmInfo.i2cMasterPath[i].instance << ((16*(3-i))-8);
+
+ // Can only fit 4 path elements into 64 bits
+ if ( i == 3 )
+ {
+ break;
+ }
+ }
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_I2C_MASTER_PATH_ERROR
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_GETI2CMASTERTARGET
+ * @userdata1[00:31] Attribute Chip Type Enum
+ * @userdata1[32:63] HUID of target
+ * @userdata2 Compressed Entity Path
+ * @devdesc I2C master entity path doesn't exist.
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_GETI2CMASTERTARGET,
+ TPM_I2C_MASTER_PATH_ERROR,
+ TWO_UINT32_TO_UINT64(
+ io_tpmInfo.chip,
+ TARGETING::get_huid(i_target) ),
+ l_epCompressed,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ ERRORLOG::ErrlUserDetailsString(
+ io_tpmInfo.i2cMasterPath.toString()).addToLog(err);
+
+ break;
+ }
+
+ // Since it exists, convert to a target
+ io_tpmInfo.i2cTarget = tS.toTarget( io_tpmInfo.i2cMasterPath );
+
+ if( NULL == io_tpmInfo.i2cTarget )
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmGetI2CMasterTarget() - I2C Master "
+ "Path target was NULL!" );
+
+ // Compress the entity path
+ uint64_t l_epCompressed = 0;
+ for( uint32_t i = 0; i < io_tpmInfo.i2cMasterPath.size(); i++ )
+ {
+ // Path element: type:8 instance:8
+ l_epCompressed |=
+ io_tpmInfo.i2cMasterPath[i].type << (16*(3-i));
+ l_epCompressed |=
+ io_tpmInfo.i2cMasterPath[i].instance << ((16*(3-i))-8);
+
+ // Can only fit 4 path elements into 64 bits
+ if ( i == 3 )
+ {
+ break;
+ }
+ }
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_TARGET_NULL
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_GETI2CMASTERTARGET
+ * @userdata1[00:31] Attribute Chip Type Enum
+ * @userdata1[32:63] HUID of target
+ * @userdata2 Compressed Entity Path
+ * @devdesc I2C master path target is null.
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD::TPMDD_GETI2CMASTERTARGET,
+ TPMDD::TPM_TARGET_NULL,
+ TWO_UINT32_TO_UINT64(
+ io_tpmInfo.chip,
+ TARGETING::get_huid(i_target) ),
+ l_epCompressed,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ ERRORLOG::ErrlUserDetailsString(
+ io_tpmInfo.i2cMasterPath.toString()).addToLog(err);
+
+ break;
+ }
+
+
+ } while( 0 );
+
+ TRACDCOMP( g_trac_tpmdd,
+ EXIT_MRK"tpmGetI2CMasterTarget()" );
+
+ return err;
+} // end tpmGetI2CMasterTarget
+
+
+errlHndl_t tpmWriteReg ( tpm_info_t i_tpmInfo,
+ size_t i_offset,
+ size_t i_buflen,
+ void * i_buffer)
+{
+ i_tpmInfo.offset = i_offset;
+ return tpmWrite(i_buffer,
+ i_buflen,
+ i_tpmInfo);
+
+} // end tpmWriteReg
+
+errlHndl_t tpmReadReg ( tpm_info_t i_tpmInfo,
+ size_t i_offset,
+ size_t i_buflen,
+ void * o_buffer)
+{
+ i_tpmInfo.offset = i_offset;
+ return tpmRead(o_buffer,
+ i_buflen,
+ i_tpmInfo);
+
+} // end tpmReadReg
+
+errlHndl_t tpmReadSTSReg ( tpm_info_t i_tpmInfo,
+ tpm_sts_reg_t & o_stsReg)
+{
+ i_tpmInfo.offset = TPMDD::I2C_REG_STS;
+ return tpmRead(reinterpret_cast<void*>(&o_stsReg),
+ 1,
+ i_tpmInfo);
+} // end tpmReadSTSReg
+
+errlHndl_t tpmReadSTSRegValid ( tpm_info_t i_tpmInfo,
+ tpm_sts_reg_t & o_stsReg)
+{
+ errlHndl_t err = NULL;
+
+ i_tpmInfo.offset = TPMDD::I2C_REG_STS;
+ size_t polls = 0;
+ do
+ {
+ err = tpmRead(reinterpret_cast<void*>(&o_stsReg),
+ 1,
+ i_tpmInfo);
+ if (err)
+ {
+ break;
+ }
+
+ if (polls > TPMDD::MAX_STSVALID_POLLS)
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmReadSTSRegValid(): Timeout! "
+ "C-p/e/dA=%d-%d/%d/0x%X, %02X",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ o_stsReg.value);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_TIMEOUT
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_READSTSREGVALID
+ * @userdata1 Operation
+ * @userdata2 STS Reg
+ * @devdesc TPM timeout waiting for stsValid
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM timeout
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_READSTSREGVALID,
+ TPM_TIMEOUT,
+ i_tpmInfo.operation,
+ o_stsReg.value,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ break;
+ }
+ else if (!o_stsReg.stsValid)
+ {
+ // Sleep 10ms before attempting another read
+ nanosleep(0, 10 * NS_PER_MSEC);
+ polls++;
+ }
+ } while (!o_stsReg.stsValid);
+
+ return err;
+} // end tpmReadSTSRegValid
+
+
+errlHndl_t tpmIsCommandReady( tpm_info_t i_tpmInfo,
+ bool & o_isReady)
+{
+ tpm_sts_reg_t stsReg;
+ errlHndl_t err = tpmReadSTSReg(i_tpmInfo,
+ stsReg);
+ o_isReady = false;
+
+ if (NULL == err && stsReg.isCommandReady)
+ {
+ o_isReady = true;
+ }
+ return err;
+
+} // end tpmIsCommandReady
+
+errlHndl_t tpmPollForCommandReady( tpm_info_t i_tpmInfo)
+{
+ tpm_sts_reg_t stsReg;
+ errlHndl_t err = NULL;
+
+ // Operation TIMEOUT_B defined by TCG spec for command ready
+ for (size_t delay = 0; delay < TPMDD::TPM_TIMEOUT_B; delay += 10)
+ {
+ err = tpmReadSTSReg(i_tpmInfo,
+ stsReg);
+ if (NULL == err && stsReg.isCommandReady)
+ {
+ break;
+ }
+ // Sleep 10ms before attempting another read
+ nanosleep(0, 10 * NS_PER_MSEC);
+
+ }
+
+ if (NULL == err && !stsReg.isCommandReady)
+ {
+ // The first write to command ready may have just aborted
+ // an outstanding command, we will write it again and poll once
+ // more
+ err = tpmWriteCommandReady(i_tpmInfo);
+
+ if (NULL == err)
+ {
+ // Ok, poll again
+ // Operation TIMEOUT_B defined by TCG spec for command ready
+ for (size_t delay = 0; delay < TPMDD::TPM_TIMEOUT_B; delay += 10)
+ {
+ err = tpmReadSTSReg(i_tpmInfo,
+ stsReg);
+ if (NULL == err && stsReg.isCommandReady)
+ {
+ break;
+ }
+ // Sleep 10ms before attempting another read
+ nanosleep(0, 10 * NS_PER_MSEC);
+ }
+ }
+ }
+
+
+ if (NULL == err && !stsReg.isCommandReady)
+ {
+ // Timed out waiting for TPM to be ready
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmPollForCommandReady() - "
+ "Timeout polling for command ready! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "STS=0x%X",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr, i_tpmInfo.operation,
+ stsReg.value );
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_TIMEOUT
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_POLLFORCOMMMANDREADY
+ * @userdata1 Attribute Chip Type Enum
+ * @userdata2 STS Reg
+ * @devdesc Timeout waiting for TPM to enter command ready state.
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_POLLFORCOMMMANDREADY,
+ TPM_TIMEOUT,
+ i_tpmInfo.chip,
+ stsReg.value,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ ERRORLOG::ErrlUserDetailsString(
+ i_tpmInfo.i2cMasterPath.toString()).addToLog(err);
+
+ }
+ return err;
+
+} // end tpmPollForCommandReady
+
+errlHndl_t tpmIsExpecting( tpm_info_t i_tpmInfo,
+ bool & o_isExpecting)
+{
+ tpm_sts_reg_t stsReg;
+ errlHndl_t err = tpmReadSTSRegValid(i_tpmInfo,
+ stsReg);
+ o_isExpecting = false;
+
+ if (NULL == err && stsReg.expect)
+ {
+ o_isExpecting = true;
+ }
+ return err;
+
+} // end tpmIsExpecting
+
+errlHndl_t tpmIsDataAvail( tpm_info_t i_tpmInfo,
+ bool & o_isDataAvail)
+{
+ tpm_sts_reg_t stsReg;
+ errlHndl_t err = tpmReadSTSRegValid(i_tpmInfo,
+ stsReg);
+ o_isDataAvail = false;
+
+ if (NULL == err && stsReg.dataAvail)
+ {
+ o_isDataAvail = true;
+ }
+ return err;
+
+} // end tpmIsDataAvail
+
+errlHndl_t tpmPollForDataAvail( tpm_info_t i_tpmInfo)
+{
+ tpm_sts_reg_t stsReg;
+ errlHndl_t err = NULL;
+
+ // Operation TIMEOUT_A defined by TCG spec for data available
+ for (size_t delay = 0; delay < TPMDD::TPM_TIMEOUT_A; delay += 10)
+ {
+ err = tpmReadSTSRegValid(i_tpmInfo,
+ stsReg);
+ if (NULL == err && stsReg.dataAvail)
+ {
+ break;
+ }
+ // Sleep 10ms before attempting another read
+ nanosleep(0, 10 * NS_PER_MSEC);
+
+ }
+
+ if (NULL == err && !stsReg.dataAvail)
+ {
+ // Timed out waiting for TPM to have more data available
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmPollForDataAvail() - "
+ "Timeout polling for dataAvail! "
+ "C-p/e/dA=%d-%d/%d/0x%X, OP=%d, "
+ "STS=0x%X",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr, i_tpmInfo.operation,
+ stsReg.value );
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_TIMEOUT
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_POLLFORDATAAVAIL
+ * @userdata1 Attribute Chip Type Enum
+ * @userdata2 STS Reg
+ * @devdesc Timeout waiting for TPM data available.
+ */
+ err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_POLLFORDATAAVAIL,
+ TPM_TIMEOUT,
+ i_tpmInfo.chip,
+ stsReg.value,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+
+ ERRORLOG::ErrlUserDetailsString(
+ i_tpmInfo.i2cMasterPath.toString()).addToLog(err);
+
+ }
+ return err;
+
+} // end tpmPollForDataAvail
+
+errlHndl_t tpmReadBurstCount( tpm_info_t i_tpmInfo,
+ uint8_t & o_burstCount)
+{
+ errlHndl_t err = NULL;
+
+ o_burstCount = 0;
+ err = tpmReadReg(i_tpmInfo,
+ TPMDD::I2C_REG_BURSTCOUNT,
+ 1,
+ reinterpret_cast<void*>(&o_burstCount));
+
+ if (NULL == err &&
+ o_burstCount > TPMDD::TPM_MAXBURSTSIZE)
+ {
+ o_burstCount = TPMDD::TPM_MAXBURSTSIZE;
+ }
+
+ return err;
+
+} // end tpmReadBurstCount
+
+
+
+errlHndl_t tpmWriteCommandReady( tpm_info_t i_tpmInfo)
+{
+ tpm_sts_reg_t stsReg;
+ stsReg.value = 0;
+ stsReg.isCommandReady = 1;
+
+ return tpmWriteReg(i_tpmInfo,
+ TPMDD::I2C_REG_STS,
+ 1,
+ reinterpret_cast<void*>(&stsReg));
+
+} // end tpmWriteCommandReady
+
+errlHndl_t tpmWriteTpmGo( tpm_info_t i_tpmInfo)
+{
+ tpm_sts_reg_t stsReg;
+ stsReg.value = 0;
+ stsReg.tpmGo = 1;
+
+ return tpmWriteReg(i_tpmInfo,
+ TPMDD::I2C_REG_STS,
+ 1,
+ reinterpret_cast<void*>(&stsReg));
+
+} // end tpmWriteTpmGo
+
+errlHndl_t tpmWriteResponseRetry( tpm_info_t i_tpmInfo)
+{
+ tpm_sts_reg_t stsReg;
+ stsReg.value = 0;
+ stsReg.responseRetry = 1;
+
+ return tpmWriteReg(i_tpmInfo,
+ TPMDD::I2C_REG_STS,
+ 1,
+ reinterpret_cast<void*>(&stsReg));
+
+} // end tpmWriteResponseRetry
+
+
+errlHndl_t tpmWriteFifo( tpm_info_t i_tpmInfo,
+ void * i_buffer,
+ size_t i_buflen)
+{
+ size_t delay = 0;
+ size_t curByte = 0;
+ uint8_t* bytePtr = (uint8_t*)i_buffer;
+ uint8_t* curBytePtr = NULL;
+ uint8_t burstCount = 0;
+ errlHndl_t err = NULL;
+ bool expecting = false;
+ // We will transfer the command except for the last byte
+ // that will be transfered separately to allow for
+ // overflow checking
+ size_t length = i_buflen - 1;
+ size_t tx_len = 0;
+
+ do
+ {
+ err = tpmReadBurstCount(i_tpmInfo,
+ burstCount);
+ if (err)
+ {
+ break;
+ }
+ else if (0 == burstCount)
+ {
+ // Need to delay to allow the TPM time
+ nanosleep(0, 10 * NS_PER_MSEC); // 10ms
+ delay += 10;
+ continue;
+ }
+
+ // Send in some data
+ delay = 0;
+ curBytePtr = &(bytePtr[curByte]);
+ tx_len = (curByte + burstCount > length ?
+ (length - curByte) :
+ burstCount);
+ err = tpmWriteReg(i_tpmInfo,
+ TPMDD::I2C_REG_WR_FIFO,
+ tx_len,
+ curBytePtr);
+ if (err)
+ {
+ break;
+ }
+ curByte += tx_len;
+
+ // TPM should be expecting more data from the command
+ err = tpmIsExpecting(i_tpmInfo,
+ expecting);
+
+ if (NULL == err && !expecting)
+ {
+ // TPM is not expecting more data, we overflowed
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmWriteFifo(): Data Overflow! "
+ "C-p/e/dA=%d-%d/%d/0x%X, blen=%d, "
+ "clen=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_buflen, curByte);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_OVERFLOW_ERROR
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_WRITEFIFO
+ * @userdata1[0:31] Current byte
+ * @userdata1[32:63] Buffer Length (in Bytes)
+ * @userdata2 8 bytes of command buffer
+ * @devdesc TPM expected less data during FIFO write
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM overflow
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_WRITEFIFO,
+ TPM_OVERFLOW_ERROR,
+ TWO_UINT32_TO_UINT64(
+ curByte,
+ i_buflen ),
+ *(reinterpret_cast<uint64_t*>
+ (i_buffer)),
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ }
+ if (err)
+ {
+ break;
+ }
+
+ // Everything but the last byte sent?
+ if (curByte >= length)
+ {
+ break;
+ }
+
+
+ // Operation TIMEOUT_D defined by TCG spec for FIFO availability
+ } while (delay < TPMDD::TPM_TIMEOUT_D);
+
+ if (NULL == err &&
+ delay < TPMDD::TPM_TIMEOUT_D)
+ {
+ delay = 0;
+
+ // Send the final byte
+ do
+ {
+ err = tpmReadBurstCount(i_tpmInfo,
+ burstCount);
+ if (err)
+ {
+ break;
+ }
+ else if (0 == burstCount)
+ {
+ // Need to delay to allow the TPM time
+ nanosleep(0, 10 * NS_PER_MSEC); // 10ms
+ delay += 10;
+ continue;
+ }
+
+ // Send in some data
+ delay = 0;
+ curBytePtr = &(bytePtr[curByte]);
+ err = tpmWriteReg(i_tpmInfo,
+ TPMDD::I2C_REG_WR_FIFO,
+ 1,
+ curBytePtr);
+ // done
+ break;
+ // Operation TIMEOUT_D defined by TCG spec for FIFO availability
+ } while (delay < TPMDD::TPM_TIMEOUT_D);
+
+ }
+
+
+ if (delay >= TPMDD::TPM_TIMEOUT_D)
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmWriteFifo(): Timeout! "
+ "C-p/e/dA=%d-%d/%d/0x%X, blen=%d, "
+ "clen=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_buflen, curByte);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_TIMEOUT
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_WRITEFIFO
+ * @userdata1[0:31] Current Byte
+ * @userdata1[32:63] Buffer Length (in Bytes)
+ * @userdata2 8 bytes of command buffer
+ * @devdesc TPM timeout writing to FIFO
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM timeout
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_WRITEFIFO,
+ TPM_TIMEOUT,
+ TWO_UINT32_TO_UINT64(
+ curByte,
+ i_buflen ),
+ *(reinterpret_cast<uint64_t*>
+ (i_buffer)),
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ }
+
+
+
+ if (NULL == err)
+ {
+ err = tpmIsExpecting(i_tpmInfo,
+ expecting);
+
+ if (NULL == err && expecting)
+ {
+ // TPM is expecting more data even though we think we are done
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmWriteFifo(): Data Underflow! "
+ "C-p/e/dA=%d-%d/%d/0x%X, blen=%d, "
+ "clen=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ i_buflen, curByte);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_UNDERFLOW_ERROR
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_WRITEFIFO
+ * @userdata1[0:31] Current Byte
+ * @userdata1[32:63] Buffer Length (in Bytes)
+ * @userdata2 8 bytes of command buffer
+ * @devdesc TPM expected more data during FIFO write
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM underflow
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_WRITEFIFO,
+ TPM_UNDERFLOW_ERROR,
+ TWO_UINT32_TO_UINT64(
+ curByte,
+ i_buflen ),
+ *(reinterpret_cast<uint64_t*>
+ (i_buffer)),
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ }
+
+ }
+
+
+
+ return err;
+
+} // end tpmWriteFifo
+
+errlHndl_t tpmReadFifo( tpm_info_t i_tpmInfo,
+ void * o_buffer,
+ size_t & io_buflen)
+{
+ size_t delay = 0;
+ size_t curByte = 0;
+ uint8_t* bytePtr = (uint8_t*)o_buffer;
+ uint8_t* curBytePtr = NULL;
+ uint8_t burstCount = 0;
+ errlHndl_t err = NULL;
+ bool dataAvail = false;
+
+ // Verify the TPM has data waiting for us
+ err = tpmPollForDataAvail(i_tpmInfo);
+ if( !err )
+ {
+ do
+ {
+ err = tpmReadBurstCount(i_tpmInfo,
+ burstCount);
+ if (err)
+ {
+ break;
+ }
+ else if (0 == burstCount)
+ {
+ // Need to delay to allow the TPM time
+ nanosleep(0, 10 * NS_PER_MSEC); // 10ms
+ delay += 10;
+ continue;
+ }
+
+ // Check for a buffer overflow
+ if (curByte + burstCount >
+ io_buflen)
+ {
+ // TPM is expecting more data even though we think we are done
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmReadFifo(): Data Overflow! "
+ "C-p/e/dA=%d-%d/%d/0x%X, blen=%d, "
+ "clen=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ io_buflen, curByte);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_OVERFLOW_ERROR
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_READFIFO
+ * @userdata1[0:31] Operation
+ * @userdata1[32:63] Buffer Length (in Bytes)
+ * @userdata2 Current Byte
+ * @devdesc TPM provided more data during FIFO read
+ * then buffer space provided
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM overflow
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_READFIFO,
+ TPM_OVERFLOW_ERROR,
+ TWO_UINT32_TO_UINT64(
+ i_tpmInfo.operation,
+ io_buflen ),
+ curByte,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ break;
+ }
+
+ // Read some data
+ delay = 0;
+ curBytePtr = &(bytePtr[curByte]);
+ err = tpmReadReg(i_tpmInfo,
+ TPMDD::I2C_REG_RD_FIFO,
+ burstCount,
+ curBytePtr);
+ if (err)
+ {
+ break;
+ }
+ curByte += burstCount;
+
+ err = tpmIsDataAvail(i_tpmInfo,
+ dataAvail);
+ if (err || !dataAvail)
+ {
+ break;
+ }
+
+ // Operation TIMEOUT_D defined by TCG spec for FIFO availability
+ } while (delay < TPMDD::TPM_TIMEOUT_D);
+
+ }
+
+ if (!err && delay >= TPMDD::TPM_TIMEOUT_D)
+ {
+ TRACFCOMP( g_trac_tpmdd,
+ ERR_MRK"tpmReadFifo(): Timeout! "
+ "C-p/e/dA=%d-%d/%d/0x%X, blen=%d, "
+ "clen=%d",
+ i_tpmInfo.chip, i_tpmInfo.port,
+ i_tpmInfo.engine, i_tpmInfo.devAddr,
+ io_buflen, curByte);
+
+ /*@
+ * @errortype
+ * @reasoncode TPM_TIMEOUT
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid TPMDD_READFIFO
+ * @userdata1[0:31] Operation
+ * @userdata1[32:63] Buffer Length (in Bytes)
+ * @userdata2 Current Byte
+ * @devdesc TPM timeout writing to FIFO
+ * @custdesc A problem occurred during the IPL of the
+ * system: TPM timeout
+ */
+ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ TPMDD_READ,
+ TPM_TIMEOUT,
+ TWO_UINT32_TO_UINT64(
+ i_tpmInfo.operation,
+ io_buflen ),
+ curByte,
+ true /*Add HB SW Callout*/ );
+
+ err->collectTrace( TPMDD_COMP_NAME );
+ }
+
+ if (NULL == err)
+ {
+ // We read it properly tell the caller the result length
+ io_buflen = curByte;
+ }
+ else
+ {
+ io_buflen = 0;
+ }
+
+
+ return err;
+
+} // end tpmReadFifo
+
+
+
+
+} // end namespace TPMDD
+
diff --git a/src/usr/i2c/tpmdd.H b/src/usr/i2c/tpmdd.H
new file mode 100755
index 000000000..b9f2aace1
--- /dev/null
+++ b/src/usr/i2c/tpmdd.H
@@ -0,0 +1,509 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/i2c/tpmdd.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 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 */
+#ifndef __TPMDD_H
+#define __TPMDD_H
+
+/**
+ * @file tpmdd.H
+ *
+ * @brief Provides the interfaces for accessing TPMs within
+ * the system via the I2C device driver.
+ */
+
+// ----------------------------------------------
+// Includes
+// ----------------------------------------------
+#include <i2c/tpmddif.H>
+#include <errl/errlentry.H>
+
+namespace TPMDD
+{
+
+/**
+* @brief Enumerations to describe the type of devices to be accessed.
+*/
+enum tpm_addr_size_t
+{
+ ONE_BYTE_ADDR = 1,
+ TWO_BYTE_ADDR = 2,
+ LAST_DEVICE_TYPE
+};
+
+/// TPM Timeouts listed in ms
+/// Timeout names and durations are as described in the TCG specification
+enum tpm_timeouts
+{
+ TPM_TIMEOUT_A = 750, ///< 750ms
+ TPM_TIMEOUT_B = 2000, ///< 2000ms
+ TPM_TIMEOUT_C = 750, ///< 750ms
+ TPM_TIMEOUT_D = 750, ///< 750ms
+};
+
+/// TPM Driver values
+enum
+{
+ MAX_STSVALID_POLLS = 5, ///< Max poll of 50ms (5*10ms)
+};
+
+/**
+ * @brief Structure of common parameters needed by different parts of
+ * the code.
+ */
+struct tpm_info_t
+{
+ tpm_op_types_t operation; ///< TPM operation to perform
+ uint64_t port; ///< I2C Master port
+ uint64_t engine; ///< I2C Master engin
+ tpm_addr_size_t addrSize; ///< I2C Addr size
+ TARGETING::EntityPath i2cMasterPath; ///< I2C Master path
+ TARGETING::Target * i2cTarget; ///< I2C Target
+
+ uint8_t chip; ///< Chip target, primary/backup
+ uint8_t tpmEnabled; ///< Is this TPM available and functional?
+ uint8_t devAddr; ///< I2C Address
+ size_t offset; ///< TPM Device register offset
+};
+
+
+
+#ifdef CONFIG_TPM_NUVOTON
+#ifdef CONFIG_TPMDD_1_2
+/**
+ * @brief Nuvoton 1.2 TPM definitions
+ */
+enum nuvo_12_defs_t
+{
+ I2C_REG_STS = 0x0,
+ I2C_REG_BURSTCOUNT = 0x1,
+ I2C_REG_WR_FIFO = 0x20,
+ I2C_REG_RD_FIFO = 0x40,
+ I2C_REG_VENDOR = 0x60,
+
+ TPM_VENDORID = 0x5010FE00,
+ TPM_MAXBURSTSIZE = 32, ///< Max size to transfer in one i2c op
+};
+#endif
+#endif
+
+#ifdef CONFIG_TPMDD_1_2
+/**
+* @brief TPM STS register definition (TIS 1.2 Spec)
+*/
+union tpm_sts_reg_t
+{
+ uint8_t value;
+ struct
+ {
+ uint8_t stsValid : 1; // 00 // RO
+ uint8_t isCommandReady : 1; // 01 // RW
+ uint8_t tpmGo : 1; // 02 // WO
+ uint8_t dataAvail : 1; // 03 // RO
+ uint8_t expect : 1; // 04 // RO
+ uint8_t rsvd1 : 1; // 05 // RO
+ uint8_t responseRetry : 1; // 06 // WO
+ uint8_t rsvd2 : 1; // 07 // RO
+ } PACKED;
+};
+#endif
+
+
+
+/**
+*
+* @brief Perform an TPM access operation.
+*
+* @param[in] i_opType Operation Type - See DeviceFW::OperationType in
+* driververif.H
+*
+* @param[in] i_target target node.
+*
+* @param[in/out] io_buffer
+* INPUT: Pointer to the data that will be written to the target
+* device.
+* OUTPUT: Pointer to the data that was read from the target device.
+*
+* @param[in/out] io_buflen
+* INPUT: Length of the buffer to be written to target device.
+* OUTPUT: Length of buffer that was written, or length of buffer
+* to be read from target device.
+*
+* @param [in] i_accessType Access Type - See DeviceFW::AccessType in
+* usrif.H
+*
+* @param [in] i_args This is an argument list for the device driver
+* framework. This argument list consists of the chip number of
+* the TPM to access from the given I2C Master target and the
+* internal offset to use on the slave I2C device.
+*
+* @return errlHndl_t NULL if successful, otherwise a pointer to the
+* error log.
+*
+*/
+errlHndl_t tpmPerformOp( DeviceFW::OperationType i_opType,
+ TARGETING::Target * i_target,
+ void * io_buffer,
+ size_t & io_buflen,
+ int64_t i_accessType,
+ va_list i_args );
+
+/**
+ * @brief This function peforms the sequencing to do a read of the
+ * TPM that is identified.
+ *
+ * @param[out] o_buffer The buffer that will return the data read
+ * from the TPM device.
+ *
+ * @param[in] i_buflen Number of bytes to read from the TPM device.
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmRead ( void * o_buffer,
+ size_t i_buflen,
+ tpm_info_t i_tpmInfo );
+
+/**
+ * @brief This function peforms the sequencing to do a write of the
+ * TPM that is identified.
+ *
+ * @param[out] i_buffer The buffer containing data to write
+ * to the TPM device.
+ *
+ * @param[in] i_buflen Number of bytes to write to the TPM device.
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmWrite ( void * i_buffer,
+ size_t i_buflen,
+ tpm_info_t i_tpmInfo );
+
+/**
+ * @brief This function peforms the sequencing to do a transmit of the
+ * TPM that is identified.
+ *
+ * @param[in/out] io_buffer Data buffer
+ * INPUT: Command to be written to the TPM
+ * OUTPUT: Response from the TPM
+ *
+ * @param[in/out] io_buflen Buffer Length
+ * INPUT: Full length of io_buffer allocated.
+ * OUTPUT: Length of the response read from TPM.
+ *
+ * @param[in] i_commandlen Length of command to send in bytes
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmTransmit ( void * io_buffer,
+ size_t & io_buflen,
+ size_t i_commandlen,
+ tpm_info_t i_tpmInfo );
+
+/**
+ * @brief This function prepares the I2C byte address for adding to the
+ * existing buffer (for Writes), or as a separate write operation
+ * (for Reads).
+ *
+ * @param[in/out] io_buffer The buffer to be written as a byte address to
+ * the TPM device. Must be pre-allocated to MAX_BYTE_ADDR size.
+ *
+ * @param[out] o_bufSize The size of the buffer to be written.
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmPrepareAddress ( void * io_buffer,
+ size_t & o_bufSize,
+ tpm_info_t i_tpmInfo );
+
+/**
+ * @brief this function will read all of the associated attributes needed
+ * to access the intended TPM. These attributes will be used to
+ * determine the type of I2C device as well as how to address it via
+ * the I2C device driver.
+ *
+ * @param[in] i_target target node.
+ *
+ * @param[in/out] io_tpmInfo The structure that will contain the attribute data
+ * read from the target device.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmReadAttributes ( TARGETING::Target * i_target,
+ tpm_info_t & io_tpmInfo );
+
+/**
+ * @brief This function decides whether or not the target passed into the
+ * TPM device driver actually contains the I2C Master engines. If
+ * not, it will then read the attribute of the target to get the path
+ * of the target which does contain the I2C Master engine.
+ *
+ * @param[in] i_target The current Target.
+ *
+ * @param[in/out] io_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ * *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmGetI2CMasterTarget ( TARGETING::Target * i_target,
+ tpm_info_t & io_tpmInfo );
+
+
+
+/**
+ * @brief Write a Tpm Register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[in] i_offset TPM Register Offset
+ *
+ * @param[in] i_buflen Length of write
+ *
+ * @param[in] i_buffer Value to write into register
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmWriteReg ( tpm_info_t i_tpmInfo,
+ size_t i_offset,
+ size_t i_buflen,
+ void * i_buffer);
+
+/**
+ * @brief Read a Tpm Register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[in] i_offset TPM Register Offset
+ *
+ * @param[in] i_buflen Length of read
+ *
+ * @param[in] o_buffer Value read from the register
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmReadReg ( tpm_info_t i_tpmInfo,
+ size_t i_offset,
+ size_t i_buflen,
+ void * o_buffer);
+
+/**
+ * @brief Read the Tpm STS Register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[in] o_stsReg Value read from the register
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmReadSTSReg ( tpm_info_t i_tpmInfo,
+ tpm_sts_reg_t & o_stsReg);
+
+/**
+ * @brief Read the Tpm STS Register polling for stsValid
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[in] o_stsReg Value read from the register
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmReadSTSRegValid ( tpm_info_t i_tpmInfo,
+ tpm_sts_reg_t & o_stsReg);
+
+/**
+ * @brief Check for command ready in STS reg
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[out] o_isReady True if TPM in command ready state.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmIsCommandReady( tpm_info_t i_tpmInfo,
+ bool & o_isReady);
+
+/**
+ * @brief Poll the Tpm waiting for it to enter command ready state
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmPollForCommandReady( tpm_info_t i_tpmInfo);
+
+/**
+ * @brief Check for expecting state in TPM STS Register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[out] o_isExpecting True if TPM is expecting data
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmIsExpecting( tpm_info_t i_tpmInfo,
+ bool & o_isExpecting);
+
+/**
+ * @brief Check for data available state in Tpm STS register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[out] o_isDataAvail True if TPM data is available
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmIsDataAvail( tpm_info_t i_tpmInfo,
+ bool & o_isDataAvail);
+
+/**
+ * @brief Poll the Tpm waiting for data available state
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmPollForDataAvail( tpm_info_t i_tpmInfo);
+
+/**
+ * @brief Read the current burst count value
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[out] o_burstCount Current TPM burst count
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmReadBurstCount( tpm_info_t i_tpmInfo,
+ uint8_t & o_burstCount);
+
+/**
+ * @brief Write the command ready bit in the Tpm STS register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmWriteCommandReady( tpm_info_t i_tpmInfo);
+
+/**
+ * @brief Write the TpmGo bit in the STS register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmWriteTpmGo( tpm_info_t i_tpmInfo);
+
+/**
+ * @brief Write the response retry bit in the Tpm STS register
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmWriteResponseRetry( tpm_info_t i_tpmInfo);
+
+
+/**
+ * @brief Write the buffer into the TPM's input FIFO
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[in] i_buffer Input buffer to write to TPM
+ *
+ * @param[in] i_buflen Byte length of data to write
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmWriteFifo( tpm_info_t i_tpmInfo,
+ void * i_buffer,
+ size_t i_buflen);
+
+/**
+ * @brief Read from the TPM FIFO into the buffer
+ *
+ * @param[in] i_tpmInfo Structure of I2C parameters needed to execute
+ * the command to the I2C device driver.
+ *
+ * @param[in] o_buffer Output buffer
+ *
+ * @param[in] io_buflen Byte length of buffer
+ * INPUT: Full length of io_buffer allocated.
+ * OUTPUT: Length of the response read from TPM.
+ *
+ * @return errlHndl_t NULL if successful, otherwise a pointer to the
+ * error log.
+ */
+errlHndl_t tpmReadFifo( tpm_info_t i_tpmInfo,
+ void * o_buffer,
+ size_t & io_buflen);
+
+
+}; // end TPMDD namespace
+
+#endif // __TPMDD_H
OpenPOWER on IntegriCloud