sandbox: tpm: Split out common nvdata code
authorSimon Glass <sjg@chromium.org>
Sun, 18 Jul 2021 20:17:57 +0000 (14:17 -0600)
committerSimon Glass <sjg@chromium.org>
Sun, 1 Aug 2021 15:05:24 +0000 (09:05 -0600)
We want to support nvdata in TPM2 as well. To avoid code duplicating the
associated code, move it into a common file.

Drop the special-case logic for the kernel space. This can be handled by
the higher-level code now, i.e. in vboot itself.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/tpm/Makefile
drivers/tpm/sandbox_common.c [new file with mode: 0644]
drivers/tpm/sandbox_common.h [new file with mode: 0644]
drivers/tpm/tpm_tis_sandbox.c

index f64d200..c65be52 100644 (file)
@@ -6,11 +6,11 @@ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-uclass.o
 obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
 obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o
 obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
-obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
+obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o sandbox_common.o
 obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o
 obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o
 
 obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o
-obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o
+obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o
 obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_spi.o
 obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
diff --git a/drivers/tpm/sandbox_common.c b/drivers/tpm/sandbox_common.c
new file mode 100644 (file)
index 0000000..13f5e03
--- /dev/null
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Common features for sandbox TPM1 and TPM2 implementations
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#define LOG_CATEGORY   UCLASS_TPM
+
+#include <common.h>
+#include <tpm-v1.h>
+#include <tpm-v2.h>
+#include <asm/unaligned.h>
+#include "sandbox_common.h"
+
+#define TPM_ERR_CODE_OFS       (2 + 4)         /* after tag and size */
+
+int sb_tpm_index_to_seq(u32 index)
+{
+       index &= ~HR_NV_INDEX;
+       switch (index) {
+       case FIRMWARE_NV_INDEX:
+               return NV_SEQ_FIRMWARE;
+       case KERNEL_NV_INDEX:
+               return NV_SEQ_KERNEL;
+       case BACKUP_NV_INDEX:
+               return NV_SEQ_BACKUP;
+       case FWMP_NV_INDEX:
+               return NV_SEQ_FWMP;
+       case MRC_REC_HASH_NV_INDEX:
+               return NV_SEQ_REC_HASH;
+       case 0:
+               return NV_SEQ_GLOBAL_LOCK;
+       case TPM_NV_INDEX_LOCK:
+               return NV_SEQ_ENABLE_LOCKING;
+       }
+
+       printf("Invalid nv index %#x\n", index);
+       return -1;
+}
+
+void sb_tpm_read_data(const struct nvdata_state nvdata[NV_SEQ_COUNT],
+                     enum sandbox_nv_space seq, u8 *buf, int data_ofs,
+                     int length)
+{
+       const struct nvdata_state *nvd = &nvdata[seq];
+
+       if (!nvd->present)
+               put_unaligned_be32(TPM_BADINDEX, buf + TPM_ERR_CODE_OFS);
+       else if (length > nvd->length)
+               put_unaligned_be32(TPM_BAD_DATASIZE, buf + TPM_ERR_CODE_OFS);
+       else
+               memcpy(buf + data_ofs, &nvd->data, length);
+}
+
+void sb_tpm_write_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
+                      enum sandbox_nv_space seq, const u8 *buf, int data_ofs,
+                      int length)
+{
+       struct nvdata_state *nvd = &nvdata[seq];
+
+       if (length > nvd->length)
+               log_err("Invalid length %x (max %x)\n", length, nvd->length);
+       else
+               memcpy(&nvdata[seq].data, buf + data_ofs, length);
+}
diff --git a/drivers/tpm/sandbox_common.h b/drivers/tpm/sandbox_common.h
new file mode 100644 (file)
index 0000000..aa5292d
--- /dev/null
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Common features for sandbox TPM1 and TPM2 implementations
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#ifndef __TPM_SANDBOX_COMMON_H
+#define __TPM_SANDBOX_COMMON_H
+
+/*
+ * These numbers derive from adding the sizes of command fields as shown in
+ * the TPM commands manual.
+ */
+#define TPM_HDR_LEN    10
+
+/* These are the different non-volatile spaces that we emulate */
+enum sandbox_nv_space {
+       NV_SEQ_ENABLE_LOCKING,
+       NV_SEQ_GLOBAL_LOCK,
+       NV_SEQ_FIRMWARE,
+       NV_SEQ_KERNEL,
+       NV_SEQ_BACKUP,
+       NV_SEQ_FWMP,
+       NV_SEQ_REC_HASH,
+
+       NV_SEQ_COUNT,
+};
+
+/* TPM NVRAM location indices */
+#define FIRMWARE_NV_INDEX              0x1007
+#define KERNEL_NV_INDEX                        0x1008
+#define BACKUP_NV_INDEX                        0x1009
+#define FWMP_NV_INDEX                  0x100a
+#define MRC_REC_HASH_NV_INDEX          0x100b
+
+/* Size of each non-volatile space */
+#define NV_DATA_SIZE           0x28
+
+/**
+ * struct nvdata_state - state of a single non-volatile-data 'space'
+ *
+ * @present: true if present
+ * @length: length in bytes (max NV_DATA_SIZE)
+ * @data: contents of non-volatile space
+ */
+struct nvdata_state {
+       bool present;
+       int length;
+       u8 data[NV_DATA_SIZE];
+};
+
+/**
+ * sb_tpm_index_to_seq() - convert an index into a space sequence number
+ *
+ * This converts the index as used by the vboot code into an internal sequence
+ * number used by the sandbox emulation.
+ *
+ * @index: Index to use (FIRMWARE_NV_INDEX, etc.)
+ * @return associated space (enum sandbox_nv_space)
+ */
+int sb_tpm_index_to_seq(uint index);
+
+/**
+ * sb_tpm_read_data() - Read non-volatile data
+ *
+ * This handles a TPM read of nvdata. If the nvdata is not present, a
+ * TPM_BADINDEX error is put in the buffer. If @length is too large,
+ * TPM_BAD_DATASIZE is put in the buffer.
+ *
+ * @nvdata: Current nvdata state
+ * @seq: Sequence number to read
+ * @recvbuf: Buffer to update with the TPM response, assumed to contain zeroes
+ * @data_ofs: Offset of the 'data' portion of @recvbuf
+ * @length: Number of bytes to read
+ */
+void sb_tpm_read_data(const struct nvdata_state nvdata[NV_SEQ_COUNT],
+                     enum sandbox_nv_space seq, u8 *recvbuf, int data_ofs,
+                     int length);
+
+/**
+ * sb_tpm_write_data() - Write non-volatile data
+ *
+ * If @length is too large, an error is logged and nothing is written.
+ *
+ * @nvdata: Current nvdata state
+ * @seq: Sequence number to read
+ * @buf: Buffer containing the data to write
+ * @data_ofs: Offset of the 'data' portion of @buf
+ * @length: Number of bytes to write
+ */
+void sb_tpm_write_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
+                      enum sandbox_nv_space seq, const u8 *buf, int data_ofs,
+                      int length);
+
+#endif
index 67139ce..294d98d 100644 (file)
@@ -9,61 +9,10 @@
 #include <asm/state.h>
 #include <asm/unaligned.h>
 #include <u-boot/crc.h>
