From f170d3b953adb04c02e0a426ae9979258ef73ef6 Mon Sep 17 00:00:00 2001 From: "wenxin.leong" Date: Wed, 28 Aug 2024 14:28:14 +0800 Subject: [PATCH] Refactor and Update the tcti-x-helper - Moved common transmit/receive FIFO protocol code to tcti-helper-common. - Refined the FIFO protocol implementation. - Updated unit test implementation so that changes to the FIFO protocol no longer require modifications to all dependent unit tests. Signed-off-by: wenxin.leong --- Makefile-test.am | 71 ++- Makefile.am | 11 +- configure.ac | 3 + src/tss2-tcti/tcti-helper-common.c | 761 +++++++++++++++++++++++++++ src/tss2-tcti/tcti-helper-common.h | 110 ++++ src/tss2-tcti/tcti-i2c-helper.c | 783 ++++++++-------------------- src/tss2-tcti/tcti-i2c-helper.h | 69 +-- src/tss2-tcti/tcti-spi-helper.c | 798 +++++++++++------------------ src/tss2-tcti/tcti-spi-helper.h | 48 +- src/tss2-tcti/tcti-spi-ltt2go.c | 19 +- src/tss2-tcti/tcti-spi-ltt2go.h | 13 + test/unit/tcti-helper-common.c | 443 ++++++++++++++++ test/unit/tcti-i2c-ftdi.c | 682 +++++++++--------------- test/unit/tcti-i2c-helper.c | 529 +++++++++++-------- test/unit/tcti-spi-ftdi.c | 310 +++++++---- test/unit/tcti-spi-helper.c | 544 +++++++++++++------- test/unit/tcti-spi-ltt2go.c | 650 ++++++++++++++++------- test/unit/tcti-spidev.c | 296 +++++++---- 18 files changed, 3704 insertions(+), 2436 deletions(-) create mode 100644 src/tss2-tcti/tcti-helper-common.c create mode 100644 src/tss2-tcti/tcti-helper-common.h create mode 100644 test/unit/tcti-helper-common.c diff --git a/Makefile-test.am b/Makefile-test.am index ecd759d80..1e7163b96 100644 --- a/Makefile-test.am +++ b/Makefile-test.am @@ -128,6 +128,9 @@ endif if ENABLE_TCTI_CMD TESTS_UNIT += test/unit/tcti-cmd endif +if ENABLE_TCTI_HELPER_COMMON +TESTS_UNIT += test/unit/tcti-helper-common +endif if ENABLE_TCTI_SPI_HELPER TESTS_UNIT += test/unit/tcti-spi-helper endif @@ -531,16 +534,30 @@ test_unit_tcti_cmd_SOURCES = test/unit/tcti-cmd.c \ test/helper/cmocka_all.h endif +if ENABLE_TCTI_HELPER_COMMON +test_unit_tcti_helper_common_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_tcti_helper_common_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_helper_common) $(libtss2_mu) $(libutil) +test_unit_tcti_helper_common_SOURCES = test/unit/tcti-helper-common.c \ + src/tss2-tcti/tcti-common.c \ + test/helper/cmocka_all.h +endif + if ENABLE_TCTI_SPI_HELPER test_unit_tcti_spi_helper_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_spi_helper_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spi_helper_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_tcti_spi_helper_LDFLAGS = -Wl,--wrap=Tcti_Helper_Common_Init \ + -Wl,--wrap=Tcti_Helper_Common_Transmit \ + -Wl,--wrap=Tcti_Helper_Common_Receive test_unit_tcti_spi_helper_SOURCES = test/unit/tcti-spi-helper.c \ - test/helper/cmocka_all.h + test/helper/cmocka_all.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-helper-common.h \ + src/tss2-tcti/tcti-spi-helper.c endif if ENABLE_TCTI_SPI_LTT2GO test_unit_tcti_spi_ltt2go_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_spi_ltt2go_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spi_ltt2go_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) test_unit_tcti_spi_ltt2go_LDFLAGS = -Wl,--wrap=libusb_bulk_transfer \ -Wl,--wrap=libusb_claim_interface \ -Wl,--wrap=libusb_open \ @@ -560,49 +577,63 @@ test_unit_tcti_spi_ltt2go_LDFLAGS = -Wl,--wrap=libusb_bulk_transfer \ -Wl,--wrap=libusb_set_auto_detach_kernel_driver \ -Wl,--wrap=libusb_strerror \ -Wl,--wrap=select \ - -Wl,--wrap=gettimeofday + -Wl,--wrap=gettimeofday \ + -Wl,--wrap=Tss2_Tcti_Spi_Helper_Init test_unit_tcti_spi_ltt2go_SOURCES = test/unit/tcti-spi-ltt2go.c \ - src/tss2-tcti/tcti-spi-ltt2go.c test/helper/cmocka_all.h + test/helper/cmocka_all.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-spi-helper.h \ + src/tss2-tcti/tcti-spi-ltt2go.c endif if ENABLE_TCTI_SPIDEV test_unit_tcti_spidev_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_spidev_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spidev_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) test_unit_tcti_spidev_LDFLAGS = -Wl,--wrap=open \ -Wl,--wrap=close \ -Wl,--wrap=ioctl \ -Wl,--wrap=select \ - -Wl,--wrap=gettimeofday + -Wl,--wrap=gettimeofday \ + -Wl,--wrap=Tss2_Tcti_Spi_Helper_Init test_unit_tcti_spidev_SOURCES = test/unit/tcti-spidev.c \ - src/tss2-tcti/tcti-spidev.c test/helper/cmocka_all.h + src/tss2-tcti/tcti-spidev.c test/helper/cmocka_all.h \ + src/tss2-tcti/tcti-common.c src/tss2-tcti/tcti-spi-helper.h endif if ENABLE_TCTI_SPI_FTDI test_unit_tcti_spi_ftdi_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_spi_ftdi_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spi_ftdi_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) test_unit_tcti_spi_ftdi_LDFLAGS = -Wl,--wrap=Close \ -Wl,--wrap=MPSSE \ - -Wl,--wrap=PinHigh \ - -Wl,--wrap=PinLow \ -Wl,--wrap=Start \ -Wl,--wrap=Stop \ -Wl,--wrap=Transfer \ -Wl,--wrap=select \ - -Wl,--wrap=gettimeofday + -Wl,--wrap=gettimeofday \ + -Wl,--wrap=Tss2_Tcti_Spi_Helper_Init test_unit_tcti_spi_ftdi_SOURCES = test/unit/tcti-spi-ftdi.c \ - src/tss2-tcti/tcti-spi-ftdi.c test/helper/cmocka_all.h + test/helper/cmocka_all.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-spi-helper.h \ + src/tss2-tcti/tcti-spi-ftdi.c endif if ENABLE_TCTI_I2C_HELPER test_unit_tcti_i2c_helper_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_i2c_helper_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_i2c_helper) +test_unit_tcti_i2c_helper_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_tcti_i2c_helper_LDFLAGS = -Wl,--wrap=Tcti_Helper_Common_Init \ + -Wl,--wrap=Tcti_Helper_Common_Transmit \ + -Wl,--wrap=Tcti_Helper_Common_Receive test_unit_tcti_i2c_helper_SOURCES = test/unit/tcti-i2c-helper.c \ - test/helper/cmocka_all.h + test/helper/cmocka_all.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-helper-common.h \ + src/tss2-tcti/tcti-i2c-helper.c endif if ENABLE_TCTI_I2C_FTDI test_unit_tcti_i2c_ftdi_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_i2c_ftdi_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_i2c_helper) +test_unit_tcti_i2c_ftdi_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) test_unit_tcti_i2c_ftdi_LDFLAGS = -Wl,--wrap=MPSSE \ -Wl,--wrap=Start \ -Wl,--wrap=Stop \ @@ -613,9 +644,13 @@ test_unit_tcti_i2c_ftdi_LDFLAGS = -Wl,--wrap=MPSSE \ -Wl,--wrap=SendAcks \ -Wl,--wrap=SendNacks \ -Wl,--wrap=select \ - -Wl,--wrap=gettimeofday + -Wl,--wrap=gettimeofday \ + -Wl,--wrap=Tss2_Tcti_I2c_Helper_Init test_unit_tcti_i2c_ftdi_SOURCES = test/unit/tcti-i2c-ftdi.c \ - src/tss2-tcti/tcti-i2c-ftdi.c test/helper/cmocka_all.h + test/helper/cmocka_all.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-i2c-helper.h \ + src/tss2-tcti/tcti-i2c-ftdi.c endif test_unit_tctildr_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) diff --git a/Makefile.am b/Makefile.am index 8af86fd3e..0fb287fb5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -422,6 +422,13 @@ endif # ENABLE_TCTI_CMD EXTRA_DIST += lib/tss2-tcti-cmd.map \ lib/tss2-tcti-cmd.def +if ENABLE_TCTI_HELPER_COMMON +libtss2_tcti_helper_common = src/tss2-tcti/libtss2-tcti-helper-common.la +noinst_LTLIBRARIES += $(libtss2_tcti_helper_common) +src_tss2_tcti_libtss2_tcti_helper_common_la_SOURCES = \ + src/tss2-tcti/tcti-helper-common.c +endif + # tcti library for spi connected tpms if ENABLE_TCTI_SPI_HELPER libtss2_tcti_spi_helper = src/tss2-tcti/libtss2-tcti-spi-helper.la @@ -434,7 +441,7 @@ if !UNIT src_tss2_tcti_libtss2_tcti_spi_helper_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-spi-helper.map endif # UNIT endif # HAVE_LD_VERSION_SCRIPT -src_tss2_tcti_libtss2_tcti_spi_helper_la_LIBADD = $(libutil) $(libtss2_mu) +src_tss2_tcti_libtss2_tcti_spi_helper_la_LIBADD = $(libutil) $(libtss2_mu) $(libtss2_tcti_helper_common) src_tss2_tcti_libtss2_tcti_spi_helper_la_SOURCES = \ src/tss2-tcti/tcti-common.c \ src/tss2-tcti/tcti-spi-helper.c \ @@ -521,7 +528,7 @@ if !UNIT src_tss2_tcti_libtss2_tcti_i2c_helper_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-i2c-helper.map endif # UNIT endif # HAVE_LD_VERSION_SCRIPT -src_tss2_tcti_libtss2_tcti_i2c_helper_la_LIBADD = $(libutil) $(libtss2_mu) +src_tss2_tcti_libtss2_tcti_i2c_helper_la_LIBADD = $(libutil) $(libtss2_mu) $(libtss2_tcti_helper_common) src_tss2_tcti_libtss2_tcti_i2c_helper_la_SOURCES = \ src/tss2-tcti/tcti-common.c \ src/tss2-tcti/tcti-i2c-helper.c \ diff --git a/configure.ac b/configure.ac index e2d579b8c..c8040a133 100644 --- a/configure.ac +++ b/configure.ac @@ -392,6 +392,9 @@ AM_CONDITIONAL([ENABLE_TCTI_I2C_FTDI], [test "x$enable_tcti_i2c_ftdi" != xno]) AS_IF([test "x$enable_tcti_i2c_ftdi" = "xyes"], AC_DEFINE([TCTI_I2C_FTDI],[1], [TCTI FOR USB BASED ACCESS TO I2C BASED TPM OVER THE FTDI MPSSE USB TO I2C BRIDGE])) +AM_CONDITIONAL([ENABLE_TCTI_HELPER_COMMON], + [test "x$enable_tcti_spi_helper" = "xyes" || test "x$enable_tcti_i2c_helper" = "xyes"]) + AC_ARG_ENABLE([tcti-fuzzing], [AS_HELP_STRING([--enable-tcti-fuzzing], [build the tcti-fuzzing module])],, diff --git a/src/tss2-tcti/tcti-helper-common.c b/src/tss2-tcti/tcti-helper-common.c new file mode 100644 index 000000000..b5e44f272 --- /dev/null +++ b/src/tss2-tcti/tcti-helper-common.c @@ -0,0 +1,761 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifdef HAVE_CONFIG_H +#include "config.h" // for MAXLOGLEVEL +#endif + +#include // for uint8_t, uint32_t, PRIu32, PRIx32 +#include // for bool, false, true +#include // for NULL, size_t +#include // for memcpy, memset + +#include "tcti-common.h" // for TSS2_TCTI_COMMON_CONTEXT, tpm_head... +#include "tcti-helper-common.h" +#include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC, TSS2_TCT... +#include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_INFO +#include "util/tss2_endian.h" // for LE_TO_HOST_32 + +#define LOGMODULE tcti +#include "util/log.h" // for LOG_ERROR, LOG_DEBUG, return_if_error + +/* + * CRC-CCITT KERMIT with following parameters: + * + * Length : 16 bit + * Poly : 0x1021 + * Init : 0x0000 + * RefIn : False + * RefOut : False + * XorOut : 0x0000 + * Output for ASCII "123456789" : 0x2189 + */ +static const uint16_t crc16_kermit_lookup[256]= { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +static uint16_t crc_ccitt (const uint8_t *buffer, size_t size) { + size_t i; + uint16_t result = 0; + + for (i = 0; i < size; i++) { + uint8_t j = buffer[i] ^ result; + result = crc16_kermit_lookup[j] ^ (result >> 8); + } + + return result; +} + +static TSS2_RC tcti_helper_common_sanity_check (enum TCTI_HELPER_COMMON_REG reg, uint8_t *buffer, size_t cnt) +{ + uint32_t zero_mask; + uint32_t value; + + switch (cnt) { + case sizeof (uint8_t): + value = buffer[0]; + break; + case sizeof (uint16_t): + value = LE_TO_HOST_16 (*((uint16_t *)buffer)); + break; + case sizeof (uint32_t): + value = LE_TO_HOST_32 (*((uint32_t *)buffer)); + break; + default: + return TSS2_RC_SUCCESS; + } + + switch (reg) { + case TCTI_HELPER_COMMON_REG_TPM_ACCESS: + zero_mask = TCTI_HELPER_COMMON_TPM_ACCESS_ZERO_MASK; + break; + case TCTI_HELPER_COMMON_REG_TPM_STS: + zero_mask = TCTI_HELPER_COMMON_TPM_STS_ZERO_MASK; + break; + case TCTI_HELPER_COMMON_REG_TPM_I2C_INTF_CAP: + zero_mask = TCTI_HELPER_COMMON_TPM_I2C_INTF_CAP_ZERO_MASK; + break; + default: + return TSS2_RC_SUCCESS; + } + + if (value & zero_mask) { + LOG_ERROR ("The TPM return value failed the sanity check"); + return TSS2_TCTI_RC_IO_ERROR; + } + + return TSS2_RC_SUCCESS; +} + +static inline size_t tcti_helper_common_size_t_min (size_t a, size_t b) +{ + if (a < b) { + return a; + } + return b; +} + +static inline uint32_t tcti_helper_common_read_be32 (const void *src) +{ + const uint8_t *s = src; + return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) | (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0); +} + +static TSS2_RC tcti_helper_common_read_sts_reg (TCTI_HELPER_COMMON_CONTEXT *ctx, uint32_t *reg) +{ + uint32_t status = 0; + TSS2_RC rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_STS, &status, sizeof (status)); + if (rc) { + return rc; + } + + rc = tcti_helper_common_sanity_check (TCTI_HELPER_COMMON_REG_TPM_STS, (uint8_t *)&status, sizeof (status)); + if (rc) { + return rc; + } + + *reg = LE_TO_HOST_32 (status); + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC tcti_helper_common_write_sts_reg (TCTI_HELPER_COMMON_CONTEXT *ctx, uint32_t status) +{ + status = HOST_TO_LE_32 (status); + return ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_STS, &status, sizeof (status)); +} + +static TSS2_RC tcti_helper_common_wait_for_burst_count (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t *count, enum TCTI_HELPER_COMMON_FIFO_TRANSFER_DIRECTION direction) +{ + TSS2_RC rc; + bool is_timeout_expired = false; + uint32_t expected_status_bits; + uint32_t status; + + rc = ctx->start_timeout (ctx->data, TIMEOUT_A); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke start_timeout()"); + return rc; + } + + /* Wait for the expected status with or without timeout */ + do { + rc = tcti_helper_common_read_sts_reg (ctx, &status); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the TPM_STS register"); + return rc; + } + + if (direction == TCTI_HELPER_COMMON_FIFO_RECEIVE) { + expected_status_bits = TCTI_HELPER_COMMON_TPM_STS_VALID | TCTI_HELPER_COMMON_TPM_STS_DATA_AVAIL; + if ((status & expected_status_bits) != expected_status_bits) { + LOG_ERROR ("Invalid stsValid and dataAvail bits in the TPM_STS register were detected during transmission"); + return TSS2_TCTI_RC_IO_ERROR; + } + } else if (direction == TCTI_HELPER_COMMON_FIFO_TRANSMIT_2) { + expected_status_bits = TCTI_HELPER_COMMON_TPM_STS_VALID | TCTI_HELPER_COMMON_TPM_STS_DATA_EXPECT; + if ((status & expected_status_bits) != expected_status_bits) { + LOG_ERROR ("Invalid stsValid and Expect bits in the TPM_STS register were detected during transmission"); + return TSS2_TCTI_RC_IO_ERROR; + } + } + + /* Return on non-zero value */ + *count = (status & TCTI_HELPER_COMMON_TPM_STS_BURST_COUNT_MASK) >> TCTI_HELPER_COMMON_TPM_STS_BURST_COUNT_SHIFT; + if (*count) { + return TSS2_RC_SUCCESS; + } + + /* Delay the next poll to prevent spamming the TPM */ + rc = ctx->sleep_ms (ctx->data, POLLING_INTERVAL_MS); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke sleep_ms()"); + return rc; + } + + rc = ctx->timeout_expired (ctx->data, &is_timeout_expired); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke timeout_expired()"); + return rc; + } + } while (!is_timeout_expired); + + /* Timed out */ + return TSS2_TCTI_RC_TRY_AGAIN; +} + +static TSS2_RC tcti_helper_common_read_access_reg (TCTI_HELPER_COMMON_CONTEXT *ctx, uint8_t *reg) +{ + uint8_t access = 0; + TSS2_RC rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_ACCESS, &access, sizeof (access)); + if (rc) { + return rc; + } + + rc = tcti_helper_common_sanity_check (TCTI_HELPER_COMMON_REG_TPM_ACCESS, (uint8_t *)&access, sizeof (access)); + if (rc) { + return rc; + } + + *reg = access; + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC tcti_helper_common_write_access_reg (TCTI_HELPER_COMMON_CONTEXT *ctx, uint8_t access_bit) +{ + TSS2_RC rc = TSS2_TCTI_RC_BAD_VALUE; + /* Writes to access register can set only 1 bit at a time */ + if (access_bit & (access_bit - 1)) { + LOG_ERROR ("Writes to access register can set only 1 bit at a time."); + } else { + rc = ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_ACCESS, &access_bit, sizeof (access_bit)); + } + + return rc; +} + +static TSS2_RC tcti_helper_common_claim_locality (TCTI_HELPER_COMMON_CONTEXT *ctx) +{ + uint8_t access; + TSS2_RC rc; + + rc = tcti_helper_common_read_access_reg (ctx, &access); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the TPM_ACCESS register"); + return rc; + } + + /* Check if tpmRegValidSts is set */ + if (!(access & TCTI_HELPER_COMMON_TPM_ACCESS_VALID)) { + LOG_ERROR ("tpmRegValidSts bit of TPM_ACCESS register is not set to 1, TPM_ACCESS: 0x%02" PRIx8, access); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Check if locality 0 is active */ + if (access & TCTI_HELPER_COMMON_TPM_ACCESS_ACTIVE_LOCALITY) { + LOG_DEBUG ("Locality 0 is already active, TPM_ACCESS: 0x%02" PRIx8, access); + return TSS2_RC_SUCCESS; + } + + /* Request for locality 0 */ + rc = tcti_helper_common_write_access_reg (ctx, TCTI_HELPER_COMMON_TPM_ACCESS_REQUEST_USE); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed writing requestUse to TPM_ACCESS register"); + return rc; + } + + rc = tcti_helper_common_read_access_reg (ctx, &access); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the TPM_ACCESS register"); + return rc; + } + + /* Check if locality 0 is active */ + if (access & (TCTI_HELPER_COMMON_TPM_ACCESS_VALID | TCTI_HELPER_COMMON_TPM_ACCESS_ACTIVE_LOCALITY)) { + LOG_DEBUG ("Successfully claimed locality 0"); + return TSS2_RC_SUCCESS; + } + + LOG_ERROR ("Failed to claim locality 0, TPM_ACCESS: 0x%02" PRIx8, access); + return TSS2_TCTI_RC_IO_ERROR; +} + +static TSS2_RC tcti_helper_common_wait_for_status (TCTI_HELPER_COMMON_CONTEXT *ctx, uint32_t status_mask, uint32_t status_expected, int32_t timeout) +{ + TSS2_RC rc; + bool is_timeout_expired = false; + uint32_t status; + bool blocking = (timeout == TSS2_TCTI_TIMEOUT_BLOCK); + + if (!blocking) { + rc = ctx->start_timeout (ctx->data, timeout); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke start_timeout()"); + return rc; + } + + } + + /* Wait for the expected status with or without timeout */ + do { + rc = tcti_helper_common_read_sts_reg (ctx, &status); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the TPM_STS register"); + return rc; + } + + /* Return success on expected status */ + if ((status & status_mask) == status_expected) { + return TSS2_RC_SUCCESS; + } + /* Delay the next poll to prevent spamming the TPM */ + rc = ctx->sleep_ms (ctx->data, POLLING_INTERVAL_MS); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke sleep_ms()"); + return rc; + } + + rc = ctx->timeout_expired (ctx->data, &is_timeout_expired); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke timeout_expired()"); + return rc; + } + } while (blocking || !is_timeout_expired); + + /* Timed out */ + return TSS2_TCTI_RC_TRY_AGAIN; +} + +static TSS2_RC tcti_helper_common_fifo_transfer (TCTI_HELPER_COMMON_CONTEXT *ctx, uint8_t *transfer_buffer, size_t transfer_size, enum TCTI_HELPER_COMMON_FIFO_TRANSFER_DIRECTION direction) +{ + TSS2_RC rc; + size_t transaction_size; + size_t burst_count; + size_t handled_so_far = 0; + + do { + if ((rc = tcti_helper_common_wait_for_burst_count (ctx, &burst_count, direction))) { + LOG_ERROR ("Failed to wait for the burst count to turn non-zero"); + return rc; + } + + transaction_size = transfer_size - handled_so_far; + transaction_size = tcti_helper_common_size_t_min (transaction_size, burst_count); + transaction_size = tcti_helper_common_size_t_min (transaction_size, 64); + + if (direction == TCTI_HELPER_COMMON_FIFO_RECEIVE){ + rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (void *)(transfer_buffer + handled_so_far), transaction_size); + } else { + rc = ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (const void *)(transfer_buffer + handled_so_far), transaction_size); + } + + if (rc) { + return rc; + } + + handled_so_far += transaction_size; + + } while (handled_so_far != transfer_size); + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC tcti_helper_common_read_guard_time (TCTI_HELPER_COMMON_CONTEXT *ctx) +{ + TSS2_RC rc; + uint32_t i2c_caps; + + ctx->i2c_guard_time_read = true; + ctx->i2c_guard_time_write = true; + ctx->i2c_guard_time = TCTI_HELPER_COMMON_I2C_GUARD_TIME_US_DEFAULT; + + rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_I2C_INTF_CAP, &i2c_caps, sizeof (i2c_caps)); + if (rc) { + LOG_ERROR ("Failed to read the TPM_I2C_INTERFACE_CAPABILITY register"); + return rc; + } + + rc = tcti_helper_common_sanity_check (TCTI_HELPER_COMMON_REG_TPM_I2C_INTF_CAP, (uint8_t *)&i2c_caps, sizeof (i2c_caps)); + if (rc) { + return rc; + } + + i2c_caps = LE_TO_HOST_32 (i2c_caps); + + ctx->i2c_guard_time_read = (i2c_caps & TCTI_HELPER_COMMON_I2C_GUARD_TIME_RR_MASK) || + (i2c_caps & TCTI_HELPER_COMMON_I2C_GUARD_TIME_RW_MASK); + ctx->i2c_guard_time_write = (i2c_caps & TCTI_HELPER_COMMON_I2C_GUARD_TIME_WR_MASK) || + (i2c_caps & TCTI_HELPER_COMMON_I2C_GUARD_TIME_WW_MASK); + ctx->i2c_guard_time = (i2c_caps & TCTI_HELPER_COMMON_I2C_GUARD_TIME_MASK) >> + TCTI_HELPER_COMMON_I2C_GUARD_TIME_SHIFT; + + if (ctx->i2c_guard_time_read) { + LOG_DEBUG ("I2c guard time enabled after read"); + } + + if (ctx->i2c_guard_time_write) { + LOG_DEBUG ("I2c guard time enabled after write"); + } + + if (ctx->i2c_guard_time_read || ctx->i2c_guard_time_write) { + LOG_DEBUG ("I2c GUARD_TIME value: %"PRIu8" us", ctx->i2c_guard_time); + } else { + LOG_DEBUG ("No GUARD_TIME needed"); + } + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC tcti_helper_common_enable_crc (TCTI_HELPER_COMMON_CONTEXT *ctx) +{ + TSS2_RC rc; + uint8_t crc_enable; + + rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM_ENABLE, &crc_enable, sizeof (crc_enable)); + if (rc) { + LOG_ERROR ("Failed to read the TPM_DATA_CSUM_ENABLE register"); + return rc; + } + + if (crc_enable == 1) { + return TSS2_RC_SUCCESS; + } + + crc_enable = 1; + rc = ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM_ENABLE, &crc_enable, sizeof (crc_enable)); + if (rc) { + LOG_ERROR ("Failed to write to TPM_DATA_CSUM_ENABLE register"); + return rc; + } + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC tcti_helper_common_verify_crc (TCTI_HELPER_COMMON_CONTEXT *ctx, const uint8_t* buffer, size_t size) +{ + TSS2_RC rc; + uint16_t crc_tpm = 0; + uint16_t crc_host = 0; + + rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM, &crc_tpm, sizeof (crc_tpm)); + if (rc) { + LOG_ERROR ("Failed to read the TPM_DATA_CSUM register"); + return rc; + } + + crc_tpm = LE_TO_HOST_16 (crc_tpm); + crc_tpm = ((crc_tpm >> 8) & 0xFFu) | ((crc_tpm << 8) & 0xFF00u); + crc_host = crc_ccitt (buffer, size); + + if (crc_tpm == crc_host) { + return TSS2_RC_SUCCESS; + } + + return TSS2_TCTI_RC_IO_ERROR; +} + +TSS2_RC Tcti_Helper_Common_Init (TCTI_HELPER_COMMON_CONTEXT *ctx, bool is_i2c) +{ + TSS2_RC rc; + uint8_t rid = 0; + uint32_t did_vid = 0; + uint32_t expected_status_bits = TCTI_HELPER_COMMON_TPM_STS_COMMAND_READY; + + LOG_DEBUG ("Probing TPM..."); + + for (int retries = 100; retries > 0; retries--) { + /* In case of failed read div_vid is set to zero */ + ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DID_VID, &did_vid, sizeof (did_vid)); + if (did_vid != 0) break; + /* TPM might be resetting, let's retry in a bit */ + rc = ctx->sleep_ms (ctx->data, POLLING_INTERVAL_MS); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to invoke sleep_ms()"); + return rc; + } + } + if (did_vid == 0) { + LOG_ERROR ("Probing TPM failed"); + return TSS2_TCTI_RC_IO_ERROR; + } + LOG_DEBUG ("Probing TPM successful"); + + if (is_i2c) { + /* Read i2c guard time */ + LOG_DEBUG ("Reading the i2c GUARD_TIME value"); + rc = tcti_helper_common_read_guard_time (ctx); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Enable Data Checksum */ + LOG_DEBUG ("Enable Data Checksum"); + rc = tcti_helper_common_enable_crc (ctx); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + } + + ctx->is_i2c = is_i2c; + + /* Claim locality */ + LOG_DEBUG ("Claiming TPM locality..."); + rc = tcti_helper_common_claim_locality (ctx); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Wait up to TIMEOUT_B for TPM to become ready */ + LOG_DEBUG ("Waiting for TPM to become ready..."); + rc = tcti_helper_common_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + if (rc == TSS2_TCTI_RC_TRY_AGAIN) { + /* + * TPM did not auto transition into ready state, + * write 1 to commandReady to start the transition. + */ + if ((rc = tcti_helper_common_write_sts_reg (ctx, TCTI_HELPER_COMMON_TPM_STS_COMMAND_READY))) { + LOG_ERROR ("Failed to write the commandReady bit to TPM_STS register"); + return rc; + } + rc = tcti_helper_common_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + } + + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to wait for the TPM to become ready"); + return rc; + } + + LOG_DEBUG ("TPM is ready"); + + /* Get rid */ + rc = ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_RID, &rid, sizeof(rid)); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the TPM_RID register"); + return rc; + } + +#if MAXLOGLEVEL >= LOGL_INFO + /* Print device details */ + uint16_t vendor_id, device_id; + vendor_id = did_vid & 0xffff; + device_id = did_vid >> 16; + LOG_DEBUG ("Connected to TPM with vid:did:rid of 0x%04" PRIx16 ":%04" PRIx16 ":%02" PRIx8, vendor_id, device_id, rid); +#endif + + return TSS2_RC_SUCCESS; +} + +TSS2_RC Tcti_Helper_Common_Transmit (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t size, const uint8_t *cmd_buf) +{ + TSS2_RC rc; + tpm_header_t header; + uint32_t expected_status_bits; + + if (ctx == NULL) { + return TSS2_TCTI_RC_BAD_CONTEXT; + } + + rc = header_unmarshal (cmd_buf, &header); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + if (header.size != size) { + LOG_ERROR ("Buffer size parameter: %zu, and TPM2 command header size " + "field: %" PRIu32 " disagree.", size, header.size); + return TSS2_TCTI_RC_BAD_VALUE; + } + + LOGBLOB_DEBUG (cmd_buf, size, "Sending command with TPM_CC 0x%08"PRIx32" and size %" PRIu32, + header.code, header.size); + + /* Tell TPM to expect command */ + rc = tcti_helper_common_write_sts_reg (ctx, TCTI_HELPER_COMMON_TPM_STS_COMMAND_READY); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to write the commandReady bit to TPM_STS register"); + return rc; + } + + /* Wait until ready bit is set by TPM device */ + expected_status_bits = TCTI_HELPER_COMMON_TPM_STS_COMMAND_READY; + rc = tcti_helper_common_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to wait for the TPM to become ready (commandReady == 1)"); + return rc; + } + + /* Send the first byte of the command */ + rc = tcti_helper_common_fifo_transfer (ctx, (void *)cmd_buf, 1, TCTI_HELPER_COMMON_FIFO_TRANSMIT_1); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to send the command"); + return rc; + } + + /* Send all but the last byte in the FIFO */ + rc = tcti_helper_common_fifo_transfer (ctx, (void *)(cmd_buf + 1), size - 2, TCTI_HELPER_COMMON_FIFO_TRANSMIT_2); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to send the command"); + return rc; + } + + /* Send the last byte */ + rc = tcti_helper_common_fifo_transfer (ctx, (void *)(cmd_buf + size - 1), 1, TCTI_HELPER_COMMON_FIFO_TRANSMIT_2); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to send the command"); + return rc; + } + + /* Await TPM readiness */ + expected_status_bits = TCTI_HELPER_COMMON_TPM_STS_VALID | TCTI_HELPER_COMMON_TPM_STS_DATA_EXPECT; + rc = tcti_helper_common_wait_for_status (ctx, expected_status_bits, TCTI_HELPER_COMMON_TPM_STS_VALID, TIMEOUT_A); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to wait for the TPM to become ready (expect == 0)"); + return rc; + } + + if (ctx->is_i2c) { + /* Verify CRC */ + rc = tcti_helper_common_verify_crc (ctx, cmd_buf, size); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("CRC mismatch detected for the command"); + return rc; + } + } + + /* Tell TPM to start processing the command */ + tcti_helper_common_write_sts_reg (ctx, TCTI_HELPER_COMMON_TPM_STS_GO); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to write the tpmGo bit to TPM_STS register"); + return rc; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC Tcti_Helper_Common_Receive (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t *response_size, unsigned char *response_buffer, int32_t timeout) +{ + (void) timeout; + TSS2_RC rc; + size_t bytes_to_go; + uint32_t expected_status_bits = TCTI_HELPER_COMMON_TPM_STS_VALID | TCTI_HELPER_COMMON_TPM_STS_DATA_AVAIL; + + if (ctx == NULL) { + return TSS2_TCTI_RC_BAD_CONTEXT; + } + + /* Check if we already have received the header */ + if (ctx->response_size == 0) { + /* Wait for response to be ready */ + rc = tcti_helper_common_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_A); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to wait for the TPM to become ready (dataAvail == 1)"); + /* Return rc from wait_for_status(). May be TRY_AGAIN after timeout */ + return rc; + } + + /* Read only response header into context header buffer */ + rc = tcti_helper_common_fifo_transfer (ctx, ctx->header, TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE, TCTI_HELPER_COMMON_FIFO_RECEIVE); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the response header"); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Find out the total payload size, skipping the two byte tag and update tcti_common */ + ctx->response_size = tcti_helper_common_read_be32 (ctx->header + 2); + LOG_TRACE ("Response size: %" PRIu32 " bytes", ctx->response_size); + } + + /* Check if response size is requested */ + if (response_buffer == NULL) { + *response_size = ctx->response_size; + LOG_TRACE ("Caller requested response size. Returning size of %" PRIu32 " bytes", (uint32_t)*response_size); + return TSS2_RC_SUCCESS; + } + + /* Check if response fits in buffer and update response size */ + if (ctx->response_size > *response_size) { + LOG_ERROR ("The buffer size is smaller than the response size"); + return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; + } + *response_size = ctx->response_size; + + /* Receive the TPM response */ + LOG_TRACE ("Reading a response of size %" PRIu32, ctx->response_size); + + /* Copy already received header into response buffer */ + memcpy (response_buffer, ctx->header, TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE); + + /* Read all but the last byte in the FIFO */ + bytes_to_go = ctx->response_size - 1 - TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE; + rc = tcti_helper_common_fifo_transfer (ctx, response_buffer + TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE, bytes_to_go, TCTI_HELPER_COMMON_FIFO_RECEIVE); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read the response"); + return rc; + } + + /* Read the last byte */ + rc = tcti_helper_common_fifo_transfer (ctx, response_buffer + ctx->response_size - 1, 1, TCTI_HELPER_COMMON_FIFO_RECEIVE); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Verify that there is no more data available */ + rc = tcti_helper_common_wait_for_status (ctx, expected_status_bits, TCTI_HELPER_COMMON_TPM_STS_VALID, TIMEOUT_A); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to wait for the TPM to become ready (dataAvail == 0)"); + /* Return rc from wait_for_status(). May be TRY_AGAIN after timeout */ + return rc; + } + + LOGBLOB_DEBUG(response_buffer, ctx->response_size, "Response buffer received:"); + + if (ctx->is_i2c) { + /* Verify CRC */ + rc = tcti_helper_common_verify_crc (ctx, response_buffer, *response_size); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("CRC mismatch detected for the response"); + return rc; + } + } + + /* Set the TPM back to idle state */ + rc = tcti_helper_common_write_sts_reg (ctx, TCTI_HELPER_COMMON_TPM_STS_COMMAND_READY); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to write the commandReady bit to TPM_STS register"); + return rc; + } + + ctx->response_size = 0; + + return TSS2_RC_SUCCESS; +} diff --git a/src/tss2-tcti/tcti-helper-common.h b/src/tss2-tcti/tcti-helper-common.h new file mode 100644 index 000000000..03b5645f3 --- /dev/null +++ b/src/tss2-tcti/tcti-helper-common.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ + +#ifndef TCTI_HELPER_COMMON_H +#define TCTI_HELPER_COMMON_H +#include "tss2_tcti.h" + +#define TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE (sizeof (TPM2_ST) + sizeof (UINT32)) + +#define POLLING_INTERVAL_MS 8 + +/* The default timeout value in milliseconds as specified in the TCG spec */ +#define TIMEOUT_A 750 +#define TIMEOUT_B 2000 + +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_US_DEFAULT 250 + +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_SR_MASK 0x40000000 +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_RR_MASK 0x00100000 +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_RW_MASK 0x00080000 +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_WR_MASK 0x00040000 +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_WW_MASK 0x00020000 +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_MASK 0x0001FE00 +#define TCTI_HELPER_COMMON_I2C_GUARD_TIME_SHIFT 9 + +#define TCTI_HELPER_COMMON_TPM_I2C_INTF_CAP_ZERO_MASK 0x80000000 +#define TCTI_HELPER_COMMON_TPM_STS_ZERO_MASK 0x23 +#define TCTI_HELPER_COMMON_TPM_ACCESS_ZERO_MASK 0x48 + +enum TCTI_HELPER_COMMON_TPM_ACCESS { + TCTI_HELPER_COMMON_TPM_ACCESS_VALID = (1 << 7), + TCTI_HELPER_COMMON_TPM_ACCESS_ACTIVE_LOCALITY = (1 << 5), + TCTI_HELPER_COMMON_TPM_ACCESS_REQUEST_USE = (1 << 1) +}; + +enum TCTI_HELPER_COMMON_TPM_STATUS { + TCTI_HELPER_COMMON_TPM_STS_BURST_COUNT_SHIFT = 8, + TCTI_HELPER_COMMON_TPM_STS_BURST_COUNT_MASK = (0xFFFF << TCTI_HELPER_COMMON_TPM_STS_BURST_COUNT_SHIFT), + TCTI_HELPER_COMMON_TPM_STS_VALID = (1 << 7), + TCTI_HELPER_COMMON_TPM_STS_COMMAND_READY = (1 << 6), + TCTI_HELPER_COMMON_TPM_STS_GO = (1 << 5), + TCTI_HELPER_COMMON_TPM_STS_DATA_AVAIL = (1 << 4), + TCTI_HELPER_COMMON_TPM_STS_DATA_EXPECT = (1 << 3) +}; + +enum TCTI_HELPER_COMMON_REG { + TCTI_HELPER_COMMON_REG_TPM_STS = 0, + TCTI_HELPER_COMMON_REG_TPM_ACCESS, + TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + TCTI_HELPER_COMMON_REG_TPM_DID_VID, + TCTI_HELPER_COMMON_REG_TPM_RID, + TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM, + TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM_ENABLE, + TCTI_HELPER_COMMON_REG_TPM_I2C_INTF_CAP, +}; + +enum TCTI_HELPER_COMMON_FIFO_TRANSFER_DIRECTION { + TCTI_HELPER_COMMON_FIFO_TRANSMIT_1 = 0, + TCTI_HELPER_COMMON_FIFO_TRANSMIT_2, + TCTI_HELPER_COMMON_FIFO_RECEIVE, +}; + +typedef TSS2_RC (*TCTI_HELPER_COMMON_SLEEP_MS_FUNC) (void *data, int milliseconds); +typedef TSS2_RC (*TCTI_HELPER_COMMON_START_TIMEOUT_FUNC) (void *data, int milliseconds); +typedef TSS2_RC (*TCTI_HELPER_COMMON_TIMEOUT_EXPIRED_FUNC) (void *data, bool *result); +typedef TSS2_RC (*TCTI_HELPER_COMMON_READ_REG_FUNC) (void *data, enum TCTI_HELPER_COMMON_REG reg, void *buffer, size_t cnt); +typedef TSS2_RC (*TCTI_HELPER_COMMON_WRITE_REG_FUNC) (void *data, enum TCTI_HELPER_COMMON_REG reg, const void *buffer, size_t cnt); + +typedef struct { + uint8_t header[TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE]; + uint32_t response_size; + + bool is_i2c; + bool i2c_guard_time_read; + bool i2c_guard_time_write; + uint8_t i2c_guard_time; + + void *data; + TCTI_HELPER_COMMON_SLEEP_MS_FUNC sleep_ms; + TCTI_HELPER_COMMON_START_TIMEOUT_FUNC start_timeout; + TCTI_HELPER_COMMON_TIMEOUT_EXPIRED_FUNC timeout_expired; + TCTI_HELPER_COMMON_READ_REG_FUNC read_reg; + TCTI_HELPER_COMMON_WRITE_REG_FUNC write_reg; +} TCTI_HELPER_COMMON_CONTEXT; + +TSS2_RC Tcti_Helper_Common_Init (TCTI_HELPER_COMMON_CONTEXT *ctx, bool is_i2c); +TSS2_RC Tcti_Helper_Common_Transmit (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t size, const uint8_t *cmd_buf); +TSS2_RC Tcti_Helper_Common_Receive (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t *response_size, unsigned char *response_buffer, int32_t timeout); + +#endif /* TCTI_HELPER_COMMON_H */ diff --git a/src/tss2-tcti/tcti-i2c-helper.c b/src/tss2-tcti/tcti-i2c-helper.c index 8458dffeb..795463d77 100644 --- a/src/tss2-tcti/tcti-i2c-helper.c +++ b/src/tss2-tcti/tcti-i2c-helper.c @@ -30,6 +30,7 @@ #include "tcti-common.h" // for TSS2_TCTI_COMMON_CONTEXT, tpm_head... #include "tcti-i2c-helper.h" +#include "tcti-helper-common.h" #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC, TSS2_TCT... #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_INFO #include "tss2_tcti_i2c_helper.h" // for TSS2_TCTI_I2C_HELPER_PLATFORM, Tss... @@ -38,66 +39,6 @@ #define LOGMODULE tcti #include "util/log.h" // for LOG_ERROR, LOG_DEBUG, return_if_error -#define TIMEOUT_B 2000 /* The default timeout value as specified in the TCG spec. */ - -/* - * CRC-CCITT KERMIT with following parameters: - * - * Length : 16 bit - * Poly : 0x1021 - * Init : 0x0000 - * RefIn : False - * RefOut : False - * XorOut : 0x0000 - * Output for ASCII "123456789" : 0x2189 - */ -static const uint16_t crc16_kermit_lookup[256]= { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -static uint16_t crc_ccitt (const uint8_t *buffer, size_t size) { - size_t i; - uint16_t result = 0; - - for (i = 0; i < size; i++) { - uint8_t j = buffer[i] ^ result; - result = crc16_kermit_lookup[j] ^ (result >> 8); - } - - return result; -} - /* * This function wraps the "up-cast" of the opaque TCTI context type to the * type for the device TCTI context. The only safe-guard we have to ensure @@ -105,7 +46,7 @@ static uint16_t crc_ccitt (const uint8_t *buffer, size_t size) { * If passed a NULL context, or the magic number check fails, this function * will return NULL. */ -TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx) +TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx) { if (tcti_ctx != NULL && TSS2_TCTI_MAGIC (tcti_ctx) == TCTI_I2C_HELPER_MAGIC) { return (TSS2_TCTI_I2C_HELPER_CONTEXT*)tcti_ctx; @@ -117,7 +58,7 @@ TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper_context_cast (TSS2_TCTI_CONTEXT *t * This function down-casts the device TCTI context to the common context * defined in the tcti-common module. */ -TSS2_TCTI_COMMON_CONTEXT* tcti_i2c_helper_down_cast (TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper) +TSS2_TCTI_COMMON_CONTEXT* tcti_i2c_helper_down_cast_tcti_common (TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper) { if (tcti_i2c_helper == NULL) { return NULL; @@ -125,103 +66,19 @@ TSS2_TCTI_COMMON_CONTEXT* tcti_i2c_helper_down_cast (TSS2_TCTI_I2C_HELPER_CONTEX return &tcti_i2c_helper->common; } -static inline TSS2_RC i2c_tpm_helper_delay_us (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, int microseconds) -{ - /* Sleep a specified amount of microseconds */ - if (ctx->platform.sleep_us == NULL) { - return ctx->platform.sleep_ms (ctx->platform.user_data, (microseconds < 1000) ? 1 : (microseconds / 1000)); - } else { - return ctx->platform.sleep_us (ctx->platform.user_data, microseconds); - } -} - -static inline TSS2_RC i2c_tpm_helper_delay_ms (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, int milliseconds) -{ - /* Sleep a specified amount of milliseconds */ - if (ctx->platform.sleep_ms == NULL) { - return ctx->platform.sleep_us (ctx->platform.user_data, milliseconds * 1000); - } else { - return ctx->platform.sleep_ms (ctx->platform.user_data, milliseconds); - } -} - -static inline TSS2_RC i2c_tpm_helper_start_timeout (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, int milliseconds) -{ - /* Start a timeout timer with the specified amount of milliseconds */ - return ctx->platform.start_timeout (ctx->platform.user_data, milliseconds); -} - -static inline TSS2_RC i2c_tpm_helper_timeout_expired(TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, bool *result) -{ - /* Check if the last started tiemout expired */ - return ctx->platform.timeout_expired (ctx->platform.user_data, result); -} - -static inline TSS2_RC i2c_tpm_helper_i2c_write (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, const void *data, size_t cnt) -{ - TSS2_RC rc; - int i = TCTI_I2C_HELPER_RETRY; - - do { - /* Perform I2C write with cnt bytes */ - rc = ctx->platform.i2c_write (ctx->platform.user_data, reg_addr, data, cnt); - if (rc == TSS2_RC_SUCCESS) { - if (ctx->guard_time_write) { - i2c_tpm_helper_delay_us (ctx, ctx->guard_time); - } - break; - } - - i2c_tpm_helper_delay_us (ctx, TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US); - } while (--i); - - return rc; -} - -static inline TSS2_RC i2c_tpm_helper_i2c_read (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, void *data, size_t cnt) -{ - TSS2_RC rc; - int i = TCTI_I2C_HELPER_RETRY; - - do { - /* Perform I2C read with cnt bytes */ - rc = ctx->platform.i2c_read (ctx->platform.user_data, reg_addr, data, cnt); - if (rc == TSS2_RC_SUCCESS) { - if (ctx->guard_time_read) { - i2c_tpm_helper_delay_us (ctx, ctx->guard_time); - } - break; - } - - i2c_tpm_helper_delay_us (ctx, TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US); - } while (--i); - - return rc; -} - -static inline void i2c_tpm_helper_platform_finalize (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) -{ - /* Free user_data and resources inside */ - if (ctx->platform.finalize) - ctx->platform.finalize (ctx->platform.user_data); -} - -static TSS2_RC check_platform_conf(TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf) +/* + * This function down-casts the device TCTI context to the helper common context + * defined in the tcti-helper-common module. + */ +static TCTI_HELPER_COMMON_CONTEXT* tcti_i2c_helper_down_cast_helper_common (TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper) { - - bool required_set = (platform_conf->sleep_ms || platform_conf->sleep_us) \ - && platform_conf->i2c_write \ - && platform_conf->i2c_read && platform_conf->start_timeout \ - && platform_conf->timeout_expired; - if (!required_set) { - LOG_ERROR("Expected sleep_us/sleep_ms, i2c_write, i2c_read, start_timeout and timeout_expired to be set."); - return TSS2_TCTI_RC_BAD_VALUE; + if (tcti_i2c_helper == NULL) { + return NULL; } - - return TSS2_RC_SUCCESS; + return &tcti_i2c_helper->helper_common; } -static void i2c_tpm_helper_log_register_access (enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access, uint8_t reg_addr, const void *buffer, size_t cnt, char* err) +static void tcti_i2c_helper_log_register_access (enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access, uint8_t reg_addr, const void *buffer, size_t cnt, char *err) { #if MAXLOGLEVEL == LOGL_NONE (void) access; @@ -231,362 +88,219 @@ static void i2c_tpm_helper_log_register_access (enum TCTI_I2C_HELPER_REGISTER_AC (void) err; #else /* Print register access debug information */ - char* access_str = (access == TCTI_I2C_HELPER_REGISTER_READ) ? "READ" : "WRITE"; + char* access_str = (access == TCTI_I2C_HELPER_REGISTER_READ) ? "READ from" : "WRITE to"; if (err != NULL) { - LOG_ERROR ("%s register %#02x (%zu bytes) %s", access_str, reg_addr, cnt, err); + LOG_ERROR ("%s register 0x%02"PRIx8" (%zu bytes) %s", access_str, reg_addr, cnt, err); } else { #if MAXLOGLEVEL < LOGL_TRACE (void) buffer; #else - LOGBLOB_TRACE (buffer, cnt, "%s register %#02x (%zu bytes)", access_str, reg_addr, cnt); + LOGBLOB_TRACE (buffer, cnt, "%s register 0x%02"PRIx8, access_str, reg_addr); #endif } #endif } -static TSS2_RC i2c_tpm_sanity_check_read (uint8_t reg, uint8_t *buffer, size_t cnt) +static TSS2_RC tcti_i2c_helper_check_platform_conf (TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf) { - uint32_t zero_mask; - uint32_t value; - switch (cnt) { - case sizeof (uint8_t): - value = buffer[0]; - break; - case sizeof (uint16_t): - value = LE_TO_HOST_16 (*((uint16_t *)buffer)); - break; - case sizeof (uint32_t): - value = LE_TO_HOST_32 (*((uint32_t *)buffer)); - break; - default: - return TSS2_RC_SUCCESS; + bool required_set = (platform_conf->sleep_ms || platform_conf->sleep_us) \ + && platform_conf->i2c_write \ + && platform_conf->i2c_read && platform_conf->start_timeout \ + && platform_conf->timeout_expired; + if (!required_set) { + LOG_ERROR("Expected sleep_us/sleep_ms, i2c_write, i2c_read, start_timeout and timeout_expired to be set."); + return TSS2_TCTI_RC_BAD_VALUE; } + return TSS2_RC_SUCCESS; +} + +static TSS2_RC tcti_i2c_helper_convert_to_addr (enum TCTI_HELPER_COMMON_REG reg, uint8_t *reg_addr) +{ switch (reg) { - case TCTI_I2C_HELPER_TPM_ACCESS_REG: - zero_mask = TCTI_I2C_HELPER_TPM_ACCESS_ZERO; + case TCTI_HELPER_COMMON_REG_TPM_ACCESS: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_ACCESS; + break; + case TCTI_HELPER_COMMON_REG_TPM_STS: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_STS; + break; + case TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_DATA_FIFO; break; - case TCTI_I2C_HELPER_TPM_STS_REG: - zero_mask = TCTI_I2C_HELPER_TPM_STS_ZERO; + case TCTI_HELPER_COMMON_REG_TPM_DID_VID: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_DID_VID; break; - case TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG: - zero_mask = TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_ZERO; + case TCTI_HELPER_COMMON_REG_TPM_RID: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_RID; + break; + case TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_DATA_CSUM; + break; + case TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM_ENABLE: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_DATA_CSUM_ENABLE; + break; + case TCTI_HELPER_COMMON_REG_TPM_I2C_INTF_CAP: + *reg_addr = TCTI_I2C_HELPER_REG_TPM_I2C_INTF_CAP; break; default: - return TSS2_RC_SUCCESS; - } - - if (value & zero_mask) { - LOG_ERROR ("TPM I2C read of register 0x%02x failed sanity check", reg); - return TSS2_TCTI_RC_IO_ERROR; - } - - return TSS2_RC_SUCCESS; -} - -static TSS2_RC i2c_tpm_helper_read_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, void *buffer, size_t cnt) -{ - TSS2_RC rc; - enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access = TCTI_I2C_HELPER_REGISTER_READ; - - /* Read register */ - rc = i2c_tpm_helper_i2c_read (ctx, reg_addr, buffer, cnt); - if (rc != TSS2_RC_SUCCESS) { - i2c_tpm_helper_log_register_access (access, reg_addr, NULL, cnt, "failed in transfer"); - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Sanity check, check that the 0 bits of the TPM_STS register are indeed 0s*/ - rc = i2c_tpm_sanity_check_read (reg_addr, buffer, cnt); - if (rc != TSS2_RC_SUCCESS) { - return rc; - } - - /* Print debug information and return success */ - i2c_tpm_helper_log_register_access (access, reg_addr, buffer, cnt, NULL); - return TSS2_RC_SUCCESS; -} - -static TSS2_RC i2c_tpm_helper_write_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, const void *buffer, size_t cnt) -{ - TSS2_RC rc; - enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access = TCTI_I2C_HELPER_REGISTER_WRITE; - - /* Write register */ - rc = i2c_tpm_helper_i2c_write (ctx, reg_addr, buffer, cnt); - if (rc != TSS2_RC_SUCCESS) { - i2c_tpm_helper_log_register_access (access, reg_addr, buffer, cnt, "failed in transfer"); - return TSS2_TCTI_RC_IO_ERROR; + return TSS2_TCTI_RC_BAD_VALUE; } - /* Print debug information and return success */ - i2c_tpm_helper_log_register_access (access, reg_addr, buffer, cnt, NULL); return TSS2_RC_SUCCESS; } -static uint8_t i2c_tpm_helper_read_access_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) -{ - uint8_t access = 0; - i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_ACCESS_REG, &access, sizeof(access)); - return access; -} - -static void i2c_tpm_helper_write_access_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t access_bit) +static inline TSS2_RC tcti_i2c_helper_delay_us (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, int microseconds) { - /* Writes to access register can set only 1 bit at a time */ - if (access_bit & (access_bit - 1)) { - LOG_ERROR ("Writes to access register can set only 1 bit at a time."); + /* Sleep a specified amount of microseconds */ + if (ctx->platform.sleep_us == NULL) { + return ctx->platform.sleep_ms (ctx->platform.user_data, (microseconds < 1000) ? 1 : (microseconds / 1000)); } else { - i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_ACCESS_REG, &access_bit, sizeof(access_bit)); + return ctx->platform.sleep_us (ctx->platform.user_data, microseconds); } } -static uint32_t i2c_tpm_helper_read_sts_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +static inline TSS2_RC tcti_i2c_helper_delay_ms (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, int milliseconds) { - uint32_t status = 0; - i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_STS_REG, &status, sizeof(status)); - return LE_TO_HOST_32 (status); -} - -static void i2c_tpm_helper_write_sts_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint32_t status) -{ - status = HOST_TO_LE_32 (status); - i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_STS_REG, &status, sizeof (status)); -} - -static uint32_t i2c_tpm_helper_get_burst_count (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) -{ - uint32_t status = i2c_tpm_helper_read_sts_reg (ctx); - return (status & TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_MASK) >> TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_SHIFT; -} - -static inline size_t i2c_tpm_helper_size_t_min (size_t a, size_t b) { - if (a < b) { - return a; + /* Sleep a specified amount of milliseconds */ + if (ctx->platform.sleep_ms == NULL) { + return ctx->platform.sleep_us (ctx->platform.user_data, milliseconds * 1000); + } else { + return ctx->platform.sleep_ms (ctx->platform.user_data, milliseconds); } - return b; } -static inline uint32_t i2c_tpm_helper_read_be32 (const void *src) +static inline TSS2_RC tcti_i2c_helper_start_timeout (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, int milliseconds) { - const uint8_t *s = src; - return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) | (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0); + /* Start a timeout timer with the specified amount of milliseconds */ + return ctx->platform.start_timeout (ctx->platform.user_data, milliseconds); } -static TSS2_RC i2c_tpm_helper_claim_locality (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +static inline TSS2_RC tcti_i2c_helper_timeout_expired (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, bool *result) { - uint8_t access; - access = i2c_tpm_helper_read_access_reg (ctx); - - /* Check if locality 0 is active */ - if (access & TCTI_I2C_HELPER_TPM_ACCESS_ACTIVE_LOCALITY) { - LOG_DEBUG ("Locality 0 is already active, status: %#x", access); - return TSS2_RC_SUCCESS; - } - - /* Request locality 0 */ - i2c_tpm_helper_write_access_reg (ctx, TCTI_I2C_HELPER_TPM_ACCESS_REQUEST_USE); - access = i2c_tpm_helper_read_access_reg (ctx); - if (access & (TCTI_I2C_HELPER_TPM_ACCESS_VALID | TCTI_I2C_HELPER_TPM_ACCESS_ACTIVE_LOCALITY)) { - LOG_DEBUG ("Claimed locality 0"); - return TSS2_RC_SUCCESS; - } - - LOG_ERROR ("Failed to claim locality 0, status: %#x", access); - return TSS2_TCTI_RC_IO_ERROR; + /* Check if the last started tiemout expired */ + return ctx->platform.timeout_expired (ctx->platform.user_data, result); } -static TSS2_RC i2c_tpm_helper_init_guard_time (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +static inline TSS2_RC tcti_i2c_helper_i2c_read (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, uint8_t reg_addr, void *data, size_t cnt) { TSS2_RC rc; - uint32_t i2c_caps; - - ctx->guard_time_read = true; - ctx->guard_time_write = true; - ctx->guard_time = TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US; - - rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG, &i2c_caps, sizeof (i2c_caps)); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("Failed to read TPM_I2C_INTERFACE_CAPABILITY register"); - return rc; - } + int i = TCTI_I2C_HELPER_RETRY; - i2c_caps = LE_TO_HOST_32 (i2c_caps); + do { + /* Perform I2C read with cnt bytes */ + rc = ctx->platform.i2c_read (ctx->platform.user_data, reg_addr, data, cnt); + if (rc == TSS2_RC_SUCCESS) { + if (ctx->helper_common.i2c_guard_time_read) { + tcti_i2c_helper_delay_us (ctx, ctx->helper_common.i2c_guard_time); + } + break; + } - ctx->guard_time_read = (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_RR_MASK) || - (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_RW_MASK); - ctx->guard_time_write = (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_WR_MASK) || - (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_WW_MASK); - ctx->guard_time = (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_MASK) >> - TCTI_I2C_HELPER_TPM_GUARD_TIME_SHIFT; + tcti_i2c_helper_delay_us (ctx, TCTI_HELPER_COMMON_I2C_GUARD_TIME_US_DEFAULT); + } while (--i); - return TSS2_RC_SUCCESS; + return rc; } -static TSS2_RC i2c_tpm_helper_enable_crc (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +static TSS2_RC tcti_i2c_helper_read_reg (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, uint8_t reg_addr, void *buffer, size_t cnt) { TSS2_RC rc; - uint8_t crc_enable; + enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access = TCTI_I2C_HELPER_REGISTER_READ; - rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG, &crc_enable, sizeof (crc_enable)); + /* Read register */ + rc = tcti_i2c_helper_i2c_read (ctx, reg_addr, buffer, cnt); if (rc != TSS2_RC_SUCCESS) { - return rc; - } - - if (crc_enable == 1) { - return TSS2_RC_SUCCESS; + tcti_i2c_helper_log_register_access (access, reg_addr, NULL, cnt, "failed in transfer"); + return TSS2_TCTI_RC_IO_ERROR; } - crc_enable = 1; - return i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG, &crc_enable, sizeof (crc_enable)); + /* Print debug information and return success */ + tcti_i2c_helper_log_register_access (access, reg_addr, buffer, cnt, NULL); + return TSS2_RC_SUCCESS; } -static TSS2_RC i2c_tpm_helper_wait_for_status (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint32_t status_mask, uint32_t status_expected, int32_t timeout) +static inline TSS2_RC tcti_i2c_helper_i2c_write (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, uint8_t reg_addr, const void *data, size_t cnt) { TSS2_RC rc; - uint32_t status; - bool blocking = (timeout == TSS2_TCTI_TIMEOUT_BLOCK); - if (!blocking) { - rc = i2c_tpm_helper_start_timeout (ctx, timeout); - return_if_error(rc, "i2c_tpm_helper_start_timeout"); - } + int i = TCTI_I2C_HELPER_RETRY; - /* Wait for the expected status with or without timeout */ - bool is_timeout_expired = false; do { - status = i2c_tpm_helper_read_sts_reg (ctx); - /* Return success on expected status */ - if ((status & status_mask) == status_expected) { - return TSS2_RC_SUCCESS; + /* Perform I2C write with cnt bytes */ + rc = ctx->platform.i2c_write (ctx->platform.user_data, reg_addr, data, cnt); + if (rc == TSS2_RC_SUCCESS) { + if (ctx->helper_common.i2c_guard_time_write) { + tcti_i2c_helper_delay_us (ctx, ctx->helper_common.i2c_guard_time); + } + break; } - /* Delay next poll by 8ms to avoid spamming the TPM */ - rc = i2c_tpm_helper_delay_ms (ctx, 8); - return_if_error (rc, "i2c_tpm_helper_delay_ms"); - rc = i2c_tpm_helper_timeout_expired (ctx, &is_timeout_expired); - return_if_error (rc, "i2c_tpm_helper_timeout_expired"); - } while (blocking || !is_timeout_expired); + tcti_i2c_helper_delay_us (ctx, TCTI_HELPER_COMMON_I2C_GUARD_TIME_US_DEFAULT); + } while (--i); - /* Timed out */ - return TSS2_TCTI_RC_TRY_AGAIN; + return rc; } -static TSS2_RC i2c_tpm_helper_verify_crc (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, const uint8_t* buffer, size_t size) +static TSS2_RC tcti_i2c_helper_write_reg (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx, uint8_t reg_addr, const void *buffer, size_t cnt) { TSS2_RC rc; - uint16_t crc_tpm = 0; - uint16_t crc_host = 0; + enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access = TCTI_I2C_HELPER_REGISTER_WRITE; - rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_CSUM_REG, &crc_tpm, sizeof (crc_tpm)); + /* Write register */ + rc = tcti_i2c_helper_i2c_write (ctx, reg_addr, buffer, cnt); if (rc != TSS2_RC_SUCCESS) { - return rc; - } - - crc_tpm = LE_TO_HOST_16 (crc_tpm); - /* Reflect crc result, regardless of host endianness */ - crc_tpm = ((crc_tpm >> 8) & 0xFFu) | ((crc_tpm << 8) & 0xFF00u); - crc_host = crc_ccitt (buffer, size); - - if (crc_tpm == crc_host) { - return TSS2_RC_SUCCESS; + tcti_i2c_helper_log_register_access (access, reg_addr, buffer, cnt, "failed in transfer"); + return TSS2_TCTI_RC_IO_ERROR; } - return TSS2_TCTI_RC_IO_ERROR; + /* Print debug information and return success */ + tcti_i2c_helper_log_register_access (access, reg_addr, buffer, cnt, NULL); + return TSS2_RC_SUCCESS; } -static void i2c_tpm_helper_fifo_transfer (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t* transfer_buffer, size_t transfer_size, enum TCTI_I2C_HELPER_FIFO_TRANSFER_DIRECTION direction) +static inline void tcti_i2c_helper_platform_finalize (TSS2_TCTI_I2C_HELPER_CONTEXT *ctx) { - size_t transaction_size; - size_t burst_count; - size_t handled_so_far = 0; - - do { - do { - /* Can be zero when TPM is busy */ - burst_count = i2c_tpm_helper_get_burst_count (ctx); - } while (!burst_count); - - transaction_size = transfer_size - handled_so_far; - transaction_size = i2c_tpm_helper_size_t_min (transaction_size, burst_count); - - if (direction == TCTI_I2C_HELPER_FIFO_RECEIVE){ - i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, (void*)(transfer_buffer + handled_so_far), transaction_size); - } else { - i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, (const void*)(transfer_buffer + handled_so_far), transaction_size); - } - - handled_so_far += transaction_size; - - } while (handled_so_far != transfer_size); + /* Free user_data and resources inside */ + if (ctx->platform.finalize) + ctx->platform.finalize (ctx->platform.user_data); } -TSS2_RC tcti_i2c_helper_transmit (TSS2_TCTI_CONTEXT *tcti_ctx, size_t size, const uint8_t *cmd_buf) +TSS2_RC tcti_i2c_helper_transmit (TSS2_TCTI_CONTEXT *tcti_context, size_t size, const uint8_t *cmd_buf) { TSS2_RC rc; - TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_ctx); - TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); - tpm_header_t header; + TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast_tcti_common (tcti_i2c_helper); + TCTI_HELPER_COMMON_CONTEXT *helper_common = tcti_i2c_helper_down_cast_helper_common (tcti_i2c_helper); if (tcti_i2c_helper == NULL) { - return TSS2_TCTI_RC_BAD_CONTEXT; + return TSS2_BASE_RC_BAD_CONTEXT; } - TSS2_TCTI_I2C_HELPER_CONTEXT* ctx = tcti_i2c_helper; rc = tcti_common_transmit_checks (tcti_common, cmd_buf, TCTI_I2C_HELPER_MAGIC); if (rc != TSS2_RC_SUCCESS) { return rc; } - rc = header_unmarshal (cmd_buf, &header); - if (rc != TSS2_RC_SUCCESS) { - return rc; - } - if (header.size != size) { - LOG_ERROR("Buffer size parameter: %zu, and TPM2 command header size " - "field: %" PRIu32 " disagree.", size, header.size); - return TSS2_TCTI_RC_BAD_VALUE; - } - - LOGBLOB_DEBUG (cmd_buf, size, "Sending command with TPM_CC %#"PRIx32" and size %" PRIu32, - header.code, header.size); - - /* Tell TPM to expect command */ - i2c_tpm_helper_write_sts_reg(ctx, TCTI_I2C_HELPER_TPM_STS_COMMAND_READY); - /* Wait until ready bit is set by TPM device */ - uint32_t expected_status_bits = TCTI_I2C_HELPER_TPM_STS_COMMAND_READY; - rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + rc = Tcti_Helper_Common_Transmit (helper_common, size, cmd_buf); if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Failed waiting for TPM to become ready"); return rc; } - /* Send command */ - i2c_tpm_helper_fifo_transfer (ctx, (void*)cmd_buf, size, TCTI_I2C_HELPER_FIFO_TRANSMIT); - - /* Verify CRC */ - rc = i2c_tpm_helper_verify_crc (ctx, cmd_buf, size); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("CRC mismatch for command"); - return rc; - } - - /* Tell TPM to start processing the command */ - i2c_tpm_helper_write_sts_reg (ctx, TCTI_I2C_HELPER_TPM_STS_GO); - tcti_common->state = TCTI_STATE_RECEIVE; - return TSS2_RC_SUCCESS; + + return rc; } -TSS2_RC tcti_i2c_helper_receive (TSS2_TCTI_CONTEXT* tcti_context, size_t *response_size, unsigned char *response_buffer, int32_t timeout) +TSS2_RC tcti_i2c_helper_receive (TSS2_TCTI_CONTEXT *tcti_context, size_t *response_size, unsigned char *response_buffer, int32_t timeout) { TSS2_RC rc; - TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); - TSS2_TCTI_COMMON_CONTEXT* tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast_tcti_common (tcti_i2c_helper); + TCTI_HELPER_COMMON_CONTEXT *helper_common = tcti_i2c_helper_down_cast_helper_common (tcti_i2c_helper); if (tcti_i2c_helper == NULL) { - return TSS2_TCTI_RC_BAD_CONTEXT; + return TSS2_BASE_RC_BAD_CONTEXT; } rc = tcti_common_receive_checks (tcti_common, response_size, TCTI_I2C_HELPER_MAGIC); @@ -594,100 +308,18 @@ TSS2_RC tcti_i2c_helper_receive (TSS2_TCTI_CONTEXT* tcti_context, size_t *respon return rc; } - /* Use ctx as a shorthand for tcti_i2c_helper */ - TSS2_TCTI_I2C_HELPER_CONTEXT* ctx = tcti_i2c_helper; - - /* Expected status bits for valid status and data availabe */ - uint32_t expected_status_bits = TCTI_I2C_HELPER_TPM_STS_VALID | TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL; - - /* Check if we already have received the header */ - if (tcti_common->header.size == 0) { - /* Wait for response to be ready */ - rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, timeout); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("Failed waiting for status"); - /* Return rc from wait_for_status(). May be TRY_AGAIN after timeout. */ - return rc; - } - - /* Read only response header into context header buffer */ - rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, ctx->header, TCTI_I2C_HELPER_RESP_HEADER_SIZE); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("Failed reading response header"); - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Find out the total payload size, skipping the two byte tag and update tcti_common */ - tcti_common->header.size = i2c_tpm_helper_read_be32 (ctx->header + 2); - LOG_TRACE ("Read response size from response header: %" PRIu32 " bytes", tcti_common->header.size); - } - - /* Check if response size is requested */ - if (response_buffer == NULL) { - *response_size = tcti_common->header.size; - LOG_TRACE ("Caller requested response size. Returning size of %zu bytes", *response_size); - return TSS2_RC_SUCCESS; - } - - /* Check if response fits in buffer and update response size */ - if (tcti_common->header.size > *response_size) { - LOG_ERROR ("TPM response too long (%" PRIu32 " bytes)", tcti_common->header.size); - return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; - } - *response_size = tcti_common->header.size; - - /* Receive the TPM response */ - LOG_TRACE ("Reading response of size %" PRIu32, tcti_common->header.size); - - /* Copy already received header into response buffer */ - memcpy (response_buffer, ctx->header, TCTI_I2C_HELPER_RESP_HEADER_SIZE); - - /* Read all but the last byte in the FIFO */ - size_t bytes_to_go = tcti_common->header.size - 1 - TCTI_I2C_HELPER_RESP_HEADER_SIZE; - i2c_tpm_helper_fifo_transfer (ctx, response_buffer + TCTI_I2C_HELPER_RESP_HEADER_SIZE, bytes_to_go, TCTI_I2C_HELPER_FIFO_RECEIVE); - - /* Verify that there is still data to read */ - uint32_t status = i2c_tpm_helper_read_sts_reg (ctx); - if ((status & expected_status_bits) != expected_status_bits) { - LOG_ERROR ("Unexpected intermediate status %#"PRIx32,status); - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Read the last byte */ - rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, response_buffer + tcti_common->header.size - 1, 1); - if (rc != TSS2_RC_SUCCESS) { - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Verify that there is no more data available */ - status = i2c_tpm_helper_read_sts_reg (ctx); - if ((status & expected_status_bits) != TCTI_I2C_HELPER_TPM_STS_VALID) { - LOG_ERROR ("Unexpected final status %#"PRIx32, status); - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Verify CRC */ - rc = i2c_tpm_helper_verify_crc (ctx, response_buffer, *response_size); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("CRC mismatch for response"); - return rc; + rc = Tcti_Helper_Common_Receive (helper_common, response_size, response_buffer, timeout); + if (response_buffer != NULL && rc == TSS2_RC_SUCCESS) { + tcti_common->state = TCTI_STATE_TRANSMIT; } - LOGBLOB_DEBUG (response_buffer, tcti_common->header.size, "Response buffer received:"); - - /* Set the TPM back to idle state */ - i2c_tpm_helper_write_sts_reg(ctx, TCTI_I2C_HELPER_TPM_STS_COMMAND_READY); - - tcti_common->header.size = 0; - tcti_common->state = TCTI_STATE_TRANSMIT; - - return TSS2_RC_SUCCESS; + return rc; } -void tcti_i2c_helper_finalize (TSS2_TCTI_CONTEXT* tcti_context) +void tcti_i2c_helper_finalize (TSS2_TCTI_CONTEXT *tcti_context) { TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); - TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast_tcti_common (tcti_i2c_helper); if (tcti_i2c_helper == NULL) { return; @@ -695,16 +327,16 @@ void tcti_i2c_helper_finalize (TSS2_TCTI_CONTEXT* tcti_context) tcti_common->state = TCTI_STATE_FINAL; /* Free platform struct user data and resources inside */ - i2c_tpm_helper_platform_finalize (tcti_i2c_helper); + tcti_i2c_helper_platform_finalize (tcti_i2c_helper); } -TSS2_RC tcti_i2c_helper_cancel (TSS2_TCTI_CONTEXT* tcti_context) +TSS2_RC tcti_i2c_helper_cancel (TSS2_TCTI_CONTEXT *tcti_context) { (void)(tcti_context); return TSS2_TCTI_RC_NOT_IMPLEMENTED; } -TSS2_RC tcti_i2c_helper_get_poll_handles (TSS2_TCTI_CONTEXT* tcti_context, TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles) +TSS2_RC tcti_i2c_helper_get_poll_handles (TSS2_TCTI_CONTEXT *tcti_context, TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles) { (void)(tcti_context); (void)(handles); @@ -712,17 +344,61 @@ TSS2_RC tcti_i2c_helper_get_poll_handles (TSS2_TCTI_CONTEXT* tcti_context, TSS2_ return TSS2_TCTI_RC_NOT_IMPLEMENTED; } -TSS2_RC tcti_i2c_helper_set_locality (TSS2_TCTI_CONTEXT* tcti_context, uint8_t locality) +TSS2_RC tcti_i2c_helper_set_locality (TSS2_TCTI_CONTEXT *tcti_context, uint8_t locality) { (void)(tcti_context); (void)(locality); return TSS2_TCTI_RC_NOT_IMPLEMENTED; } -TSS2_RC Tss2_Tcti_I2c_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf) +TSS2_RC tcti_i2c_helper_common_sleep_ms (void *data, int milliseconds) +{ + TSS2_TCTI_I2C_HELPER_CONTEXT *ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *) data; + return tcti_i2c_helper_delay_ms (ctx, milliseconds); +} + +TSS2_RC tcti_i2c_helper_common_start_timeout (void *data, int milliseconds) +{ + TSS2_TCTI_I2C_HELPER_CONTEXT *ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *) data; + return tcti_i2c_helper_start_timeout (ctx, milliseconds); +} + +TSS2_RC tcti_i2c_helper_common_timeout_expired (void *data, bool *result) +{ + TSS2_TCTI_I2C_HELPER_CONTEXT *ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *) data; + return tcti_i2c_helper_timeout_expired (ctx, result); +} + +TSS2_RC tcti_i2c_helper_common_read_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, void *buffer, size_t cnt) { TSS2_RC rc; - TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper; + uint8_t reg_addr; + TSS2_TCTI_I2C_HELPER_CONTEXT *ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *) data; + + if ((rc = tcti_i2c_helper_convert_to_addr (reg, ®_addr))) { + return rc; + } + + return tcti_i2c_helper_read_reg (ctx, reg_addr, buffer, cnt); +} + +TSS2_RC tcti_i2c_helper_common_write_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, const void *buffer, size_t cnt) +{ + TSS2_RC rc; + uint8_t reg_addr; + TSS2_TCTI_I2C_HELPER_CONTEXT *ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *) data; + + if ((rc = tcti_i2c_helper_convert_to_addr (reg, ®_addr))) { + return rc; + } + + return tcti_i2c_helper_write_reg (ctx, reg_addr, buffer, cnt); +} + +TSS2_RC Tss2_Tcti_I2c_Helper_Init (TSS2_TCTI_CONTEXT *tcti_context, size_t* size, TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf) +{ + TSS2_RC rc; + TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper; TSS2_TCTI_COMMON_CONTEXT* tcti_common; if (!size) { @@ -756,90 +432,31 @@ TSS2_RC Tss2_Tcti_I2c_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size /* Init I2C TCTI context */ tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); - tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + tcti_common = tcti_i2c_helper_down_cast_tcti_common (tcti_i2c_helper); tcti_common->state = TCTI_STATE_TRANSMIT; memset (&tcti_common->header, 0, sizeof (tcti_common->header)); tcti_common->locality = 0; - rc = check_platform_conf (platform_conf); + rc = tcti_i2c_helper_check_platform_conf (platform_conf); return_if_error (rc, "platform_conf invalid"); /* Copy platform struct into context */ tcti_i2c_helper->platform = *platform_conf; - /* Probe TPM */ - TSS2_TCTI_I2C_HELPER_CONTEXT* ctx = tcti_i2c_helper; - LOG_DEBUG ("Probing TPM..."); - uint32_t did_vid = 0; - for (int retries = 100; retries > 0; retries--) { - /* In case of failed read div_vid is set to zero */ - i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DID_VID_REG, &did_vid, sizeof(did_vid)); - if (did_vid != 0) { - did_vid = LE_TO_HOST_32 (did_vid); - break; - } - /* TPM might be resetting, let's retry in a bit */ - rc = i2c_tpm_helper_delay_ms (ctx, 10); - return_if_error (rc, "i2c_tpm_helper_delay_ms"); - } - if (did_vid == 0) { - LOG_ERROR ("Probing TPM failed"); - return TSS2_TCTI_RC_IO_ERROR; - } - LOG_DEBUG ("Probing TPM successful"); - - /* Init guard time */ - LOG_DEBUG ("Initializing guard time"); - rc = i2c_tpm_helper_init_guard_time (ctx); - if (rc != TSS2_RC_SUCCESS) { - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Claim locality */ - LOG_DEBUG ("Claiming TPM locality"); - rc = i2c_tpm_helper_claim_locality (ctx); - if (rc != TSS2_RC_SUCCESS) { - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Enable Data Checksum */ - LOG_DEBUG ("Enable Data Checksum"); - rc = i2c_tpm_helper_enable_crc (ctx); - if (rc != TSS2_RC_SUCCESS) { - return TSS2_TCTI_RC_IO_ERROR; - } - - /* Wait up to TIMEOUT_B for TPM to become ready */ - LOG_DEBUG ("Waiting for TPM to become ready..."); - uint32_t expected_status_bits = TCTI_I2C_HELPER_TPM_STS_COMMAND_READY; - rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); - if (rc == TSS2_TCTI_RC_TRY_AGAIN) { - /* - * TPM did not auto transition into ready state, - * write 1 to commandReady to start the transition. - */ - i2c_tpm_helper_write_sts_reg (ctx, TCTI_I2C_HELPER_TPM_STS_COMMAND_READY); - rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); - } - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("Failed waiting for TPM to become ready"); - return rc; - } - - LOG_DEBUG ("TPM is ready"); - - /* Get rid */ - uint8_t rid = 0; - i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_RID_REG, &rid, sizeof(rid)); - -#if MAXLOGLEVEL >= LOGL_INFO - /* Print device details */ - uint16_t vendor_id, device_id, revision; - vendor_id = did_vid & 0xffff; - device_id = did_vid >> 16; - revision = rid; - LOG_INFO ("Connected to TPM with vid:did:rid of %4.4x:%4.4x:%2.2x", vendor_id, device_id, revision); -#endif + /* Register the callback functions before using the Tcti_Helper_Common_ functions */ + TCTI_HELPER_COMMON_CONTEXT helper_common = { + .data = (void *)tcti_i2c_helper, + .sleep_ms = tcti_i2c_helper_common_sleep_ms, + .start_timeout = tcti_i2c_helper_common_start_timeout, + .timeout_expired = tcti_i2c_helper_common_timeout_expired, + .read_reg = tcti_i2c_helper_common_read_reg, + .write_reg = tcti_i2c_helper_common_write_reg, + }; + tcti_i2c_helper->helper_common = helper_common; + + /* TPM probing */ + rc = Tcti_Helper_Common_Init (&tcti_i2c_helper->helper_common, true); + return_if_error (rc, "tcti initialization sequence has failed"); return TSS2_RC_SUCCESS; } diff --git a/src/tss2-tcti/tcti-i2c-helper.h b/src/tss2-tcti/tcti-i2c-helper.h index 2028dc660..4c2c83b76 100644 --- a/src/tss2-tcti/tcti-i2c-helper.h +++ b/src/tss2-tcti/tcti-i2c-helper.h @@ -25,70 +25,31 @@ #include // for bool #include "tcti-common.h" // for TSS2_TCTI_COMMON_CONTEXT +#include "tcti-helper-common.h" // for TSS2_TCTI_HELPER_COMMON_CONTEXT #include "tss2_tcti_i2c_helper.h" // for TSS2_TCTI_I2C_HELPER_PLATFORM #define TCTI_I2C_HELPER_MAGIC 0x392452ED67A5D511ULL -#define TCTI_I2C_HELPER_RESP_HEADER_SIZE 6 - -typedef struct { - TSS2_TCTI_COMMON_CONTEXT common; - TSS2_TCTI_I2C_HELPER_PLATFORM platform; - bool guard_time_read; - bool guard_time_write; - uint8_t guard_time; - char header[TCTI_I2C_HELPER_RESP_HEADER_SIZE]; -} TSS2_TCTI_I2C_HELPER_CONTEXT; - #define TCTI_I2C_HELPER_RETRY 50 -#define TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US 250 - -#define TCTI_I2C_HELPER_TPM_ACCESS_REG 0x04 -#define TCTI_I2C_HELPER_TPM_STS_REG 0x18 -#define TCTI_I2C_HELPER_TPM_DATA_FIFO_REG 0x24 -#define TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG 0x30 -#define TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG 0x40 -#define TCTI_I2C_HELPER_TPM_DATA_CSUM_REG 0x44 -#define TCTI_I2C_HELPER_TPM_DID_VID_REG 0x48 -#define TCTI_I2C_HELPER_TPM_RID_REG 0x4C - -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_SR_MASK 0x40000000 -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_RR_MASK 0x00100000 -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_RW_MASK 0x00080000 -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_WR_MASK 0x00040000 -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_WW_MASK 0x00020000 -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_MASK 0x0001FE00 -#define TCTI_I2C_HELPER_TPM_BURST_COUNT_STATIC_MASK 0x20000000 -#define TCTI_I2C_HELPER_TPM_GUARD_TIME_SHIFT 9 -#define TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_ZERO 0x80000000 -#define TCTI_I2C_HELPER_TPM_STS_ZERO 0x23 -#define TCTI_I2C_HELPER_TPM_ACCESS_ZERO 0x48 - -enum TCTI_I2C_HELPER_TPM_ACCESS { - TCTI_I2C_HELPER_TPM_ACCESS_VALID = (1 << 7), - TCTI_I2C_HELPER_TPM_ACCESS_ACTIVE_LOCALITY = (1 << 5), - TCTI_I2C_HELPER_TPM_ACCESS_REQUEST_USE = (1 << 1) -}; - -enum TCTI_I2C_HELPER_TPM_STATUS { - TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_SHIFT = 8, - TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_MASK = (0xFFFF << TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_SHIFT), - TCTI_I2C_HELPER_TPM_STS_VALID = (1 << 7), - TCTI_I2C_HELPER_TPM_STS_COMMAND_READY = (1 << 6), - TCTI_I2C_HELPER_TPM_STS_GO = (1 << 5), - TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL = (1 << 4), - TCTI_I2C_HELPER_TPM_STS_DATA_EXPECT = (1 << 3) -}; - -enum TCTI_I2C_HELPER_FIFO_TRANSFER_DIRECTION { - TCTI_I2C_HELPER_FIFO_TRANSMIT = 0, - TCTI_I2C_HELPER_FIFO_RECEIVE = 1 -}; +#define TCTI_I2C_HELPER_REG_TPM_ACCESS 0x04 +#define TCTI_I2C_HELPER_REG_TPM_STS 0x18 +#define TCTI_I2C_HELPER_REG_TPM_DATA_FIFO 0x24 +#define TCTI_I2C_HELPER_REG_TPM_I2C_INTF_CAP 0x30 +#define TCTI_I2C_HELPER_REG_TPM_DATA_CSUM_ENABLE 0x40 +#define TCTI_I2C_HELPER_REG_TPM_DATA_CSUM 0x44 +#define TCTI_I2C_HELPER_REG_TPM_DID_VID 0x48 +#define TCTI_I2C_HELPER_REG_TPM_RID 0x4C enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE { TCTI_I2C_HELPER_REGISTER_WRITE = 0, TCTI_I2C_HELPER_REGISTER_READ = 1 }; +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TCTI_HELPER_COMMON_CONTEXT helper_common; + TSS2_TCTI_I2C_HELPER_PLATFORM platform; +} TSS2_TCTI_I2C_HELPER_CONTEXT; + #endif /* TCTI_I2C_HELPER_H */ diff --git a/src/tss2-tcti/tcti-spi-helper.c b/src/tss2-tcti/tcti-spi-helper.c index 66cdb102f..fba992bd2 100644 --- a/src/tss2-tcti/tcti-spi-helper.c +++ b/src/tss2-tcti/tcti-spi-helper.c @@ -13,6 +13,7 @@ #include "tcti-common.h" // for TSS2_TCTI_COMMON_CONTEXT, tpm_head... #include "tcti-spi-helper.h" +#include "tcti-helper-common.h" #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC, TSS2_TCT... #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_INFO #include "tss2_tcti_spi_helper.h" // for TSS2_TCTI_SPI_HELPER_PLATFORM, Tss... @@ -21,158 +22,178 @@ #define LOGMODULE tcti #include "util/log.h" // for LOG_ERROR, LOG_DEBUG, return_if_error -#define TIMEOUT_B 2000 // The default timeout value as specified in the TCG spec +static TSS2_RC tcti_spi_helper_build_header (enum TCTI_HELPER_COMMON_REG reg, uint32_t *spi_header) +{ + switch (reg) { + case TCTI_HELPER_COMMON_REG_TPM_ACCESS: + *spi_header = TCTI_SPI_HELPER_HEAD_TPM_ACCESS; + break; + case TCTI_HELPER_COMMON_REG_TPM_STS: + *spi_header = TCTI_SPI_HELPER_HEAD_TPM_STS; + break; + case TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO: + *spi_header = TCTI_SPI_HELPER_HEAD_TPM_DATA_FIFO; + break; + case TCTI_HELPER_COMMON_REG_TPM_DID_VID: + *spi_header = TCTI_SPI_HELPER_HEAD_TPM_DID_VID; + break; + case TCTI_HELPER_COMMON_REG_TPM_RID: + *spi_header = TCTI_SPI_HELPER_HEAD_TPM_RID; + break; + default: + return TSS2_TCTI_RC_BAD_VALUE; + } + + return TSS2_RC_SUCCESS; +} -static inline TSS2_RC spi_tpm_helper_delay_ms(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, int milliseconds) +static inline TSS2_RC tcti_spi_helper_delay_ms (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx, int milliseconds) { - // Sleep a specified amount of milliseconds - return ctx->platform.sleep_ms(ctx->platform.user_data, milliseconds); + /* Sleep a specified amount of milliseconds */ + return ctx->platform.sleep_ms (ctx->platform.user_data, milliseconds); } -static inline TSS2_RC spi_tpm_helper_start_timeout(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, int milliseconds) +static inline TSS2_RC tcti_spi_helper_start_timeout (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx, int milliseconds) { - // Start a timeout timer with the specified amount of milliseconds - return ctx->platform.start_timeout(ctx->platform.user_data, milliseconds); + /* Start a timeout timer with the specified amount of milliseconds */ + return ctx->platform.start_timeout (ctx->platform.user_data, milliseconds); } -static inline TSS2_RC spi_tpm_helper_timeout_expired(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, bool *result) +static inline TSS2_RC tcti_spi_helper_timeout_expired (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx, bool *result) { - // Check if the last started tiemout expired - return ctx->platform.timeout_expired(ctx->platform.user_data, result); + /* Check if the last started tiemout expired */ + return ctx->platform.timeout_expired (ctx->platform.user_data, result); } -static inline TSS2_RC spi_tpm_helper_spi_acquire(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) +static inline TSS2_RC tcti_spi_helper_spi_acquire (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx) { if (ctx->platform.spi_acquire == NULL) { return TSS2_RC_SUCCESS; } - // Reserve SPI bus until transaction is over and keep pulling CS - return ctx->platform.spi_acquire(ctx->platform.user_data); + /* Reserve SPI bus until transaction is over and keep pulling CS */ + return ctx->platform.spi_acquire (ctx->platform.user_data); } -static inline TSS2_RC spi_tpm_helper_spi_release(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) +static inline TSS2_RC tcti_spi_helper_spi_release (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx) { if (ctx->platform.spi_release == NULL) { return TSS2_RC_SUCCESS; } - // Release SPI bus and release CS - return ctx->platform.spi_release(ctx->platform.user_data); + /* Release SPI bus and release CS */ + return ctx->platform.spi_release (ctx->platform.user_data); } -static inline TSS2_RC spi_tpm_helper_spi_transfer(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, const void *data_out, void *data_in, size_t cnt) +static inline TSS2_RC tcti_spi_helper_spi_transfer (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx, const void *data_out, void *data_in, size_t cnt) { - // Perform SPI transaction with cnt bytes - return ctx->platform.spi_transfer(ctx->platform.user_data, data_out, data_in, cnt); + /* Perform SPI transaction with cnt bytes */ + return ctx->platform.spi_transfer (ctx->platform.user_data, data_out, data_in, cnt); } -static inline void spi_tpm_helper_platform_finalize(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) +static inline void tcti_spi_helper_platform_finalize (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx) { - // Free user_data and resources inside + /* Free user_data and resources inside */ if (ctx->platform.finalize) - ctx->platform.finalize(ctx->platform.user_data); + ctx->platform.finalize (ctx->platform.user_data); } -static inline uint32_t spi_tpm_helper_read_be32(const void *src) -{ - const uint8_t *s = src; - return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) | (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0); -} - -static TSS2_RC spi_tpm_helper_start_transaction(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, size_t bytes, uint32_t addr) +static TSS2_RC tcti_spi_helper_start_transaction (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx, enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, size_t bytes, uint32_t spi_header) { TSS2_RC rc; - // Build spi header + /* Build spi header */ uint8_t header[4]; - // Transaction type and transfer size + /* Transaction type and transfer size */ header[0] = ((access == TCTI_SPI_HELPER_REGISTER_READ) ? 0x80 : 0x00) | (bytes - 1); - // TPM register address - header[1] = addr >> 16 & 0xff; - header[2] = addr >> 8 & 0xff; - header[3] = addr >> 0 & 0xff; + /* TPM register spi_headeress */ + header[1] = spi_header >> 16 & 0xff; + header[2] = spi_header >> 8 & 0xff; + header[3] = spi_header >> 0 & 0xff; - // Reserve SPI bus until transaction is over and keep pulling CS - rc = spi_tpm_helper_spi_acquire(ctx); + /* Reserve SPI bus until transaction is over and keep pulling CS */ + rc = tcti_spi_helper_spi_acquire (ctx); if (rc != TSS2_RC_SUCCESS) { return TSS2_TCTI_RC_IO_ERROR; } - // Send header + /* Send header */ uint8_t header_response[4]; - rc = spi_tpm_helper_spi_transfer(ctx, header, header_response, 4); + rc = tcti_spi_helper_spi_transfer (ctx, header, header_response, 4); if (rc != TSS2_RC_SUCCESS) { return TSS2_TCTI_RC_IO_ERROR; } - // Wait until the TPM exits the wait state and sends a 1 bit + /* Wait until the TPM exits the wait state and sends a 1 bit */ uint8_t byte; - // The 1 bit is often already set in the last byte of the transaction header + /* The 1 bit is often already set in the last byte of the transaction header */ byte = header_response[3]; if (byte & 1) { return TSS2_RC_SUCCESS; } - // With most current TPMs there shouldn't be any more waitstate at all, but according to - // the spec, we have to retry until there is no more waitstate inserted. So we try again - // a few times by reading only one byte at a time and waiting in between. + /* + * With most current TPMs there shouldn't be any more waitstate at all, but according to + * the spec, we have to retry until there is no more waitstate inserted. So we try again + * a few times by reading only one byte at a time and waiting in between. + */ uint8_t zero = 0; for (int retries = 256; retries > 0; retries--) { - rc = spi_tpm_helper_spi_transfer(ctx, &zero, &byte, 1); + rc = tcti_spi_helper_spi_transfer (ctx, &zero, &byte, 1); if (rc != TSS2_RC_SUCCESS) { return TSS2_TCTI_RC_IO_ERROR; } if (byte & 1) { return TSS2_RC_SUCCESS; } - rc = spi_tpm_helper_delay_ms(ctx, 1); - return_if_error(rc, "spi_tpm_helper_delay_ms"); + rc = tcti_spi_helper_delay_ms (ctx, 1); + return_if_error (rc, "tcti_spi_helper_delay_ms"); } - // The TPM did not exit the wait state in time + /* The TPM did not exit the wait state in time */ return TSS2_TCTI_RC_IO_ERROR; } -static TSS2_RC spi_tpm_helper_end_transaction(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) +static TSS2_RC tcti_spi_helper_end_transaction (TSS2_TCTI_SPI_HELPER_CONTEXT *ctx) { - // Release CS (ends the transaction) and release the bus for other devices - return spi_tpm_helper_spi_release(ctx); + /* Release CS (ends the transaction) and release the bus for other devices */ + return tcti_spi_helper_spi_release (ctx); } -static void spi_tpm_helper_log_register_access(enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, uint32_t reg_number, const void *buffer, size_t cnt, char* err) { +static void tcti_spi_helper_log_register_access (enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, uint32_t spi_header, const void *buffer, size_t cnt, char* err) { #if MAXLOGLEVEL == LOGL_NONE (void) access; - (void) reg_number; + (void) spi_header; (void) buffer; (void) cnt; (void) err; #else - // Print register access debug information - char* access_str = (access == TCTI_SPI_HELPER_REGISTER_READ) ? "READ" : "WRITE"; + /* Print register access debug information */ + char* access_str = (access == TCTI_SPI_HELPER_REGISTER_READ) ? "READ from" : "WRITE to"; + uint16_t reg_addr = (uint16_t)(spi_header & 0xFFFF); if (err != NULL) { - LOG_ERROR("%s register %#02"PRIx32" (%zu bytes) %s", access_str, reg_number, cnt, err); + LOG_ERROR ("%s register 0x%04"PRIx16" (%zu bytes) %s", access_str, reg_addr, cnt, err); } else { #if MAXLOGLEVEL < LOGL_TRACE (void) buffer; #else - LOGBLOB_TRACE(buffer, cnt, "%s register %#02"PRIx32" (%zu bytes)", access_str, reg_number, cnt); + LOGBLOB_TRACE (buffer, cnt, "%s register 0x%04"PRIx16, access_str, reg_addr); #endif } #endif } -static size_t spi_tpm_helper_no_waitstate_preprocess(enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, uint32_t addr, uint8_t *buffer1, uint8_t *buffer2, size_t cnt) +static size_t tcti_spi_helper_no_waitstate_preprocess (enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, uint32_t addr, uint8_t *buffer1, uint8_t *buffer2, size_t cnt) { - // Transaction type and transfer size + /* Transaction type and transfer size */ buffer2[0] = ((access == TCTI_SPI_HELPER_REGISTER_READ) ? 0x80 : 0x00) | (cnt - 1); - // TPM register address + /* TPM register address */ buffer2[1] = addr >> 16 & 0xff; buffer2[2] = addr >> 8 & 0xff; buffer2[3] = addr >> 0 & 0xff; @@ -186,7 +207,7 @@ static size_t spi_tpm_helper_no_waitstate_preprocess(enum TCTI_SPI_HELPER_REGIST return cnt + 4; } -static void spi_tpm_helper_no_waitstate_postprocess(enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, uint8_t *buffer1, uint8_t *buffer2, size_t cnt) +static void tcti_spi_helper_no_waitstate_postprocess (enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access, uint8_t *buffer1, uint8_t *buffer2, size_t cnt) { if (access == TCTI_SPI_HELPER_REGISTER_WRITE) { return; @@ -195,243 +216,7 @@ static void spi_tpm_helper_no_waitstate_postprocess(enum TCTI_SPI_HELPER_REGISTE memcpy(buffer1, &buffer2[4], cnt - 4); } -static TSS2_RC spi_tpm_helper_read_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint32_t reg_number, void *buffer, size_t cnt) -{ - TSS2_RC rc; - enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access = TCTI_SPI_HELPER_REGISTER_READ; - bool has_waitstate = true; - uint8_t buffer2[68]; - size_t cnt2 = 0; - - // Check maximum register transfer size is 64 byte - if (cnt > 64) { - return TSS2_TCTI_RC_BAD_VALUE; - } - - // Detect wait state configuration - if (ctx->platform.spi_acquire == NULL || ctx->platform.spi_release == NULL) { - has_waitstate = false; - } - - if (has_waitstate) { - // Start read transaction - rc = spi_tpm_helper_start_transaction(ctx, access, cnt, reg_number); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_log_register_access(access, reg_number, NULL, cnt, "failed in transaction start"); - spi_tpm_helper_end_transaction(ctx); - return TSS2_TCTI_RC_IO_ERROR; - } - // Read register - rc = spi_tpm_helper_spi_transfer(ctx, NULL, buffer, cnt); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_log_register_access(access, reg_number, NULL, cnt, "failed in transfer"); - spi_tpm_helper_end_transaction(ctx); - return TSS2_TCTI_RC_IO_ERROR; - } - // End transaction - rc = spi_tpm_helper_end_transaction(ctx); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_log_register_access(access, reg_number, NULL, cnt, "failed ending the transaction"); - return TSS2_TCTI_RC_IO_ERROR; - } - } else { - // Append header - cnt2 = spi_tpm_helper_no_waitstate_preprocess(access, reg_number, (uint8_t *)buffer, buffer2, cnt); - // Read register - rc = spi_tpm_helper_spi_transfer(ctx, buffer2, buffer2, cnt2); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_log_register_access(access, reg_number, NULL, cnt, "failed in transfer"); - spi_tpm_helper_end_transaction(ctx); - return TSS2_TCTI_RC_IO_ERROR; - } - // Trim the response - spi_tpm_helper_no_waitstate_postprocess(access, (uint8_t *)buffer, buffer2, cnt2); - } - - // Print debug information and return success - spi_tpm_helper_log_register_access(access, reg_number, buffer, cnt, NULL); - return TSS2_RC_SUCCESS; -} - -static TSS2_RC spi_tpm_helper_write_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint32_t reg_number, const void *buffer, size_t cnt) -{ - TSS2_RC rc; - enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access = TCTI_SPI_HELPER_REGISTER_WRITE; - bool has_waitstate = true; - uint8_t buffer2[68]; - size_t cnt2 = 0; - - // Check maximum register transfer size is 64 byte - if (cnt > 64) { - return TSS2_TCTI_RC_BAD_VALUE; - } - - // Detect wait state configuration - if (ctx->platform.spi_acquire == NULL || ctx->platform.spi_release == NULL) { - has_waitstate = false; - } - - // Start write transaction - if (has_waitstate) { - rc = spi_tpm_helper_start_transaction(ctx, access, cnt, reg_number); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_end_transaction(ctx); - spi_tpm_helper_log_register_access(access, reg_number, buffer, cnt, "failed in transaction start"); - return TSS2_TCTI_RC_IO_ERROR; - } - // Write register - rc = spi_tpm_helper_spi_transfer(ctx, buffer, NULL, cnt); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_end_transaction(ctx); - spi_tpm_helper_log_register_access(access, reg_number, buffer, cnt, "failed in transfer"); - return TSS2_TCTI_RC_IO_ERROR; - } - // End transaction - rc = spi_tpm_helper_end_transaction(ctx); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_log_register_access(access, reg_number, NULL, cnt, "failed ending the transaction"); - return TSS2_TCTI_RC_IO_ERROR; - } - } else { - // Append header - cnt2 = spi_tpm_helper_no_waitstate_preprocess(access, reg_number, (uint8_t *)buffer, buffer2, cnt); - // Write register - rc = spi_tpm_helper_spi_transfer(ctx, buffer2, NULL, cnt2); - if (rc != TSS2_RC_SUCCESS) { - spi_tpm_helper_end_transaction(ctx); - spi_tpm_helper_log_register_access(access, reg_number, buffer, cnt, "failed in transfer"); - return TSS2_TCTI_RC_IO_ERROR; - } - } - - // Print debug information and return success - spi_tpm_helper_log_register_access(access, reg_number, buffer, cnt, NULL); - return TSS2_RC_SUCCESS; -} - -static uint32_t spi_tpm_helper_read_sts_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) -{ - uint32_t status = 0; - spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_STS_REG, &status, sizeof(status)); - return LE_TO_HOST_32(status); -} - -static void spi_tpm_helper_write_sts_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint32_t status) -{ - spi_tpm_helper_write_reg(ctx, TCTI_SPI_HELPER_TPM_STS_REG, &status, sizeof(status)); -} - -static uint32_t spi_tpm_helper_get_burst_count(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) -{ - uint32_t status = spi_tpm_helper_read_sts_reg(ctx); - return (status & TCTI_SPI_HELPER_TPM_STS_BURST_COUNT_MASK) >> TCTI_SPI_HELPER_TPM_STS_BURST_COUNT_SHIFT; -} - -static uint8_t spi_tpm_helper_read_access_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) -{ - uint8_t access = 0; - spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_ACCESS_REG, &access, sizeof(access)); - return access; -} - -static void spi_tpm_helper_write_access_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint8_t access_bit) -{ - // Writes to access register can set only 1 bit at a time - if (access_bit & (access_bit - 1)) { - LOG_ERROR("Writes to access register can set only 1 bit at a time."); - } else { - spi_tpm_helper_write_reg(ctx, TCTI_SPI_HELPER_TPM_ACCESS_REG, &access_bit, sizeof(access_bit)); - } -} - -static TSS2_RC spi_tpm_helper_claim_locality(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) -{ - uint8_t access; - access = spi_tpm_helper_read_access_reg(ctx); - - // Check if locality 0 is active - if (access & TCTI_SPI_HELPER_TPM_ACCESS_ACTIVE_LOCALITY) { - LOG_DEBUG("Locality 0 is already active, status: %#x", access); - return TSS2_RC_SUCCESS; - } - - // Request locality 0 - spi_tpm_helper_write_access_reg(ctx, TCTI_SPI_HELPER_TPM_ACCESS_REQUEST_USE); - access = spi_tpm_helper_read_access_reg(ctx); - if (access & (TCTI_SPI_HELPER_TPM_ACCESS_VALID | TCTI_SPI_HELPER_TPM_ACCESS_ACTIVE_LOCALITY)) { - LOG_DEBUG("Claimed locality 0"); - return TSS2_RC_SUCCESS; - } - - LOG_ERROR("Failed to claim locality 0, status: %#x", access); - return TSS2_TCTI_RC_IO_ERROR; -} - -static TSS2_RC spi_tpm_helper_wait_for_status(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint32_t status_mask, uint32_t status_expected, int32_t timeout) -{ - TSS2_RC rc; - uint32_t status; - bool blocking = (timeout == TSS2_TCTI_TIMEOUT_BLOCK); - if (!blocking) { - rc = spi_tpm_helper_start_timeout(ctx, timeout); - return_if_error(rc, "spi_tpm_helper_start_timeout"); - } - - // Wait for the expected status with or without timeout - bool is_timeout_expired = false; - do { - status = spi_tpm_helper_read_sts_reg(ctx); - // Return success on expected status - if ((status & status_mask) == status_expected) { - return TSS2_RC_SUCCESS; - } - // Delay next poll by 8ms to avoid spamming the TPM - rc = spi_tpm_helper_delay_ms(ctx, 8); - return_if_error(rc, "spi_tpm_helper_delay_ms"); - - rc = spi_tpm_helper_timeout_expired(ctx, &is_timeout_expired); - return_if_error(rc, "spi_tpm_helper_timeout_expired"); - } while (blocking || !is_timeout_expired); - - // Timed out - return TSS2_TCTI_RC_TRY_AGAIN; -} - -static inline size_t spi_tpm_helper_size_t_min(size_t a, size_t b) { - if (a < b) { - return a; - } - return b; -} - -static void spi_tpm_helper_fifo_transfer(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint8_t* transfer_buffer, size_t transfer_size, enum TCTI_SPI_HELPER_FIFO_TRANSFER_DIRECTION direction) -{ - size_t transaction_size; - size_t burst_count; - size_t handled_so_far = 0; - - do { - do { - // Can be zero when TPM is busy - burst_count = spi_tpm_helper_get_burst_count(ctx); - } while (!burst_count); - - transaction_size = transfer_size - handled_so_far; - transaction_size = spi_tpm_helper_size_t_min(transaction_size, burst_count); - transaction_size = spi_tpm_helper_size_t_min(transaction_size, 64); - - if (direction == TCTI_SPI_HELPER_FIFO_RECEIVE){ - spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_DATA_FIFO_REG, (void*)(transfer_buffer + handled_so_far), transaction_size); - } else { - spi_tpm_helper_write_reg(ctx, TCTI_SPI_HELPER_TPM_DATA_FIFO_REG, (const void*)(transfer_buffer + handled_so_far), transaction_size); - } - - handled_so_far += transaction_size; - - } while (handled_so_far != transfer_size); -} - -static TSS2_RC check_platform_conf(TSS2_TCTI_SPI_HELPER_PLATFORM *platform_conf) +static TSS2_RC tcti_spi_helper_check_platform_conf (TSS2_TCTI_SPI_HELPER_PLATFORM *platform_conf) { bool required_set = platform_conf->sleep_ms && platform_conf->spi_transfer \ @@ -456,7 +241,7 @@ static TSS2_RC check_platform_conf(TSS2_TCTI_SPI_HELPER_PLATFORM *platform_conf) * If passed a NULL context, or the magic number check fails, this function * will return NULL. */ -TSS2_TCTI_SPI_HELPER_CONTEXT* tcti_spi_helper_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx) +static TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx) { if (tcti_ctx != NULL && TSS2_TCTI_MAGIC (tcti_ctx) == TCTI_SPI_HELPER_MAGIC) { return (TSS2_TCTI_SPI_HELPER_CONTEXT*)tcti_ctx; @@ -468,7 +253,7 @@ TSS2_TCTI_SPI_HELPER_CONTEXT* tcti_spi_helper_context_cast (TSS2_TCTI_CONTEXT *t * This function down-casts the device TCTI context to the common context * defined in the tcti-common module. */ -TSS2_TCTI_COMMON_CONTEXT* tcti_spi_helper_down_cast (TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper) +static TSS2_TCTI_COMMON_CONTEXT* tcti_spi_helper_down_cast_tcti_common (TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper) { if (tcti_spi_helper == NULL) { return NULL; @@ -476,200 +261,259 @@ TSS2_TCTI_COMMON_CONTEXT* tcti_spi_helper_down_cast (TSS2_TCTI_SPI_HELPER_CONTEX return &tcti_spi_helper->common; } -TSS2_RC tcti_spi_helper_receive (TSS2_TCTI_CONTEXT* tcti_context, size_t *response_size, unsigned char *response_buffer, int32_t timeout) +/* + * This function down-casts the device TCTI context to the helper common context + * defined in the tcti-helper-common module. + */ +static TCTI_HELPER_COMMON_CONTEXT* tcti_spi_helper_down_cast_helper_common (TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper) { - TSS2_RC rc; - TSS2_TCTI_SPI_HELPER_CONTEXT* tcti_spi_helper = tcti_spi_helper_context_cast (tcti_context); - TSS2_TCTI_COMMON_CONTEXT* tcti_common = tcti_spi_helper_down_cast (tcti_spi_helper); - if (tcti_spi_helper == NULL) { - return TSS2_TCTI_RC_BAD_CONTEXT; - } - - rc = tcti_common_receive_checks (tcti_common, response_size, TCTI_SPI_HELPER_MAGIC); - if (rc != TSS2_RC_SUCCESS) { - return rc; + return NULL; } + return &tcti_spi_helper->helper_common; +} - // Use ctx as a shorthand for tcti_spi_helper - TSS2_TCTI_SPI_HELPER_CONTEXT* ctx = tcti_spi_helper; - - // Expected status bits for valid status and data availabe - uint32_t expected_status_bits = TCTI_SPI_HELPER_TPM_STS_VALID | TCTI_SPI_HELPER_TPM_STS_DATA_AVAIL; - - // Check if we already have received the header - if (tcti_common->header.size == 0) { - // Wait for response to be ready - rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, timeout); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Failed waiting for status"); - // Return rc from wait_for_status(). May be TRY_AGAIN after timeout. - return rc; - } - // Read only response header into context header buffer - rc = spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_DATA_FIFO_REG, ctx->header, TCTI_SPI_HELPER_RESP_HEADER_SIZE); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Failed reading response header"); - return TSS2_TCTI_RC_IO_ERROR; - } +TSS2_RC tcti_spi_helper_transmit (TSS2_TCTI_CONTEXT *tcti_context, size_t size, const uint8_t *cmd_buf) +{ + TSS2_RC rc; + TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper = tcti_spi_helper_context_cast (tcti_context); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_spi_helper_down_cast_tcti_common (tcti_spi_helper); + TCTI_HELPER_COMMON_CONTEXT *helper_common = tcti_spi_helper_down_cast_helper_common (tcti_spi_helper); - // Find out the total payload size, skipping the two byte tag and update tcti_common - tcti_common->header.size = spi_tpm_helper_read_be32(ctx->header + 2); - LOG_TRACE("Read response size from response header: %" PRIu32 " bytes", tcti_common->header.size); + if (tcti_spi_helper == NULL) { + return TSS2_BASE_RC_BAD_CONTEXT; } - // Check if response size is requested - if (response_buffer == NULL) { - *response_size = tcti_common->header.size; - LOG_TRACE("Caller requested response size. Returning size of %zu bytes", *response_size); - return TSS2_RC_SUCCESS; + rc = tcti_common_transmit_checks (tcti_common, cmd_buf, TCTI_SPI_HELPER_MAGIC); + if (rc != TSS2_RC_SUCCESS) { + return rc; } - // Check if response fits in buffer and update response size - if (tcti_common->header.size > *response_size) { - LOG_ERROR("TPM response too long (%" PRIu32 " bytes)", tcti_common->header.size); - return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; + rc = Tcti_Helper_Common_Transmit (helper_common, size, cmd_buf); + if (rc == TSS2_RC_SUCCESS) { + tcti_common->state = TCTI_STATE_RECEIVE; } - *response_size = tcti_common->header.size; - // Receive the TPM response - LOG_TRACE("Reading response of size %" PRIu32, tcti_common->header.size); - - // Copy already received header into response buffer - memcpy(response_buffer, ctx->header, TCTI_SPI_HELPER_RESP_HEADER_SIZE); + return rc; +} - // Read all but the last byte in the FIFO - size_t bytes_to_go = tcti_common->header.size - 1 - TCTI_SPI_HELPER_RESP_HEADER_SIZE; - spi_tpm_helper_fifo_transfer(ctx, response_buffer + TCTI_SPI_HELPER_RESP_HEADER_SIZE, bytes_to_go, TCTI_SPI_HELPER_FIFO_RECEIVE); +TSS2_RC tcti_spi_helper_receive (TSS2_TCTI_CONTEXT *tcti_context, size_t *response_size, unsigned char *response_buffer, int32_t timeout) +{ + TSS2_RC rc; + TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper = tcti_spi_helper_context_cast (tcti_context); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_spi_helper_down_cast_tcti_common (tcti_spi_helper); + TCTI_HELPER_COMMON_CONTEXT *helper_common = tcti_spi_helper_down_cast_helper_common (tcti_spi_helper); - // Verify that there is still data to read - uint32_t status = spi_tpm_helper_read_sts_reg(ctx); - if ((status & expected_status_bits) != expected_status_bits) { - LOG_ERROR("Unexpected intermediate status %#"PRIx32,status); - return TSS2_TCTI_RC_IO_ERROR; + if (tcti_spi_helper == NULL) { + return TSS2_BASE_RC_BAD_CONTEXT; } - // Read the last byte - rc = spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_DATA_FIFO_REG, response_buffer + tcti_common->header.size - 1, 1); + rc = tcti_common_receive_checks (tcti_common, response_size, TCTI_SPI_HELPER_MAGIC); if (rc != TSS2_RC_SUCCESS) { - return TSS2_TCTI_RC_IO_ERROR; + return rc; } - // Verify that there is no more data available - status = spi_tpm_helper_read_sts_reg(ctx); - if ((status & expected_status_bits) != TCTI_SPI_HELPER_TPM_STS_VALID) { - LOG_ERROR("Unexpected final status %#"PRIx32, status); - return TSS2_TCTI_RC_IO_ERROR; + rc = Tcti_Helper_Common_Receive (helper_common, response_size, response_buffer, timeout); + if (response_buffer != NULL && rc == TSS2_RC_SUCCESS) { + tcti_common->state = TCTI_STATE_TRANSMIT; } - LOGBLOB_DEBUG(response_buffer, tcti_common->header.size, "Response buffer received:"); - - // Set the TPM back to idle state - spi_tpm_helper_write_sts_reg(ctx, TCTI_SPI_HELPER_TPM_STS_COMMAND_READY); - - tcti_common->header.size = 0; - tcti_common->state = TCTI_STATE_TRANSMIT; - - return TSS2_RC_SUCCESS; + return rc; } -void tcti_spi_helper_finalize (TSS2_TCTI_CONTEXT* tcti_context) +void tcti_spi_helper_finalize (TSS2_TCTI_CONTEXT *tcti_context) { TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper = tcti_spi_helper_context_cast (tcti_context); - TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_spi_helper_down_cast (tcti_spi_helper); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_spi_helper_down_cast_tcti_common (tcti_spi_helper); if (tcti_spi_helper == NULL) { return; } tcti_common->state = TCTI_STATE_FINAL; - // Free platform struct user data and resources inside - spi_tpm_helper_platform_finalize(tcti_spi_helper); + /* Free platform struct user data and resources inside */ + tcti_spi_helper_platform_finalize (tcti_spi_helper); } -TSS2_RC tcti_spi_helper_transmit (TSS2_TCTI_CONTEXT *tcti_ctx, size_t size, const uint8_t *cmd_buf) +TSS2_RC tcti_spi_helper_cancel (TSS2_TCTI_CONTEXT *tcti_context) { - TSS2_RC rc; - TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper = tcti_spi_helper_context_cast (tcti_ctx); - TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_spi_helper_down_cast (tcti_spi_helper); - tpm_header_t header; + (void)(tcti_context); + return TSS2_TCTI_RC_NOT_IMPLEMENTED; +} - if (tcti_spi_helper == NULL) { - return TSS2_TCTI_RC_BAD_CONTEXT; - } - TSS2_TCTI_SPI_HELPER_CONTEXT* ctx = tcti_spi_helper; +TSS2_RC tcti_spi_helper_get_poll_handles (TSS2_TCTI_CONTEXT *tcti_context, TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles) +{ + (void)(tcti_context); + (void)(handles); + (void)(num_handles); + return TSS2_TCTI_RC_NOT_IMPLEMENTED; +} - rc = tcti_common_transmit_checks (tcti_common, cmd_buf, TCTI_SPI_HELPER_MAGIC); - if (rc != TSS2_RC_SUCCESS) { - return rc; - } - rc = header_unmarshal (cmd_buf, &header); - if (rc != TSS2_RC_SUCCESS) { - return rc; - } - if (header.size != size) { - LOG_ERROR("Buffer size parameter: %zu, and TPM2 command header size " - "field: %" PRIu32 " disagree.", size, header.size); +TSS2_RC tcti_spi_helper_set_locality (TSS2_TCTI_CONTEXT *tcti_context, uint8_t locality) +{ + (void)(tcti_context); + (void)(locality); + return TSS2_TCTI_RC_NOT_IMPLEMENTED; +} + +TSS2_RC tcti_spi_helper_common_sleep_ms (void *data, int milliseconds) +{ + TSS2_TCTI_SPI_HELPER_CONTEXT *ctx = (TSS2_TCTI_SPI_HELPER_CONTEXT *) data; + return tcti_spi_helper_delay_ms (ctx, milliseconds); +} + +TSS2_RC tcti_spi_helper_common_start_timeout (void *data, int milliseconds) +{ + TSS2_TCTI_SPI_HELPER_CONTEXT *ctx = (TSS2_TCTI_SPI_HELPER_CONTEXT *) data; + return tcti_spi_helper_start_timeout (ctx, milliseconds); +} + +TSS2_RC tcti_spi_helper_common_timeout_expired (void *data, bool *result) +{ + TSS2_TCTI_SPI_HELPER_CONTEXT *ctx = (TSS2_TCTI_SPI_HELPER_CONTEXT *) data; + return tcti_spi_helper_timeout_expired (ctx, result); +} + +TSS2_RC tcti_spi_helper_common_read_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, void *buffer, size_t cnt) +{ + TSS2_RC rc; + TSS2_TCTI_SPI_HELPER_CONTEXT *ctx = (TSS2_TCTI_SPI_HELPER_CONTEXT *) data; + enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access = TCTI_SPI_HELPER_REGISTER_READ; + bool has_waitstate = true; + uint32_t spi_header = 0; + uint8_t buffer2[68]; + size_t cnt2 = 0; + + /* Check maximum register transfer size is 64 byte */ + if (cnt > 64) { return TSS2_TCTI_RC_BAD_VALUE; } - LOGBLOB_DEBUG (cmd_buf, size, "Sending command with TPM_CC %#"PRIx32" and size %" PRIu32, - header.code, header.size); - - // Tell TPM to expect command - spi_tpm_helper_write_sts_reg(ctx, TCTI_SPI_HELPER_TPM_STS_COMMAND_READY); + /* Detect wait state configuration */ + if (ctx->platform.spi_acquire == NULL || ctx->platform.spi_release == NULL) { + has_waitstate = false; + } - // Wait until ready bit is set by TPM device - uint32_t expected_status_bits = TCTI_SPI_HELPER_TPM_STS_COMMAND_READY; - rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Failed waiting for TPM to become ready"); + /* Set register address */ + if ((rc = tcti_spi_helper_build_header (reg, &spi_header))) { return rc; } - // Send command - spi_tpm_helper_fifo_transfer(ctx, (void*)cmd_buf, size, TCTI_SPI_HELPER_FIFO_TRANSMIT); - - // Tell TPM to start processing the command - spi_tpm_helper_write_sts_reg(ctx, TCTI_SPI_HELPER_TPM_STS_GO); + if (has_waitstate) { + /* Start read transaction */ + rc = tcti_spi_helper_start_transaction (ctx, access, cnt, spi_header); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_log_register_access (access, spi_header, NULL, cnt, "failed in transaction start"); + tcti_spi_helper_end_transaction (ctx); + return TSS2_TCTI_RC_IO_ERROR; + } + /* Read register */ + rc = tcti_spi_helper_spi_transfer (ctx, NULL, buffer, cnt); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_log_register_access (access, spi_header, NULL, cnt, "failed in transfer"); + tcti_spi_helper_end_transaction (ctx); + return TSS2_TCTI_RC_IO_ERROR; + } + /* End transaction */ + rc = tcti_spi_helper_end_transaction (ctx); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_log_register_access (access, spi_header, NULL, cnt, "failed ending the transaction"); + return TSS2_TCTI_RC_IO_ERROR; + } + } else { + /* Append header */ + cnt2 = tcti_spi_helper_no_waitstate_preprocess (access, spi_header, (uint8_t *)buffer, buffer2, cnt); + /* Read register */ + rc = tcti_spi_helper_spi_transfer (ctx, buffer2, buffer2, cnt2); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_log_register_access (access, spi_header, NULL, cnt, "failed in transfer"); + tcti_spi_helper_end_transaction (ctx); + return TSS2_TCTI_RC_IO_ERROR; + } + /* Trim the response */ + tcti_spi_helper_no_waitstate_postprocess (access, (uint8_t *)buffer, buffer2, cnt2); + } - tcti_common->state = TCTI_STATE_RECEIVE; + /* Print debug information and return success */ + tcti_spi_helper_log_register_access (access, spi_header, buffer, cnt, NULL); return TSS2_RC_SUCCESS; } -TSS2_RC tcti_spi_helper_cancel (TSS2_TCTI_CONTEXT* tcti_context) +TSS2_RC tcti_spi_helper_common_write_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, const void *buffer, size_t cnt) { - (void)(tcti_context); - return TSS2_TCTI_RC_NOT_IMPLEMENTED; -} + TSS2_RC rc; + TSS2_TCTI_SPI_HELPER_CONTEXT *ctx = (TSS2_TCTI_SPI_HELPER_CONTEXT *) data; + enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE access = TCTI_SPI_HELPER_REGISTER_WRITE; + bool has_waitstate = true; + uint32_t spi_header = 0; + uint8_t buffer2[68]; + size_t cnt2 = 0; -TSS2_RC tcti_spi_helper_get_poll_handles (TSS2_TCTI_CONTEXT* tcti_context, TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles) -{ - (void)(tcti_context); - (void)(handles); - (void)(num_handles); - return TSS2_TCTI_RC_NOT_IMPLEMENTED; -} + /* Check maximum register transfer size is 64 byte */ + if (cnt > 64) { + return TSS2_TCTI_RC_BAD_VALUE; + } -TSS2_RC tcti_spi_helper_set_locality (TSS2_TCTI_CONTEXT* tcti_context, uint8_t locality) -{ - (void)(tcti_context); - (void)(locality); - return TSS2_TCTI_RC_NOT_IMPLEMENTED; + /* Detect wait state configuration */ + if (ctx->platform.spi_acquire == NULL || ctx->platform.spi_release == NULL) { + has_waitstate = false; + } + + /* Set register address */ + if ((rc = tcti_spi_helper_build_header (reg, &spi_header))) { + return rc; + } + + /* Start write transaction */ + if (has_waitstate) { + rc = tcti_spi_helper_start_transaction (ctx, access, cnt, spi_header); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_end_transaction (ctx); + tcti_spi_helper_log_register_access (access, spi_header, buffer, cnt, "failed in transaction start"); + return TSS2_TCTI_RC_IO_ERROR; + } + /* Write register */ + rc = tcti_spi_helper_spi_transfer (ctx, buffer, NULL, cnt); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_end_transaction (ctx); + tcti_spi_helper_log_register_access (access, spi_header, buffer, cnt, "failed in transfer"); + return TSS2_TCTI_RC_IO_ERROR; + } + /* End transaction */ + rc = tcti_spi_helper_end_transaction (ctx); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_log_register_access (access, spi_header, NULL, cnt, "failed ending the transaction"); + return TSS2_TCTI_RC_IO_ERROR; + } + } else { + /* Append header */ + cnt2 = tcti_spi_helper_no_waitstate_preprocess (access, spi_header, (uint8_t *)buffer, buffer2, cnt); + /* Write register */ + rc = tcti_spi_helper_spi_transfer (ctx, buffer2, NULL, cnt2); + if (rc != TSS2_RC_SUCCESS) { + tcti_spi_helper_end_transaction (ctx); + tcti_spi_helper_log_register_access (access, spi_header, buffer, cnt, "failed in transfer"); + return TSS2_TCTI_RC_IO_ERROR; + } + } + + /* Print debug information and return success */ + tcti_spi_helper_log_register_access (access, spi_header, buffer, cnt, NULL); + return TSS2_RC_SUCCESS; } -TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, TSS2_TCTI_SPI_HELPER_PLATFORM *platform_conf) +TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT *tcti_context, size_t *size, TSS2_TCTI_SPI_HELPER_PLATFORM *platform_conf) { TSS2_RC rc; - TSS2_TCTI_SPI_HELPER_CONTEXT* tcti_spi_helper; - TSS2_TCTI_COMMON_CONTEXT* tcti_common; + TSS2_TCTI_SPI_HELPER_CONTEXT *tcti_spi_helper; + TSS2_TCTI_COMMON_CONTEXT *tcti_common; if (!size) { return TSS2_TCTI_RC_BAD_VALUE; } - // Check if context size is requested + /* Check if context size is requested */ if (tcti_context == NULL) { *size = sizeof (TSS2_TCTI_SPI_HELPER_CONTEXT); return TSS2_RC_SUCCESS; @@ -683,7 +527,7 @@ TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; } - // Init TCTI context + /* Init TCTI context */ TSS2_TCTI_MAGIC (tcti_context) = TCTI_SPI_HELPER_MAGIC; TSS2_TCTI_VERSION (tcti_context) = TCTI_VERSION; TSS2_TCTI_TRANSMIT (tcti_context) = tcti_spi_helper_transmit; @@ -694,75 +538,33 @@ TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size TSS2_TCTI_SET_LOCALITY (tcti_context) = tcti_spi_helper_set_locality; TSS2_TCTI_MAKE_STICKY (tcti_context) = tcti_make_sticky_not_implemented; - // Init SPI TCTI context + /* Init SPI TCTI context */ tcti_spi_helper = tcti_spi_helper_context_cast (tcti_context); - tcti_common = tcti_spi_helper_down_cast (tcti_spi_helper); + tcti_common = tcti_spi_helper_down_cast_tcti_common (tcti_spi_helper); tcti_common->state = TCTI_STATE_TRANSMIT; memset (&tcti_common->header, 0, sizeof (tcti_common->header)); tcti_common->locality = 0; - rc = check_platform_conf(platform_conf); - return_if_error(rc, "platform_conf invalid"); + rc = tcti_spi_helper_check_platform_conf (platform_conf); + return_if_error (rc, "invalid platform_conf"); - // Copy platform struct into context + /* Copy platform struct into context */ tcti_spi_helper->platform = *platform_conf; - // Probe TPM - TSS2_TCTI_SPI_HELPER_CONTEXT* ctx = tcti_spi_helper; - LOG_DEBUG("Probing TPM..."); - uint32_t did_vid = 0; - for (int retries = 100; retries > 0; retries--) { - // In case of failed read div_vid is set to zero - spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_DID_VID_REG, &did_vid, sizeof(did_vid)); - if (did_vid != 0) break; - // TPM might be resetting, let's retry in a bit - rc = spi_tpm_helper_delay_ms(ctx, 10); - return_if_error(rc, "spi_tpm_helper_delay_ms"); - } - if (did_vid == 0) { - LOG_ERROR("Probing TPM failed"); - return TSS2_TCTI_RC_IO_ERROR; - } - LOG_DEBUG("Probing TPM successful"); - - // Claim locality - LOG_DEBUG("Claiming TPM locality..."); - rc = spi_tpm_helper_claim_locality(ctx); - if (rc != TSS2_RC_SUCCESS) { - return TSS2_TCTI_RC_IO_ERROR; - } - - // Wait up to TIMEOUT_B for TPM to become ready - LOG_DEBUG("Waiting for TPM to become ready..."); - uint32_t expected_status_bits = TCTI_SPI_HELPER_TPM_STS_COMMAND_READY; - rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); - if (rc == TSS2_TCTI_RC_TRY_AGAIN) { - /* - * TPM did not auto transition into ready state, - * write 1 to commandReady to start the transition. - */ - spi_tpm_helper_write_sts_reg(ctx, TCTI_SPI_HELPER_TPM_STS_COMMAND_READY); - rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); - } - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Failed waiting for TPM to become ready"); - return rc; - } - - LOG_DEBUG("TPM is ready"); - - // Get rid - uint8_t rid = 0; - spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_RID_REG, &rid, sizeof(rid)); - -#if MAXLOGLEVEL >= LOGL_INFO - // Print device details - uint16_t vendor_id, device_id, revision; - vendor_id = did_vid & 0xffff; - device_id = did_vid >> 16; - revision = rid; - LOG_INFO("Connected to TPM with vid:did:rid of %4.4x:%4.4x:%2.2x", vendor_id, device_id, revision); -#endif + /* Register the callback functions before using the Tcti_Helper_Common_ functions */ + TCTI_HELPER_COMMON_CONTEXT helper_common = { + .data = (void *)tcti_spi_helper, + .sleep_ms = tcti_spi_helper_common_sleep_ms, + .start_timeout = tcti_spi_helper_common_start_timeout, + .timeout_expired = tcti_spi_helper_common_timeout_expired, + .read_reg = tcti_spi_helper_common_read_reg, + .write_reg = tcti_spi_helper_common_write_reg, + }; + tcti_spi_helper->helper_common = helper_common; + + /* TPM probing */ + rc = Tcti_Helper_Common_Init (&tcti_spi_helper->helper_common, false); + return_if_error (rc, "tcti initialization sequence has failed"); return TSS2_RC_SUCCESS; } @@ -780,7 +582,7 @@ static const TSS2_TCTI_INFO tss2_tcti_info = { .init = NULL, }; -const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) +const TSS2_TCTI_INFO *Tss2_Tcti_Info (void) { return &tss2_tcti_info; } diff --git a/src/tss2-tcti/tcti-spi-helper.h b/src/tss2-tcti/tcti-spi-helper.h index 4c32d0051..487e72985 100644 --- a/src/tss2-tcti/tcti-spi-helper.h +++ b/src/tss2-tcti/tcti-spi-helper.h @@ -5,49 +5,27 @@ #ifndef TCTI_SPI_HELPER_HELPER_H #define TCTI_SPI_HELPER_HELPER_H #include "tcti-common.h" // for TSS2_TCTI_COMMON_CONTEXT +#include "tcti-helper-common.h" // for TSS2_TCTI_HELPER_COMMON_CONTEXT #include "tss2_tcti_spi_helper.h" // for TSS2_TCTI_SPI_HELPER_PLATFORM #define TCTI_SPI_HELPER_MAGIC 0x4D5C6E8BD4811477ULL -#define TCTI_SPI_HELPER_RESP_HEADER_SIZE 6 - -typedef struct { - TSS2_TCTI_COMMON_CONTEXT common; - TSS2_TCTI_SPI_HELPER_PLATFORM platform; - char header[TCTI_SPI_HELPER_RESP_HEADER_SIZE]; -} TSS2_TCTI_SPI_HELPER_CONTEXT; - -#define TCTI_SPI_HELPER_TPM_LOCALITY_0 0x00D40000 -#define TCTI_SPI_HELPER_TPM_ACCESS_REG (TCTI_SPI_HELPER_TPM_LOCALITY_0 + 0) -#define TCTI_SPI_HELPER_TPM_STS_REG (TCTI_SPI_HELPER_TPM_LOCALITY_0 + 0x18) -#define TCTI_SPI_HELPER_TPM_DATA_FIFO_REG (TCTI_SPI_HELPER_TPM_LOCALITY_0 + 0x24) -#define TCTI_SPI_HELPER_TPM_DID_VID_REG (TCTI_SPI_HELPER_TPM_LOCALITY_0 + 0xF00) -#define TCTI_SPI_HELPER_TPM_RID_REG (TCTI_SPI_HELPER_TPM_LOCALITY_0 + 0xF04) - -enum TCTI_SPI_HELPER_TPM_ACCESS { - TCTI_SPI_HELPER_TPM_ACCESS_VALID = (1 << 7), - TCTI_SPI_HELPER_TPM_ACCESS_ACTIVE_LOCALITY = (1 << 5), - TCTI_SPI_HELPER_TPM_ACCESS_REQUEST_USE = (1 << 1) -}; - -enum TCTI_SPI_HELPER_TPM_STATUS { - TCTI_SPI_HELPER_TPM_STS_BURST_COUNT_SHIFT = 8, - TCTI_SPI_HELPER_TPM_STS_BURST_COUNT_MASK = (0xFFFF << TCTI_SPI_HELPER_TPM_STS_BURST_COUNT_SHIFT), - TCTI_SPI_HELPER_TPM_STS_VALID = (1 << 7), - TCTI_SPI_HELPER_TPM_STS_COMMAND_READY = (1 << 6), - TCTI_SPI_HELPER_TPM_STS_GO = (1 << 5), - TCTI_SPI_HELPER_TPM_STS_DATA_AVAIL = (1 << 4), - TCTI_SPI_HELPER_TPM_STS_DATA_EXPECT = (1 << 3) -}; - -enum TCTI_SPI_HELPER_FIFO_TRANSFER_DIRECTION { - TCTI_SPI_HELPER_FIFO_TRANSMIT = 0, - TCTI_SPI_HELPER_FIFO_RECEIVE = 1 -}; +#define TCTI_SPI_HELPER_HEAD_LOCALITY_0 0x00D40000 +#define TCTI_SPI_HELPER_HEAD_TPM_ACCESS (TCTI_SPI_HELPER_HEAD_LOCALITY_0 + 0) +#define TCTI_SPI_HELPER_HEAD_TPM_STS (TCTI_SPI_HELPER_HEAD_LOCALITY_0 + 0x18) +#define TCTI_SPI_HELPER_HEAD_TPM_DATA_FIFO (TCTI_SPI_HELPER_HEAD_LOCALITY_0 + 0x24) +#define TCTI_SPI_HELPER_HEAD_TPM_DID_VID (TCTI_SPI_HELPER_HEAD_LOCALITY_0 + 0xF00) +#define TCTI_SPI_HELPER_HEAD_TPM_RID (TCTI_SPI_HELPER_HEAD_LOCALITY_0 + 0xF04) enum TCTI_SPI_HELPER_REGISTER_ACCESS_TYPE { TCTI_SPI_HELPER_REGISTER_WRITE = 0, TCTI_SPI_HELPER_REGISTER_READ = 1 }; +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TCTI_HELPER_COMMON_CONTEXT helper_common; + TSS2_TCTI_SPI_HELPER_PLATFORM platform; +} TSS2_TCTI_SPI_HELPER_CONTEXT; + #endif /* TCTI_SPI_HELPER_HELPER_H */ diff --git a/src/tss2-tcti/tcti-spi-ltt2go.c b/src/tss2-tcti/tcti-spi-ltt2go.c index 81c998276..5e15bbf75 100644 --- a/src/tss2-tcti/tcti-spi-ltt2go.c +++ b/src/tss2-tcti/tcti-spi-ltt2go.c @@ -20,19 +20,6 @@ #define LOGMODULE tcti #include "util/log.h" // for LOG_ERROR, LOG_WARNING -#define VID_PI3G 0x365Du -#define PID_LTT2GO 0x1337u -#define TIMEOUT 1000 -#define CTRL_SET 0xC0u -#define CTRL_GET 0x40u -#define CY_CMD_SPI 0xCAu -#define CY_CMD_GPIO_SET 0xDBu -#define CY_SPI_WRITEREAD 0x03u -#define EP_OUT 0x01u -#define EP_IN 0x82u - -#define SPI_MAX_TRANSFER (4 + 64) - TSS2_RC platform_spi_transfer (void *user_data, const void *data_out, void *data_in, size_t cnt) { @@ -66,7 +53,7 @@ platform_spi_transfer (void *user_data, const void *data_out, void *data_in, siz memcpy (spi_dma_buffer, data_out, length); } - ret = libusb_control_transfer (dev_handle, CTRL_SET, CY_CMD_SPI, CY_SPI_WRITEREAD, length, NULL, 0, TIMEOUT); + ret = libusb_control_transfer (dev_handle, CTRL_SET, CY_CMD_SPI, CY_SPI_WRITEREAD, length, NULL, 0, LTT2GO_TIMEOUT_MS); if (ret) { LOG_ERROR ("libusb_control_transfer failed with error: %s.", libusb_strerror(ret)); ret = TSS2_TCTI_RC_IO_ERROR; @@ -74,7 +61,7 @@ platform_spi_transfer (void *user_data, const void *data_out, void *data_in, siz } while (transfered != cnt){ - ret = libusb_bulk_transfer (dev_handle, EP_OUT, spi_dma_buffer+transfered, (int) length, &act_len, TIMEOUT); + ret = libusb_bulk_transfer (dev_handle, EP_OUT, spi_dma_buffer+transfered, (int) length, &act_len, LTT2GO_TIMEOUT_MS); if (ret) { LOG_ERROR ("libusb_bulk_transfer write failed with error: %s.", libusb_strerror(ret)); ret = TSS2_TCTI_RC_IO_ERROR; @@ -87,7 +74,7 @@ platform_spi_transfer (void *user_data, const void *data_out, void *data_in, siz transfered = 0; length = cnt; while(transfered != cnt){ - ret = libusb_bulk_transfer (dev_handle, EP_IN, spi_dma_buffer+transfered, (int) length, &act_len, TIMEOUT); + ret = libusb_bulk_transfer (dev_handle, EP_IN, spi_dma_buffer+transfered, (int) length, &act_len, LTT2GO_TIMEOUT_MS); if (ret) { if (retry++ > 5) { LOG_ERROR ("libusb_bulk_transfer read failed with error: %s.", libusb_strerror(ret)); diff --git a/src/tss2-tcti/tcti-spi-ltt2go.h b/src/tss2-tcti/tcti-spi-ltt2go.h index eb8c1dec0..5b5ddaf38 100644 --- a/src/tss2-tcti/tcti-spi-ltt2go.h +++ b/src/tss2-tcti/tcti-spi-ltt2go.h @@ -8,6 +8,19 @@ #include // for uint8_t #include // for timeval +#define VID_PI3G 0x365Du +#define PID_LTT2GO 0x1337u +#define LTT2GO_TIMEOUT_MS 1000 +#define CTRL_SET 0xC0u +#define CTRL_GET 0x40u +#define CY_CMD_SPI 0xCAu +#define CY_CMD_GPIO_SET 0xDBu +#define CY_SPI_WRITEREAD 0x03u +#define EP_OUT 0x01u +#define EP_IN 0x82u + +#define SPI_MAX_TRANSFER (4 + 64) + typedef struct { struct timeval timeout; libusb_device_handle *dev_handle; diff --git a/test/unit/tcti-helper-common.c b/test/unit/tcti-helper-common.c new file mode 100644 index 000000000..326127c68 --- /dev/null +++ b/test/unit/tcti-helper-common.c @@ -0,0 +1,443 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2024 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifdef HAVE_CONFIG_H +#include "config.h" // IWYU pragma: keep +#endif + +#include // for uint8_t, int32_t +#include // for false, bool, true +#include // for NULL, size_t +#include // for free, calloc, malloc +#include // for memcpy, strncmp + +#include "../helper/cmocka_all.h" // for assert_int_equal, assert_stri... +#include "tss2-tcti/tcti-common.h" // for TCTI_STATE_RECEIVE, TCTI_VERSION +#include "tss2-tcti/tcti-helper-common.h" +#include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC, TSS... +#include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_... + +typedef struct { + void *func; + enum TCTI_HELPER_COMMON_REG reg; + char *buffer; + union { + size_t size; /* for callback_read_reg, callback_write_reg */ + int ms; /* for callback_sleep_ms, callback_start_timeout */ + bool is_expired; /* for callback_timeout_expired */ + } u; +} struct_audit; + +typedef struct { + TCTI_HELPER_COMMON_CONTEXT helper_common; + int audit_step; + struct_audit *audit; +} tester_context; + +static TSS2_RC callback_sleep_ms (void *data, int milliseconds); +static TSS2_RC callback_start_timeout (void *data, int milliseconds); +static TSS2_RC callback_timeout_expired (void *data, bool *result); +static TSS2_RC callback_read_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, void *buffer, size_t cnt); +static TSS2_RC callback_write_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, const void *buffer, size_t cnt); + +/* TPM2_Startup command and response */ +static const unsigned char TPM2_STARTUP_CMD[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static const unsigned char TPM2_STARTUP_RESP[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00 }; + +/* + * The goal is to verify the TPM 2.0 FIFO communication protocol implementation by checking the order + * in which the callbacks are invoked. The audit arrays (audit_init, audit_transmission, audit_receive) + * contain this information. Each entry specifies the expected callback to be invoked, the command to + * be received, or the response to be written back in a specific order. The tester_context.audit_step + * (audit array index) variable keeps track of the sequence of these operations. + * + * The audit arrays are implementated based on the TCG PC Client Device Driver Design Principles for TPM 2.0: + * - Send Command using the FIFO Protocol + * - Receive Response using the FIFO Protocol + * + * Clarification: + * - callback_read_reg: Host library read data from a TPM register + * - callback_write_reg: Host library write data to a TPM register + */ + +static struct_audit audit_spi_init[] = { + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DID_VID, "\x00\x00\x00\x00", 4 }, /* Return TPM_DID_VID = 0x00000000 */ + { callback_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DID_VID, "\xd1\x15\x1b\x00", 4 }, /* Return TPM_DID_VID = 0xD1151B00 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_ACCESS, "\x80", 1 }, /* Return tpmRegValidSts = 1 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_ACCESS, "\x02", 1 }, /* Verify requestUse == 1 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_ACCESS, "\xA0", 1 }, /* Return tpmRegValidSts = 1, activeLocality = 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_B }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x00\x00\x00\x00", 4 }, /* Return commandReady = 0 */ + { callback_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { callback_timeout_expired, 0, NULL, true }, /* timeout occurred */ + + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Verify commandReady == 1*/ + + { callback_start_timeout, 0, NULL, TIMEOUT_B }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Return commandReady = 1 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_RID, "\x00", 1 }, /* Return TPM_RID */ + + { 0 }, +}; + +static struct_audit audit_i2c_init[] = { + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DID_VID, "\x00\x00\x00\x00", 4 }, /* Return TPM_DID_VID = 0x00000000 */ + { callback_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DID_VID, "\xd1\x15\x1b\x00", 4 }, /* Return TPM_DID_VID = 0xD1151B00 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_I2C_INTF_CAP, + "\x00\xf4\x1f\x00", 4 }, /* Return GUARD_TIME = TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US, RR = RW = WR = WW = 1 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM_ENABLE, "\x00", 1 }, /* Return dataCSumEnable = 0 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM_ENABLE, "\x01", 1 }, /* Return dataCSumEnable = 1 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_ACCESS, "\x80", 1 }, /* Return tpmRegValidSts = 1 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_ACCESS, "\x02", 1 }, /* Verify requestUse == 1 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_ACCESS, "\xA0", 1 }, /* Return tpmRegValidSts = 1, activeLocality = 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_B }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x00\x00\x00\x00", 4 }, /* Return commandReady = 0 */ + { callback_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { callback_timeout_expired, 0, NULL, true }, /* timeout occurred */ + + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Verify commandReady == 1*/ + + { callback_start_timeout, 0, NULL, TIMEOUT_B }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Return commandReady = 1 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_RID, "\x00", 1 }, /* Return TPM_RID */ + + { 0 }, +}; + +static struct_audit audit_spi_transmission[] = { + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Verify commandReady == 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_B }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Return commandReady = 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x00\xFF\x00\x00", 4 }, /* Return burstCount = 0x00FF */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + (char *)TPM2_STARTUP_CMD, 1 }, /* Verify incoming TPM_DATA_FIFO (1st byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\x00\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 0 */ + { callback_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { callback_timeout_expired, 0, NULL, false }, /* To retry without a timeout occurring */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\x01\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 1 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_CMD + 1, 1 }, /* Verify incoming TPM_DATA_FIFO (2nd byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\xFF\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 255 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_CMD + 2, + sizeof (TPM2_STARTUP_CMD) - 3 }, /* Verify incoming TPM_DATA_FIFO (all but the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\xFF\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 255 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + (char *)TPM2_STARTUP_CMD + sizeof (TPM2_STARTUP_CMD) - 1, 1 }, /* Verify incoming TPM_DATA_FIFO (the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x80\x00\x00\x00", 4 }, /* Return stsValid = 1, Expect = 0 */ + + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x20\x00\x00\x00", 4 }, /* Verify tpmGo == 1 */ + + { 0 }, +}; + +static struct_audit audit_i2c_transmission[] = { + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Verify commandReady == 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_B }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Return commandReady = 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x00\xFF\x00\x00", 4 }, /* Return burstCount = 0x00FF */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_CMD, 1 }, /* Verify incoming TPM_DATA_FIFO (1st byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\x00\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 0 */ + { callback_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { callback_timeout_expired, 0, NULL, false }, /* To retry without a timeout occurring */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\x01\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 1 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_CMD + 1, 1 }, /* Verify incoming TPM_DATA_FIFO (2nd byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\xFF\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 255 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_CMD + 2, + sizeof (TPM2_STARTUP_CMD) - 3 }, /* Verify incoming TPM_DATA_FIFO (all but the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x88\xFF\x00\x00", 4 }, /* Return stsValid = 1, Expect = 1, burstCount = 255 */ + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + (char *)TPM2_STARTUP_CMD + sizeof (TPM2_STARTUP_CMD) - 1, 1 }, /* Verify incoming TPM_DATA_FIFO (the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x80\x00\x00\x00", 4 }, /* Return stsValid = 1, Expect = 0 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM, "\x33\x67", 2 }, /* Return CRC-16/KERMIT value of TPM2_STARTUP_CMD */ + + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x20\x00\x00\x00", 4 }, /* Verify tpmGo == 1 */ + + { 0 }, +}; + +static struct_audit audit_spi_receive[] = { + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x00\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x02\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 2 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP, 2 }, /* Return TPM_DATA_FIFO (first 2 bytes) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\xFF\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 255 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP + 2, + TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE - 2 }, /* Return TPM_DATA_FIFO (next 4 bytes) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x34\x12\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 4660 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP + TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE, + sizeof (TPM2_STARTUP_RESP) - TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE - 1 }, /* Return TPM_DATA_FIFO (all but the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x34\x12\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 4660 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP + sizeof (TPM2_STARTUP_RESP) - 1, + 1 }, /* Return TPM_DATA_FIFO (the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x80\x00\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 0 */ + + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Verify commandReady == 1 */ + + { 0 }, +}; + +static struct_audit audit_i2c_receive[] = { + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x00\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 1 */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x02\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 2 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP, 2 }, /* Return TPM_DATA_FIFO (first 2 bytes) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\xFF\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 255 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP + 2, + TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE - 2 }, /* Return TPM_DATA_FIFO (next 4 bytes) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x34\x12\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 4660 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP + TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE, + sizeof (TPM2_STARTUP_RESP) - TCTI_HELPER_COMMON_RESP_HEADER_MIN_SIZE - 1 }, /* Return TPM_DATA_FIFO (all but the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x90\x34\x12\x00", 4 }, /* Return stsValid = 1, dataAvail = 1, burstCount = 4660 */ + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP + sizeof (TPM2_STARTUP_RESP) - 1, + 1 }, /* Return TPM_DATA_FIFO (the last byte) */ + + { callback_start_timeout, 0, NULL, TIMEOUT_A }, + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x80\x00\x00\x00", 4 }, /* Return stsValid = 1, dataAvail = 0 */ + + { callback_read_reg, TCTI_HELPER_COMMON_REG_TPM_DATA_CSUM, "\xa3\xa3", 2 }, /* Return CRC-16/KERMIT value of TPM2_STARTUP_RESP */ + + { callback_write_reg, TCTI_HELPER_COMMON_REG_TPM_STS, "\x40\x00\x00\x00", 4 }, /* Verify commandReady == 1 */ + + { 0 }, +}; + +static TSS2_RC callback_sleep_ms (void *data, int milliseconds) +{ + tester_context *ctx = (tester_context *)data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + + assert_ptr_equal (callback_sleep_ms, ctx->audit[i].func); + assert_int_equal (milliseconds, ctx->audit[i].u.ms); + + ctx->audit_step++; + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC callback_start_timeout (void *data, int milliseconds) +{ + tester_context *ctx = (tester_context *)data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + + assert_ptr_equal (callback_start_timeout, ctx->audit[i].func); + assert_int_equal (milliseconds, ctx->audit[i].u.ms); + + ctx->audit_step++; + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC callback_timeout_expired (void *data, bool *result) +{ + tester_context *ctx = (tester_context *)data; + int i; + + assert_non_null (ctx); + assert_non_null (result); + i = ctx->audit_step; + + assert_ptr_equal (callback_timeout_expired, ctx->audit[i].func); + + *result = ctx->audit[i].u.is_expired; + + ctx->audit_step++; + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC callback_read_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, void *buffer, size_t cnt) +{ + tester_context *ctx = (tester_context *)data; + int i; + + assert_non_null (ctx); + assert_non_null (buffer); + i = ctx->audit_step; + + assert_ptr_equal (callback_read_reg, ctx->audit[i].func); + assert_int_equal (reg, ctx->audit[i].reg); + assert_int_equal (cnt, ctx->audit[i].u.size); + memcpy (buffer, ctx->audit[i].buffer, cnt); + + ctx->audit_step++; + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC callback_write_reg (void *data, enum TCTI_HELPER_COMMON_REG reg, const void *buffer, size_t cnt) +{ + tester_context *ctx = (tester_context *)data; + int i; + + assert_non_null (ctx); + assert_non_null (buffer); + i = ctx->audit_step; + + assert_ptr_equal (callback_write_reg, ctx->audit[i].func); + assert_int_equal (reg, ctx->audit[i].reg); + assert_int_equal (cnt, ctx->audit[i].u.size); + assert_true (!memcmp (buffer, ctx->audit[i].buffer, cnt)); + + ctx->audit_step++; + + return TSS2_RC_SUCCESS; +} + +static void +tcti_generic_test (void **state, bool is_i2c) +{ + TSS2_RC rc; + tester_context tester_ctx = { 0 }; + size_t size = sizeof (TPM2_STARTUP_RESP) + 1; + unsigned char buffer[sizeof (TPM2_STARTUP_RESP) + 1] = { 0 }; + + /* Reset test */ + if (is_i2c) { + tester_ctx.audit = audit_i2c_init; + } else { + tester_ctx.audit = audit_spi_init; + } + tester_ctx.audit_step = 0; + + /* Register the callback functions before using the Tcti_Helper_Common_ functions */ + TCTI_HELPER_COMMON_CONTEXT helper_common = { + .response_size = 0, + .data = (void *)&tester_ctx, + .sleep_ms = callback_sleep_ms, + .start_timeout = callback_start_timeout, + .timeout_expired = callback_timeout_expired, + .read_reg = callback_read_reg, + .write_reg = callback_write_reg, + }; + tester_ctx.helper_common = helper_common; + + rc = Tcti_Helper_Common_Init (&tester_ctx.helper_common, is_i2c); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Reset test */ + if (is_i2c) { + tester_ctx.audit = audit_i2c_transmission; + } else { + tester_ctx.audit = audit_spi_transmission; + } + tester_ctx.audit_step = 0; + + rc = Tcti_Helper_Common_Transmit (&tester_ctx.helper_common, sizeof (TPM2_STARTUP_CMD), TPM2_STARTUP_CMD); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Reset test */ + if (is_i2c) { + tester_ctx.audit = audit_i2c_receive; + } else { + tester_ctx.audit = audit_spi_receive; + } + tester_ctx.audit_step = 0; + + rc = Tcti_Helper_Common_Receive (&tester_ctx.helper_common, &size, buffer, 0); + assert_int_equal (rc, TSS2_RC_SUCCESS); + assert_int_equal (size, sizeof (TPM2_STARTUP_RESP)); + assert_true (!memcmp (buffer, TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP))); +} + +static void +tcti_spi_test (void **state) +{ + tcti_generic_test (state, false); +} + +static void +tcti_i2c_test (void **state) +{ + tcti_generic_test (state, true); +} + +int +main (int argc, + char *argv[]) +{ + (void) argc; + (void) argv; + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_spi_test), + cmocka_unit_test (tcti_i2c_test), + }; + + return cmocka_run_group_tests (tests, NULL, NULL); +} diff --git a/test/unit/tcti-i2c-ftdi.c b/test/unit/tcti-i2c-ftdi.c index 7ec046090..59f002b5c 100644 --- a/test/unit/tcti-i2c-ftdi.c +++ b/test/unit/tcti-i2c-ftdi.c @@ -40,150 +40,95 @@ #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_... #include "tss2_tcti_i2c_ftdi.h" // for Tss2_Tcti_I2c_Ftdi_Init -struct timeval; -struct timezone; - -typedef enum { - I2C_IDLE = 0, - /* Read sequence */ - R_I2C_START_0, - R_I2C_WRITE_0, - R_I2C_GET_ACK_0, - R_I2C_STOP_0, - R_I2C_START_1, - R_I2C_WRITE_1, - R_I2C_GET_ACK_1, - R_I2C_SEND_ACKS, - R_I2C_READ_0, - R_I2C_SEND_NACKS, - R_I2C_READ_1, - R_I2C_STOP_1, - R_I2C_LAST, - /* Write sequence */ - W_I2C_START, - W_I2C_WRITE_0, - W_I2C_GET_ACK, - W_I2C_WRITE_1, - W_I2C_STOP, - W_I2C_LAST -} i2c_state_t; - -typedef enum { - /* Tss2_Tcti_I2c_Ftdi_Init () */ - R_TPM_DID_VID = 0, - R_TPM_INTERFACE_CAP, - R_TPM_ACCESS, - R_TPM_CSUM_ENABLE, - W_TPM_CSUM_ENABLE, - R_TPM_STS_00, - R_TPM_RID, - /* TSS2_TCTI_TRANSMIT () */ - W_TPM_STS_00, - R_TPM_STS_01, - R_TPM_STS_02, - W_TPM_FIFO, - R_TPM_CSUM_00, - W_TPM_STS_01, - /* TSS2_TCTI_RECEIVE () */ - R_TPM_STS_03, - R_TPM_STS_04, - R_TPM_FIFO_00, - R_TPM_STS_05, - R_TPM_FIFO_01, - R_TPM_STS_06, - R_TPM_FIFO_02, - R_TPM_STS_07, - R_TPM_CSUM_01, - W_TPM_STS_02, -} tpm_state_t; - -static struct m_state_t { - tpm_state_t tpm; - i2c_state_t i2c; -} m_state = {R_TPM_DID_VID, I2C_IDLE}; - -static const uint8_t R_TPM_DID_VID_DATA[] = {0xd1, 0x15, 0x1b, 0x00}; -static const uint8_t R_TPM_INTERFACE_CAP_DATA[] = {0x82, 0x00, 0xe0, 0x1a}; -static const uint8_t R_TPM_ACCESS_DATA[] = {0xa1}; -static const uint8_t R_TPM_CSUM_ENABLE_DATA[] = {0x00}; -static const uint8_t R_TPM_RID_DATA[] = {0x00}; -static const uint8_t R_TPM_STS_00_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; -static const uint8_t R_TPM_STS_02_05_DATA[] = {0x00, 0x40, 0x00, 0x00}; -static const uint8_t R_TPM_STS_04_06_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID | TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL, - 0x00, 0x00, 0x00}; -static const uint8_t R_TPM_CSUM_DATA[] = {0xf7, 0x4b}; /* CRC-16 (KERMIT) of RW_TPM_FIFO_DATA */ -static const uint8_t R_TPM_STS_03_07_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID, 0x00, 0x00, 0x00}; -static const uint8_t W_TPM_STS_00_02_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; -static const uint8_t W_TPM_STS_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_GO, 0x00, 0x00, 0x00}; -static const uint8_t W_TPM_CSUM_ENABLE_DATA[] = {0x01}; -static const uint8_t RW_TPM_FIFO_DATA[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xde, 0xad, 0xbe, 0xef}; - -static struct mpsse_context *_mpsse; - -static void state_machine (void) -{ - while (true) { - switch (m_state.tpm) { - case R_TPM_DID_VID: - case R_TPM_INTERFACE_CAP: - case R_TPM_CSUM_ENABLE: - case R_TPM_CSUM_00: - case R_TPM_CSUM_01: - case R_TPM_ACCESS: - case R_TPM_STS_00: - case R_TPM_STS_01: - case R_TPM_STS_02: - case R_TPM_STS_03: - case R_TPM_STS_04: - case R_TPM_STS_05: - case R_TPM_STS_06: - case R_TPM_STS_07: - case R_TPM_RID: - case R_TPM_FIFO_00: - case R_TPM_FIFO_01: - case R_TPM_FIFO_02: - if (m_state.i2c == I2C_IDLE) { - /* Start a new read sequence */ - m_state.i2c = R_I2C_START_0; - goto exit; - } else if (m_state.i2c == R_I2C_LAST - 1) { - /* Read sequence has ended */ - m_state.i2c = I2C_IDLE; - m_state.tpm++; - } else { - /* Amidst a read sequence */ - m_state.i2c++; - goto exit; - } - break; - case W_TPM_FIFO: - case W_TPM_CSUM_ENABLE: - case W_TPM_STS_00: - case W_TPM_STS_01: - case W_TPM_STS_02: - if (m_state.i2c == I2C_IDLE) { - /* Start a new write sequence */ - m_state.i2c = W_I2C_START; - goto exit; - } else if (m_state.i2c == W_I2C_LAST - 1) { - /* Write sequence has ended */ - m_state.i2c = I2C_IDLE; - m_state.tpm++; - } else { - /* Amidst a write sequence */ - m_state.i2c++; - goto exit; - } - break; - default: - assert_true (false); - return; - } - } +/* + * The goal is to verify the FTDI I2C implementation by checking + * the order in which libftdi functions are invoked when using functions in + * the TSS2_TCTI_I2C_HELPER_PLATFORM (e.g., sleep_ms, start_timeout, + * timeout_expired, i2c_write, and i2c_read). + + * The audit arrays (e.g., audit_general) contain this information. Each + * entry specifies the expected libftdi function to be invoked, the command + * to be received, or the response to be written back in a specific order. + * The tester_context.audit_step (audit array index) variable tracks the + * sequence of these operations. + */ -exit: - return; -} +#define MPSSE_DUMMY_PTR ((void *)0xA5A5A5A5) +#define TIME_US 250 +#define TIME_MS 450 + +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TSS2_TCTI_I2C_HELPER_PLATFORM platform; +} TSS2_TCTI_I2C_FTDI_TEST_CONTEXT; + +typedef struct { + int nfds; + void *readfds; + void *writefds; + void *exceptfds; + struct timeval timeout; +} fn_select; + +typedef struct { + struct timeval tv; + void *tz; +} fn_gettimeofday; + +typedef struct { + enum modes mode; + int freq; + int endianess; + void *ret; +} fn_mpsse; + +typedef struct { + void *mpsse; +} fn_start, fn_stop, + fn_close, fn_getack, + fn_sendacks, fn_sendnacks; + +typedef struct { + void *mpsse; + void *data; + int size; +} fn_read; + +typedef struct { + void *mpsse; + void *data; + int size; +} fn_write; + +typedef struct { + void *func; + union { + fn_select select; + fn_gettimeofday gtod; + fn_mpsse mpsse; + fn_start start; + fn_stop stop; + fn_close close; + fn_read read; + fn_write write; + fn_getack getack; + fn_sendacks sendacks; + fn_sendnacks sendnacks; + } args; +} struct_audit; + +typedef struct { + int audit_step; + struct_audit *audit; +} tester_context; + +static tester_context tester_ctx; +static const unsigned char REG_ADDR_W[] = { I2C_DEV_ADDR_DEFAULT << 1, TCTI_I2C_HELPER_REG_TPM_DATA_FIFO }; +static const unsigned char REG_ADDR_R[] = { I2C_DEV_ADDR_DEFAULT << 1 | 0x1 }; +static const unsigned char TPM2_STARTUP_CMD[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static const unsigned char TPM2_STARTUP_RESP[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00 }; /* * Mock function select @@ -193,12 +138,15 @@ int __wrap_select (int nfds, fd_set *readfds, fd_set *exceptfds, struct timeval *timeout) { + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - assert_int_equal (nfds, 0); - assert_null (readfds); - assert_null (writefds); - assert_null (exceptfds); - assert_non_null (timeout); + assert_ptr_equal (__wrap_select, audit->func); + assert_int_equal (nfds, audit->args.select.nfds); + assert_int_equal (readfds, audit->args.select.readfds); + assert_int_equal (writefds, audit->args.select.writefds); + assert_int_equal (exceptfds, audit->args.select.exceptfds); + assert_int_equal (timeout->tv_sec, audit->args.select.timeout.tv_sec); + assert_int_equal (timeout->tv_usec, audit->args.select.timeout.tv_usec); return 0; } @@ -209,11 +157,14 @@ int __wrap_select (int nfds, fd_set *readfds, int __wrap_gettimeofday (struct timeval *tv, struct timezone *tz) { - assert_null (tz); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_gettimeofday, audit->func); assert_non_null (tv); + assert_ptr_equal (tz, audit->args.gtod.tz); - tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_sec = audit->args.gtod.tv.tv_sec; + tv->tv_usec = audit->args.gtod.tv.tv_usec; return 0; } @@ -223,13 +174,16 @@ int __wrap_gettimeofday (struct timeval *tv, */ struct mpsse_context *__wrap_MPSSE (enum modes mode, int freq, int endianess) { - assert_int_equal (mode, I2C); - assert_int_equal (freq, ONE_HUNDRED_KHZ); - assert_int_equal (endianess, MSB); + struct mpsse_context *ret; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - _mpsse = malloc (sizeof (struct mpsse_context)); + assert_ptr_equal (__wrap_MPSSE, audit->func); + assert_int_equal (mode, audit->args.mpsse.mode); + assert_int_equal (freq, audit->args.mpsse.freq); + assert_int_equal (endianess, audit->args.mpsse.endianess); + ret = (struct mpsse_context *)audit->args.mpsse.ret; - return _mpsse; + return ret; } /* @@ -237,11 +191,11 @@ struct mpsse_context *__wrap_MPSSE (enum modes mode, int freq, int endianess) */ int __wrap_Start (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - assert_true ((m_state.i2c == R_I2C_START_0) || - (m_state.i2c == R_I2C_START_1) || - (m_state.i2c == W_I2C_START)); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_Start, audit->func); + assert_ptr_equal (mpsse, audit->args.start.mpsse); + return MPSSE_OK; } @@ -250,11 +204,10 @@ int __wrap_Start (struct mpsse_context *mpsse) */ int __wrap_Stop (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - assert_true ((m_state.i2c == R_I2C_STOP_0) || - (m_state.i2c == R_I2C_STOP_1) || - (m_state.i2c == W_I2C_STOP)); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + assert_ptr_equal (__wrap_Stop, audit->func); + assert_ptr_equal (mpsse, audit->args.stop.mpsse); + return MPSSE_OK; } @@ -263,9 +216,10 @@ int __wrap_Stop (struct mpsse_context *mpsse) */ void __wrap_Close (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - free (_mpsse); - _mpsse = NULL; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_Close, audit->func); + assert_ptr_equal (mpsse, audit->args.close.mpsse); } /* @@ -273,95 +227,18 @@ void __wrap_Close (struct mpsse_context *mpsse) */ char *__wrap_Read (struct mpsse_context *mpsse, int size) { - const uint8_t *payload = NULL; - int payload_size = 0; - char *out = NULL; - - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - - switch (m_state.tpm) { - case R_TPM_DID_VID: - payload = R_TPM_DID_VID_DATA; - payload_size = sizeof (R_TPM_DID_VID_DATA); - break; - case R_TPM_INTERFACE_CAP: - payload = R_TPM_INTERFACE_CAP_DATA; - payload_size = sizeof (R_TPM_INTERFACE_CAP_DATA); - break; - case R_TPM_CSUM_ENABLE: - payload = R_TPM_CSUM_ENABLE_DATA; - payload_size = sizeof (R_TPM_CSUM_ENABLE_DATA); - break; - case R_TPM_CSUM_00: - case R_TPM_CSUM_01: - payload = R_TPM_CSUM_DATA; - payload_size = sizeof (R_TPM_CSUM_DATA); - break; - case R_TPM_ACCESS: - payload = R_TPM_ACCESS_DATA; - payload_size = sizeof (R_TPM_ACCESS_DATA); - break; - case R_TPM_STS_00: - case R_TPM_STS_01: - payload = R_TPM_STS_00_01_DATA; - payload_size = sizeof (R_TPM_STS_00_01_DATA); - break; - case R_TPM_STS_02: - case R_TPM_STS_05: - payload = R_TPM_STS_02_05_DATA; - payload_size = sizeof (R_TPM_STS_02_05_DATA); - break; - case R_TPM_STS_03: - case R_TPM_STS_07: - payload = R_TPM_STS_03_07_DATA; - payload_size = sizeof (R_TPM_STS_03_07_DATA); - break; - case R_TPM_STS_04: - case R_TPM_STS_06: - payload = R_TPM_STS_04_06_DATA; - payload_size = sizeof (R_TPM_STS_04_06_DATA); - break; - case R_TPM_RID: - payload = R_TPM_RID_DATA; - payload_size = sizeof (R_TPM_RID_DATA); - break; - case R_TPM_FIFO_00: - payload = RW_TPM_FIFO_DATA; - payload_size = TCTI_I2C_HELPER_RESP_HEADER_SIZE; - break; - case R_TPM_FIFO_01: - payload = RW_TPM_FIFO_DATA + TCTI_I2C_HELPER_RESP_HEADER_SIZE; - payload_size = sizeof (RW_TPM_FIFO_DATA) - 1 - TCTI_I2C_HELPER_RESP_HEADER_SIZE; - break; - case R_TPM_FIFO_02: - payload = RW_TPM_FIFO_DATA + sizeof (RW_TPM_FIFO_DATA) - 1; - payload_size = 1; - break; - default: - assert_true (false); - } + char *ptr; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - switch (m_state.i2c) { - case R_I2C_READ_0: - assert_int_equal (size, payload_size - 1); - out = malloc (size); - assert_non_null (out); - memcpy (out, payload, payload_size - 1); - return out; - break; - case R_I2C_READ_1: - assert_int_equal (size, 1); - out = malloc (1); - assert_non_null (out); - memcpy (out, payload + payload_size - 1, 1); - return out; - break; - default: - assert_true (false); - } + assert_ptr_equal (__wrap_Read, audit->func); + assert_ptr_equal (mpsse, audit->args.read.mpsse); + assert_ptr_equal (size, audit->args.read.size); - return NULL; + ptr = calloc (1, size); + assert_non_null (ptr); + memcpy (ptr, audit->args.read.data, size); + + return ptr; } /* @@ -369,126 +246,12 @@ char *__wrap_Read (struct mpsse_context *mpsse, int size) */ int __wrap_Write (struct mpsse_context *mpsse, char *data, int size) { - const uint8_t *payload = NULL; - int payload_size = 0; - uint8_t addr[2] = {I2C_DEV_ADDR_DEFAULT << 1, 0x0}; - - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - - switch (m_state.tpm) { - case R_TPM_DID_VID: - addr[1] = TCTI_I2C_HELPER_TPM_DID_VID_REG; - break; - case R_TPM_INTERFACE_CAP: - addr[1] = TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG; - break; - case R_TPM_CSUM_ENABLE: - addr[1] = TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG; - break; - case R_TPM_CSUM_00: - case R_TPM_CSUM_01: - addr[1] = TCTI_I2C_HELPER_TPM_DATA_CSUM_REG; - break; - case R_TPM_ACCESS: - addr[1] = TCTI_I2C_HELPER_TPM_ACCESS_REG; - break; - case R_TPM_STS_00: - case R_TPM_STS_01: - case R_TPM_STS_02: - case R_TPM_STS_03: - case R_TPM_STS_04: - case R_TPM_STS_05: - case R_TPM_STS_06: - case R_TPM_STS_07: - addr[1] = TCTI_I2C_HELPER_TPM_STS_REG; - break; - case R_TPM_RID: - addr[1] = TCTI_I2C_HELPER_TPM_RID_REG; - break; - case R_TPM_FIFO_00: - case R_TPM_FIFO_01: - case R_TPM_FIFO_02: - addr[1] = TCTI_I2C_HELPER_TPM_DATA_FIFO_REG; - break; - case W_TPM_STS_00: - case W_TPM_STS_02: - addr[1] = TCTI_I2C_HELPER_TPM_STS_REG; - payload = W_TPM_STS_00_02_DATA; - payload_size = sizeof (W_TPM_STS_00_02_DATA); - break; - case W_TPM_STS_01: - addr[1] = TCTI_I2C_HELPER_TPM_STS_REG; - payload = W_TPM_STS_01_DATA; - payload_size = sizeof (W_TPM_STS_01_DATA); - break; - case W_TPM_CSUM_ENABLE: - addr[1] = TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG; - payload = W_TPM_CSUM_ENABLE_DATA; - payload_size = sizeof (W_TPM_CSUM_ENABLE_DATA); - break; - case W_TPM_FIFO: - addr[1] = TCTI_I2C_HELPER_TPM_DATA_FIFO_REG; - payload = RW_TPM_FIFO_DATA; - payload_size = sizeof (RW_TPM_FIFO_DATA); - break; - default: - assert_true (false); - } + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - switch (m_state.tpm) { - case R_TPM_DID_VID: - case R_TPM_INTERFACE_CAP: - case R_TPM_CSUM_ENABLE: - case R_TPM_CSUM_00: - case R_TPM_CSUM_01: - case R_TPM_ACCESS: - case R_TPM_STS_00: - case R_TPM_STS_01: - case R_TPM_STS_02: - case R_TPM_STS_03: - case R_TPM_STS_04: - case R_TPM_STS_05: - case R_TPM_STS_06: - case R_TPM_STS_07: - case R_TPM_RID: - case R_TPM_FIFO_00: - case R_TPM_FIFO_01: - case R_TPM_FIFO_02: - switch (m_state.i2c) { - case R_I2C_WRITE_0: - assert_int_equal (size, 2); - assert_int_equal (strncmp ((const void *)addr, data, 2), 0); - break; - case R_I2C_WRITE_1: - assert_int_equal (size, 1); - assert_int_equal ((uint8_t)data[0], addr[0] | 0x01); - break; - default: - assert_true (false); - } - break; - case W_TPM_STS_00: - case W_TPM_STS_01: - case W_TPM_STS_02: - case W_TPM_FIFO: - case W_TPM_CSUM_ENABLE: - switch (m_state.i2c) { - case W_I2C_WRITE_0: - assert_int_equal (size, 2); - assert_int_equal (strncmp ((const void *)addr, data, 2), 0); - break; - case W_I2C_WRITE_1: - assert_int_equal (size, payload_size); - assert_int_equal (strncmp ((const char *)payload, data, payload_size), 0); - break; - default: - assert_true (false); - } - break; - default: - assert_true (false); - } + assert_ptr_equal (__wrap_Write, audit->func); + assert_ptr_equal (mpsse, audit->args.write.mpsse); + assert_ptr_equal (size, audit->args.write.size); + assert_true (!memcmp (data, audit->args.write.data, size)); return 0; } @@ -498,11 +261,11 @@ int __wrap_Write (struct mpsse_context *mpsse, char *data, int size) */ int __wrap_GetAck (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - assert_true ((m_state.i2c == R_I2C_GET_ACK_0) || - (m_state.i2c == R_I2C_GET_ACK_1) || - (m_state.i2c == W_I2C_GET_ACK)); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_GetAck, audit->func); + assert_ptr_equal (mpsse, audit->args.getack.mpsse); + return ACK; } @@ -511,9 +274,10 @@ int __wrap_GetAck (struct mpsse_context *mpsse) */ void __wrap_SendAcks (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - assert_true (m_state.i2c == R_I2C_SEND_ACKS); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_SendAcks, audit->func); + assert_ptr_equal (mpsse, audit->args.sendacks.mpsse); } /* @@ -521,72 +285,129 @@ void __wrap_SendAcks (struct mpsse_context *mpsse) */ void __wrap_SendNacks (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - state_machine (); - assert_true (m_state.i2c == R_I2C_SEND_NACKS); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_SendNacks, audit->func); + assert_ptr_equal (mpsse, audit->args.sendnacks.mpsse); +} + +static struct_audit audit_general[] = { + /* Tss2_Tcti_I2c_Ftdi_Init (tcti_ctx, &size, NULL) */ + { .func = __wrap_MPSSE, .args.mpsse = { I2C, ONE_HUNDRED_KHZ, MSB, MPSSE_DUMMY_PTR } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's sleep_us */ + { .func = __wrap_select, .args.select = + { 0, NULL, NULL, NULL, { TIME_US / 1000000, TIME_US % 1000000 } } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's sleep_ms */ + { .func = __wrap_select, .args.select = + { 0, NULL, NULL, NULL, { (TIME_MS * 1000) / 1000000, (TIME_MS * 1000) % 1000000 } } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's start_timeout */ + { .func = __wrap_gettimeofday, .args.gtod = { { 0, 0 }, NULL } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's timeout_expired */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 1, 0 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) }, NULL } }, /* Return a value <= TIME_MS, no timeout occured */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) + 1 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's i2c_write */ + { .func = __wrap_Start, .args.start = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Write, .args.write = + { MPSSE_DUMMY_PTR, (void *)REG_ADDR_W, sizeof (REG_ADDR_W) } }, + { .func = __wrap_GetAck, .args.getack = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Write, .args.write = + { MPSSE_DUMMY_PTR, (void *)TPM2_STARTUP_CMD, sizeof (TPM2_STARTUP_CMD) } }, + { .func = __wrap_Stop, .args.stop = { MPSSE_DUMMY_PTR } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's i2c_read */ + { .func = __wrap_Start, .args.start = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Write, .args.write = + { MPSSE_DUMMY_PTR, (void *)REG_ADDR_W, sizeof (REG_ADDR_W) } }, + { .func = __wrap_GetAck, .args.getack = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Stop, .args.stop = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Start, .args.start = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Write, .args.write = + { MPSSE_DUMMY_PTR, (void *)REG_ADDR_R, sizeof (REG_ADDR_R) } }, + { .func = __wrap_GetAck, .args.getack = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_SendAcks, .args.sendacks = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Read, .args.read = + { MPSSE_DUMMY_PTR, (void *)TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP) - 1 } }, + { .func = __wrap_SendNacks, .args.sendacks = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Read, .args.read = + { MPSSE_DUMMY_PTR, (void *)TPM2_STARTUP_RESP + sizeof (TPM2_STARTUP_RESP) - 1, 1 } }, + { .func = __wrap_Stop, .args.stop = { MPSSE_DUMMY_PTR } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's finalize */ + { .func = __wrap_Close, .args.close = { MPSSE_DUMMY_PTR } }, + + { 0 }, +}; + +TSS2_RC __wrap_Tss2_Tcti_I2c_Helper_Init (TSS2_TCTI_CONTEXT *tcti_context, size_t *size, + TSS2_TCTI_I2C_HELPER_PLATFORM *platform) +{ + void *data; + bool is_expired = false; + uint8_t response[sizeof (TPM2_STARTUP_RESP)] = { 0 }; + + if (tcti_context == NULL) { + *size = sizeof (TSS2_TCTI_I2C_FTDI_TEST_CONTEXT); + return TSS2_RC_SUCCESS; + } + + /* Test TSS2_TCTI_I2C_HELPER_PLATFORM's callbacks */ + + data = platform->user_data; + assert_non_null (data); + + assert_int_equal (platform->sleep_us (data, TIME_US), TSS2_RC_SUCCESS); + assert_int_equal (platform->sleep_ms (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->start_timeout (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_false (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->i2c_write (data, TCTI_I2C_HELPER_REG_TPM_DATA_FIFO, + TPM2_STARTUP_CMD, sizeof (TPM2_STARTUP_CMD)), TSS2_RC_SUCCESS); + assert_int_equal (platform->i2c_read (data, TCTI_I2C_HELPER_REG_TPM_DATA_FIFO, + response, sizeof (response)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM2_STARTUP_RESP, sizeof (response))); + + platform->finalize (data); + + return TSS2_RC_SUCCESS; } -/* - * The test will call Tss2_Tcti_I2c_Ftdi_Init(), - * which will perform several tasks including reading - * the TPM_DID_VID, checking locality, reading TPM_STS, - * and reading TPM_RID before exiting the Init function. - * The TSS2_TCTI_CONTEXT core functions will be tested as well. - * For testing purposes, the TPM responses are hardcoded. - */ static void -tcti_i2c_generic_test (void **state) +tcti_i2c_general_test (void **state) { TSS2_RC rc; size_t size; - uint8_t response[10] = {0}; - TSS2_TCTI_CONTEXT* tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_ctx; - m_state.tpm = 0; - m_state.i2c = 0; + /* Initialize tester context */ + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_general; /* Get requested TCTI context size */ rc = Tss2_Tcti_I2c_Ftdi_Init (NULL, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); /* Allocate TCTI context size */ - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); /* Initialize TCTI context */ rc = Tss2_Tcti_I2c_Ftdi_Init (tcti_ctx, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); - /* Verify the TCTI core functions */ - assert_int_equal (TSS2_TCTI_MAGIC (tcti_ctx), TCTI_I2C_HELPER_MAGIC); - assert_int_equal (TSS2_TCTI_VERSION (tcti_ctx), TCTI_VERSION); - assert_int_equal ( - TSS2_TCTI_TRANSMIT (tcti_ctx) ( - tcti_ctx, sizeof (RW_TPM_FIFO_DATA), RW_TPM_FIFO_DATA - ), - TSS2_RC_SUCCESS - ); - size = 0; - assert_int_equal ( - TSS2_TCTI_RECEIVE (tcti_ctx) ( - tcti_ctx, &size, NULL, 200 - ), - TSS2_RC_SUCCESS - ); - assert_int_equal (size, sizeof (RW_TPM_FIFO_DATA)); - assert_int_equal ( - TSS2_TCTI_RECEIVE (tcti_ctx) ( - tcti_ctx, &size, response, 200 - ), - TSS2_RC_SUCCESS - ); - assert_int_equal (TSS2_TCTI_CANCEL (tcti_ctx) (NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); - assert_int_equal (TSS2_TCTI_GET_POLL_HANDLES (tcti_ctx) (NULL, NULL, NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); - assert_int_equal (TSS2_TCTI_SET_LOCALITY (tcti_ctx) (NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); - assert_int_equal (TSS2_TCTI_MAKE_STICKY (tcti_ctx) (NULL, NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); - /* Clean up */ - TSS2_TCTI_FINALIZE (tcti_ctx) (tcti_ctx); free (tcti_ctx); } @@ -595,7 +416,8 @@ main (int argc, char *argv[]) { const struct CMUnitTest tests[] = { - cmocka_unit_test (tcti_i2c_generic_test), + cmocka_unit_test (tcti_i2c_general_test), }; + return cmocka_run_group_tests (tests, NULL, NULL); } diff --git a/test/unit/tcti-i2c-helper.c b/test/unit/tcti-i2c-helper.c index a57d741a7..210a5c150 100644 --- a/test/unit/tcti-i2c-helper.c +++ b/test/unit/tcti-i2c-helper.c @@ -32,241 +32,357 @@ #include "../helper/cmocka_all.h" // for assert_int_equal, assert_stri... #include "tss2-tcti/tcti-common.h" // for TCTI_STATE_RECEIVE, TCTI_VERSION +#include "tss2-tcti/tcti-helper-common.h" #include "tss2-tcti/tcti-i2c-helper.h" // for TCTI_I2C_HELPER_TPM_STS_REG #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC, TSS... #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_... #include "tss2_tcti_i2c_helper.h" // for TSS2_TCTI_I2C_HELPER_PLATFORM -#define DUMMY_PLATFORM_DATA "my platform data" - -typedef enum { - /* Tss2_Tcti_I2c_Helper_Init () */ - R_TPM_DID_VID = 0, - R_TPM_INTERFACE_CAP, - R_TPM_ACCESS, - R_TPM_CSUM_ENABLE, - W_TPM_CSUM_ENABLE, - R_TPM_STS_00, - R_TPM_RID, - /* TSS2_TCTI_TRANSMIT () */ - W_TPM_STS_00, - R_TPM_STS_01, - R_TPM_STS_02, - W_TPM_FIFO, - R_TPM_CSUM_00, - W_TPM_STS_01, - /* TSS2_TCTI_RECEIVE (); is_timeout_blocked == true */ - R_TPM_STS_03, - R_TPM_STS_04, - R_TPM_FIFO_00, - R_TPM_STS_05, - R_TPM_FIFO_01, - R_TPM_STS_06, - R_TPM_FIFO_02, - R_TPM_STS_07, - R_TPM_CSUM_01, - W_TPM_STS_02, - /* TSS2_TCTI_RECEIVE (); is_timeout_blocked == false */ - R_TPM_STS_08 -} tpm_state_t; - -static const uint8_t R_TPM_DID_VID_DATA[] = {0xd1, 0x15, 0x1b, 0x00}; -static const uint8_t R_TPM_INTERFACE_CAP_DATA[] = {0x82, 0x00, 0xe0, 0x1a}; -static const uint8_t R_TPM_ACCESS_DATA[] = {0xa1}; -static const uint8_t R_TPM_CSUM_ENABLE_DATA[] = {0x00}; -static const uint8_t R_TPM_RID_DATA[] = {0x00}; -static const uint8_t R_TPM_STS_00_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; -static const uint8_t R_TPM_STS_02_05_DATA[] = {0x00, 0x40, 0x00, 0x00}; -static const uint8_t R_TPM_STS_04_06_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID | TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL, - 0x00, 0x00, 0x00}; -static const uint8_t R_TPM_CSUM_DATA[] = {0xf7, 0x4b}; /* CRC-16 (KERMIT) of RW_TPM_FIFO_DATA */ -static const uint8_t R_TPM_STS_03_07_08_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID, 0x00, 0x00, 0x00}; -static const uint8_t W_TPM_STS_00_02_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; -static const uint8_t W_TPM_STS_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_GO, 0x00, 0x00, 0x00}; -static const uint8_t W_TPM_CSUM_ENABLE_DATA[] = {0x01}; -static const uint8_t RW_TPM_FIFO_DATA[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xde, 0xad, 0xbe, 0xef}; - -static tpm_state_t tpm_state; -static bool is_timeout_blocked; +/* + * The goal is to verify the I2C communication protocol implementation by checking + * the order in which platform functions are invoked when using functions in the + * TCTI_HELPER_COMMON_CONTEXT (such as sleep_ms, start_timeout, timeout_expired, + * read_reg, and write_reg). + * + * The audit arrays (e.g., audit_general, audit_write_reg) contain this + * information. Each entry specifies the expected platform function to be invoked, + * the command to be received, or the response to be written back in a specific order. + * The tester_context.audit_step (audit array index) variable keeps track of the + * sequence of these operations. + */ -TSS2_RC -platform_sleep_us (void* user_data, int32_t microseconds) +typedef struct { + void *func; + uint8_t reg_addr; + char *data; + union { + size_t size; /* for platform_i_transfer */ + int us; /* for platform_sleep_us */ + int ms; /* for platform_sleep_ms, platform_start_timeout */ + bool is_expired; /* for platform_timeout_expired */ + } u; +} struct_audit; + +typedef struct { + bool with_waitstate; + int audit_step; + struct_audit *audit; +} tester_context; + +static const unsigned char TPM_DID_VID[] = { 0xD1, 0x15, 0x1B, 0x00 }; +static const unsigned char TPM_RID[] = { 0x55 }; +static const unsigned char TPM_ACCESS[] = { 0x80 }; /* tpmRegValidSts = 1 */ +static const unsigned char TPM_STS_VALID[] = { 0x80, 0x00, 0x00, 0x00 }; /* stsValid = 1 */ +static const unsigned char TPM_STS_GO[] = { 0x20, 0x00, 0x00, 0x00 }; /* tpmGo = 1 */ + +static const unsigned char TPM2_STARTUP_CMD[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static const unsigned char TPM2_STARTUP_RESP[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00 }; + +TSS2_RC platform_sleep_ms (void *user_data, int32_t milliseconds) { - (void) microseconds; - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_sleep_ms, ctx->audit[i].func); + assert_int_equal (milliseconds, ctx->audit[i].u.ms); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } TSS2_RC -platform_sleep_ms (void* user_data, int32_t milliseconds) +platform_sleep_us (void *user_data, int32_t microseconds) { - (void) milliseconds; - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_sleep_us, ctx->audit[i].func); + assert_int_equal (microseconds, ctx->audit[i].u.us); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } TSS2_RC -platform_start_timeout (void* user_data, int32_t milliseconds) +platform_start_timeout (void *user_data, int32_t milliseconds) { - (void) milliseconds; - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_start_timeout, ctx->audit[i].func); + assert_int_equal (milliseconds, ctx->audit[i].u.ms); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } TSS2_RC -platform_timeout_expired (void* user_data, bool *is_timeout_expired) +platform_timeout_expired (void *user_data, bool *is_timeout_expired) { - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - *is_timeout_expired = (is_timeout_blocked) ? false : true; + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_timeout_expired, ctx->audit[i].func); + *is_timeout_expired = ctx->audit[i].u.is_expired; + ctx->audit_step++; + return TSS2_RC_SUCCESS; } TSS2_RC platform_i2c_write (void *user_data, uint8_t reg_addr, const void *data, size_t cnt) { - size_t data_len = 0; + tester_context *ctx = (tester_context *)user_data; + int i; - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - assert_non_null (data); - - switch (tpm_state++) { - case W_TPM_CSUM_ENABLE: - data_len = sizeof (W_TPM_CSUM_ENABLE_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG); - assert_int_equal (strncmp ((const void *)W_TPM_CSUM_ENABLE_DATA, data, data_len), 0); - break; - case W_TPM_STS_00: - case W_TPM_STS_02: - data_len = sizeof (W_TPM_STS_00_02_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); - assert_int_equal (strncmp ((const void *)W_TPM_STS_00_02_DATA, data, data_len), 0); - break; - case W_TPM_STS_01: - data_len = sizeof (W_TPM_STS_01_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); - assert_int_equal (strncmp ((const void *)W_TPM_STS_01_DATA, data, data_len), 0); - break; - case W_TPM_FIFO: - data_len = sizeof (RW_TPM_FIFO_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); - assert_int_equal (strncmp ((const void *)RW_TPM_FIFO_DATA, data, data_len), 0); - break; - default: - assert_true (false); - } + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_i2c_write, ctx->audit[i].func); + assert_int_equal (cnt, ctx->audit[i].u.size); + assert_int_equal (reg_addr, ctx->audit[i].reg_addr); - assert_int_equal (cnt, data_len); + assert_non_null (data); + assert_true (!memcmp (data, ctx->audit[i].data, cnt)); + ctx->audit_step++; return TSS2_RC_SUCCESS; } TSS2_RC -platform_i2c_read (void* user_data, uint8_t reg_addr, void *data, size_t cnt) +platform_i2c_read (void *user_data, uint8_t reg_addr, void *data, size_t cnt) { - size_t data_len = 0; + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_i2c_read, ctx->audit[i].func); + assert_int_equal (cnt, ctx->audit[i].u.size); + assert_int_equal (reg_addr, ctx->audit[i].reg_addr); - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); assert_non_null (data); + memcpy (data, ctx->audit[i].data, cnt); + ctx->audit_step++; - switch (tpm_state++) { - case R_TPM_DID_VID: - data_len = sizeof (R_TPM_DID_VID_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DID_VID_REG); - memcpy (data, R_TPM_DID_VID_DATA, data_len); - break; - case R_TPM_INTERFACE_CAP: - data_len = sizeof (R_TPM_INTERFACE_CAP_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG); - memcpy (data, R_TPM_INTERFACE_CAP_DATA, data_len); - break; - case R_TPM_ACCESS: - data_len = sizeof (R_TPM_ACCESS_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_ACCESS_REG); - memcpy (data, R_TPM_ACCESS_DATA, data_len); - break; - case R_TPM_CSUM_ENABLE: - data_len = sizeof (R_TPM_CSUM_ENABLE_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG); - memcpy (data, R_TPM_CSUM_ENABLE_DATA, data_len); - break; - case R_TPM_RID: - data_len = sizeof (R_TPM_RID_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_RID_REG); - memcpy (data, R_TPM_RID_DATA, data_len); - break; - case R_TPM_STS_00: - case R_TPM_STS_01: - data_len = sizeof (R_TPM_STS_00_01_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); - memcpy (data, R_TPM_STS_00_01_DATA, data_len); - break; - case R_TPM_STS_02: - case R_TPM_STS_05: - data_len = sizeof (R_TPM_STS_02_05_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); - memcpy (data, R_TPM_STS_02_05_DATA, data_len); - break; - case R_TPM_STS_04: - case R_TPM_STS_06: - data_len = sizeof (R_TPM_STS_04_06_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); - memcpy (data, R_TPM_STS_04_06_DATA, data_len); - break; - case R_TPM_STS_03: - case R_TPM_STS_07: - case R_TPM_STS_08: - data_len = sizeof (R_TPM_STS_03_07_08_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); - memcpy (data, R_TPM_STS_03_07_08_DATA, data_len); - break; - case R_TPM_FIFO_00: - data_len = TCTI_I2C_HELPER_RESP_HEADER_SIZE; - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); - memcpy (data, RW_TPM_FIFO_DATA, data_len); - break; - case R_TPM_FIFO_01: - data_len = sizeof (RW_TPM_FIFO_DATA) - 1 - TCTI_I2C_HELPER_RESP_HEADER_SIZE; - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); - memcpy (data, RW_TPM_FIFO_DATA + TCTI_I2C_HELPER_RESP_HEADER_SIZE, data_len); - break; - case R_TPM_FIFO_02: - data_len = 1; - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); - memcpy (data, RW_TPM_FIFO_DATA + sizeof (RW_TPM_FIFO_DATA) - 1, 1); - break; - case R_TPM_CSUM_00: - case R_TPM_CSUM_01: - data_len = sizeof (R_TPM_CSUM_DATA); - assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_CSUM_REG); - memcpy (data, R_TPM_CSUM_DATA, data_len); - break; - default: - assert_true (false); - } + return TSS2_RC_SUCCESS; +} + +void +platform_finalize (void *user_data) +{ + assert_non_null (user_data); + free (user_data); +} - assert_int_equal (cnt, data_len); +static struct_audit audit_general[] = { + { platform_sleep_ms, 0, NULL, POLLING_INTERVAL_MS }, + { platform_start_timeout, 0, NULL, TIMEOUT_A }, + { platform_timeout_expired, 0, NULL, true }, + { 0 }, +}; + +static struct_audit audit_write_reg[] = { + { platform_i2c_write, TCTI_I2C_HELPER_REG_TPM_DID_VID, (char *)TPM_DID_VID, sizeof (TPM_DID_VID) }, + { platform_i2c_write, TCTI_I2C_HELPER_REG_TPM_RID, (char *)TPM_RID, sizeof (TPM_RID) }, + { platform_i2c_write, TCTI_I2C_HELPER_REG_TPM_ACCESS, (char *)TPM_ACCESS, sizeof (TPM_ACCESS) }, + { platform_i2c_write, TCTI_I2C_HELPER_REG_TPM_STS, (char *)TPM_STS_GO, sizeof (TPM_STS_GO) }, + { platform_i2c_write, TCTI_I2C_HELPER_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_CMD, sizeof (TPM2_STARTUP_CMD) }, + { 0 }, +}; + +static struct_audit audit_read_reg[] = { + { platform_i2c_read, TCTI_I2C_HELPER_REG_TPM_DID_VID, (char *)TPM_DID_VID, sizeof (TPM_DID_VID) }, + { platform_i2c_read, TCTI_I2C_HELPER_REG_TPM_RID, (char *)TPM_RID, sizeof (TPM_RID) }, + { platform_i2c_read, TCTI_I2C_HELPER_REG_TPM_ACCESS, (char *)TPM_ACCESS, sizeof (TPM_ACCESS) }, + { platform_i2c_read, TCTI_I2C_HELPER_REG_TPM_STS, (char *)TPM_STS_VALID, sizeof (TPM_STS_VALID) }, + { platform_i2c_read, TCTI_I2C_HELPER_REG_TPM_DATA_FIFO, (char *)TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP) }, + { 0 }, +}; + +static struct_audit audit_post_init[] = { + { 0 }, +}; + +static struct_audit audit_post_transmit[] = { + { 0 }, +}; + +static struct_audit audit_post_receive[] = { + { 0 }, +}; + +TSS2_RC __wrap_Tcti_Helper_Common_Init (TCTI_HELPER_COMMON_CONTEXT *ctx, bool is_i2c) +{ + (void) is_i2c; + bool is_timeout_expired = false; + uint8_t response[128] = { 0 }; + TSS2_TCTI_I2C_HELPER_CONTEXT *i2c_helper_ctx; + TSS2_TCTI_I2C_HELPER_PLATFORM *i2c_helper_platform; + tester_context *tester_ctx; + + assert_non_null (ctx); + assert_non_null (ctx->sleep_ms); + assert_non_null (ctx->start_timeout); + assert_non_null (ctx->timeout_expired); + assert_non_null (ctx->write_reg); + assert_non_null (ctx->read_reg); + + i2c_helper_ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *)ctx->data; + assert_non_null (i2c_helper_ctx); + + i2c_helper_platform = &i2c_helper_ctx->platform; + assert_non_null (i2c_helper_platform); + + tester_ctx = (tester_context *)i2c_helper_platform->user_data; + assert_non_null (tester_ctx); + + /* Testing TCTI_HELPER_COMMON_CONTEXT's sleep_ms, start_timout, timeout_expired */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_general; + + assert_int_equal (ctx->sleep_ms (ctx->data, POLLING_INTERVAL_MS), TSS2_RC_SUCCESS); + assert_int_equal (ctx->start_timeout (ctx->data, TIMEOUT_A), TSS2_RC_SUCCESS); + assert_int_equal (ctx->timeout_expired (ctx->data, &is_timeout_expired), TSS2_RC_SUCCESS); + assert_true (is_timeout_expired); + + /* Testing TCTI_HELPER_COMMON_CONTEXT's write_reg (TPM_DID_VID, TPM_RID, TPM_ACCESS, TPM_STS, TPM_DATA_FIFO) */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_write_reg; + + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DID_VID, + TPM_DID_VID, sizeof (TPM_DID_VID)), TSS2_RC_SUCCESS); + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_RID, + TPM_RID, sizeof (TPM_RID)), TSS2_RC_SUCCESS); + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_ACCESS, + TPM_ACCESS, sizeof (TPM_ACCESS)), TSS2_RC_SUCCESS); + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_STS, + TPM_STS_GO, sizeof (TPM_STS_GO)), TSS2_RC_SUCCESS); + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + TPM2_STARTUP_CMD, sizeof (TPM2_STARTUP_CMD)), TSS2_RC_SUCCESS); + + /* Testing TCTI_HELPER_COMMON_CONTEXT's read_reg (TPM_DID_VID, TPM_RID, TPM_ACCESS, TPM_STS, TPM_DATA_FIFO) */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_read_reg; + + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DID_VID, + response, sizeof (TPM_DID_VID)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM_DID_VID, sizeof (TPM_DID_VID))); + memset (response, 0, sizeof (response)); + + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_RID, + response, sizeof (TPM_RID)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM_RID, sizeof (TPM_RID))); + memset (response, 0, sizeof (response)); + + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_ACCESS, + response, sizeof (TPM_ACCESS)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM_ACCESS, sizeof (TPM_ACCESS))); + memset (response, 0, sizeof (response)); + + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_STS, + response, sizeof (TPM_STS_VALID)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM_STS_VALID, sizeof (TPM_STS_VALID))); + memset (response, 0, sizeof (response)); + + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + response, sizeof (TPM2_STARTUP_RESP)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP))); + memset (response, 0, sizeof (response)); + + /* Post-init test */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_post_init; return TSS2_RC_SUCCESS; } -void -platform_finalize (void* user_data) +TSS2_RC __wrap_Tcti_Helper_Common_Transmit (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t size, + const uint8_t *cmd_buf) { - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - free(user_data); + TSS2_TCTI_I2C_HELPER_CONTEXT *i2c_helper_ctx; + TSS2_TCTI_I2C_HELPER_PLATFORM *i2c_helper_platform; + tester_context *tester_ctx; + + assert_non_null (ctx); + assert_int_equal (size, sizeof (TPM2_STARTUP_CMD)); + assert_ptr_equal (cmd_buf, TPM2_STARTUP_CMD); + + i2c_helper_ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *)ctx->data; + assert_non_null (i2c_helper_ctx); + + i2c_helper_platform = &i2c_helper_ctx->platform; + assert_non_null (i2c_helper_platform); + + tester_ctx = (tester_context *)i2c_helper_platform->user_data; + assert_non_null (tester_ctx); + + /* Post-transmit test */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_post_transmit; + + return TSS2_RC_SUCCESS; +} + +TSS2_RC __wrap_Tcti_Helper_Common_Receive (TCTI_HELPER_COMMON_CONTEXT *ctx, + size_t *response_size, unsigned char *response_buffer, int32_t timeout) +{ + TSS2_TCTI_I2C_HELPER_CONTEXT *i2c_helper_ctx; + TSS2_TCTI_I2C_HELPER_PLATFORM *i2c_helper_platform; + tester_context *tester_ctx; + + assert_int_equal (timeout, TIMEOUT_A); + assert_non_null (ctx); + assert_non_null (response_size); + + if (!response_buffer) { + *response_size = sizeof (TPM2_STARTUP_RESP); + } else { + assert_int_equal (*response_size, sizeof (TPM2_STARTUP_RESP)); + memcpy (response_buffer, TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP)); + } + + i2c_helper_ctx = (TSS2_TCTI_I2C_HELPER_CONTEXT *)ctx->data; + assert_non_null (i2c_helper_ctx); + + i2c_helper_platform = &i2c_helper_ctx->platform; + assert_non_null (i2c_helper_platform); + + tester_ctx = (tester_context *)i2c_helper_platform->user_data; + assert_non_null (tester_ctx); + + /* Post-receive test */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_post_receive; + + return TSS2_RC_SUCCESS; } -TSS2_TCTI_I2C_HELPER_PLATFORM +static TSS2_TCTI_I2C_HELPER_PLATFORM create_tcti_i2c_helper_platform (void) { - TSS2_TCTI_I2C_HELPER_PLATFORM platform = {}; + TSS2_TCTI_I2C_HELPER_PLATFORM platform = { 0 }; - // Create dummy platform user data - char *platform_data = malloc (sizeof (DUMMY_PLATFORM_DATA)); - memcpy (platform_data, DUMMY_PLATFORM_DATA, sizeof (DUMMY_PLATFORM_DATA)); + /* Create tester context */ + tester_context *tester_ctx = calloc (1, sizeof (tester_context)); - // Create TCTI I2C platform struct with custom platform methods - platform.user_data = platform_data; + /* Create TCTI I2C platform struct with custom platform methods */ + platform.user_data = (void *)tester_ctx; platform.sleep_us = platform_sleep_us; platform.sleep_ms = platform_sleep_ms; platform.start_timeout = platform_start_timeout; @@ -278,32 +394,21 @@ create_tcti_i2c_helper_platform (void) return platform; } -/* - * The test will call Tss2_Tcti_I2c_Helper_Init(), - * which will perform several tasks including reading - * the TPM_DID_VID, checking locality, reading TPM_STS, - * and reading TPM_RID before exiting the Init function. - * The TSS2_TCTI_CONTEXT core functions will be tested as well. - * For testing purposes, the TPM responses are hardcoded. - */ static void tcti_i2c_generic_test (void **state) { TSS2_RC rc; size_t size; - uint8_t response[10] = {0}; - - TSS2_TCTI_I2C_HELPER_PLATFORM tcti_platform = {}; - TSS2_TCTI_CONTEXT* tcti_ctx; - - tpm_state = R_TPM_DID_VID; + uint8_t response[sizeof (TPM2_STARTUP_RESP)] = { 0 }; + TSS2_TCTI_I2C_HELPER_PLATFORM tcti_platform = { 0 }; + TSS2_TCTI_CONTEXT *tcti_ctx; /* Get requested TCTI context size */ rc = Tss2_Tcti_I2c_Helper_Init (NULL, &size, &tcti_platform); assert_int_equal (rc, TSS2_RC_SUCCESS); /* Allocate TCTI context size */ - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); /* Initialize TCTI context */ @@ -312,45 +417,35 @@ tcti_i2c_generic_test (void **state) assert_int_equal (rc, TSS2_RC_SUCCESS); /* Verify the TCTI core functions */ + assert_int_equal (TSS2_TCTI_MAGIC (tcti_ctx), TCTI_I2C_HELPER_MAGIC); assert_int_equal (TSS2_TCTI_VERSION (tcti_ctx), TCTI_VERSION); assert_int_equal ( TSS2_TCTI_TRANSMIT (tcti_ctx) ( - tcti_ctx, sizeof (RW_TPM_FIFO_DATA), RW_TPM_FIFO_DATA + tcti_ctx, sizeof (TPM2_STARTUP_CMD), TPM2_STARTUP_CMD ), TSS2_RC_SUCCESS ); size = 0; - is_timeout_blocked = true; assert_int_equal ( TSS2_TCTI_RECEIVE (tcti_ctx) ( - tcti_ctx, &size, NULL, 200 + tcti_ctx, &size, NULL, TIMEOUT_A ), TSS2_RC_SUCCESS ); - assert_int_equal (size, sizeof (RW_TPM_FIFO_DATA)); + assert_int_equal (size, sizeof (TPM2_STARTUP_RESP)); assert_int_equal ( TSS2_TCTI_RECEIVE (tcti_ctx) ( - tcti_ctx, &size, response, 200 + tcti_ctx, &size, response, TIMEOUT_A ), TSS2_RC_SUCCESS ); + assert_true (!memcmp (response, TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP))); assert_int_equal (TSS2_TCTI_CANCEL (tcti_ctx) (NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); assert_int_equal (TSS2_TCTI_GET_POLL_HANDLES (tcti_ctx) (NULL, NULL, NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); assert_int_equal (TSS2_TCTI_SET_LOCALITY (tcti_ctx) (NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); assert_int_equal (TSS2_TCTI_MAKE_STICKY (tcti_ctx) (NULL, NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); - /* Test the behavior of TSS2_TCTI_RECEIVE() in a timeout condition */ - size = 0; - is_timeout_blocked = false; - ((TSS2_TCTI_I2C_HELPER_CONTEXT*)tcti_ctx)->common.state = TCTI_STATE_RECEIVE; - assert_int_equal ( - TSS2_TCTI_RECEIVE (tcti_ctx) ( - tcti_ctx, &size, NULL, 200 - ), - TSS2_TCTI_RC_TRY_AGAIN - ); - /* Clean up */ TSS2_TCTI_FINALIZE (tcti_ctx) (tcti_ctx); free (tcti_ctx); @@ -362,14 +457,14 @@ tcti_i2c_bad_callbacks_test (void **state) TSS2_RC rc; size_t size; TSS2_TCTI_I2C_HELPER_PLATFORM tcti_platform = {}; - TSS2_TCTI_CONTEXT* tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_ctx; /* Get requested TCTI context size */ rc = Tss2_Tcti_I2c_Helper_Init (NULL, &size, &tcti_platform); assert_int_equal (rc, TSS2_RC_SUCCESS); /* Allocate TCTI context size */ - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); /* Initialize TCTI context */ diff --git a/test/unit/tcti-spi-ftdi.c b/test/unit/tcti-spi-ftdi.c index 2f123ab4f..31b9afdcb 100644 --- a/test/unit/tcti-spi-ftdi.c +++ b/test/unit/tcti-spi-ftdi.c @@ -16,28 +16,89 @@ #include "../helper/cmocka_all.h" // for assert_int_equal, assert_ptr_equal #include "tss2-tcti/mpsse/mpsse.h" // for MPSSE_OK, GPIOL0, FIFTEEN_MHZ, MSB +#include "tss2-tcti/tcti-common.h" // for TCTI_VERSION +#include "tss2-tcti/tcti-spi-ftdi.h" +#include "tss2-tcti/tcti-spi-helper.h" #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT, TSS2_TCTI_FINA... #include "tss2_tcti_spi_ftdi.h" // for Tss2_Tcti_Spi_Ftdi_Init -struct timeval; -struct timezone; - -typedef enum { - TPM_DID_VID = 0, - TPM_ACCESS, - TPM_STS_CMD_NOT_READY, - TPM_STS_CMD_READY, - TPM_RID, -} tpm_state_t; - -static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; -static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; -static const unsigned char TPM_STS_0_CMD_NOT_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00}; -static const unsigned char TPM_STS_0_CMD_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; -static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; +/* + * The goal is to verify the FTDI SPI implementation by checking + * the order in which libftdi functions are invoked when using functions in + * the TSS2_TCTI_SPI_HELPER_PLATFORM (e.g., sleep_ms, start_timeout, + * timeout_expired, spi_transfer). + + * The audit arrays (e.g., audit_general) contain this information. Each + * entry specifies the expected libftdi function to be invoked, the command + * to be received, or the response to be written back in a specific order. + * The tester_context.audit_step (audit array index) variable tracks the + * sequence of these operations. + */ -static struct mpsse_context *_mpsse; +#define MPSSE_DUMMY_PTR ((void *)0xA5A5A5A5) +#define TIME_MS 450 + +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TSS2_TCTI_SPI_HELPER_PLATFORM platform; +} TSS2_TCTI_SPI_FTDI_TEST_CONTEXT; + +typedef struct { + int nfds; + void *readfds; + void *writefds; + void *exceptfds; + struct timeval timeout; +} fn_select; + +typedef struct { + struct timeval tv; + void *tz; +} fn_gettimeofday; + +typedef struct { + enum modes mode; + int freq; + int endianess; + void *ret; +} fn_mpsse; + +typedef struct { + void *mpsse; +} fn_start, fn_stop, + fn_close; + +typedef struct { + void *mpsse; + void *mosi; + void *miso; + size_t size; +} fn_transfer; + +typedef struct { + void *func; + union { + fn_select select; + fn_gettimeofday gtod; + fn_mpsse mpsse; + fn_start start; + fn_stop stop; + fn_close close; + fn_transfer transfer; + } args; +} struct_audit; + +typedef struct { + int audit_step; + struct_audit *audit; +} tester_context; + +static tester_context tester_ctx; +static const unsigned char TPM2_STARTUP_CMD_MOSI[] = + { 0x0B, 0xD4, 0x00, 0x24, 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static const unsigned char TPM2_STARTUP_CMD_MISO[] = + { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* * Mock function select @@ -47,12 +108,15 @@ int __wrap_select (int nfds, fd_set *readfds, fd_set *exceptfds, struct timeval *timeout) { + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - assert_int_equal (nfds, 0); - assert_null (readfds); - assert_null (writefds); - assert_null (exceptfds); - assert_non_null (timeout); + assert_ptr_equal (__wrap_select, audit->func); + assert_int_equal (nfds, audit->args.select.nfds); + assert_int_equal (readfds, audit->args.select.readfds); + assert_int_equal (writefds, audit->args.select.writefds); + assert_int_equal (exceptfds, audit->args.select.exceptfds); + assert_int_equal (timeout->tv_sec, audit->args.select.timeout.tv_sec); + assert_int_equal (timeout->tv_usec, audit->args.select.timeout.tv_usec); return 0; } @@ -63,11 +127,14 @@ int __wrap_select (int nfds, fd_set *readfds, int __wrap_gettimeofday (struct timeval *tv, struct timezone *tz) { - assert_null (tz); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_gettimeofday, audit->func); assert_non_null (tv); + assert_ptr_equal (tz, audit->args.gtod.tz); - tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_sec = audit->args.gtod.tv.tv_sec; + tv->tv_usec = audit->args.gtod.tv.tv_usec; return 0; } @@ -77,44 +144,52 @@ int __wrap_gettimeofday (struct timeval *tv, */ struct mpsse_context *__wrap_MPSSE (enum modes mode, int freq, int endianess) { - assert_int_equal (mode, SPI0); - assert_int_equal (freq, FIFTEEN_MHZ); - assert_int_equal (endianess, MSB); + struct mpsse_context *ret; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - _mpsse = malloc (sizeof (struct mpsse_context)); + assert_ptr_equal (__wrap_MPSSE, audit->func); + assert_int_equal (mode, audit->args.mpsse.mode); + assert_int_equal (freq, audit->args.mpsse.freq); + assert_int_equal (endianess, audit->args.mpsse.endianess); + ret = (struct mpsse_context *)audit->args.mpsse.ret; - return _mpsse; + return ret; } /* - * Mock function PinLow + * Mock function Start */ -int __wrap_PinLow (struct mpsse_context *mpsse, int pin) +int __wrap_Start (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - assert_int_equal (pin, GPIOL0); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_Start, audit->func); + assert_ptr_equal (mpsse, audit->args.start.mpsse); return MPSSE_OK; } /* - * Mock function PinHigh + * Mock function Stop */ -int __wrap_PinHigh (struct mpsse_context *mpsse, int pin) +int __wrap_Stop (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - assert_int_equal (pin, GPIOL0); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + assert_ptr_equal (__wrap_Stop, audit->func); + assert_ptr_equal (mpsse, audit->args.stop.mpsse); return MPSSE_OK; } /* - * Mock function Start + * Mock function Close */ -int __wrap_Start (struct mpsse_context *mpsse) +void __wrap_Close (struct mpsse_context *mpsse) { - assert_ptr_equal (mpsse, _mpsse); - return MPSSE_OK; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_Close, audit->func); + assert_ptr_equal (mpsse, audit->args.close.mpsse); } /* @@ -122,94 +197,109 @@ int __wrap_Start (struct mpsse_context *mpsse) */ char *__wrap_Transfer (struct mpsse_context *mpsse, char *data, int size) { + char *ptr; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - static tpm_state_t tpm_state = TPM_DID_VID; - char *ret = malloc (size); - - assert_non_null (ret); - assert_ptr_equal (mpsse, _mpsse); - - switch (tpm_state++) { - case TPM_DID_VID: - assert_int_equal (size, 8); - assert_true (!memcmp (data, TPM_DID_VID_0, 4)); - memcpy (ret, TPM_DID_VID_0, sizeof (TPM_DID_VID_0)); - break; - case TPM_ACCESS: - assert_int_equal (size, 5); - assert_true (!memcmp (data, TPM_ACCESS_0, 4)); - memcpy (ret, TPM_ACCESS_0, sizeof (TPM_ACCESS_0)); - break; - case TPM_STS_CMD_NOT_READY: - assert_int_equal (size, 8); - assert_true (!memcmp (data, TPM_STS_0_CMD_NOT_READY, 4)); - memcpy (ret, TPM_STS_0_CMD_NOT_READY, sizeof (TPM_STS_0_CMD_NOT_READY)); - break; - case TPM_STS_CMD_READY: - assert_int_equal (size, 8); - assert_true (!memcmp (data, TPM_STS_0_CMD_READY, 4)); - memcpy (ret, TPM_STS_0_CMD_READY, sizeof (TPM_STS_0_CMD_READY)); - break; - case TPM_RID: - assert_int_equal (size, 5); - assert_true (!memcmp (data, TPM_RID_0, 4)); - memcpy (ret, TPM_RID_0, sizeof (TPM_RID_0)); - break; - default: - assert_true (false); - } + assert_ptr_equal (__wrap_Transfer, audit->func); + assert_ptr_equal (mpsse, audit->args.transfer.mpsse); + assert_ptr_equal (size, audit->args.transfer.size); + assert_true (!memcmp (data, audit->args.transfer.mosi, size)); - return ret; -} + ptr = calloc (1, size); + assert_non_null (ptr); + memcpy (ptr, audit->args.transfer.miso, size); -/* - * Mock function Stop - */ -int __wrap_Stop (struct mpsse_context *mpsse) -{ - assert_ptr_equal (mpsse, _mpsse); - return MPSSE_OK; + return ptr; } -/* - * Mock function Close - */ -void __wrap_Close (struct mpsse_context *mpsse) +static struct_audit audit_general[] = { + /* Tss2_Tcti_Spi_Ftdi_Init (tcti_ctx, &size, NULL) */ + { .func = __wrap_MPSSE, .args.mpsse = { SPI0, FIFTEEN_MHZ, MSB, MPSSE_DUMMY_PTR } }, + + /* TSS2_TCTI_SPI_HELPER_PLATFORM's sleep_ms */ + { .func = __wrap_select, .args.select = + { 0, NULL, NULL, NULL, { (TIME_MS * 1000) / 1000000, (TIME_MS * 1000) % 1000000 } } }, + + /* TSS2_TCTI_SPI_HELPER_PLATFORM's start_timeout */ + { .func = __wrap_gettimeofday, .args.gtod = { { 0, 0 }, NULL } }, + + /* TSS2_TCTI_SPI_HELPER_PLATFORM's timeout_expired */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 1, 0 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) }, NULL } }, /* Return a value <= TIME_MS, no timeout occured */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) + 1 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + + /* TSS2_TCTI_SPI_HELPER_PLATFORM's transfer */ + { .func = __wrap_Start, .args.start = { MPSSE_DUMMY_PTR } }, + { .func = __wrap_Transfer, .args.transfer = + { MPSSE_DUMMY_PTR, (void *)TPM2_STARTUP_CMD_MOSI, (void *)TPM2_STARTUP_CMD_MISO, sizeof (TPM2_STARTUP_CMD_MISO) } }, + { .func = __wrap_Stop, .args.stop = { MPSSE_DUMMY_PTR } }, + + /* TSS2_TCTI_SPI_HELPER_PLATFORM's finalize */ + { .func = __wrap_Close, .args.close = { MPSSE_DUMMY_PTR } }, + + { 0 }, +}; + +TSS2_RC __wrap_Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT *tcti_context, size_t *size, TSS2_TCTI_SPI_HELPER_PLATFORM *platform) { - assert_ptr_equal (mpsse, _mpsse); - free (_mpsse); - _mpsse = NULL; + void *data; + bool is_expired = false; + uint8_t response[sizeof (TPM2_STARTUP_CMD_MISO)] = { 0 }; + + if (tcti_context == NULL) { + *size = sizeof (TSS2_TCTI_SPI_FTDI_TEST_CONTEXT); + return TSS2_RC_SUCCESS; + } + + /* Test TSS2_TCTI_SPI_HELPER_PLATFORM's callbacks */ + + data = platform->user_data; + assert_non_null (data); + + assert_int_equal (platform->sleep_ms (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->start_timeout (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_false (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->spi_transfer (data, TPM2_STARTUP_CMD_MOSI, response, + sizeof (response)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM2_STARTUP_CMD_MISO, sizeof (response))); + + platform->finalize (data); + + return TSS2_RC_SUCCESS; } -/* - * The test will invoke Tss2_Tcti_Spi_Ftdi_Init() and subsequently - * it will start reading TPM_DID_VID, claim locality, read TPM_STS, - * and finally read TPM_RID before exiting the Init function. - * For testing purpose, the TPM responses are hardcoded. - * SPI wait state is not supported in this test. - */ static void -tcti_spi_no_wait_state_success_test (void **state) +tcti_spi_general_test (void **state) { TSS2_RC rc; size_t size; - TSS2_TCTI_CONTEXT* tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_ctx; + + /* Initialize tester context */ + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_general; - // Get requested TCTI context size + /* Get requested TCTI context size */ rc = Tss2_Tcti_Spi_Ftdi_Init (NULL, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); - // Allocate TCTI context size - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); - // Initialize TCTI context + /* Initialize TCTI context */ rc = Tss2_Tcti_Spi_Ftdi_Init (tcti_ctx, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); - // Finalize - TSS2_TCTI_FINALIZE(tcti_ctx)(tcti_ctx); - + /* Clean up */ free (tcti_ctx); } @@ -218,7 +308,7 @@ main (int argc, char *argv[]) { const struct CMUnitTest tests[] = { - cmocka_unit_test (tcti_spi_no_wait_state_success_test), + cmocka_unit_test (tcti_spi_general_test), }; return cmocka_run_group_tests (tests, NULL, NULL); diff --git a/test/unit/tcti-spi-helper.c b/test/unit/tcti-spi-helper.c index 7d941c252..460642ff3 100644 --- a/test/unit/tcti-spi-helper.c +++ b/test/unit/tcti-spi-helper.c @@ -15,262 +15,460 @@ #include // for memcpy, memcmp #include "../helper/cmocka_all.h" // for assert_int_equal, assert_true, ass... +#include "tss2-tcti/tcti-common.h" // for TCTI_STATE_RECEIVE, TCTI_VERSION +#include "tss2-tcti/tcti-helper-common.h" +#include "tss2-tcti/tcti-spi-helper.h" #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC, TSS2_TCT... #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT #include "tss2_tcti_spi_helper.h" // for Tss2_Tcti_Spi_Helper_Init, TSS2_TC... -#define DUMMY_PLATFORM_DATA "my platform data" - -typedef enum { - TPM_DID_VID_HEAD = 0, - TPM_DID_VID_BODY, - TPM_ACCESS_HEAD, - TPM_ACCESS_BODY, - TPM_STS_HEAD, - TPM_STS_BODY, - TPM_RID_HEAD, - TPM_RID_BODY -} tpm_state_t; - -static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; -static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; -static const unsigned char TPM_STS_0[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; -static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; - -TSS2_RC platform_sleep_ms (void* user_data, int32_t milliseconds) +/* + * The goal is to verify the SPI communication protocol implementation by checking + * the order in which platform functions are invoked when using functions in the + * TCTI_HELPER_COMMON_CONTEXT (such as sleep_ms, start_timeout, timeout_expired, + * read_reg, and write_reg). + * + * The audit arrays (e.g., audit_general, audit_no_wait_state_write_reg) contain this + * information. Each entry specifies the expected platform function to be invoked, + * the command to be received, or the response to be written back in a specific order. + * The tester_context.audit_step (audit array index) variable keeps track of the + * sequence of these operations. + */ + +typedef struct { + void *func; + char *spi_mosi; + char *spi_miso; + union { + size_t size; /* for platform_spi_transfer */ + int ms; /* for platform_sleep_ms, platform_start_timeout */ + bool is_expired; /* for platform_timeout_expired */ + } u; +} struct_audit; + +typedef struct { + bool with_waitstate; + int audit_step; + struct_audit *audit; +} tester_context; + +static const unsigned char MISO_NO_WAIT[] = { 0x00, 0x00, 0x00, 0x01 }; +static const unsigned char MISO_INSERT_WAIT[] = { 0x00, 0x00, 0x00, 0x00 }; + +static const unsigned char WRITE_TPM_ACCESS_MOSI[] = + { 0x00, 0xD4, 0x00, 0x00, 0x82 }; /* tpmRegValidSts = 1, requestUse = 1 */ +static const unsigned char WRITE_TPM_STS_MOSI[] = + { 0x03, 0xD4, 0x00, 0x18, 0x90, 0x00, 0x00, 0x00 }; /* stsValid = 1, dataAvail = 1 */ +static const unsigned char WRITE_TPM_DATA_FIFO_MOSI[] = + { 0x0B, 0xD4, 0x00, 0x24, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; /* Based on TPM2_Startup command */ + +static const unsigned char READ_TPM_ACCESS_MOSI[] = { 0x80, 0xD4, 0x00, 0x00, 0x00 }; +static const unsigned char READ_TPM_ACCESS_MISO[] = { 0x00, 0x00, 0x00, 0x01, 0x80 }; /* tpmRegValidSts = 1 */ + +static const unsigned char READ_TPM_STS_MOSI[] = + { 0x83, 0xD4, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00 }; +static const unsigned char READ_TPM_STS_MISO[] = + { 0x00, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00 }; /* stsValid = 1, dataAvail = 1 */ + +static const unsigned char READ_TPM_DATA_FIFO_MOSI[] = + { 0x89, 0xD4, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const unsigned char READ_TPM_DATA_FIFO_MISO[] = + { 0x00, 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x24, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00 }; /* Based on TPM2_Startup response */ + +static const unsigned char TPM2_STARTUP_CMD[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static const unsigned char TPM2_STARTUP_RESP[] = + { 0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00 }; + +TSS2_RC platform_sleep_ms (void *user_data, int32_t milliseconds) { - (void) milliseconds; - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_sleep_ms, ctx->audit[i].func); + assert_int_equal (milliseconds, ctx->audit[i].u.ms); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } -TSS2_RC platform_start_timeout (void* user_data, int32_t milliseconds) +TSS2_RC platform_start_timeout (void *user_data, int32_t milliseconds) { - (void) milliseconds; - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_start_timeout, ctx->audit[i].func); + assert_int_equal (milliseconds, ctx->audit[i].u.ms); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } -TSS2_RC platform_timeout_expired (void* user_data, bool *is_timeout_expired) +TSS2_RC platform_timeout_expired (void *user_data, bool *is_timeout_expired) { - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - *is_timeout_expired = true; + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_timeout_expired, ctx->audit[i].func); + *is_timeout_expired = ctx->audit[i].u.is_expired; + ctx->audit_step++; + return TSS2_RC_SUCCESS; } -TSS2_RC platform_spi_acquire (void* user_data) +TSS2_RC platform_spi_acquire (void *user_data) { - (void) user_data; + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_spi_acquire, ctx->audit[i].func); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } -TSS2_RC platform_spi_release (void* user_data) +TSS2_RC platform_spi_release (void *user_data) { - (void) user_data; + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_spi_release, ctx->audit[i].func); + ctx->audit_step++; + return TSS2_RC_SUCCESS; } -TSS2_RC platform_spi_transfer_no_wait_state (void* user_data, const void *data_out, void *data_in, size_t cnt) +TSS2_RC platform_spi_transfer (void *user_data, const void *data_out, void *data_in, size_t cnt) { - static tpm_state_t tpm_state = TPM_DID_VID_HEAD; - - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - - switch (tpm_state) { - case TPM_DID_VID_HEAD: - assert_int_equal (cnt, 8); - assert_true (!memcmp (data_out, TPM_DID_VID_0, 4)); - memcpy (data_in, TPM_DID_VID_0, sizeof (TPM_DID_VID_0)); - break; - case TPM_ACCESS_HEAD: - assert_int_equal (cnt, 5); - assert_true (!memcmp (data_out, TPM_ACCESS_0, 4)); - memcpy (data_in, TPM_ACCESS_0, sizeof (TPM_ACCESS_0)); - break; - case TPM_STS_HEAD: - assert_int_equal (cnt, 8); - assert_true (!memcmp (data_out, TPM_STS_0, 4)); - memcpy (data_in, TPM_STS_0, sizeof (TPM_STS_0)); - break; - case TPM_RID_HEAD: - assert_int_equal (cnt, 5); - assert_true (!memcmp (data_out, TPM_RID_0, 4)); - memcpy (data_in, TPM_RID_0, sizeof (TPM_RID_0)); - break; - default: - assert_true (false); + tester_context *ctx = (tester_context *)user_data; + int i; + + assert_non_null (ctx); + i = ctx->audit_step; + assert_ptr_equal (platform_spi_transfer, ctx->audit[i].func); + assert_int_equal (cnt, ctx->audit[i].u.size); + if (ctx->audit[i].spi_mosi) { + assert_non_null (data_out); + assert_true (!memcmp (data_out, ctx->audit[i].spi_mosi, cnt)); + } else { + assert_null (data_out); } - tpm_state += 2; + if (ctx->audit[i].spi_miso) { + assert_non_null (data_in); + memcpy (data_in, ctx->audit[i].spi_miso, cnt); + } else { + assert_null (data_in); + } + + ctx->audit_step++; return TSS2_RC_SUCCESS; } -TSS2_RC platform_spi_transfer_with_wait_state (void* user_data, const void *data_out, void *data_in, size_t cnt) +void platform_finalize(void *user_data) +{ + assert_non_null (user_data); + free (user_data); +} + +static struct_audit audit_general[] = { + { platform_sleep_ms, NULL, NULL, POLLING_INTERVAL_MS }, + { platform_start_timeout, NULL, NULL, TIMEOUT_A }, + { platform_timeout_expired, NULL, NULL, true }, + { 0 }, +}; + +static struct_audit audit_no_wait_state_write_reg[] = { + { platform_spi_transfer, (char *)WRITE_TPM_ACCESS_MOSI, NULL, sizeof (WRITE_TPM_ACCESS_MOSI) }, + { platform_spi_transfer, (char *)WRITE_TPM_STS_MOSI, NULL, sizeof (WRITE_TPM_STS_MOSI) }, + { platform_spi_transfer, (char *)WRITE_TPM_DATA_FIFO_MOSI, NULL, sizeof (WRITE_TPM_DATA_FIFO_MOSI) }, + { 0 }, +}; + +static struct_audit audit_wait_state_write_reg[] = { + /* TPM_ACCESS */ + { platform_spi_acquire, NULL, NULL, false }, + { platform_spi_transfer, (char *)WRITE_TPM_ACCESS_MOSI, (char *)MISO_INSERT_WAIT, 4 }, + { platform_spi_transfer, "\x00", "\x00", 1 }, /* Insert wait */ + { platform_sleep_ms, NULL, NULL, 1 }, + { platform_spi_transfer, "\x00", "\x01", 1 }, /* Exit wait */ + { platform_spi_transfer, (char *)WRITE_TPM_ACCESS_MOSI + 4, NULL, sizeof (WRITE_TPM_ACCESS_MOSI) - 4 }, + { platform_spi_release, NULL, NULL, false }, + + /* TPM_STS */ + { platform_spi_acquire, NULL, NULL, false }, + { platform_spi_transfer, (char *)WRITE_TPM_STS_MOSI, (char *)MISO_NO_WAIT, 4 }, + { platform_spi_transfer, (char *)WRITE_TPM_STS_MOSI + 4, NULL, sizeof (WRITE_TPM_STS_MOSI) - 4 }, + { platform_spi_release, NULL, NULL, false }, + + /* TPM_DATA_FIFO */ + { platform_spi_acquire, NULL, NULL, false }, + { platform_spi_transfer, (char *)WRITE_TPM_DATA_FIFO_MOSI, (char *)MISO_NO_WAIT, 4 }, + { platform_spi_transfer, (char *)WRITE_TPM_DATA_FIFO_MOSI + 4, NULL, sizeof (WRITE_TPM_DATA_FIFO_MOSI) - 4 }, + { platform_spi_release, NULL, NULL, false }, + + { 0 }, +}; + +static struct_audit audit_no_wait_state_read_reg[] = { + { platform_spi_transfer, (char *)READ_TPM_ACCESS_MOSI, (char *)READ_TPM_ACCESS_MISO, sizeof (READ_TPM_ACCESS_MOSI) }, + { platform_spi_transfer, (char *)READ_TPM_STS_MOSI, (char *)READ_TPM_STS_MISO, sizeof (READ_TPM_STS_MOSI) }, + { platform_spi_transfer, (char *)READ_TPM_DATA_FIFO_MOSI, (char *)READ_TPM_DATA_FIFO_MISO, sizeof (READ_TPM_DATA_FIFO_MOSI) }, + { 0 }, +}; + +static struct_audit audit_wait_state_read_reg[] = { + /* TPM_ACCESS */ + { platform_spi_acquire, NULL, NULL, false }, + { platform_spi_transfer, (char *)READ_TPM_ACCESS_MOSI, (char *)MISO_INSERT_WAIT, 4 }, + { platform_spi_transfer, "\x00", "\x00", 1 }, /* Insert wait */ + { platform_sleep_ms, NULL, NULL, 1 }, + { platform_spi_transfer, "\x00", "\x01", 1 }, /* Exit wait */ + { platform_spi_transfer, NULL, (char *)READ_TPM_ACCESS_MISO + 4, sizeof (READ_TPM_ACCESS_MISO) - 4 }, + { platform_spi_release, NULL, NULL, false }, + + /* TPM_STS */ + { platform_spi_acquire, NULL, NULL, false }, + { platform_spi_transfer, (char *)READ_TPM_STS_MOSI, (char *)MISO_NO_WAIT, 4 }, + { platform_spi_transfer, NULL, (char *)READ_TPM_STS_MISO + 4, sizeof (READ_TPM_STS_MISO) - 4 }, + { platform_spi_release, NULL, NULL, false }, + + /* TPM_DATA_FIFO */ + { platform_spi_acquire, NULL, NULL, false }, + { platform_spi_transfer, (char *)READ_TPM_DATA_FIFO_MOSI, (char *)MISO_NO_WAIT, 4 }, + { platform_spi_transfer, NULL, (char *)READ_TPM_DATA_FIFO_MISO + 4, sizeof (READ_TPM_DATA_FIFO_MISO) - 4 }, + { platform_spi_release, NULL, NULL, false }, + + { 0 }, +}; + +TSS2_RC __wrap_Tcti_Helper_Common_Init (TCTI_HELPER_COMMON_CONTEXT *ctx, bool is_i2c) { - static tpm_state_t tpm_state = TPM_DID_VID_HEAD; - - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - - switch (tpm_state++) { - case TPM_DID_VID_HEAD: - assert_int_equal (cnt, 4); - assert_true (!memcmp (data_out, TPM_DID_VID_0, 4)); - memcpy (data_in, TPM_DID_VID_0, 4); - ((unsigned char *)data_in)[3] |= 0x01; - break; - case TPM_DID_VID_BODY: - assert_int_equal (cnt, sizeof (TPM_DID_VID_0) - 4); - memcpy (data_in, TPM_DID_VID_0 + 4, sizeof (TPM_DID_VID_0) - 4); - break; - case TPM_ACCESS_HEAD: - assert_int_equal (cnt, 4); - assert_true (!memcmp (data_out, TPM_ACCESS_0, 4)); - memcpy (data_in, TPM_ACCESS_0, 4); - ((unsigned char *)data_in)[3] |= 0x01; - break; - case TPM_ACCESS_BODY: - assert_int_equal (cnt, sizeof (TPM_ACCESS_0) - 4); - memcpy (data_in, TPM_ACCESS_0 + 4, sizeof (TPM_ACCESS_0) - 4); - break; - case TPM_STS_HEAD: - assert_int_equal (cnt, 4); - assert_true (!memcmp (data_out, TPM_STS_0, 4)); - memcpy (data_in, TPM_STS_0, 4); - ((unsigned char *)data_in)[3] |= 0x01; - break; - case TPM_STS_BODY: - assert_int_equal (cnt, sizeof (TPM_STS_0) - 4); - memcpy (data_in, TPM_STS_0 + 4, sizeof (TPM_STS_0) - 4); - break; - case TPM_RID_HEAD: - assert_int_equal (cnt, 4); - assert_true (!memcmp (data_out, TPM_RID_0, 4)); - memcpy (data_in, TPM_RID_0, 4); - ((unsigned char *)data_in)[3] |= 0x01; - break; - case TPM_RID_BODY: - assert_int_equal (cnt, sizeof (TPM_RID_0) - 4); - memcpy (data_in, TPM_RID_0 + 4, 1); - break; - default: - assert_true (false); + (void) is_i2c; + bool is_timeout_expired = false; + uint8_t response[128] = { 0 }; + TSS2_TCTI_SPI_HELPER_CONTEXT *spi_helper_ctx; + TSS2_TCTI_SPI_HELPER_PLATFORM *spi_helper_platform; + tester_context *tester_ctx; + + assert_non_null (ctx); + assert_non_null (ctx->sleep_ms); + assert_non_null (ctx->start_timeout); + assert_non_null (ctx->timeout_expired); + assert_non_null (ctx->write_reg); + assert_non_null (ctx->read_reg); + + spi_helper_ctx = (TSS2_TCTI_SPI_HELPER_CONTEXT *)ctx->data; + assert_non_null (spi_helper_ctx); + + spi_helper_platform = &spi_helper_ctx->platform; + assert_non_null (spi_helper_platform); + + tester_ctx = (tester_context *)spi_helper_platform->user_data; + assert_non_null (tester_ctx); + + /* Testing TCTI_HELPER_COMMON_CONTEXT's sleep_ms, start_timout, timeout_expired */ + + tester_ctx->audit_step = 0; + tester_ctx->audit = audit_general; + + assert_int_equal (ctx->sleep_ms (ctx->data, POLLING_INTERVAL_MS), TSS2_RC_SUCCESS); + assert_int_equal (ctx->start_timeout (ctx->data, TIMEOUT_A), TSS2_RC_SUCCESS); + assert_int_equal (ctx->timeout_expired (ctx->data, &is_timeout_expired), TSS2_RC_SUCCESS); + assert_true (is_timeout_expired); + + /* Testing TCTI_HELPER_COMMON_CONTEXT's write_reg (TPM_ACCESS, TPM_STS, TPM_DATA_FIFO) */ + + tester_ctx->audit_step = 0; + if (tester_ctx->with_waitstate) { + tester_ctx->audit = audit_wait_state_write_reg; + } else { + tester_ctx->audit = audit_no_wait_state_write_reg; } + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_ACCESS, + &WRITE_TPM_ACCESS_MOSI[4], 1), TSS2_RC_SUCCESS); + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_STS, + &WRITE_TPM_STS_MOSI[4], sizeof (WRITE_TPM_STS_MOSI) - 4), TSS2_RC_SUCCESS); + assert_int_equal (ctx->write_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, + &WRITE_TPM_DATA_FIFO_MOSI[4], sizeof (WRITE_TPM_DATA_FIFO_MOSI) - 4), TSS2_RC_SUCCESS); + + /* Testing TCTI_HELPER_COMMON_CONTEXT's read_reg (TPM_ACCESS, TPM_STS, TPM_DATA_FIFO) */ + + tester_ctx->audit_step = 0; + if (tester_ctx->with_waitstate) { + tester_ctx->audit = audit_wait_state_read_reg; + } else { + tester_ctx->audit = audit_no_wait_state_read_reg; + } + + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_ACCESS, response, 1), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, &READ_TPM_ACCESS_MISO[4], sizeof (READ_TPM_ACCESS_MISO) - 4)); + + memset (response, 0, sizeof (response)); + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_STS, response, + sizeof (READ_TPM_STS_MOSI) - 4), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, &READ_TPM_STS_MISO[4], sizeof (READ_TPM_STS_MISO) - 4)); + + memset (response, 0, sizeof (response)); + assert_int_equal (ctx->read_reg (ctx->data, TCTI_HELPER_COMMON_REG_TPM_DATA_FIFO, response, + sizeof (READ_TPM_DATA_FIFO_MOSI) - 4), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, &READ_TPM_DATA_FIFO_MISO[4], sizeof (READ_TPM_DATA_FIFO_MISO) - 4)); + return TSS2_RC_SUCCESS; } -void platform_finalize(void* user_data) +TSS2_RC __wrap_Tcti_Helper_Common_Transmit (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t size, + const uint8_t *cmd_buf) { - assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); - free(user_data); + assert_non_null (ctx); + assert_int_equal (size, sizeof (TPM2_STARTUP_CMD)); + assert_ptr_equal (cmd_buf, TPM2_STARTUP_CMD); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC __wrap_Tcti_Helper_Common_Receive (TCTI_HELPER_COMMON_CONTEXT *ctx, size_t *response_size, + unsigned char *response_buffer, int32_t timeout) +{ + assert_int_equal (timeout, TIMEOUT_A); + assert_non_null (ctx); + assert_non_null (response_size); + + if (!response_buffer) { + *response_size = sizeof (TPM2_STARTUP_RESP); + } else { + assert_int_equal (*response_size, sizeof (TPM2_STARTUP_RESP)); + memcpy (response_buffer, TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP)); + } + + return TSS2_RC_SUCCESS; } -TSS2_TCTI_SPI_HELPER_PLATFORM create_tcti_spi_helper_platform (bool wait_state) +static TSS2_TCTI_SPI_HELPER_PLATFORM +create_tcti_spi_helper_platform (bool wait_state) { TSS2_TCTI_SPI_HELPER_PLATFORM platform = {}; - // Create dummy platform user data - char *platform_data = malloc (sizeof (DUMMY_PLATFORM_DATA)); - memcpy (platform_data, DUMMY_PLATFORM_DATA, sizeof (DUMMY_PLATFORM_DATA)); + /* Create tester context */ + tester_context *tester_ctx = calloc (1, sizeof (tester_context)); + tester_ctx->with_waitstate = wait_state; - // Create TCTI SPI platform struct with custom platform methods - platform.user_data = platform_data; + /* Create TCTI SPI platform struct with custom platform methods */ + platform.user_data = (void *) tester_ctx; platform.sleep_ms = platform_sleep_ms; platform.start_timeout = platform_start_timeout; platform.timeout_expired = platform_timeout_expired; if (wait_state) { platform.spi_acquire = platform_spi_acquire; platform.spi_release = platform_spi_release; - platform.spi_transfer = platform_spi_transfer_with_wait_state; } else { platform.spi_acquire = NULL; platform.spi_release = NULL; - platform.spi_transfer = platform_spi_transfer_no_wait_state; } + platform.spi_transfer = platform_spi_transfer; platform.finalize = platform_finalize; return platform; } -/* - * The test will invoke Tss2_Tcti_Spi_Helper_Init() and subsequently - * it will start reading TPM_DID_VID, claim locality, read TPM_STS, - * and finally read TPM_RID before exiting the Init function. - * For testing purpose, the TPM responses are hardcoded. - * SPI wait state is not supported in this test. - */ static void -tcti_spi_no_wait_state_success_test (void **state) +tcti_spi_success_test (void **state, bool with_wait_state) { TSS2_RC rc; size_t size; - TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = {}; - TSS2_TCTI_CONTEXT* tcti_ctx; + uint8_t response[sizeof (TPM2_STARTUP_RESP)] = { 0 }; + TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = { 0 }; + TSS2_TCTI_CONTEXT *tcti_ctx; - // Get requested TCTI context size + /* Get requested TCTI context size */ rc = Tss2_Tcti_Spi_Helper_Init (NULL, &size, &tcti_platform); assert_int_equal (rc, TSS2_RC_SUCCESS); - // Allocate TCTI context size - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); - // Initialize TCTI context - tcti_platform = create_tcti_spi_helper_platform (false); + /* Initialize TCTI context */ + tcti_platform = create_tcti_spi_helper_platform (with_wait_state); rc = Tss2_Tcti_Spi_Helper_Init (tcti_ctx, &size, &tcti_platform); assert_int_equal (rc, TSS2_RC_SUCCESS); - free (tcti_platform.user_data); + /* Verify the TCTI core functions */ + assert_int_equal (TSS2_TCTI_MAGIC (tcti_ctx), TCTI_SPI_HELPER_MAGIC); + assert_int_equal (TSS2_TCTI_VERSION (tcti_ctx), TCTI_VERSION); + assert_int_equal ( + TSS2_TCTI_TRANSMIT (tcti_ctx) ( + tcti_ctx, sizeof (TPM2_STARTUP_CMD), TPM2_STARTUP_CMD + ), + TSS2_RC_SUCCESS + ); + size = 0; + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, NULL, TIMEOUT_A + ), + TSS2_RC_SUCCESS + ); + assert_int_equal (size, sizeof (TPM2_STARTUP_RESP)); + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, response, TIMEOUT_A + ), + TSS2_RC_SUCCESS + ); + assert_true (!memcmp (response, TPM2_STARTUP_RESP, sizeof (TPM2_STARTUP_RESP))); + assert_int_equal (TSS2_TCTI_CANCEL (tcti_ctx) (NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_GET_POLL_HANDLES (tcti_ctx) (NULL, NULL, NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_SET_LOCALITY (tcti_ctx) (NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_MAKE_STICKY (tcti_ctx) (NULL, NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); + + /* Clean up */ + TSS2_TCTI_FINALIZE (tcti_ctx) (tcti_ctx); free (tcti_ctx); } -/* - * Similar to tcti_spi_no_wait_state_success_test - * except wait state is supported here. - */ static void -tcti_spi_with_wait_state_success_test (void **state) +tcti_spi_no_wait_state_success_test (void **state) { - TSS2_RC rc; - size_t size; - TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = {}; - TSS2_TCTI_CONTEXT* tcti_ctx; - - // Get requested TCTI context size - rc = Tss2_Tcti_Spi_Helper_Init (NULL, &size, &tcti_platform); - assert_int_equal (rc, TSS2_RC_SUCCESS); - - // Allocate TCTI context size - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); - assert_non_null (tcti_ctx); - - // Initialize TCTI context - tcti_platform = create_tcti_spi_helper_platform (true); - rc = Tss2_Tcti_Spi_Helper_Init (tcti_ctx, &size, &tcti_platform); - assert_int_equal (rc, TSS2_RC_SUCCESS); + tcti_spi_success_test (state, false); +} - free (tcti_platform.user_data); - free (tcti_ctx); +static void +tcti_spi_with_wait_state_success_test (void **state) +{ + tcti_spi_success_test (state, true); } static void -tcti_spi_with_bad_callbacks_test (void **state) +tcti_spi_bad_callbacks_test (void **state) { TSS2_RC rc; size_t size; TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = {}; - TSS2_TCTI_CONTEXT* tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_ctx; - // Get requested TCTI context size + /* Get requested TCTI context size */ rc = Tss2_Tcti_Spi_Helper_Init (NULL, &size, &tcti_platform); assert_int_equal (rc, TSS2_RC_SUCCESS); - // Allocate TCTI context size - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); - // Initialize TCTI context + /* Initialize TCTI context */ tcti_platform = create_tcti_spi_helper_platform (false); tcti_platform.sleep_ms = NULL; rc = Tss2_Tcti_Spi_Helper_Init (tcti_ctx, &size, &tcti_platform); @@ -281,22 +479,22 @@ tcti_spi_with_bad_callbacks_test (void **state) } static void -tcti_spi_with_wait_state_bad_callbacks_test (void **state) +tcti_spi_wait_state_bad_callbacks_test (void **state) { TSS2_RC rc; size_t size; TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = {}; - TSS2_TCTI_CONTEXT* tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_ctx; - // Get requested TCTI context size + /* Get requested TCTI context size */ rc = Tss2_Tcti_Spi_Helper_Init (NULL, &size, &tcti_platform); assert_int_equal (rc, TSS2_RC_SUCCESS); - // Allocate TCTI context size - tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc (1, size); assert_non_null (tcti_ctx); - // Initialize TCTI context + /* Initialize TCTI context */ tcti_platform = create_tcti_spi_helper_platform (true); tcti_platform.spi_acquire = NULL; rc = Tss2_Tcti_Spi_Helper_Init (tcti_ctx, &size, &tcti_platform); @@ -313,8 +511,8 @@ main (int argc, const struct CMUnitTest tests[] = { cmocka_unit_test (tcti_spi_no_wait_state_success_test), cmocka_unit_test (tcti_spi_with_wait_state_success_test), - cmocka_unit_test (tcti_spi_with_bad_callbacks_test), - cmocka_unit_test (tcti_spi_with_wait_state_bad_callbacks_test) + cmocka_unit_test (tcti_spi_bad_callbacks_test), + cmocka_unit_test (tcti_spi_wait_state_bad_callbacks_test) }; return cmocka_run_group_tests (tests, NULL, NULL); } diff --git a/test/unit/tcti-spi-ltt2go.c b/test/unit/tcti-spi-ltt2go.c index c273b19c9..d32356dc6 100644 --- a/test/unit/tcti-spi-ltt2go.c +++ b/test/unit/tcti-spi-ltt2go.c @@ -18,52 +18,187 @@ #include "../helper/cmocka_all.h" // for assert_int_equal, assert_ptr_... #include "tss2-tcti/tcti-spi-helper.h" // for TSS2_TCTI_SPI_HELPER_CONTEXT +#include "tss2-tcti/tcti-common.h" +#include "tss2-tcti/tcti-spi-ltt2go.h" +#include "tss2-tcti/tcti-spi-helper.h" #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT #include "tss2_tcti_spi_helper.h" // for TSS2_TCTI_SPI_HELPER_PLATFORM #include "tss2_tcti_spi_ltt2go.h" // for Tss2_Tcti_Spi_Ltt2go_Init -struct timeval; -struct timezone; +/* + * The goal is to verify the LTT2GO (LetsTrust-TPM2Go) implementation by checking + * the order in which libusb functions are invoked when using functions in + * the TSS2_TCTI_SPI_HELPER_PLATFORM (e.g., sleep_ms, start_timeout, + * timeout_expired, spi_transfer). + + * The audit arrays (e.g., audit_general) contain this information. Each + * entry specifies the expected libusb function to be invoked, the command + * to be received, or the response to be written back in a specific order. + * The tester_context.audit_step (audit array index) variable tracks the + * sequence of these operations. + */ #define DEV_DESC_SERIAL_NUMBER_INDEX 1 #define DEV_DESC_SERIAL_NUMBER "Y23CW29NR00000RND987654321012" -#define VID_PI3G 0x365Du -#define PID_LTT2GO 0x1337u - -#define CTRL_SET 0xC0u -#define CY_CMD_SPI 0xCAu -#define CY_SPI_WRITEREAD 0x03u -#define TIMEOUT 1000 -#define EP_OUT 0x01u -#define EP_IN 0x82u - -typedef enum { - TPM_DID_VID_HEAD_RX = 0, - TPM_DID_VID_HEAD_TX, - TPM_ACCESS_HEAD_RX, - TPM_ACCESS_HEAD_TX, - TPM_STS_HEAD_RX, - TPM_STS_HEAD_TX, - TPM_RID_HEAD_RX, - TPM_RID_HEAD_TX, -} tpm_state_t; - -static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; -static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; -static const unsigned char TPM_STS_0[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; -static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; - -static tpm_state_t tpm_state = TPM_DID_VID_HEAD_RX; -static libusb_device_handle *device_handle; -static libusb_context *context; -static libusb_device *device; -static libusb_device **device_list; -static struct libusb_config_descriptor *config_descriptor; -static unsigned char *device_mem_alloc; -static size_t device_mem_alloc_length; -static uint16_t transfer_length; +#define DUMMY_PTR ((void *)0xA5A5A5A5) +#define TIME_MS 450 + +/* Define the incomplete struct */ +struct libusb_device { + int dummy; +}; + +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TSS2_TCTI_SPI_HELPER_PLATFORM platform; +} TSS2_TCTI_SPI_LTT2GO_TEST_CONTEXT; + +typedef struct { + int nfds; + void *readfds; + void *writefds; + void *exceptfds; + struct timeval timeout; +} fn_select; + +typedef struct { + struct timeval tv; + void *tz; +} fn_gettimeofday; + +typedef struct { + libusb_context *ctx; + libusb_device **list; + ssize_t size; +} fn_libusb_get_device_list; + +typedef struct { + libusb_device *dev; + struct libusb_device_descriptor desc; +} fn_libusb_get_device_descriptor; + +typedef struct { + libusb_device_handle *dev_handle; + uint8_t desc_index; + unsigned char *data; + int length; +} fn_libusb_get_string_descriptor_ascii; + +typedef struct { + libusb_device *dev; + uint8_t config_index; + struct libusb_config_descriptor *config; +} fn_libusb_get_config_descriptor; + +typedef struct { + struct libusb_config_descriptor *config; +} fn_libusb_free_config_descriptor; + +typedef struct { + libusb_device **list; + int unref_devices; +} fn_libusb_free_device_list; + +typedef struct { + libusb_device_handle *dev_handle; + int enable; +} fn_libusb_set_auto_detach_kernel_driver; + +typedef struct { + libusb_device_handle *dev_handle; + int interface_number; +} fn_libusb_claim_interface, fn_libusb_release_interface; + +typedef struct { + libusb_device_handle *dev_handle; + uint8_t request_type; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + unsigned char *data; + uint16_t wLength; + unsigned int timeout; +} fn_libusb_control_transfer; + +typedef struct { + libusb_device_handle *dev_handle; + unsigned char endpoint; + unsigned char *data; + int length; + unsigned int timeout; +} fn_libusb_bulk_transfer; + +typedef struct { + libusb_device *dev; + libusb_device_handle *dev_handle; +} fn_libusb_open; + +typedef struct { + libusb_device_handle *dev_handle; +} fn_libusb_close; + +typedef struct { + libusb_context *ctx; +} fn_libusb_exit, fn_libusb_init; + +typedef struct { + int errcode; +} fn_libusb_strerror; + +typedef struct { + libusb_device_handle *dev_handle; + unsigned char *buffer; + size_t length; +} fn_libusb_dev_mem_alloc; + +typedef struct { + libusb_device_handle *dev_handle; + unsigned char *buffer; + size_t length; +} fn_libusb_dev_mem_free; + +typedef struct { + void *func; + union { + fn_select select; + fn_gettimeofday gtod; + fn_libusb_get_device_list gdl; + fn_libusb_get_device_descriptor gdd; + fn_libusb_get_string_descriptor_ascii gsda; + fn_libusb_get_config_descriptor gcd; + fn_libusb_free_config_descriptor fcd; + fn_libusb_free_device_list fdl; + fn_libusb_set_auto_detach_kernel_driver sadkd; + fn_libusb_claim_interface ci; + fn_libusb_release_interface ri; + fn_libusb_control_transfer ct; + fn_libusb_bulk_transfer bt; + fn_libusb_open open; + fn_libusb_close close; + fn_libusb_exit exit; + fn_libusb_init init; + fn_libusb_strerror strerr; + fn_libusb_dev_mem_alloc dma; + fn_libusb_dev_mem_free dmf; + } args; +} struct_audit; + +typedef struct { + int audit_step; + struct_audit *audit; + bool is_regex_test; +} tester_context; + +static tester_context tester_ctx; +static unsigned char TPM2_STARTUP_CMD_MOSI[] = + { 0x0B, 0xD4, 0x00, 0x24, 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static unsigned char TPM2_STARTUP_CMD_MISO[] = + { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static libusb_device *dummy_device_list[] = { DUMMY_PTR }; +static struct libusb_config_descriptor dummy_config_desc = { .bNumInterfaces = 1 }; +static uint8_t spi_dma_buffer[SPI_MAX_TRANSFER]; /* * Mock function select @@ -73,12 +208,15 @@ int __wrap_select (int nfds, fd_set *readfds, fd_set *exceptfds, struct timeval *timeout) { + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - assert_int_equal (nfds, 0); - assert_null (readfds); - assert_null (writefds); - assert_null (exceptfds); - assert_non_null (timeout); + assert_ptr_equal (__wrap_select, audit->func); + assert_int_equal (nfds, audit->args.select.nfds); + assert_int_equal (readfds, audit->args.select.readfds); + assert_int_equal (writefds, audit->args.select.writefds); + assert_int_equal (exceptfds, audit->args.select.exceptfds); + assert_int_equal (timeout->tv_sec, audit->args.select.timeout.tv_sec); + assert_int_equal (timeout->tv_usec, audit->args.select.timeout.tv_usec); return 0; } @@ -89,11 +227,14 @@ int __wrap_select (int nfds, fd_set *readfds, int __wrap_gettimeofday (struct timeval *tv, struct timezone *tz) { - assert_null (tz); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_gettimeofday, audit->func); assert_non_null (tv); + assert_ptr_equal (tz, audit->args.gtod.tz); - tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_sec = audit->args.gtod.tv.tv_sec; + tv->tv_usec = audit->args.gtod.tv.tv_usec; return 0; } @@ -103,14 +244,14 @@ int __wrap_gettimeofday (struct timeval *tv, */ ssize_t __wrap_libusb_get_device_list (libusb_context *ctx, libusb_device ***list) { - ssize_t num_of_devs = 1; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - assert_ptr_equal (ctx, context); + assert_ptr_equal (__wrap_libusb_get_device_list, audit->func); + assert_ptr_equal (ctx, audit->args.gdl.ctx); + assert_non_null (list); + *list = audit->args.gdl.list; - *list = device_list = malloc (sizeof (*list)); - **list = device = malloc (sizeof (**list)); - - return num_of_devs; + return audit->args.gdl.size; } /* @@ -119,12 +260,12 @@ ssize_t __wrap_libusb_get_device_list (libusb_context *ctx, libusb_device ***li int __wrap_libusb_get_device_descriptor (libusb_device *dev, struct libusb_device_descriptor *desc) { - assert_ptr_equal (dev, device); - assert_non_null (desc); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - desc->idVendor = VID_PI3G; - desc->idProduct = PID_LTT2GO; - desc->iSerialNumber = DEV_DESC_SERIAL_NUMBER_INDEX; + assert_ptr_equal (__wrap_libusb_get_device_descriptor, audit->func); + assert_ptr_equal (dev, audit->args.gdd.dev); + assert_non_null (desc); + *desc = audit->args.gdd.desc; return 0; } @@ -135,18 +276,21 @@ int __wrap_libusb_get_device_descriptor (libusb_device *dev, int __wrap_libusb_get_string_descriptor_ascii (libusb_device_handle *dev_handle, uint8_t desc_index, unsigned char *data, int length) { - unsigned char *sn = (unsigned char *)DEV_DESC_SERIAL_NUMBER; - int sn_size = strlen ((const char *)sn) + 1; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + int l; - assert_ptr_equal (dev_handle, device_handle); - assert_int_equal (desc_index, DEV_DESC_SERIAL_NUMBER_INDEX); + assert_ptr_equal (__wrap_libusb_get_string_descriptor_ascii, audit->func); + assert_ptr_equal (dev_handle, audit->args.gsda.dev_handle); + assert_int_equal (desc_index, audit->args.gsda.desc_index); assert_non_null (data); - assert_int_equal (length, 256); - assert_true (length >= sn_size); + assert_int_equal (length, audit->args.gsda.length); - memcpy (data, (const void *)sn, sn_size); + l = (int) strlen ((const char *)audit->args.gsda.data); + assert_true (length >= l); + memcpy (data, audit->args.gsda.data, l); + data[l] = 0; /* NULL byte */ - return sn_size; + return l; } /* @@ -155,11 +299,13 @@ int __wrap_libusb_get_string_descriptor_ascii (libusb_device_handle *dev_handle int __wrap_libusb_get_config_descriptor (libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config) { - assert_ptr_equal (dev, device); - assert_int_equal (config_index, 0); - config_descriptor = malloc (sizeof (struct libusb_config_descriptor)); - config_descriptor->bNumInterfaces = 2; - *config = config_descriptor; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_get_config_descriptor, audit->func); + assert_ptr_equal (dev, audit->args.gcd.dev); + assert_int_equal (config_index, audit->args.gcd.config_index); + assert_non_null (config); + *config = audit->args.gcd.config; return 0; } @@ -170,9 +316,9 @@ int __wrap_libusb_get_config_descriptor (libusb_device *dev, void __wrap_libusb_free_config_descriptor ( struct libusb_config_descriptor *config) { - assert_ptr_equal (config, config_descriptor); - free (config_descriptor); - config_descriptor = NULL; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + assert_ptr_equal (__wrap_libusb_free_config_descriptor, audit->func); + assert_ptr_equal (config, audit->args.fcd.config); } /* @@ -181,13 +327,10 @@ void __wrap_libusb_free_config_descriptor ( void __wrap_libusb_free_device_list ( libusb_device **list, int unref_devices) { - assert_ptr_equal (list, device_list); - assert_ptr_equal (*list, device); - assert_int_equal (unref_devices, 1); - free (device); - free (device_list); - device = NULL; - device_list = NULL; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + assert_ptr_equal (__wrap_libusb_free_device_list, audit->func); + assert_ptr_equal (list, audit->args.fdl.list); + assert_int_equal (unref_devices, audit->args.fdl.unref_devices); } /* @@ -196,8 +339,11 @@ void __wrap_libusb_free_device_list ( int __wrap_libusb_set_auto_detach_kernel_driver ( libusb_device_handle *dev_handle, int enable) { - assert_ptr_equal (dev_handle, device_handle); - assert_int_equal (enable, 1); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_set_auto_detach_kernel_driver, audit->func); + assert_ptr_equal (dev_handle, audit->args.sadkd.dev_handle); + assert_int_equal (enable, audit->args.sadkd.enable); return 0; } @@ -208,8 +354,11 @@ int __wrap_libusb_set_auto_detach_kernel_driver ( int __wrap_libusb_claim_interface (libusb_device_handle *dev_handle, int interface_number) { - assert_ptr_equal (dev_handle, device_handle); - assert_int_equal (interface_number, 0); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_claim_interface, audit->func); + assert_ptr_equal (dev_handle, audit->args.ci.dev_handle); + assert_int_equal (interface_number, audit->args.ci.interface_number); return 0; } @@ -220,8 +369,11 @@ int __wrap_libusb_claim_interface (libusb_device_handle *dev_handle, int __wrap_libusb_release_interface (libusb_device_handle *dev_handle, int interface_number) { - assert_ptr_equal (dev_handle, device_handle); - assert_int_equal (interface_number, 0); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_release_interface, audit->func); + assert_ptr_equal (dev_handle, audit->args.ri.dev_handle); + assert_int_equal (interface_number, audit->args.ci.interface_number); return 0; } @@ -233,82 +385,46 @@ int __wrap_libusb_control_transfer (libusb_device_handle *dev_handle, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout) { - assert_ptr_equal (dev_handle, device_handle); - assert_int_equal (request_type, CTRL_SET); - assert_int_equal (bRequest, CY_CMD_SPI); - assert_int_equal (wValue, CY_SPI_WRITEREAD); - assert_null (data); - assert_int_equal (wLength, 0); - assert_int_equal (timeout, TIMEOUT); - - transfer_length = wIndex; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_control_transfer, audit->func); + assert_ptr_equal (dev_handle, audit->args.ct.dev_handle); + assert_int_equal (request_type, audit->args.ct.request_type); + assert_int_equal (bRequest, audit->args.ct.bRequest); + assert_int_equal (wValue, audit->args.ct.wValue); + assert_int_equal (wIndex, audit->args.ct.wIndex); + assert_int_equal (wLength, audit->args.ct.wLength); + assert_int_equal (timeout, audit->args.ct.timeout); + assert_ptr_equal (data, audit->args.ct.data); return 0; } /* * Mock function libusb_bulk_transfer. - * - * Here we are imitating the best case scenario where the - * actual_length is always equal to length. In actual world, - * the transmission can be fragmented hence the actual_length < length, - * and multiple retries can happen to process the remaining length. */ int __wrap_libusb_bulk_transfer (libusb_device_handle *dev_handle, unsigned char endpoint, unsigned char *data, int length, int *actual_length, unsigned int timeout) { - assert_ptr_equal (dev_handle, device_handle); - assert_int_equal (timeout, TIMEOUT); - assert_int_equal (length, transfer_length); - - switch (tpm_state) { - case TPM_DID_VID_HEAD_RX: - assert_true (endpoint == EP_OUT); - assert_int_equal (length, 8); - assert_true (!memcmp (data, TPM_DID_VID_0, 4)); - break; - case TPM_DID_VID_HEAD_TX: - assert_true (endpoint == EP_IN); - assert_int_equal (length, 8); - memcpy (data, TPM_DID_VID_0, sizeof (TPM_DID_VID_0)); - break; - case TPM_ACCESS_HEAD_RX: - assert_true (endpoint == EP_OUT); - assert_int_equal (length, 5); - assert_true (!memcmp (data, TPM_ACCESS_0, 4)); - break; - case TPM_ACCESS_HEAD_TX: - assert_true (endpoint == EP_IN); - assert_int_equal (length, 5); - memcpy (data, TPM_ACCESS_0, sizeof (TPM_ACCESS_0)); - break; - case TPM_STS_HEAD_RX: - assert_true (endpoint == EP_OUT); - assert_int_equal (length, 8); - assert_true (!memcmp (data, TPM_STS_0, 4)); - break; - case TPM_STS_HEAD_TX: - assert_true (endpoint == EP_IN); - assert_int_equal (length, 8); - memcpy (data, TPM_STS_0, sizeof (TPM_STS_0)); - break; - case TPM_RID_HEAD_RX: - assert_true (endpoint == EP_OUT); - assert_int_equal (length, 5); - assert_true (!memcmp (data, TPM_RID_0, 4)); - break; - case TPM_RID_HEAD_TX: - assert_true (endpoint == EP_IN); - assert_int_equal (length, 5); - memcpy (data, TPM_RID_0, sizeof (TPM_RID_0)); - break; - default: + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_bulk_transfer, audit->func); + assert_ptr_equal (dev_handle, audit->args.bt.dev_handle); + assert_int_equal (endpoint, audit->args.bt.endpoint); + assert_non_null (data); + assert_int_equal (length, audit->args.bt.length); + assert_non_null (actual_length); + assert_int_equal (timeout, audit->args.bt.timeout); + + if (endpoint == EP_OUT) { + assert_true (!memcmp (data, audit->args.bt.data, length)); + } else if (endpoint == EP_IN) { + memcpy (data, audit->args.bt.data, length); + } else { assert_true (false); } - - tpm_state += 1; - *actual_length = length; + *actual_length = audit->args.bt.length; return 0; } @@ -318,9 +434,12 @@ int __wrap_libusb_bulk_transfer (libusb_device_handle *dev_handle, */ int __wrap_libusb_open (libusb_device *dev, libusb_device_handle **dev_handle) { - assert_ptr_equal (dev, device); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_open, audit->func); + assert_ptr_equal (dev, audit->args.open.dev); assert_non_null (dev_handle); - *dev_handle = device_handle = malloc (1); + *dev_handle = audit->args.open.dev_handle; return 0; } @@ -330,9 +449,9 @@ int __wrap_libusb_open (libusb_device *dev, libusb_device_handle **dev_handle) */ void __wrap_libusb_close (libusb_device_handle *dev_handle) { - assert_ptr_equal (dev_handle, device_handle); - free (device_handle); - device_handle = NULL; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + assert_ptr_equal (__wrap_libusb_close, audit->func); + assert_ptr_equal (dev_handle, audit->args.close.dev_handle); } /* @@ -340,9 +459,9 @@ void __wrap_libusb_close (libusb_device_handle *dev_handle) */ void __wrap_libusb_exit (libusb_context *ctx) { - assert_ptr_equal (ctx, context); - free (context); - context = NULL; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + assert_ptr_equal (__wrap_libusb_exit, audit->func); + assert_ptr_equal (ctx, audit->args.exit.ctx); } /* @@ -350,8 +469,11 @@ void __wrap_libusb_exit (libusb_context *ctx) */ int __wrap_libusb_init (libusb_context **ctx) { - context = malloc (1); - *ctx = context; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_init, audit->func); + assert_non_null (ctx); + *ctx = audit->args.init.ctx; return 0; } @@ -361,6 +483,8 @@ int __wrap_libusb_init (libusb_context **ctx) */ const char * __wrap_libusb_strerror (int errcode) { + (void) errcode; + assert_true (false); return NULL; } @@ -370,12 +494,13 @@ const char * __wrap_libusb_strerror (int errcode) unsigned char * __wrap_libusb_dev_mem_alloc (libusb_device_handle *dev_handle, size_t length) { - assert_ptr_equal (dev_handle, device_handle); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - device_mem_alloc_length = length; - device_mem_alloc = malloc (length); + assert_ptr_equal (__wrap_libusb_dev_mem_alloc, audit->func); + assert_ptr_equal (dev_handle, audit->args.dma.dev_handle); + assert_int_equal (length, audit->args.dma.length); - return device_mem_alloc; + return audit->args.dma.buffer; } /* @@ -384,30 +509,160 @@ unsigned char * __wrap_libusb_dev_mem_alloc (libusb_device_handle *dev_handle, int __wrap_libusb_dev_mem_free (libusb_device_handle *dev_handle, unsigned char *buffer, size_t length) { - assert_ptr_equal (dev_handle, device_handle); - assert_ptr_equal (buffer, device_mem_alloc); - assert_int_equal (length, device_mem_alloc_length); - free (device_mem_alloc); - device_mem_alloc = NULL; - device_mem_alloc_length = 0; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_libusb_dev_mem_free, audit->func); + assert_ptr_equal (dev_handle, audit->args.dmf.dev_handle); + assert_ptr_equal (buffer, audit->args.dmf.buffer); + assert_int_equal (length, audit->args.dmf.length); return 0; } -/* - * The test will invoke Tss2_Tcti_Spi_Ltt2go_Init() and subsequently - * it will start reading TPM_DID_VID, claim locality, read TPM_STS, - * and finally read TPM_RID before exiting the Init function. - * For testing purpose, the TPM responses are hardcoded. - * SPI wait state is not supported in this test. - */ +static struct_audit audit_general[] = { + /* Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, NULL) */ + { .func = __wrap_libusb_init, .args.init = { DUMMY_PTR } }, + { .func = __wrap_libusb_get_device_list, .args.gdl = + { DUMMY_PTR, dummy_device_list, sizeof (dummy_device_list) / sizeof(dummy_device_list[0]) } }, + { .func = __wrap_libusb_get_device_descriptor, .args.gdd = { DUMMY_PTR, + { .idVendor = VID_PI3G, .idProduct = PID_LTT2GO, .iSerialNumber = DEV_DESC_SERIAL_NUMBER_INDEX } } }, + { .func = __wrap_libusb_get_config_descriptor, .args.gcd = { DUMMY_PTR, 0, &dummy_config_desc } }, + { .func = __wrap_libusb_free_config_descriptor, .args.fcd = { &dummy_config_desc } }, + { .func = __wrap_libusb_open, .args.open = { DUMMY_PTR, DUMMY_PTR } }, + { .func = __wrap_libusb_get_string_descriptor_ascii, .args.gsda = + { DUMMY_PTR, DEV_DESC_SERIAL_NUMBER_INDEX, (unsigned char *)DEV_DESC_SERIAL_NUMBER, 256 } }, + { .func = __wrap_libusb_set_auto_detach_kernel_driver, .args.sadkd = { DUMMY_PTR, 1 } }, + { .func = __wrap_libusb_claim_interface, .args.sadkd = { DUMMY_PTR, 0 } }, + { .func = __wrap_libusb_dev_mem_alloc, .args.dma = { DUMMY_PTR, spi_dma_buffer, sizeof (spi_dma_buffer) } }, + { .func = __wrap_libusb_free_device_list, .args.fdl = { dummy_device_list, 1 } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's sleep_ms */ + { .func = __wrap_select, .args.select = + { 0, NULL, NULL, NULL,{ (TIME_MS * 1000) / 1000000, (TIME_MS * 1000) % 1000000 } } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's start_timeout */ + { .func = __wrap_gettimeofday, .args.gtod = { { 0, 0 }, NULL } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's timeout_expired */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 1, 0 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) }, NULL } }, /* Return a value <= TIME_MS, no timeout occured */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) + 1 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's spi_transfer */ + { .func = __wrap_libusb_control_transfer, .args.ct = + { DUMMY_PTR, CTRL_SET, CY_CMD_SPI, CY_SPI_WRITEREAD, sizeof (TPM2_STARTUP_CMD_MOSI), NULL, 0, LTT2GO_TIMEOUT_MS } }, + { .func = __wrap_libusb_bulk_transfer, .args.bt = + { DUMMY_PTR, EP_OUT, TPM2_STARTUP_CMD_MOSI, sizeof (TPM2_STARTUP_CMD_MOSI), LTT2GO_TIMEOUT_MS } }, + { .func = __wrap_libusb_bulk_transfer, .args.bt = + { DUMMY_PTR, EP_IN, TPM2_STARTUP_CMD_MISO, sizeof (TPM2_STARTUP_CMD_MISO), LTT2GO_TIMEOUT_MS } }, + + /* platform->finalize */ + { .func = __wrap_libusb_dev_mem_free, .args.dmf = { DUMMY_PTR, spi_dma_buffer, sizeof (spi_dma_buffer) } }, + { .func = __wrap_libusb_release_interface, .args.ri = { DUMMY_PTR, 0 } }, + { .func = __wrap_libusb_close, .args.close = { DUMMY_PTR } }, + { .func = __wrap_libusb_exit, .args.exit = { DUMMY_PTR } }, + + { 0 }, +}; + +static struct_audit audit_regex[] = { + /* Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, XXXXX) */ + { .func = __wrap_libusb_init, .args.init = { DUMMY_PTR } }, + { .func = __wrap_libusb_get_device_list, .args.gdl = + { DUMMY_PTR, dummy_device_list , sizeof (dummy_device_list) / sizeof(dummy_device_list[0]) } }, + { .func = __wrap_libusb_get_device_descriptor, .args.gdd = + { DUMMY_PTR, { .idVendor = VID_PI3G, .idProduct = PID_LTT2GO, .iSerialNumber = DEV_DESC_SERIAL_NUMBER_INDEX } } }, + { .func = __wrap_libusb_get_config_descriptor, .args.gcd = { DUMMY_PTR, 0, &dummy_config_desc } }, + { .func = __wrap_libusb_free_config_descriptor, .args.fcd = { &dummy_config_desc } }, + { .func = __wrap_libusb_open, .args.open = { DUMMY_PTR, DUMMY_PTR } }, + { .func = __wrap_libusb_get_string_descriptor_ascii, .args.gsda = + { DUMMY_PTR, DEV_DESC_SERIAL_NUMBER_INDEX, (unsigned char *)DEV_DESC_SERIAL_NUMBER, 256 } }, + { .func = __wrap_libusb_set_auto_detach_kernel_driver, .args.sadkd = { DUMMY_PTR, 1 } }, + { .func = __wrap_libusb_claim_interface, .args.sadkd = { DUMMY_PTR, 0 } }, + { .func = __wrap_libusb_dev_mem_alloc, .args.dma = { DUMMY_PTR, spi_dma_buffer, sizeof (spi_dma_buffer) } }, + { .func = __wrap_libusb_free_device_list, .args.fdl = { dummy_device_list, 1 } }, + + /* platform->finalize */ + { .func = __wrap_libusb_dev_mem_free, .args.dmf = { DUMMY_PTR, spi_dma_buffer, sizeof (spi_dma_buffer) } }, + { .func = __wrap_libusb_release_interface, .args.ri = { DUMMY_PTR, 0 } }, + { .func = __wrap_libusb_close, .args.close = { DUMMY_PTR } }, + { .func = __wrap_libusb_exit, .args.exit = { DUMMY_PTR } }, + + { 0 }, +}; + +static struct_audit audit_regex_nok[] = { + /* Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, XXXXX) */ + { .func = __wrap_libusb_init, .args.init = { DUMMY_PTR } }, + { .func = __wrap_libusb_get_device_list, .args.gdl = + { DUMMY_PTR, dummy_device_list , sizeof (dummy_device_list) / sizeof(dummy_device_list[0]) } }, + { .func = __wrap_libusb_get_device_descriptor, .args.gdd = + { DUMMY_PTR, { .idVendor = VID_PI3G, .idProduct = PID_LTT2GO, .iSerialNumber = DEV_DESC_SERIAL_NUMBER_INDEX } } }, + { .func = __wrap_libusb_get_config_descriptor, .args.gcd = { DUMMY_PTR, 0, &dummy_config_desc } }, + { .func = __wrap_libusb_free_config_descriptor, .args.fcd = { &dummy_config_desc } }, + { .func = __wrap_libusb_open, .args.open = { DUMMY_PTR, DUMMY_PTR } }, + { .func = __wrap_libusb_get_string_descriptor_ascii, .args.gsda = + { DUMMY_PTR, DEV_DESC_SERIAL_NUMBER_INDEX, (unsigned char *)DEV_DESC_SERIAL_NUMBER, 256 } }, + { .func = __wrap_libusb_close, .args.close = { DUMMY_PTR } }, + { .func = __wrap_libusb_free_device_list, .args.fdl = { dummy_device_list, 1 } }, + { .func = __wrap_libusb_exit, .args.exit = { DUMMY_PTR } }, + + { 0 }, +}; + +TSS2_RC __wrap_Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT *tcti_context, size_t *size, TSS2_TCTI_SPI_HELPER_PLATFORM *platform) +{ + void *data; + bool is_expired = false; + uint8_t response[sizeof (TPM2_STARTUP_CMD_MISO)] = { 0 }; + + if (tcti_context == NULL) { + *size = sizeof (TSS2_TCTI_SPI_LTT2GO_TEST_CONTEXT); + return TSS2_RC_SUCCESS; + } + + data = platform->user_data; + assert_non_null (data); + + if (tester_ctx.is_regex_test) { + platform->finalize (data); + return TSS2_RC_SUCCESS; + } + + /* Test TSS2_TCTI_SPI_HELPER_PLATFORM's callbacks */ + + assert_int_equal (platform->sleep_ms (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->start_timeout (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_false (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->spi_transfer (data, TPM2_STARTUP_CMD_MOSI, + response, sizeof (response)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM2_STARTUP_CMD_MISO, sizeof (response))); + + platform->finalize (data); + + return TSS2_RC_SUCCESS; +} + static void -tcti_spi_no_wait_state_success_test (void **state) +tcti_spi_general_test (void **state) { TSS2_RC rc; size_t size; TSS2_TCTI_CONTEXT* tcti_ctx; + /* Initialize tester context */ + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_general; + tester_ctx.is_regex_test = false; + /* Get requested TCTI context size */ rc = Tss2_Tcti_Spi_Ltt2go_Init (NULL, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); @@ -417,26 +672,26 @@ tcti_spi_no_wait_state_success_test (void **state) assert_non_null (tcti_ctx); /* Initialize TCTI context */ - tpm_state = TPM_DID_VID_HEAD_RX; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); - Tss2_Tcti_Finalize (tcti_ctx); free (tcti_ctx); } /* - * This test is similar to tcti_spi_no_wait_state_success_test(), - * with the difference being that the serial number is provided as - * one of the input arguments. The focus of this test is to verify - * the serial number matching algorithm. + * The focus of this test is to verify the implementation of serial number matching */ static void -tcti_spi_no_wait_state_regex_success_test (void **state) +tcti_spi_regex_test (void **state) { TSS2_RC rc; size_t size; - TSS2_TCTI_CONTEXT* tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_ctx; + + /* Initialize tester context */ + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex; + tester_ctx.is_regex_test = true; /* Get requested TCTI context size */ rc = Tss2_Tcti_Spi_Ltt2go_Init (NULL, &size, NULL); @@ -449,49 +704,50 @@ tcti_spi_no_wait_state_regex_success_test (void **state) /* Positive tests: */ /* Initialize TCTI context with S/N: DEV_DESC_SERIAL_NUMBER */ - tpm_state = TPM_DID_VID_HEAD_RX; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, DEV_DESC_SERIAL_NUMBER); assert_int_equal (rc, TSS2_RC_SUCCESS); - Tss2_Tcti_Finalize (tcti_ctx); memset (tcti_ctx, 0, size); /* Initialize TCTI context with S/N starting with "Y23CW" */ - tpm_state = TPM_DID_VID_HEAD_RX; + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, "^Y23CW"); assert_int_equal (rc, TSS2_RC_SUCCESS); - Tss2_Tcti_Finalize (tcti_ctx); memset (tcti_ctx, 0, size); /* Initialize TCTI context with S/N containing "RND9876" */ - tpm_state = TPM_DID_VID_HEAD_RX; + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, "RND9876"); assert_int_equal (rc, TSS2_RC_SUCCESS); - Tss2_Tcti_Finalize (tcti_ctx); memset (tcti_ctx, 0, size); /* Initialize TCTI context with S/N ending with "321012" */ - tpm_state = TPM_DID_VID_HEAD_RX; + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, "321012$"); assert_int_equal (rc, TSS2_RC_SUCCESS); - Tss2_Tcti_Finalize (tcti_ctx); memset (tcti_ctx, 0, size); /* Negative tests: */ /* Initialize TCTI context with S/N starting with "Z23CW" */ - tpm_state = TPM_DID_VID_HEAD_RX; + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex_nok; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, "^Z23CW"); assert_int_equal (rc, TSS2_BASE_RC_IO_ERROR); memset (tcti_ctx, 0, size); /* Initialize TCTI context with S/N containing "RND8876" */ - tpm_state = TPM_DID_VID_HEAD_RX; + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex_nok; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, "RND8876"); assert_int_equal (rc, TSS2_BASE_RC_IO_ERROR); memset (tcti_ctx, 0, size); /* Initialize TCTI context with S/N ending with "321011" */ - tpm_state = TPM_DID_VID_HEAD_RX; + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_regex_nok; rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, "321011$"); assert_int_equal (rc, TSS2_BASE_RC_IO_ERROR); @@ -504,8 +760,8 @@ main (int argc, char *argv[]) { const struct CMUnitTest tests[] = { - cmocka_unit_test (tcti_spi_no_wait_state_success_test), - cmocka_unit_test (tcti_spi_no_wait_state_regex_success_test), + cmocka_unit_test (tcti_spi_general_test), + cmocka_unit_test (tcti_spi_regex_test), }; return cmocka_run_group_tests (tests, NULL, NULL); diff --git a/test/unit/tcti-spidev.c b/test/unit/tcti-spidev.c index 8a553e045..e50ee7591 100644 --- a/test/unit/tcti-spidev.c +++ b/test/unit/tcti-spidev.c @@ -15,39 +15,91 @@ #include // for free, calloc #include // for memcpy, strncmp #include // for fd_set, timeval +#include #include "../helper/cmocka_all.h" // for assert_int_equal, assert_memo... #include // for spi_ioc_transfer #include "tss2-tcti/tcti-spi-helper.h" // for TSS2_TCTI_SPI_HELPER_CONTEXT +#include "tss2-tcti/tcti-common.h" #include "tss2_common.h" // for TSS2_RC_SUCCESS, TSS2_RC #include "tss2_tcti.h" // for TSS2_TCTI_CONTEXT #include "tss2_tcti_spi_helper.h" // for TSS2_TCTI_SPI_HELPER_PLATFORM #include "tss2_tcti_spidev.h" // for Tss2_Tcti_Spidev_Init -struct timeval; -struct timezone; - -typedef enum { - TPM_DID_VID_HEAD = 0, - TPM_DID_VID_DATA, - TPM_ACCESS_HEAD, - TPM_ACCESS_DATA, - TPM_STS_CMD_NOT_READY_HEAD, - TPM_STS_CMD_NOT_READY_DATA, - TPM_STS_CMD_READY_HEAD, - TPM_STS_CMD_READY_DATA, - TPM_RID_HEAD, - TPM_RID_DATA, -} tpm_state_t; - -// First 4 bytes are the request, the remainder is the response -static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; -static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; -static const unsigned char TPM_STS_0_CMD_NOT_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00}; -static const unsigned char TPM_STS_0_CMD_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; -static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; +/* + * The goal is to verify the spidev implementation by checking + * the order in which file_operations functions are invoked when using functions in + * the TSS2_TCTI_SPI_HELPER_PLATFORM (e.g., sleep_ms, start_timeout, + * timeout_expired, spi_transfer). + + * The audit arrays (e.g., audit_general) contain this information. Each + * entry specifies the expected function to be invoked, the command + * to be received, or the response to be written back in a specific order. + * The tester_context.audit_step (audit array index) variable tracks the + * sequence of these operations. + */ + +#define TIME_MS 450 +#define DUMMY_FD 5 +#define DUMMY_SPIDEV_PATH "/dev/spidev0.1" + +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TSS2_TCTI_SPI_HELPER_PLATFORM platform; +} TSS2_TCTI_SPI_LTT2GO_TEST_CONTEXT; + +typedef struct { + int nfds; + void *readfds; + void *writefds; + void *exceptfds; + struct timeval timeout; +} fn_select; + +typedef struct { + struct timeval tv; + void *tz; +} fn_gettimeofday; + +typedef struct { + char *path; + int flags; + int fd; +} fn_open; + +typedef struct { + int fd; +} fn_close; + +typedef struct { + int fd; + unsigned long request; + struct spi_ioc_transfer tr; +} fn_ioctl; + +typedef struct { + void *func; + union { + fn_select select; + fn_gettimeofday gtod; + fn_open open; + fn_close close; + fn_ioctl ioctl; + } args; +} struct_audit; + +typedef struct { + int audit_step; + struct_audit *audit; +} tester_context; + +static tester_context tester_ctx; +static unsigned char TPM2_STARTUP_CMD_MOSI[] = + { 0x0B, 0xD4, 0x00, 0x24, 0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00 }; +static unsigned char TPM2_STARTUP_CMD_MISO[] = + { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* * Mock function select @@ -57,12 +109,15 @@ int __wrap_select (int nfds, fd_set *readfds, fd_set *exceptfds, struct timeval *timeout) { + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - assert_int_equal (nfds, 0); - assert_null (readfds); - assert_null (writefds); - assert_null (exceptfds); - assert_non_null (timeout); + assert_ptr_equal (__wrap_select, audit->func); + assert_int_equal (nfds, audit->args.select.nfds); + assert_int_equal (readfds, audit->args.select.readfds); + assert_int_equal (writefds, audit->args.select.writefds); + assert_int_equal (exceptfds, audit->args.select.exceptfds); + assert_int_equal (timeout->tv_sec, audit->args.select.timeout.tv_sec); + assert_int_equal (timeout->tv_usec, audit->args.select.timeout.tv_usec); return 0; } @@ -73,111 +128,144 @@ int __wrap_select (int nfds, fd_set *readfds, int __wrap_gettimeofday (struct timeval *tv, struct timezone *tz) { - assert_null (tz); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_ptr_equal (__wrap_gettimeofday, audit->func); assert_non_null (tv); + assert_ptr_equal (tz, audit->args.gtod.tz); - tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_sec = audit->args.gtod.tv.tv_sec; + tv->tv_usec = audit->args.gtod.tv.tv_usec; return 0; } int __real_open(const char *path, int flags); -#define FD_NO 5 int __wrap_open(const char *path, int flags) { + struct_audit *audit; + assert_ptr_not_equal(path, NULL); + if (!!strncmp(path, "/dev/spidev", sizeof("/dev/spidev") - 1)) return __real_open(path, flags); - assert_int_equal(flags, O_RDWR); - return FD_NO; + + audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_true (!memcmp (path, audit->args.open.path, strlen (DUMMY_SPIDEV_PATH))); + assert_int_equal(flags, audit->args.open.flags); + + return audit->args.open.fd; } int __wrap_close(int fd) { - assert_int_equal(fd, FD_NO); + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; + + assert_int_equal(fd, audit->args.close.fd); + return 0; } int __wrap_ioctl(int fd, unsigned long request, struct spi_ioc_transfer *tr) { - assert_int_equal(tr->delay_usecs, 0); - assert_int_equal(tr->bits_per_word, 8); - - size_t len = tr->len; + struct_audit *audit = &tester_ctx.audit[tester_ctx.audit_step++]; - /* Use size_t to cast 64 bit number to pointer (needed for 32 bit systems) */ - uint8_t *tx_buf = (uint8_t *)(size_t) tr->tx_buf; - uint8_t *rx_buf = (uint8_t *)(size_t) tr->rx_buf; + assert_int_equal(fd, audit->args.close.fd); + assert_int_equal (request, audit->args.ioctl.request); - static tpm_state_t tpm_state = TPM_DID_VID_HEAD; + assert_int_equal (tr->delay_usecs, audit->args.ioctl.tr.delay_usecs); + assert_int_equal (tr->speed_hz, audit->args.ioctl.tr.speed_hz); + assert_int_equal (tr->bits_per_word, audit->args.ioctl.tr.bits_per_word); + assert_int_equal (tr->cs_change, audit->args.ioctl.tr.cs_change); + assert_int_equal (tr->len, audit->args.ioctl.tr.len); - // Check for CS-acquire/-release which have no payload - if (len == 0) { - goto done; + if (tr->len) { + assert_non_null (tr->tx_buf); + assert_non_null (tr->rx_buf); + assert_true (!memcmp ((void *)tr->tx_buf, (void *)audit->args.ioctl.tr.tx_buf, tr->len)); + memcpy ((void *)tr->rx_buf, (void *)audit->args.ioctl.tr.rx_buf, tr->len); } - switch (tpm_state++) { - case TPM_DID_VID_HEAD: - assert_int_equal (len, 4); - assert_memory_equal(&tx_buf[0], TPM_DID_VID_0, 4); - rx_buf[3] = 0x01; // Set Waitstate OK - break; - case TPM_DID_VID_DATA: - assert_int_equal (len, sizeof (TPM_DID_VID_0) - 4); - memcpy (&rx_buf[0], &TPM_DID_VID_0[4], sizeof (TPM_DID_VID_0) - 4); - break; - case TPM_ACCESS_HEAD: - assert_int_equal (len, 4); - assert_memory_equal(&tx_buf[0], TPM_ACCESS_0, 4); - rx_buf[3] = 0x01; // Set Waitstate OK - break; - case TPM_ACCESS_DATA: - assert_int_equal (len, sizeof (TPM_ACCESS_0) - 4); - memcpy (&rx_buf[0], &TPM_ACCESS_0[4], sizeof (TPM_ACCESS_0) - 4); - break; - case TPM_STS_CMD_NOT_READY_HEAD: - assert_int_equal (len, 4); - assert_memory_equal(&tx_buf[0], TPM_STS_0_CMD_NOT_READY, 4); - rx_buf[3] = 0x01; // Set Waitstate OK - break; - case TPM_STS_CMD_NOT_READY_DATA: - assert_int_equal (len, sizeof (TPM_STS_0_CMD_NOT_READY) - 4); - memcpy (&rx_buf[0], &TPM_STS_0_CMD_NOT_READY[4], sizeof (TPM_STS_0_CMD_NOT_READY) - 4); - break; - case TPM_STS_CMD_READY_HEAD: - assert_int_equal (len, 4); - assert_memory_equal(&tx_buf[0], TPM_STS_0_CMD_READY, 4); - rx_buf[3] = 0x01; // Set Waitstate OK - break; - case TPM_STS_CMD_READY_DATA: - assert_int_equal (len, sizeof (TPM_STS_0_CMD_READY) - 4); - memcpy (&rx_buf[0], &TPM_STS_0_CMD_READY[4], sizeof (TPM_STS_0_CMD_READY) - 4); - break; - case TPM_RID_HEAD: - assert_int_equal (len, 4); - assert_memory_equal(&tx_buf[0], TPM_RID_0, 4); - rx_buf[3] = 0x01; // Set Waitstate OK - break; - case TPM_RID_DATA: - assert_int_equal (len, sizeof (TPM_RID_0) - 4); - memcpy (&rx_buf[0], &TPM_RID_0[4], sizeof (TPM_RID_0) - 4); - break; - default: - assert_true (false); + return 0; +} + +static struct_audit audit_general[] = { + /* Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, NULL) */ + { .func = __wrap_open, .args.open = { DUMMY_SPIDEV_PATH, O_RDWR, DUMMY_FD } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's sleep_ms */ + { .func = __wrap_select, .args.select = + { 0, NULL, NULL, NULL, { (TIME_MS * 1000) / 1000000, (TIME_MS * 1000) % 1000000 } } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's start_timeout */ + { .func = __wrap_gettimeofday, .args.gtod = { { 0, 0 }, NULL } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's timeout_expired */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 1, 0 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) }, NULL } }, /* Return a value <= TIME_MS, no timeout occured */ + { .func = __wrap_gettimeofday, .args.gtod = + { { 0, (TIME_MS * 1000) + 1 }, NULL } }, /* Return a value > TIME_MS to trigger a timeout event */ + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's spi_acquire */ + { .func = __wrap_ioctl, .args.ioctl = { DUMMY_FD, SPI_IOC_MESSAGE(1), .tr = + { .delay_usecs = 0, .speed_hz = 5000000, .bits_per_word = 8, .cs_change = 1, .len = 0, } } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's spi_release */ + { .func = __wrap_ioctl, .args.ioctl = { DUMMY_FD, SPI_IOC_MESSAGE(1), .tr = + { .delay_usecs = 0, .speed_hz = 5000000, .bits_per_word = 8, .cs_change = 0, .len = 0, } } }, + + /* TSS2_TCTI_I2C_HELPER_PLATFORM's spi_transfer */ + { .func = __wrap_ioctl, .args.ioctl = { DUMMY_FD, SPI_IOC_MESSAGE(1), .tr = + { .delay_usecs = 0, .speed_hz = 5000000, .bits_per_word = 8, .cs_change = 1, + .len = sizeof (TPM2_STARTUP_CMD_MOSI), .tx_buf = (unsigned long)TPM2_STARTUP_CMD_MOSI, + .rx_buf = (unsigned long)TPM2_STARTUP_CMD_MISO } } }, + + /* platform->finalize */ + { .func = __wrap_close, .args.close = { DUMMY_FD } }, + + { 0 }, +}; + +TSS2_RC __wrap_Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT *tcti_context, + size_t *size, TSS2_TCTI_SPI_HELPER_PLATFORM *platform) +{ + void *data; + bool is_expired = false; + uint8_t response[sizeof (TPM2_STARTUP_CMD_MISO)] = { 0 }; + + if (tcti_context == NULL) { + *size = sizeof (TSS2_TCTI_SPI_LTT2GO_TEST_CONTEXT); + return TSS2_RC_SUCCESS; } -done: - return 0; + /* Test TSS2_TCTI_SPI_HELPER_PLATFORM's callbacks */ + + data = platform->user_data; + assert_non_null (data); + + assert_int_equal (platform->sleep_ms (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->start_timeout (data, TIME_MS), TSS2_RC_SUCCESS); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_false (is_expired); + assert_int_equal (platform->timeout_expired (data, &is_expired), TSS2_RC_SUCCESS); + assert_true (is_expired); + assert_int_equal (platform->spi_acquire (data), TSS2_RC_SUCCESS); + assert_int_equal (platform->spi_release (data), TSS2_RC_SUCCESS); + assert_int_equal (platform->spi_transfer (data, TPM2_STARTUP_CMD_MOSI, + response, sizeof (response)), TSS2_RC_SUCCESS); + assert_true (!memcmp (response, TPM2_STARTUP_CMD_MISO, sizeof (response))); + + platform->finalize (data); + + return TSS2_RC_SUCCESS; } -/* - * The test will invoke Tss2_Tcti_Spidev_Init() and subsequently - * it will start reading TPM_DID_VID, claim locality, read TPM_STS, - * and finally read TPM_RID before exiting the Init function. - * For testing purpose, the TPM responses are hardcoded. - */ static void tcti_spi_init_test (void **state) { @@ -185,6 +273,10 @@ tcti_spi_init_test (void **state) size_t size; TSS2_TCTI_CONTEXT* tcti_ctx; + /* Initialize tester context */ + tester_ctx.audit_step = 0; + tester_ctx.audit = audit_general; + /* Get requested TCTI context size */ rc = Tss2_Tcti_Spidev_Init (NULL, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); @@ -197,8 +289,6 @@ tcti_spi_init_test (void **state) rc = Tss2_Tcti_Spidev_Init (tcti_ctx, &size, NULL); assert_int_equal (rc, TSS2_RC_SUCCESS); - TSS2_TCTI_SPI_HELPER_PLATFORM platform = ((TSS2_TCTI_SPI_HELPER_CONTEXT *) tcti_ctx)->platform; - free (platform.user_data); free (tcti_ctx); }