summaryrefslogtreecommitdiff
path: root/drivers/tpm
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2021-07-18 23:18:04 +0300
committerSimon Glass <sjg@chromium.org>2021-08-01 18:05:24 +0300
commita986216e348153705e0a019afc95da65baa1fff0 (patch)
tree0e5581b55e4dfdbfb1f86131fc5ab93dcbf71a13 /drivers/tpm
parentd8f105dd7170bcb0370b8ce18503834cdeeec7c1 (diff)
downloadu-boot-a986216e348153705e0a019afc95da65baa1fff0.tar.xz
sandbox: tpm: Support storing device state in tpm2
At present the tpm2 emulator does not support storing the device state. Add this so we can handle the normal vboot flow through the sandbox executables (VPL->SPL etc.) with the TPM contents staying in place. Note: sandbox has not yet been converted to use livetree for the state information, since livetree does not yet support writing to the tree. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/tpm')
-rw-r--r--drivers/tpm/tpm2_tis_sandbox.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index 1d38a79a86..ed9c9a0bc9 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -79,6 +79,145 @@ struct sandbox_tpm2 {
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