-
-/* TPM NVRAM location indices. */
-#define FIRMWARE_NV_INDEX              0x1007
-#define KERNEL_NV_INDEX                        0x1008
-#define BACKUP_NV_INDEX                 0x1009
-#define FWMP_NV_INDEX                   0x100a
-#define REC_HASH_NV_INDEX               0x100b
-#define REC_HASH_NV_SIZE                VB2_SHA256_DIGEST_SIZE
+#include "sandbox_common.h"
 
 #define NV_DATA_PUBLIC_PERMISSIONS_OFFSET      60
 
-/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
-#define ROLLBACK_SPACE_KERNEL_VERSION  2
-#define ROLLBACK_SPACE_KERNEL_UID      0x4752574C  /* 'GRWL' */
-
-struct rollback_space_kernel {
-       /* Struct version, for backwards compatibility */
-       uint8_t struct_version;
-       /* Unique ID to detect space redefinition */
-       uint32_t uid;
-       /* Kernel versions */
-       uint32_t kernel_versions;
-       /* Reserved for future expansion */
-       uint8_t reserved[3];
-       /* Checksum (v2 and later only) */
-       uint8_t crc8;
-} __packed rollback_space_kernel;
-
-/*
- * These numbers derive from adding the sizes of command fields as shown in
- * the TPM commands manual.
- */
-#define TPM_REQUEST_HEADER_LENGTH      10
-#define TPM_RESPONSE_HEADER_LENGTH     10
-
-/* These are the different non-volatile spaces that we emulate */
-enum {
-       NV_GLOBAL_LOCK,
-       NV_SEQ_FIRMWARE,
-       NV_SEQ_KERNEL,
-       NV_SEQ_BACKUP,
-       NV_SEQ_FWMP,
-       NV_SEQ_REC_HASH,
-
-       NV_SEQ_COUNT,
-};
-
-/* Size of each non-volatile space */
-#define NV_DATA_SIZE           0x20
-
-struct nvdata_state {
-       bool present;
-       u8 data[NV_DATA_SIZE];
-};
-
 /*
  * Information about our TPM emulation. This is preserved in the sandbox
  * state file if enabled.
@@ -140,27 +89,6 @@ static int sandbox_tpm_write_state(void *blob, int node)
 SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
                 sandbox_tpm_write_state);
 
-static int index_to_seq(uint32_t index)
-{
-       switch (index) {
-       case FIRMWARE_NV_INDEX:
-               return NV_SEQ_FIRMWARE;
-       case KERNEL_NV_INDEX:
-               return NV_SEQ_KERNEL;
-       case BACKUP_NV_INDEX:
-               return NV_SEQ_BACKUP;
-       case FWMP_NV_INDEX:
-               return NV_SEQ_FWMP;
-       case REC_HASH_NV_INDEX:
-               return NV_SEQ_REC_HASH;
-       case 0:
-               return NV_GLOBAL_LOCK;
-       }
-
-       printf("Invalid nv index %#x\n", index);
-       return -1;
-}
-
 static void handle_cap_flag_space(u8 **datap, uint index)
 {
        struct tpm_nv_data_public pub;
@@ -246,48 +174,25 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
        case TPM_CMD_NV_WRITE_VALUE:
                index = get_unaligned_be32(sendbuf + 10);
                length = get_unaligned_be32(sendbuf + 18);
-               seq = index_to_seq(index);
+               seq = sb_tpm_index_to_seq(index);
                if (seq < 0)
                        return -EINVAL;
                printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
-               memcpy(&tpm->nvdata[seq].data, sendbuf + 22, length);
-               tpm->nvdata[seq].present = true;
-               *recv_len = 12;
-               memset(recvbuf, '\0', *recv_len);
+               sb_tpm_write_data(tpm->nvdata, seq, sendbuf, 22, length);
                break;
        case TPM_CMD_NV_READ_VALUE: /* nvread */
                index = get_unaligned_be32(sendbuf + 10);
                length = get_unaligned_be32(sendbuf + 18);
