aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-08-01 14:41:22 -0400
committerTom Rini <trini@konsulko.com>2021-08-01 14:41:22 -0400
commit72ffb41a873722993d89c02bae4743a8ad6f16f9 (patch)
tree2508a115df4604adc9395b4f72e8ec3ec8fff90f /drivers
parent5371593aed56ee11cbb6cc6ac8d058fcd9b8f58c (diff)
parenteec44c7218a3c3ce924a282cc46a59e83feb9de1 (diff)
Merge tag 'dm-pull-1aug21' of https://source.denx.de/u-boot/custodians/u-boot-dm
sandbox TPM-emulator improvements rST documentation and fixes for moveconfig handle empty 'ranges' property in dtoc patman warning for invalid tag clean-ups to 'fdt add' command
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tpm/Makefile4
-rw-r--r--drivers/tpm/sandbox_common.c77
-rw-r--r--drivers/tpm/sandbox_common.h108
-rw-r--r--drivers/tpm/tpm2_tis_sandbox.c283
-rw-r--r--drivers/tpm/tpm_tis_sandbox.c171
5 files changed, 486 insertions, 157 deletions
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index f64d20067f..c65be52670 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -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
index 0000000000..7e0b2502e3
--- /dev/null
+++ b/drivers/tpm/sandbox_common.c
@@ -0,0 +1,77 @@
+// 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);
+}
+
+void sb_tpm_define_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
+ enum sandbox_nv_space seq, int length)
+{
+ struct nvdata_state *nvd = &nvdata[seq];
+
+ if (length > NV_DATA_SIZE)
+ log_err("Invalid length %x (max %x)\n", length, NV_DATA_SIZE);
+ nvd->length = length;
+ nvd->present = true;
+}
diff --git a/drivers/tpm/sandbox_common.h b/drivers/tpm/sandbox_common.h
new file mode 100644
index 0000000000..e822a200fd
--- /dev/null
+++ b/drivers/tpm/sandbox_common.h
@@ -0,0 +1,108 @@
+/* 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);
+
+/**
+ * sb_tpm_define_data() - Set up non-volatile data
+ *
+ * If @length is too large, an error is logged and nothing is written.
+ *
+ * @nvdata: Current nvdata state
+ * @seq: Sequence number to set up
+ * @length: Length of space in bytes
+ */
+void sb_tpm_define_data(struct nvdata_state nvdata[NV_SEQ_COUNT],
+ enum sandbox_nv_space seq, int length);
+
+#endif
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index 24c804a564..ac6eb14353 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -11,6 +11,8 @@
#include <asm/unaligned.h>
#include <linux/bitops.h>
#include <u-boot/crc.h>
+#include <u-boot/sha256.h>
+#include "sandbox_common.h"
/* Hierarchies */
enum tpm2_hierarchy {
@@ -38,29 +40,178 @@ enum tpm2_cap_tpm_property {
#define SANDBOX_TPM_PCR_NB 1
-static const u8 sandbox_extended_once_pcr[] = {
- 0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30,
- 0x27, 0x98, 0xef, 0x6e, 0xd3, 0x09, 0x97, 0x9b,
- 0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8,
- 0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x4b,
-};
-
+/*
+ * Information about our TPM emulation. This is preserved in the sandbox
+ * state file if enabled.
+ *
+ * @valid: true if this is valid (only used in s_state)
+ * @init_done: true if open() has been called
+ * @startup_done: true if TPM2_CC_STARTUP has been processed
+ * @tests_done: true if TPM2_CC_SELF_TEST has be processed
+ * @pw: TPM password per hierarchy
+ * @pw_sz: Size of each password in bytes
+ * @properties: TPM properties
+ * @pcr: TPM Platform Configuration Registers. Each of these holds a hash and
+ * can be 'extended' a number of times, meaning another hash is added into
+ * its value (initial value all zeroes)
+ * @pcr_extensions: Number of times each PCR has been extended (starts at 0)
+ * @nvdata: non-volatile data, used to store important things for the platform
+ */
struct sandbox_tpm2 {
+ bool valid;
/* TPM internal states */
bool init_done;
bool startup_done;
bool tests_done;
- /* TPM password per hierarchy */
char pw[TPM2_HIERARCHY_NB][TPM2_DIGEST_LEN + 1];
int pw_sz[TPM2_HIERARCHY_NB];
- /* TPM properties */
u32 properties[TPM2_PROPERTY_NB];
- /* TPM PCRs */
u8 pcr[SANDBOX_TPM_PCR_NB][TPM2_DIGEST_LEN];
- /* TPM PCR extensions */
u32 pcr_extensions[SANDBOX_TPM_PCR_NB];
+ struct nvdata_state nvdata[NV_SEQ_COUNT];
};
+static struct sandbox_tpm2 s_state, *g_state;
+
+/**
+ * sandbox_tpm2_read_state() - read the sandbox EC state from the state file
+ *
+ * If data is available, then blob and node will provide access to it. If
+ * not this function sets up an empty TPM.
+ *
+ * @blob: Pointer to device tree blob, or NULL if no data to read
+ * @node: Node offset to read from
+ */
+static int sandbox_tpm2_read_state(const void *blob, int node)
+{
+ struct sandbox_tpm2 *state = &s_state;
+ char prop_name[20];
+ const char *prop;
+ int len;
+ int i;
+
+ if (!blob)
+ return 0;
+ state->tests_done = fdtdec_get_int(blob, node, "tests-done", 0);
+
+ for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
+ snprintf(prop_name, sizeof(prop_name), "pw%d", i);
+
+ prop = fdt_getprop(blob, node, prop_name, &len);
+ if (len > TPM2_DIGEST_LEN)
+ return log_msg_ret("pw", -E2BIG);
+ if (prop) {
+ memcpy(state->pw[i], prop, len);
+ state->pw_sz[i] = len;
+ }
+ }
+
+ for (i = 0; i < TPM2_PROPERTY_NB; i++) {
+ snprintf(prop_name, sizeof(prop_name), "properties%d", i);
+ state->properties[i] = fdtdec_get_uint(blob, node, prop_name,
+ 0);
+ }
+
+ for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
+ int subnode;
+
+ snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
+ subnode = fdt_subnode_offset(blob, node, prop_name);
+ if (subnode < 0)
+ continue;
+ prop = fdt_getprop(blob, subnode, "value", &len);
+ if (len != TPM2_DIGEST_LEN)
+ return log_msg_ret("pcr", -E2BIG);
+ memcpy(state->pcr[i], prop, TPM2_DIGEST_LEN);
+ state->pcr_extensions[i] = fdtdec_get_uint(blob, subnode,
+ "extensions", 0);
+ }
+
+ for (i = 0; i < NV_SEQ_COUNT; i++) {
+ struct nvdata_state *nvd = &state->nvdata[i];
+
+ sprintf(prop_name, "nvdata%d", i);
+ prop = fdt_getprop(blob, node, prop_name, &len);
+ if (len > NV_DATA_SIZE)
+ return log_msg_ret("nvd", -E2BIG);
+ if (prop) {
+ memcpy(nvd->data, prop, len);
+ nvd->length = len;
+ nvd->present = true;
+ }
+ }
+ s_state.valid = true;
+
+ return 0;
+}
+
+/**
+ * sandbox_tpm2_write_state() - Write out our state to the state file
+ *
+ * The caller will ensure that there is a node ready for the state. The node
+ * may already contain the old state, in which case it is overridden.
+ *
+ * @blob: Device tree blob holding state
+ * @node: Node to write our state into
+ */
+static int sandbox_tpm2_write_state(void *blob, int node)
+{
+ const struct sandbox_tpm2 *state = g_state;
+ char prop_name[20];
+ int i;
+
+ if (!state)
+ return 0;
+
+ /*
+ * We are guaranteed enough space to write basic properties. This is
+ * SANDBOX_STATE_MIN_SPACE.
+ *
+ * We could use fdt_add_subnode() to put each set of data in its
+ * own node - perhaps useful if we add access information to each.
+ */
+ fdt_setprop_u32(blob, node, "tests-done", state->tests_done);
+
+ for (i = 0; i < TPM2_HIERARCHY_NB; i++) {
+ if (state->pw_sz[i]) {
+ snprintf(prop_name, sizeof(prop_name), "pw%d", i);
+ fdt_setprop(blob, node, prop_name, state->pw[i],
+ state->pw_sz[i]);
+ }
+ }
+
+ for (i = 0; i < TPM2_PROPERTY_NB; i++) {
+ snprintf(prop_name, sizeof(prop_name), "properties%d", i);
+ fdt_setprop_u32(blob, node, prop_name, state->properties[i]);
+ }
+
+ for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
+ int subnode;
+
+ snprintf(prop_name, sizeof(prop_name), "pcr%d", i);
+ subnode = fdt_add_subnode(blob, node, prop_name);
+ fdt_setprop(blob, subnode, "value", state->pcr[i],
+ TPM2_DIGEST_LEN);
+ fdt_setprop_u32(blob, subnode, "extensions",
+ state->pcr_extensions[i]);
+ }
+
+ for (i = 0; i < NV_SEQ_COUNT; i++) {
+ const struct nvdata_state *nvd = &state->nvdata[i];
+
+ if (nvd->present) {
+ snprintf(prop_name, sizeof(prop_name), "nvdata%d", i);
+ fdt_setprop(blob, node, prop_name, nvd->data,
+ nvd->length);
+ }
+ }
+
+ return 0;
+}
+
+SANDBOX_STATE_IO(sandbox_tpm2, "sandbox,tpm2", sandbox_tpm2_read_state,
+ sandbox_tpm2_write_state);
+
/*
* Check the tag validity depending on the command (authentication required or
* not). If authentication is required, check it is valid. Update the auth
@@ -93,6 +244,10 @@ static int sandbox_tpm2_check_session(struct udevice *dev, u32 command, u16 tag,
case TPM2_CC_DAM_RESET:
case TPM2_CC_DAM_PARAMETERS:
case TPM2_CC_PCR_EXTEND:
+ case TPM2_CC_NV_READ:
+ case TPM2_CC_NV_WRITE:
+ case TPM2_CC_NV_WRITELOCK:
+ case TPM2_CC_NV_DEFINE_SPACE:
if (tag != TPM2_ST_SESSIONS) {
printf("Session required for command 0x%x\n", command);
return TPM2_RC_AUTH_CONTEXT;
@@ -121,6 +276,10 @@ static int sandbox_tpm2_check_session(struct udevice *dev, u32 command, u16 tag,
break;
case TPM2_RH_PLATFORM:
*hierarchy = TPM2_HIERARCHY_PLATFORM;
+ if (command == TPM2_CC_NV_READ ||
+ command == TPM2_CC_NV_WRITE ||
+ command == TPM2_CC_NV_WRITELOCK)
+ *auth += sizeof(u32);
break;
default:
printf("Wrong handle 0x%x\n", handle);
@@ -242,15 +401,17 @@ static int sandbox_tpm2_extend(struct udevice *dev, int pcr_index,
const u8 *extension)
{
struct sandbox_tpm2 *tpm = dev_get_priv(dev);
- int i;
+ sha256_context ctx;
- /* Only simulate the first extensions from all '0' with only '0' */
- for (i = 0; i < TPM2_DIGEST_LEN; i++)
- if (tpm->pcr[pcr_index][i] || extension[i])
- return TPM2_RC_FAILURE;
+ /* Zero the PCR if this is the first use */
+ if (!tpm->pcr_extensions[pcr_index])
+ memset(tpm->pcr[pcr_index], '\0', TPM2_DIGEST_LEN);
+
+ sha256_starts(&ctx);
+ sha256_update(&ctx, tpm->pcr[pcr_index], TPM2_DIGEST_LEN);
+ sha256_update(&ctx, extension, TPM2_DIGEST_LEN);
+ sha256_finish(&ctx, tpm->pcr[pcr_index]);
- memcpy(tpm->pcr[pcr_index], sandbox_extended_once_pcr,
- TPM2_DIGEST_LEN);
tpm->pcr_extensions[pcr_index]++;
return 0;
@@ -477,15 +638,8 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
for (i = 0; i < pcr_array_sz; i++)
pcr_map += (u64)sent[i] << (i * 8);
- if (pcr_map >> SANDBOX_TPM_PCR_NB) {
- printf("Sandbox TPM handles up to %d PCR(s)\n",
- SANDBOX_TPM_PCR_NB);
- rc = TPM2_RC_VALUE;
- return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
- }
-
if (!pcr_map) {
- printf("Empty PCR map.\n");
+ printf("Empty PCR map\n");
rc = TPM2_RC_VALUE;
return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
}
@@ -494,6 +648,13 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
if (pcr_map & BIT(i))
pcr_index = i;
+ if (pcr_index >= SANDBOX_TPM_PCR_NB) {
+ printf("Invalid index %d, sandbox TPM handles up to %d PCR(s)\n",
+ pcr_index, SANDBOX_TPM_PCR_NB);
+ rc = TPM2_RC_VALUE;
+ return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
+ }
+
/* Write tag */
put_unaligned_be16(tag, recv);
recv += sizeof(tag);
@@ -527,9 +688,9 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
pcr_index = get_unaligned_be32(sendbuf + sizeof(tag) +
sizeof(length) +
sizeof(command));
- if (pcr_index > SANDBOX_TPM_PCR_NB) {
- printf("Sandbox TPM handles up to %d PCR(s)\n",
- SANDBOX_TPM_PCR_NB);
+ if (pcr_index >= SANDBOX_TPM_PCR_NB) {
+ printf("Invalid index %d, sandbox TPM handles up to %d PCR(s)\n",
+ pcr_index, SANDBOX_TPM_PCR_NB);
rc = TPM2_RC_VALUE;
}
@@ -557,6 +718,64 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
break;
+ case TPM2_CC_NV_READ: {
+ int index, seq;
+
+ index = get_unaligned_be32(sendbuf + TPM2_HDR_LEN + 4);
+ length = get_unaligned_be16(sent);
+ /* ignore offset */
+ seq = sb_tpm_index_to_seq(index);
+ if (seq < 0)
+ return log_msg_ret("index", -EINVAL);
+ printf("tpm: nvread index=%#02x, len=%#02x, seq=%#02x\n", index,
+ length, seq);
+ *recv_len = TPM2_HDR_LEN + 6 + length;
+ memset(recvbuf, '\0', *recv_len);
+ put_unaligned_be32(length, recvbuf + 2);
+ sb_tpm_read_data(tpm->nvdata, seq, recvbuf,
+ TPM2_HDR_LEN + 4 + 2, length);
+ break;
+ }
+ case TPM2_CC_NV_WRITE: {
+ int index, seq;
+
+ index = get_unaligned_be32(sendbuf + TPM2_HDR_LEN + 4);
+ length = get_unaligned_be16(sent);
+ sent += sizeof(u16);
+
+ /* ignore offset */
+ seq = sb_tpm_index_to_seq(index);
+ if (seq < 0)
+ return log_msg_ret("index", -EINVAL);
+ printf("tpm: nvwrite index=%#02x, len=%#02x, seq=%#02x\n", index,
+ length, seq);
+ memcpy(&tpm->nvdata[seq].data, sent, length);
+ tpm->nvdata[seq].present = true;
+ *recv_len = TPM2_HDR_LEN + 2;
+ memset(recvbuf, '\0', *recv_len);
+ break;
+ }
+ case TPM2_CC_NV_DEFINE_SPACE: {
+ int policy_size, index, seq;
+
+ policy_size = get_unaligned_be16(sent + 12);
+ index = get_unaligned_be32(sent + 2);
+ sent += 14 + policy_size;
+ length = get_unaligned_be16(sent);
+ seq = sb_tpm_index_to_seq(index);
+ if (seq < 0)
+ return -EINVAL;
+ printf("tpm: define_space index=%x, len=%x, seq=%x, policy_size=%x\n",
+ index, length, seq, policy_size);
+ sb_tpm_define_data(tpm->nvdata, seq, length);
+ *recv_len = 12;
+ memset(recvbuf, '\0', *recv_len);
+ break;
+ }
+ case TPM2_CC_NV_WRITELOCK:
+ *recv_len = 12;
+ memset(recvbuf, '\0', *recv_len);
+ break;
default:
printf("TPM2 command %02x unknown in Sandbox\n", command);
rc = TPM2_RC_COMMAND_CODE;
@@ -594,11 +813,13 @@ static int sandbox_tpm2_probe(struct udevice *dev)
/* Use the TPM v2 stack */
priv->version = TPM_V2;
- memset(tpm, 0, sizeof(*tpm));
-
priv->pcr_count = 32;
priv->pcr_select_min = 2;
+ if (s_state.valid)
+ memcpy(tpm, &s_state, sizeof(*tpm));
+ g_state = tpm;
+
return 0;
}
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c
index 67139cea3b..efbeb00ab6 100644
--- a/drivers/tpm/tpm_tis_sandbox.c
+++ b/drivers/tpm/tpm_tis_sandbox.c
@@ -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.
@@ -71,7 +20,7 @@ struct nvdata_state {
static struct tpm_state {
bool valid;
struct nvdata_state nvdata[NV_SEQ_COUNT];
-} g_state;
+} s_state, *g_state;
/**
* sandbox_tpm_read_state() - read the sandbox EC state from the state file
@@ -84,6 +33,7 @@ static struct tpm_state {
*/
static int sandbox_tpm_read_state(const void *blob, int node)
{
+ struct tpm_state *state = &s_state;
const char *prop;
int len;
int i;
@@ -92,22 +42,27 @@ static int sandbox_tpm_read_state(const void *blob, int node)
return 0;
for (i = 0; i < NV_SEQ_COUNT; i++) {
+ struct nvdata_state *nvd = &state->nvdata[i];
char prop_name[20];
sprintf(prop_name, "nvdata%d", i);
prop = fdt_getprop(blob, node, prop_name, &len);
- if (prop && len == NV_DATA_SIZE) {
- memcpy(g_state.nvdata[i].data, prop, NV_DATA_SIZE);
- g_state.nvdata[i].present = true;
+ if (len >= NV_DATA_SIZE)
+ return log_msg_ret("nvd", -E2BIG);
+ if (prop) {
+ memcpy(nvd->data, prop, len);
+ nvd->length = len;
+ nvd->present = true;
}
}
- g_state.valid = true;
+
+ s_state.valid = true;
return 0;
}
/**
- * cros_ec_write_state() - Write out our state to the state file
+ * sandbox_tpm_write_state() - Write out our state to the state file
*
* The caller will ensure that there is a node ready for the state. The node
* may already contain the old state, in which case it is overridden.
@@ -117,20 +72,25 @@ static int sandbox_tpm_read_state(const void *blob, int node)
*/
static int sandbox_tpm_write_state(void *blob, int node)
{
+ const struct tpm_state *state = g_state;
int i;
+ if (!state)
+ return 0;
+
/*
* We are guaranteed enough space to write basic properties.
* We could use fdt_add_subnode() to put each set of data in its
* own node - perhaps useful if we add access informaiton to each.
*/
for (i = 0; i < NV_SEQ_COUNT; i++) {
+ const struct nvdata_state *nvd = &state->nvdata[i];
char prop_name[20];
- if (g_state.nvdata[i].present) {
- sprintf(prop_name, "nvdata%d", i);
- fdt_setprop(blob, node, prop_name,
- g_state.nvdata[i].data, NV_DATA_SIZE);
+ if (nvd->present) {
+ snprintf(prop_name, sizeof(prop_name), "nvdata%d", i);
+ fdt_setprop(blob, node, prop_name, nvd->data,
+ nvd->length);
}
}
@@ -140,27 +100,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;
@@ -201,16 +140,13 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
printf("Get flags index %#02x\n", index);
*recv_len = 22;
memset(recvbuf, '\0', *recv_len);
- data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
- sizeof(uint32_t);
+ data = recvbuf + TPM_HDR_LEN + sizeof(uint32_t);
switch (index) {
case FIRMWARE_NV_INDEX:
break;
case KERNEL_NV_INDEX:
handle_cap_flag_space(&data, index);
- *recv_len = data - recvbuf -
- TPM_RESPONSE_HEADER_LENGTH -
- sizeof(uint32_t);
+ *recv_len = data - recvbuf;
break;
case TPM_CAP_FLAG_PERMANENT: {
struct tpm_permanent_flags *pflags;
@@ -227,15 +163,12 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
printf(" ** Unknown flags index %x\n", index);
return -ENOSYS;
}
- put_unaligned_be32(*recv_len,
- recvbuf +
- TPM_RESPONSE_HEADER_LENGTH);
+ put_unaligned_be32(*recv_len, recvbuf + TPM_HDR_LEN);
break;
case TPM_CAP_NV_INDEX:
index = get_unaligned_be32(sendbuf + 18);
printf("Get cap nv index %#02x\n", index);
- put_unaligned_be32(22, recvbuf +
- TPM_RESPONSE_HEADER_LENGTH);
+ put_unaligned_be32(22, recvbuf + TPM_HDR_LEN);
break;
default:
printf(" ** Unknown 0x65 command type %#02x\n",
@@ -246,54 +179,42 @@ 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;
memset(recvbuf, '\0', *recv_len);
break;
case TPM_CMD_NV_DEFINE_SPACE:
+ index = get_unaligned_be32(sendbuf + 12);
+ length = get_unaligned_be32(sendbuf + 77);
+ seq = sb_tpm_index_to_seq(index);
+ if (seq < 0)
+ return -EINVAL;
+ printf("tpm: define_space index=%#02x, len=%#02x, seq=%#02x\n",
+ index, length, seq);
+ sb_tpm_define_data(tpm->nvdata, seq, length);
+ *recv_len = 12;
+ memset(recvbuf, '\0', *recv_len);
+ break;
case 0x15: /* pcr read */
case 0x5d: /* force clear */
case 0x6f: /* physical enable */
@@ -328,7 +249,9 @@ static int sandbox_tpm_probe(struct udevice *dev)
{
struct tpm_state *tpm = dev_get_priv(dev);
- memcpy(tpm, &g_state, sizeof(*tpm));
+ if (s_state.valid)
+ memcpy(tpm, &s_state, sizeof(*tpm));
+ g_state = tpm;
return 0;
}