[Skiboot] [PATCH v2 13/31] libstb/drivers/tpm_i2c_nuvoton.c: check command ready

Claudio Carvalho cclaudio at linux.vnet.ibm.com
Wed Sep 28 18:01:12 AEST 2016


This adds the 1/5 step performed by the TPM I2C Nuvoton driver to
transmit a command to the TPM device. In this step the driver
checks if the TPM device is ready to receive a new command.

Signed-off-by: Claudio Carvalho <cclaudio at linux.vnet.ibm.com>
---
 libstb/drivers/Makefile.inc      |   2 +-
 libstb/drivers/tpm_i2c_nuvoton.c | 134 +++++++++++++++++++++++++++++++++++++++
 libstb/status_codes.h            |   3 +
 3 files changed, 138 insertions(+), 1 deletion(-)
 create mode 100644 libstb/drivers/tpm_i2c_nuvoton.c

diff --git a/libstb/drivers/Makefile.inc b/libstb/drivers/Makefile.inc
index f0f3d70..2817378 100644
--- a/libstb/drivers/Makefile.inc
+++ b/libstb/drivers/Makefile.inc
@@ -4,7 +4,7 @@ DRIVERS_DIR = libstb/drivers
 
 SUBDIRS += $(DRIVERS_DIR)
 
-DRIVERS_SRCS = romcode.c tpm_i2c_interface.c
+DRIVERS_SRCS = romcode.c tpm_i2c_interface.c tpm_i2c_nuvoton.c
 DRIVERS_OBJS = $(DRIVERS_SRCS:%.c=%.o)
 DRIVERS = $(DRIVERS_DIR)/built-in.o
 
diff --git a/libstb/drivers/tpm_i2c_nuvoton.c b/libstb/drivers/tpm_i2c_nuvoton.c
new file mode 100644
index 0000000..ead0f15
--- /dev/null
+++ b/libstb/drivers/tpm_i2c_nuvoton.c
@@ -0,0 +1,134 @@
+/* Copyright 2013-2016 IBM 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.
+ */
+
+/****************************************************************************
+ * THIS DRIVER WAS DEVELOPED BASED ON:
+ * https://github.com/open-power/hostboot/blob/master-p8/src/usr/i2c/tpmdd.C
+ ****************************************************************************/
+
+#include <timebase.h>
+#include <skiboot.h>
+#include <i2c.h>
+#include "../status_codes.h"
+#include "../tpm_chip.h"
+#include "tpm_i2c_interface.h"
+
+//#define DBG(fmt, ...) prlog(PR_DEBUG, fmt, ##__VA_ARGS__)
+#define DBG(fmt, ...)
+
+/*
+ * Timings between various states or transitions within the interface protocol
+ * as defined in the TCG PC Client Platform TPM Profile specification, Revision
+ * 00.43.
+ */
+#define TCG_PTP_TIMEOUT_B	2000
+
+/* I2C interface offsets */
+#define NUVOTON_TPM_STS			0x00
+
+/* Bit masks for the TPM STATUS register */
+#define TCG_PTP_STS_COMMAND_READY	0x40
+
+/* TPM Driver values */
+#define TPM_TIMEOUT_INTERVAL	10
+
+static struct tpm_dev *tpm_device = NULL;
+
+static int tpm_status_write_byte(uint8_t byte)
+{
+	uint8_t value = byte;
+	return tpm_i2c_request_send(tpm_device->bus_id, tpm_device->xscom_base,
+				    SMBUS_WRITE, NUVOTON_TPM_STS, 1, &value,
+				    sizeof(value));
+}
+
+static bool tpm_is_command_ready(int* rc)
+{
+	uint8_t value = 0;
+	*rc = tpm_i2c_request_send(tpm_device->bus_id, tpm_device->xscom_base,
+				   SMBUS_READ, NUVOTON_TPM_STS, 1, &value,
+				   sizeof(value));
+	if (*rc == 0  &&
+	   ((value & TCG_PTP_STS_COMMAND_READY) == TCG_PTP_STS_COMMAND_READY)){
+		DBG("---- TPM is command ready\n");
+		return true;
+	}
+	return false;
+}
+
+static int tpm_poll_for_command_ready(void)
+{
+	int rc, polls, delay;
+	/*
+	 * The first write to command ready may just abort an
+	 * outstanding command, so we poll twice
+	 */
+	for (polls=0; polls<2; polls++) {
+		rc = tpm_status_write_byte(TCG_PTP_STS_COMMAND_READY);
+		if (rc < 0) {
+			return rc;
+		}
+		for (delay = 0; delay < TCG_PTP_TIMEOUT_B;
+		     delay += TPM_TIMEOUT_INTERVAL) {
+			if (tpm_is_command_ready(&rc))
+				return rc;
+			time_wait_ms(TPM_TIMEOUT_INTERVAL);
+		}
+		DBG("--- Command ready polling, delay %d/%d\n",
+		    delay, TCG_PTP_TIMEOUT_B);
+	}
+	/**
+	 * @fwts-label TPMCommandReadyBitTimeout
+	 * @fwts-advice The command ready bit of the tpm status register is
+	 * taking longer to be settled. Either the wait time need to be
+	 * increased or the TPM device is not functional.
+	 */
+	prlog(PR_ERR, "TPM: command ready polling timeout\n");
+	return STB_TPM_TIMEOUT;
+}
+
+static int tpm_transmit(struct tpm_dev *dev, uint8_t* buf, size_t cmdlen,
+			size_t* buflen)
+{
+	int rc = 0;
+	if (!dev) {
+		/**
+		 * @fwts-label TPMDeviceNotInitialized
+		 * @fwts-advice TPM device is not initialized. This indicates a
+		 * bug in the tpm_transmit() caller
+		 */
+		prlog(PR_ERR, "TPM: tpm device not initialized\n");
+		return STB_ARG_ERROR;
+	}
+	tpm_device = dev;
+	DBG("**** %s: dev %#x/%#x buf %016llx cmdlen %zu"
+	    " buflen %zu ****\n",
+	    __func__, dev->bus_id, dev->xscom_base, *(uint64_t*) buf,
+	    cmdlen, *buflen);
+
+	DBG("step 1/5: check command ready\n");
+	if (!tpm_is_command_ready(&rc)) {
+		if (rc < 0)
+			goto out;
+		rc = tpm_poll_for_command_ready();
+		if (rc < 0)
+			goto out;
+	}
+out:
+	DBG("**** tpm_transmit %s, rc=%d ****\n",
+	    (rc) ? "ERROR" : "SUCCESS", rc);
+	return rc;
+}
diff --git a/libstb/status_codes.h b/libstb/status_codes.h
index 385e764..88443b9 100644
--- a/libstb/status_codes.h
+++ b/libstb/status_codes.h
@@ -25,4 +25,7 @@
 /* secure boot */
 #define STB_VERIFY_FAILED  		-100
 
+/* TPM */
+#define STB_TPM_TIMEOUT	-301
+
 #endif /* __STB_STATUS_CODES_H */
-- 
1.9.1



More information about the Skiboot mailing list