-               seq = index_to_seq(index);
+               seq = sb_tpm_index_to_seq(index);
                if (seq < 0)
                        return -EINVAL;
                printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
                       length, seq);
-               *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
-                                       length;
+               *recv_len = TPM_HDR_LEN + sizeof(uint32_t) + length;
                memset(recvbuf, '\0', *recv_len);
-               put_unaligned_be32(length, recvbuf +
-                                  TPM_RESPONSE_HEADER_LENGTH);
-               if (seq == NV_SEQ_KERNEL) {
-                       struct rollback_space_kernel rsk;
-
-                       data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
-                                       sizeof(uint32_t);
-                       memset(&rsk, 0, sizeof(struct rollback_space_kernel));
-                       rsk.struct_version = 2;
-                       rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
-                       rsk.crc8 = crc8(0, (unsigned char *)&rsk,
-                                       offsetof(struct rollback_space_kernel,
-                                                crc8));
-                       memcpy(data, &rsk, sizeof(rsk));
-               } else if (!tpm->nvdata[seq].present) {
-                       put_unaligned_be32(TPM_BADINDEX, recvbuf +
-                                          sizeof(uint16_t) + sizeof(uint32_t));
-               } else {
-                       memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
-                              sizeof(uint32_t), &tpm->nvdata[seq].data,
-                              length);
-               }
+               put_unaligned_be32(length, recvbuf + TPM_HDR_LEN);
+               sb_tpm_read_data(tpm->nvdata, seq, recvbuf, TPM_HDR_LEN + 4,
+                                length);
                break;
        case TPM_CMD_EXTEND:
                *recv_len = 30;