u-boot.lists.denx.de archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/7] tpm: Various minor fixes and enhancements
@ 2022-08-23 17:12 Simon Glass
  2022-08-23 17:12 ` [PATCH v4 1/7] tpm: Require a digest source when extending the PCR Simon Glass
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Simon Glass, Heinrich Schuchardt, Ilias Apalodimas,
	Masahisa Kojima, Mathew McBride, Ruchika Gupta, Sughosh Ganu

This series contains some minor enhancements for the TPM code to make it
work with Chromium OS verified boot.

Changes in v4:
- Rename function and add arguments for the command/subcmd
- Rename function and add arguments for the command/subcmd

Changes in v3:
- Drop limits on the TPM hash size
- Update commit message

Changes in v2:
- Use "cmd" for the digest type in the tpm command
- Update comment for tpm_pcr_extend() 'name' parameter
- Use constants instead of open-coded values

Simon Glass (7):
  tpm: Require a digest source when extending the PCR
  tpm: Correct the permissions command in TPMv1
  tpm: Correct the define-space command in TPMv2
  tpm: sandbox: Allow init of TPM in a different phase
  tpm: Allow reporting the internal state
  tpm: Implement state command for Cr50
  tpm: Allow committing non-volatile data

 cmd/tpm-common.c               |  20 ++++
 cmd/tpm-user-utils.h           |   2 +
 cmd/tpm-v1.c                   |   3 +-
 cmd/tpm-v2.c                   |   3 +
 cmd/tpm_test.c                 |   5 +-
 drivers/tpm/cr50_i2c.c         | 163 +++++++++++++++++++++++++++++++++
 drivers/tpm/tpm-uclass.c       |  10 ++
 drivers/tpm/tpm2_tis_sandbox.c |  17 +++-
 include/tpm-common.h           |  20 ++++
 include/tpm-v2.h               |  30 ++++++
 include/tpm_api.h              |   8 +-
 lib/tpm-v1.c                   |   5 +-
 lib/tpm-v2.c                   |  70 ++++++++++++--
 lib/tpm_api.c                  |  10 +-
 test/dm/Makefile               |   1 +
 test/dm/tpm.c                  |  34 +++++++
 16 files changed, 380 insertions(+), 21 deletions(-)
 create mode 100644 test/dm/tpm.c

-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 1/7] tpm: Require a digest source when extending the PCR
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-08-26  6:30   ` Ilias Apalodimas
  2022-08-23 17:12 ` [PATCH v4 2/7] tpm: Correct the permissions command in TPMv1 Simon Glass
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Simon Glass, Heinrich Schuchardt, Ilias Apalodimas,
	Masahisa Kojima, Mathew McBride, Ruchika Gupta, Sughosh Ganu

This feature is used for measured boot, so we can add a log entry to the
TCPA with some information about where the digest comes from. It is not
currently supported in the TPM drivers, but add it to the API so that
code which expects it can signal its request.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v3)

Changes in v3:
- Drop limits on the TPM hash size
- Update commit message

Changes in v2:
- Use "cmd" for the digest type in the tpm command
- Update comment for tpm_pcr_extend() 'name' parameter

 cmd/tpm-v1.c      |  3 ++-
 cmd/tpm_test.c    |  5 +++--
 include/tpm_api.h |  8 +++++---
 lib/tpm-v2.c      |  2 ++
 lib/tpm_api.c     | 10 ++++++----
 5 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c
index bf238a9f2e3..0efb079b0a9 100644
--- a/cmd/tpm-v1.c
+++ b/cmd/tpm-v1.c
@@ -131,7 +131,8 @@ static int do_tpm_extend(struct cmd_tbl *cmdtp, int flag, int argc,
 		return CMD_RET_FAILURE;
 	}
 
-	rc = tpm_pcr_extend(dev, index, in_digest, out_digest);
+	rc = tpm_pcr_extend(dev, index, in_digest, sizeof(in_digest),
+			    out_digest, "cmd");
 	if (!rc) {
 		puts("PCR value after execution of the command:\n");
 		print_byte_string(out_digest, sizeof(out_digest));
diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c
index a3ccb12f53a..b35eae81dc3 100644
--- a/cmd/tpm_test.c
+++ b/cmd/tpm_test.c
@@ -91,7 +91,8 @@ static int test_early_extend(struct udevice *dev)
 	tpm_init(dev);
 	TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR));
 	TPM_CHECK(tpm_continue_self_test(dev));
-	TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out));
+	TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, sizeof(value_in), value_out,
+				 "test"));
 	printf("done\n");
 	return 0;
 }
@@ -438,7 +439,7 @@ static int test_timing(struct udevice *dev)
 		   100);
 	TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)),
 		   100);
-	TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200);
+	TTPM_CHECK(tpm_pcr_extend(dev, 0, in, sizeof(in), out, "test"), 200);
 	TTPM_CHECK(tpm_set_global_lock(dev), 50);
 	TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100);
 	printf("done\n");
diff --git a/include/tpm_api.h b/include/tpm_api.h
index 11aa14eb793..8979d9d6df7 100644
--- a/include/tpm_api.h
+++ b/include/tpm_api.h
@@ -81,14 +81,16 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
  *
  * @param dev		TPM device
  * @param index		index of the PCR
- * @param in_digest	160-bit value representing the event to be
+ * @param in_digest	160/256-bit value representing the event to be
  *			recorded
- * @param out_digest	160-bit PCR value after execution of the
+ * @param size		size of digest in bytes
+ * @param out_digest	160/256-bit PCR value after execution of the
  *			command
+ * @param name		digest source, used for log output
  * Return: return code of the operation
  */
 u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
-		   void *out_digest);
+		   uint size, void *out_digest, const char *name);
 
 /**
  * Issue a TPM_PCRRead command.
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 1bf627853af..6058f2e1e4f 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -157,6 +157,8 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
 	};
 	int ret;
 
+	if (!digest)
+		return -EINVAL;
 	/*
 	 * Fill the command structure starting from the first buffer:
 	 *     - the digest
diff --git a/lib/tpm_api.c b/lib/tpm_api.c
index 032f383ca04..aa4a9fd406c 100644
--- a/lib/tpm_api.c
+++ b/lib/tpm_api.c
@@ -140,15 +140,17 @@ u32 tpm_write_lock(struct udevice *dev, u32 index)
 }
 
 u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
-		   void *out_digest)
+		   uint size, void *out_digest, const char *name)
 {
-	if (tpm_is_v1(dev))
+	if (tpm_is_v1(dev)) {
 		return tpm1_extend(dev, index, in_digest, out_digest);
-	else if (tpm_is_v2(dev))
+	} else if (tpm_is_v2(dev)) {
 		return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest,
 				       TPM2_DIGEST_LEN);
-	else
+		/* @name is ignored as we do not support measured boot */
+	} else {
 		return -ENOSYS;
+	}
 }
 
 u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 2/7] tpm: Correct the permissions command in TPMv1
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
  2022-08-23 17:12 ` [PATCH v4 1/7] tpm: Require a digest source when extending the PCR Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-08-26  6:30   ` Ilias Apalodimas
  2022-08-23 17:12 ` [PATCH v4 3/7] tpm: Correct the define-space command in TPMv2 Simon Glass
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List; +Cc: Simon Glass, Ilias Apalodimas, Mathew McBride

The offset here is incorrect. Fix it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 lib/tpm-v1.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c
index 22a769c5874..d0e3ab1b21d 100644
--- a/lib/tpm-v1.c
+++ b/lib/tpm-v1.c
@@ -456,12 +456,13 @@ u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
 		0x0, 0x0, 0x0, 0x4,
 	};
 	const size_t index_offset = 18;
-	const size_t perm_offset = 60;
+	const size_t perm_offset = 74;
 	u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
 	size_t response_length = sizeof(response);
 	u32 err;
 
-	if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
+	if (pack_byte_string(buf, sizeof(buf), "sd",
+			     0, command, sizeof(command),
 			     index_offset, index))
 		return TPM_LIB_ERROR;
 	err = tpm_sendrecv_command(dev, buf, response, &response_length);
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 3/7] tpm: Correct the define-space command in TPMv2
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
  2022-08-23 17:12 ` [PATCH v4 1/7] tpm: Require a digest source when extending the PCR Simon Glass
  2022-08-23 17:12 ` [PATCH v4 2/7] tpm: Correct the permissions command in TPMv1 Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-08-26  6:31   ` Ilias Apalodimas
  2022-08-23 17:12 ` [PATCH v4 4/7] tpm: sandbox: Allow init of TPM in a different phase Simon Glass
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Simon Glass, Ilias Apalodimas, Masahisa Kojima, Ruchika Gupta

The message format is incorrect. Fix it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v2)

Changes in v2:
- Use constants instead of open-coded values

 lib/tpm-v2.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 6058f2e1e4f..3e240bb4c67 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -89,14 +89,18 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
 	 * Calculate the offset of the nv_policy piece by adding each of the
 	 * chunks below.
 	 */
-	uint offset = 10 + 8 + 13 + 14;
+	const int platform_len = sizeof(u32);
+	const int session_hdr_len = 13;
+	const int message_len = 14;
+	uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
+		message_len;
 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
 		/* header 10 bytes */
 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
-		tpm_u32(offset + nv_policy_size),/* Length */
+		tpm_u32(offset + nv_policy_size + 2),/* Length */
 		tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
 
-		/* handles 8 bytes */
+		/* handles 4 bytes */
 		tpm_u32(TPM2_RH_PLATFORM),	/* Primary platform seed */
 
 		/* session header 13 bytes */
@@ -107,12 +111,15 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
 		tpm_u16(0),			/* auth_size */
 
 		/* message 14 bytes + policy */
-		tpm_u16(12 + nv_policy_size),	/* size */
+		tpm_u16(message_len + nv_policy_size),	/* size */
 		tpm_u32(space_index),
 		tpm_u16(TPM2_ALG_SHA256),
 		tpm_u32(nv_attributes),
 		tpm_u16(nv_policy_size),
-		/* nv_policy */
+		/*
+		 * nv_policy
+		 * space_size
+		 */
 	};
 	int ret;
 
@@ -120,8 +127,9 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
 	 * Fill the command structure starting from the first buffer:
 	 *     - the password (if any)
 	 */
-	ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
-			       offset, nv_policy, nv_policy_size);
+	ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
+			       offset, nv_policy, nv_policy_size,
+			       offset + nv_policy_size, space_size);
 	if (ret)
 		return TPM_LIB_ERROR;
 
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 4/7] tpm: sandbox: Allow init of TPM in a different phase
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
                   ` (2 preceding siblings ...)
  2022-08-23 17:12 ` [PATCH v4 3/7] tpm: Correct the define-space command in TPMv2 Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-08-23 17:12 ` [PATCH v4 5/7] tpm: Allow reporting the internal state Simon Glass
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List; +Cc: Simon Glass, Ilias Apalodimas

At present the emulator assumes that the TPM is inited in the same phase
where it is used. But in fact SPL may init the TPM, so we don't want to
complain when U-Boot proper later uses it. Remove this check.

It might be best to save this information into the device state for the
TPM, so that we can make sure the TPM was inited at some point. For now,
this seems good enough.

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 drivers/tpm/tpm2_tis_sandbox.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index ac6eb143539..c26f5d35abf 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -366,8 +366,10 @@ static int sandbox_tpm2_check_readyness(struct udevice *dev, int command)
 
 		break;
 	default:
-		if (!tpm->tests_done)
-			return TPM2_RC_NEEDS_TEST;
+		/* Skip this, since the startup may have happened in SPL
+		 * if (!tpm->tests_done)
+		 *    return TPM2_RC_NEEDS_TEST;
+		 */
 
 		break;
 	}
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 5/7] tpm: Allow reporting the internal state
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
                   ` (3 preceding siblings ...)
  2022-08-23 17:12 ` [PATCH v4 4/7] tpm: sandbox: Allow init of TPM in a different phase Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-08-26  6:37   ` Ilias Apalodimas
  2022-08-23 17:12 ` [PATCH v4 6/7] tpm: Implement state command for Cr50 Simon Glass
  2022-08-23 17:12 ` [PATCH v4 7/7] tpm: Allow committing non-volatile data Simon Glass
  6 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Simon Glass, Heinrich Schuchardt, Ilias Apalodimas, Ruchika Gupta

It is useful to read information about the current TPM state, where
supported, e.g. for debugging purposes when verified boot fails.

Add support for this to the TPM interface as well as Cr50. Add a simple
sandbox test.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 cmd/tpm-common.c               | 20 ++++++++++++++++++++
 cmd/tpm-user-utils.h           |  2 ++
 cmd/tpm-v2.c                   |  3 +++
 drivers/tpm/tpm-uclass.c       | 10 ++++++++++
 drivers/tpm/tpm2_tis_sandbox.c | 11 +++++++++++
 include/tpm-common.h           | 20 ++++++++++++++++++++
 test/dm/Makefile               |  1 +
 test/dm/tpm.c                  | 34 ++++++++++++++++++++++++++++++++++
 8 files changed, 101 insertions(+)
 create mode 100644 test/dm/tpm.c

diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c
index 47adaffd184..d0c63cadf41 100644
--- a/cmd/tpm-common.c
+++ b/cmd/tpm-common.c
@@ -333,6 +333,26 @@ int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	return 0;
 }
 
+int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	struct udevice *dev;
+	char buf[80];
+	int rc;
+
+	rc = get_tpm(&dev);
+	if (rc)
+		return rc;
+	rc = tpm_report_state(dev, buf, sizeof(buf));
+	if (rc < 0) {
+		printf("Couldn't get TPM state (%d)\n", rc);
+		return CMD_RET_FAILURE;
+	}
+	printf("%s\n", buf);
+
+	return 0;
+}
+
 int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	struct udevice *dev;
diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h
index 358ddff5761..de4a934aab6 100644
--- a/cmd/tpm-user-utils.h
+++ b/cmd/tpm-user-utils.h
@@ -21,6 +21,8 @@ int do_tpm_device(struct cmd_tbl *cmdtp, int flag, int argc,
 		  char *const argv[]);
 int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
+int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[]);
 int do_tpm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 
 #endif /* __TPM_USER_UTILS_H */
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
index 4ea5f9f094f..d93b83ada93 100644
--- a/cmd/tpm-v2.c
+++ b/cmd/tpm-v2.c
@@ -359,6 +359,7 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
 static struct cmd_tbl tpm2_commands[] = {
 	U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
 	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
+	U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""),
 	U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
 	U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""),
 	U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""),
@@ -389,6 +390,8 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "    Show all devices or set the specified device\n"
 "info\n"
 "    Show information about the TPM.\n"
+"state\n"
+"    Show internal state from the TPM (if available)\n"
 "init\n"
 "    Initialize the software stack. Always the first command to issue.\n"
 "startup <mode>\n"
diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
index 0eb35f50c4e..5ff0cd3958c 100644
--- a/drivers/tpm/tpm-uclass.c
+++ b/drivers/tpm/tpm-uclass.c
@@ -49,6 +49,16 @@ int tpm_get_desc(struct udevice *dev, char *buf, int size)
 	return ops->get_desc(dev, buf, size);
 }
 
+int tpm_report_state(struct udevice *dev, char *buf, int size)
+{
+	struct tpm_ops *ops = tpm_get_ops(dev);
+
+	if (!ops->report_state)
+		return -ENOSYS;
+
+	return ops->report_state(dev, buf, size);
+}
+
 /* Returns max number of milliseconds to wait */
 static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
 					       u32 ordinal)
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index c26f5d35abf..dd94bdc31fb 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -795,6 +795,16 @@ static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size)
 	return snprintf(buf, size, "Sandbox TPM2.x");
 }
 
+static int sandbox_tpm2_report_state(struct udevice *dev, char *buf, int size)
+{
+	struct sandbox_tpm2 *priv = dev_get_priv(dev);
+
+	if (size < 40)
+		return -ENOSPC;
+
+	return snprintf(buf, size, "init_done=%d", priv->init_done);
+}
+
 static int sandbox_tpm2_open(struct udevice *dev)
 {
 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
@@ -834,6 +844,7 @@ static const struct tpm_ops sandbox_tpm2_ops = {
 	.open		= sandbox_tpm2_open,
 	.close		= sandbox_tpm2_close,
 	.get_desc	= sandbox_tpm2_get_desc,
+	.report_state	= sandbox_tpm2_report_state,
 	.xfer		= sandbox_tpm2_xfer,
 };
 
diff --git a/include/tpm-common.h b/include/tpm-common.h
index a28629e7013..b2c5404430f 100644
--- a/include/tpm-common.h
+++ b/include/tpm-common.h
@@ -119,6 +119,16 @@ struct tpm_ops {
 	 */
 	int (*get_desc)(struct udevice *dev, char *buf, int size);
 
+	/**
+	 * report_state() - Collect information about the current TPM state
+	 *
+	 * @dev:	Device to check
+	 * @buf:	Buffer to put the string
+	 * @size:	Maximum size of buffer
+	 * Return: return code of the operation (0 = success)
+	 */
+	int (*report_state)(struct udevice *dev, char *buf, int size);
+
 	/**
 	 * send() - send data to the TPM
 	 *
@@ -234,6 +244,16 @@ u32 tpm_clear_and_reenable(struct udevice *dev);
  */
 int tpm_get_desc(struct udevice *dev, char *buf, int size);
 
+/**
+ * tpm_report_state() - Collect information about the current TPM state
+ *
+ * @dev:	Device to check
+ * @buf:	Buffer to put the string
+ * @size:	Maximum size of buffer
+ * Return: return code of the operation (0 = success)
+ */
+int tpm_report_state(struct udevice *dev, char *buf, int size);
+
 /**
  * tpm_xfer() - send data to the TPM and get response
  *
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 52fe178a828..7543df8823c 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
 obj-$(CONFIG_UT_DM) += tag.o
 obj-$(CONFIG_TEE) += tee.o
 obj-$(CONFIG_TIMER) += timer.o
+obj-$(CONFIG_TPM_V2) += tpm.o
 obj-$(CONFIG_DM_USB) += usb.o
 obj-$(CONFIG_DM_VIDEO) += video.o
 ifeq ($(CONFIG_VIRTIO_SANDBOX),y)
diff --git a/test/dm/tpm.c b/test/dm/tpm.c
new file mode 100644
index 00000000000..0b46f799591
--- /dev/null
+++ b/test/dm/tpm.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <tpm_api.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+/* Basic test of the TPM uclass */
+static int dm_test_tpm(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	char buf[50];
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_TPM, &dev));
+	ut_assert(tpm_is_v2(dev));
+
+	ut_assert(tpm_report_state(dev, buf, sizeof(buf)));
+	ut_asserteq_str("init_done=0", buf);
+
+	ut_assertok(tpm_init(dev));
+
+	ut_assert(tpm_report_state(dev, buf, sizeof(buf)));
+	ut_asserteq_str("init_done=1", buf);
+
+	return 0;
+}
+DM_TEST(dm_test_tpm, UT_TESTF_SCAN_FDT);
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 6/7] tpm: Implement state command for Cr50
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
                   ` (4 preceding siblings ...)
  2022-08-23 17:12 ` [PATCH v4 5/7] tpm: Allow reporting the internal state Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-08-24  8:32   ` Ilias Apalodimas
  2022-09-03 13:51   ` Ilias Apalodimas
  2022-08-23 17:12 ` [PATCH v4 7/7] tpm: Allow committing non-volatile data Simon Glass
  6 siblings, 2 replies; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Simon Glass, Heinrich Schuchardt, Ilias Apalodimas,
	Masahisa Kojima, Ruchika Gupta

Add a vendor-specific TPM2 command for this and implement it for Cr50.
Note: This is not part of the TPM spec, but is a Cr50 extension.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v4:
- Rename function and add arguments for the command/subcmd

 drivers/tpm/cr50_i2c.c | 163 +++++++++++++++++++++++++++++++++++++++++
 include/tpm-v2.h       |  13 ++++
 lib/tpm-v2.c           |  25 +++++++
 3 files changed, 201 insertions(+)

diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
index f8c30878947..08d417a844c 100644
--- a/drivers/tpm/cr50_i2c.c
+++ b/drivers/tpm/cr50_i2c.c
@@ -13,11 +13,13 @@
 #include <irq.h>
 #include <log.h>
 #include <spl.h>
+#include <tpm-common.h>
 #include <tpm-v2.h>
 #include <acpi/acpigen.h>
 #include <acpi/acpi_device.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
+#include <asm/unaligned.h>
 #include <linux/delay.h>
 #include <dm/acpi.h>
 
@@ -37,6 +39,50 @@ enum {
 	CR50_MAX_BUF_SIZE = 63,
 };
 
+/*
+ * Operations specific to the Cr50 TPM used on Chromium OS and Android devices
+ *
+ * FIXME: below is not enough to differentiate between vendors commands
+ * of numerous devices. However, the current tpm2 APIs aren't very amenable
+ * to extending generically because the marshaling code is assuming all
+ * knowledge of all commands.
+ */
+#define TPM2_CC_VENDOR_BIT_MASK			0x20000000
+
+#define TPM2_CR50_VENDOR_COMMAND		(TPM2_CC_VENDOR_BIT_MASK | 0)
+#define TPM2_CR50_SUB_CMD_IMMEDIATE_RESET	19
+#define TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS	21
+#define TPM2_CR50_SUB_CMD_REPORT_TPM_STATE	23
+#define TPM2_CR50_SUB_CMD_TURN_UPDATE_ON	24
+#define TPM2_CR50_SUB_CMD_GET_REC_BTN		29
+#define TPM2_CR50_SUB_CMD_TPM_MODE		40
+#define TPM2_CR50_SUB_CMD_GET_BOOT_MODE		52
+#define TPM2_CR50_SUB_CMD_RESET_EC		53
+
+/* Cr50 vendor-specific error codes. */
+#define VENDOR_RC_ERR              0x00000500
+enum cr50_vendor_rc {
+	VENDOR_RC_INTERNAL_ERROR	= (VENDOR_RC_ERR | 6),
+	VENDOR_RC_NO_SUCH_SUBCOMMAND	= (VENDOR_RC_ERR | 8),
+	VENDOR_RC_NO_SUCH_COMMAND	= (VENDOR_RC_ERR | 127),
+};
+
+enum cr50_tpm_mode {
+	/*
+	 * Default state: TPM is enabled, and may be set to either
+	 * TPM_MODE_ENABLED or TPM_MODE_DISABLED.
+	 */
+	TPM_MODE_ENABLED_TENTATIVE = 0,
+
+	/* TPM is enabled, and mode may not be changed. */
+	TPM_MODE_ENABLED = 1,
+
+	/* TPM is disabled, and mode may not be changed. */
+	TPM_MODE_DISABLED = 2,
+
+	TPM_MODE_INVALID,
+};
+
 /**
  * struct cr50_priv - Private driver data
  *
@@ -54,6 +100,41 @@ struct cr50_priv {
 	bool use_irq;
 };
 
+/*
+ * The below structure represents the body of the response to the 'report tpm
+ * state' vendor command.
+ *
+ * It is transferred over the wire, so it needs to be serialized/deserialized,
+ * and it is likely to change, so its contents must be versioned.
+ */
+#define TPM_STATE_VERSION	1
+struct tpm_vendor_state {
+	u32 version;
+	/*
+	 * The following three fields are set by the TPM in case of an assert.
+	 * There is no other processing than setting the source code line
+	 * number, error code and the first 4 characters of the function name.
+	 *
+	 * We don't expect this happening, but it is included in the report
+	 * just in case.
+	 */
+	u32 fail_line;	/* s_failLIne */
+	u32 fail_code;	/* s_failCode */
+	char func_name[4];	/* s_failFunction, limited to 4 chars */
+
+	/*
+	 * The following two fields are the current time filtered value of the
+	 * 'failed tries' TPM counter, and the maximum allowed value of the
+	 * counter.
+	 *
+	 * failed_tries == max_tries is the definition of the TPM lockout
+	 * condition.
+	 */
+	u32 failed_tries;	/* gp.failedTries */
+	u32 max_tries;	/* gp.maxTries */
+	/* The below fields are present in version 2 and above */
+};
+
 /* Wait for interrupt to indicate TPM is ready */
 static int cr50_i2c_wait_tpm_ready(struct udevice *dev)
 {
@@ -573,6 +654,87 @@ static int cr50_i2c_get_desc(struct udevice *dev, char *buf, int size)
 	return len;
 }
 
+static int stringify_state(char *buf, int len, char *str, size_t max_size)
+{
+	struct tpm_vendor_state state;
+	size_t text_size = 0;
+
+	state.version = get_unaligned_be32(buf +
+		offsetof(struct tpm_vendor_state, version));
+	state.fail_line = get_unaligned_be32(buf +
+		offsetof(struct tpm_vendor_state, fail_line));
+	state.fail_code = get_unaligned_be32(buf +
+		offsetof(struct tpm_vendor_state, fail_code));
+	memcpy(state.func_name,
+	       buf + offsetof(struct tpm_vendor_state, func_name),
+	       sizeof(state.func_name));
+	state.failed_tries = get_unaligned_be32(buf +
+		offsetof(struct tpm_vendor_state, failed_tries));
+	state.max_tries = get_unaligned_be32(buf +
+		offsetof(struct tpm_vendor_state, max_tries));
+
+	text_size += snprintf(str + text_size, max_size - text_size,
+			      "v=%d", state.version);
+	if (text_size >= max_size)
+		return -ENOSPC;
+
+	if (state.version > TPM_STATE_VERSION)
+		text_size += snprintf(str + text_size,
+				      max_size - text_size,
+				      " not fully supported\n");
+	if (text_size >= max_size)
+		return -ENOSPC;
+
+	if (state.version == 0)
+		return -EINVAL;	/* This should never happen */
+
+	text_size += snprintf(str + text_size,
+			      max_size - text_size,
+			      " failed_tries=%d max_tries=%d\n",
+			      state.failed_tries, state.max_tries);
+	if (text_size >= max_size)
+		return -ENOSPC;
+
+	if (state.fail_line) {
+		/* make sure function name is zero terminated. */
+		char func_name[sizeof(state.func_name) + 1];
+
+		memcpy(func_name, state.func_name, sizeof(state.func_name));
+		func_name[sizeof(state.func_name)] = '\0';
+
+		text_size += snprintf(str + text_size,
+				      max_size - text_size,
+				      "tpm failed: f %s line %d code %d",
+				      func_name,
+				      state.fail_line,
+				      state.fail_code);
+		if (text_size >= max_size)
+			return -ENOSPC;
+	}
+
+	return 0;
+}
+
+static int cr50_i2c_report_state(struct udevice *dev, char *str, int str_max)
+{
+	char buf[50];
+	int buf_size = sizeof(buf);
+	int ret;
+
+	ret = tpm2_report_state(dev, TPM2_CR50_VENDOR_COMMAND,
+				TPM2_CR50_SUB_CMD_REPORT_TPM_STATE,
+				buf, &buf_size);
+	if (ret)
+		return ret;
+
+	/* TPM responded as expected */
+	ret = stringify_state(buf, buf_size, str, str_max);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 static int cr50_i2c_open(struct udevice *dev)
 {
 	char buf[80];
@@ -730,6 +892,7 @@ struct acpi_ops cr50_acpi_ops = {
 static const struct tpm_ops cr50_i2c_ops = {
 	.open		= cr50_i2c_open,
 	.get_desc	= cr50_i2c_get_desc,
+	.report_state	= cr50_i2c_report_state,
 	.send		= cr50_i2c_send,
 	.recv		= cr50_i2c_recv,
 	.cleanup	= cr50_i2c_cleanup,
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index e79c90b9395..36c6ac0be6e 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -658,4 +658,17 @@ u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
 u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
 			u8 *recvbuf, size_t *recv_size);
 
+/**
+ * tpm_cr50_report_state() - Report the Cr50 internal state
+ *
+ * @dev:	TPM device
+ * @vendor_cmd:	Vendor command number to send
+ * @vendor_subcmd: Vendor sub-command number to send
+ * @recvbuf:	Buffer to save the response to
+ * @recv_size:	Pointer to the size of the response buffer
+ * Return: result of the operation
+ */
+u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
+		      u8 *recvbuf, size_t *recv_size);
+
 #endif /* __TPM_V2_H */
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 3e240bb4c67..edee9854a7c 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -679,3 +679,28 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
 {
 	return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
 }
+
+u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
+		      u8 *recvbuf, size_t *recv_size)
+{
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_NO_SESSIONS),		/* TAG */
+		tpm_u32(10 + 2),			/* Length */
+		tpm_u32(vendor_cmd),	/* Command code */
+
+		tpm_u16(vendor_subcmd),
+	};
+	int ret;
+
+	ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
+	log_debug("ret=%s, %x\n", dev->name, ret);
+	if (ret)
+		return ret;
+	if (*recv_size < 12)
+		return -ENODATA;
+	*recv_size -= 12;
+	memcpy(recvbuf, recvbuf + 12, *recv_size);
+
+	return 0;
+}
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 7/7] tpm: Allow committing non-volatile data
  2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
                   ` (5 preceding siblings ...)
  2022-08-23 17:12 ` [PATCH v4 6/7] tpm: Implement state command for Cr50 Simon Glass
@ 2022-08-23 17:12 ` Simon Glass
  2022-09-03 14:05   ` Ilias Apalodimas
  6 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2022-08-23 17:12 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Simon Glass, Heinrich Schuchardt, Ilias Apalodimas,
	Masahisa Kojima, Ruchika Gupta

Add an option to tell the TPM to commit non-volatile data immediately it
is changed, rather than waiting until later. This is needed in some
situations, since if the device reboots it may not write the data.

Add definitions for the rest of the Cr50 commands while we are here.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v4:
- Rename function and add arguments for the command/subcmd

 include/tpm-v2.h | 17 +++++++++++++++++
 lib/tpm-v2.c     | 21 +++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 36c6ac0be6e..737e57551d7 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -671,4 +671,21 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
 u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
 		      u8 *recvbuf, size_t *recv_size);
 
+/**
+ * tpm2_enable_nvcommits() - Tell TPM to commit NV data immediately
+ *
+ * For Chromium OS verified boot, we may reboot or reset at different times,
+ * possibly leaving non-volatile data unwritten by the TPM.
+ *
+ * This vendor command is used to indicate that non-volatile data should be
+ * written to its store immediately.
+ *
+ * @dev		TPM device
+ * @vendor_cmd:	Vendor command number to send
+ * @vendor_subcmd: Vendor sub-command number to send
+ * Return: result of the operation
+ */
+u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
+			  uint vendor_subcmd);
+
 #endif /* __TPM_V2_H */
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index edee9854a7c..697b982e079 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -704,3 +704,24 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
 
 	return 0;
 }
+
+u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
+			  uint vendor_subcmd)
+{
+	u8 command_v2[COMMAND_BUFFER_SIZE] = {
+		/* header 10 bytes */
+		tpm_u16(TPM2_ST_NO_SESSIONS),		/* TAG */
+		tpm_u32(10 + 2),			/* Length */
+		tpm_u32(vendor_cmd),	/* Command code */
+
+		tpm_u16(vendor_subcmd),
+	};
+	int ret;
+
+	ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+	log_debug("ret=%s, %x\n", dev->name, ret);
+	if (ret)
+		return ret;
+
+	return 0;
+}
-- 
2.37.2.609.g9ff673ca1a-goog


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 6/7] tpm: Implement state command for Cr50
  2022-08-23 17:12 ` [PATCH v4 6/7] tpm: Implement state command for Cr50 Simon Glass
@ 2022-08-24  8:32   ` Ilias Apalodimas
  2022-09-03 13:51   ` Ilias Apalodimas
  1 sibling, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-08-24  8:32 UTC (permalink / raw)
  To: Simon Glass
  Cc: U-Boot Mailing List, Heinrich Schuchardt, Masahisa Kojima, Ruchika Gupta

Hi Simon,


[...]

> +
> +static int cr50_i2c_report_state(struct udevice *dev, char *str, int str_max)
> +{
> +       char buf[50];
> +       int buf_size = sizeof(buf);

Shouldn't this be size_t?  I'll go through the rest of the patches, if
that's the only issue I find, I'll fix it while merging

Thanks
/Ilias
> +       int ret;
> +
> +       ret = tpm2_report_state(dev, TPM2_CR50_VENDOR_COMMAND,
> +                               TPM2_CR50_SUB_CMD_REPORT_TPM_STATE,
> +                               buf, &buf_size);
> +       if (ret)
> +               return ret;
> +
> +       /* TPM responded as expected */
> +       ret = stringify_state(buf, buf_size, str, str_max);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
>  static int cr50_i2c_open(struct udevice *dev)
>  {
>         char buf[80];
> @@ -730,6 +892,7 @@ struct acpi_ops cr50_acpi_ops = {
>  static const struct tpm_ops cr50_i2c_ops = {
>         .open           = cr50_i2c_open,
>         .get_desc       = cr50_i2c_get_desc,
> +       .report_state   = cr50_i2c_report_state,
>         .send           = cr50_i2c_send,
>         .recv           = cr50_i2c_recv,
>         .cleanup        = cr50_i2c_cleanup,
> diff --git a/include/tpm-v2.h b/include/tpm-v2.h
> index e79c90b9395..36c6ac0be6e 100644
> --- a/include/tpm-v2.h
> +++ b/include/tpm-v2.h
> @@ -658,4 +658,17 @@ u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
>  u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
>                         u8 *recvbuf, size_t *recv_size);
>
> +/**
> + * tpm_cr50_report_state() - Report the Cr50 internal state
> + *
> + * @dev:       TPM device
> + * @vendor_cmd:        Vendor command number to send
> + * @vendor_subcmd: Vendor sub-command number to send
> + * @recvbuf:   Buffer to save the response to
> + * @recv_size: Pointer to the size of the response buffer
> + * Return: result of the operation
> + */
> +u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
> +                     u8 *recvbuf, size_t *recv_size);
> +
>  #endif /* __TPM_V2_H */
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index 3e240bb4c67..edee9854a7c 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -679,3 +679,28 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
>  {
>         return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
>  }
> +
> +u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
> +                     u8 *recvbuf, size_t *recv_size)
> +{
> +       u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +               /* header 10 bytes */
> +               tpm_u16(TPM2_ST_NO_SESSIONS),           /* TAG */
> +               tpm_u32(10 + 2),                        /* Length */
> +               tpm_u32(vendor_cmd),    /* Command code */
> +
> +               tpm_u16(vendor_subcmd),
> +       };
> +       int ret;
> +
> +       ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
> +       log_debug("ret=%s, %x\n", dev->name, ret);
> +       if (ret)
> +               return ret;
> +       if (*recv_size < 12)
> +               return -ENODATA;
> +       *recv_size -= 12;
> +       memcpy(recvbuf, recvbuf + 12, *recv_size);
> +
> +       return 0;
> +}
> --
> 2.37.2.609.g9ff673ca1a-goog
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 1/7] tpm: Require a digest source when extending the PCR
  2022-08-23 17:12 ` [PATCH v4 1/7] tpm: Require a digest source when extending the PCR Simon Glass
@ 2022-08-26  6:30   ` Ilias Apalodimas
  0 siblings, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-08-26  6:30 UTC (permalink / raw)
  To: Simon Glass
  Cc: U-Boot Mailing List, Heinrich Schuchardt, Masahisa Kojima,
	Mathew McBride, Ruchika Gupta, Sughosh Ganu

On Tue, 23 Aug 2022 at 20:12, Simon Glass <sjg@chromium.org> wrote:
>
> This feature is used for measured boot, so we can add a log entry to the
> TCPA with some information about where the digest comes from. It is not
> currently supported in the TPM drivers, but add it to the API so that
> code which expects it can signal its request.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> (no changes since v3)
>
> Changes in v3:
> - Drop limits on the TPM hash size
> - Update commit message
>
> Changes in v2:
> - Use "cmd" for the digest type in the tpm command
> - Update comment for tpm_pcr_extend() 'name' parameter
>
>  cmd/tpm-v1.c      |  3 ++-
>  cmd/tpm_test.c    |  5 +++--
>  include/tpm_api.h |  8 +++++---
>  lib/tpm-v2.c      |  2 ++
>  lib/tpm_api.c     | 10 ++++++----
>  5 files changed, 18 insertions(+), 10 deletions(-)
>
> diff --git a/cmd/tpm-v1.c b/cmd/tpm-v1.c
> index bf238a9f2e3..0efb079b0a9 100644
> --- a/cmd/tpm-v1.c
> +++ b/cmd/tpm-v1.c
> @@ -131,7 +131,8 @@ static int do_tpm_extend(struct cmd_tbl *cmdtp, int flag, int argc,
>                 return CMD_RET_FAILURE;
>         }
>
> -       rc = tpm_pcr_extend(dev, index, in_digest, out_digest);
> +       rc = tpm_pcr_extend(dev, index, in_digest, sizeof(in_digest),
> +                           out_digest, "cmd");
>         if (!rc) {
>                 puts("PCR value after execution of the command:\n");
>                 print_byte_string(out_digest, sizeof(out_digest));
> diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c
> index a3ccb12f53a..b35eae81dc3 100644
> --- a/cmd/tpm_test.c
> +++ b/cmd/tpm_test.c
> @@ -91,7 +91,8 @@ static int test_early_extend(struct udevice *dev)
>         tpm_init(dev);
>         TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR));
>         TPM_CHECK(tpm_continue_self_test(dev));
> -       TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out));
> +       TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, sizeof(value_in), value_out,
> +                                "test"));
>         printf("done\n");
>         return 0;
>  }
> @@ -438,7 +439,7 @@ static int test_timing(struct udevice *dev)
>                    100);
>         TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)),
>                    100);
> -       TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200);
> +       TTPM_CHECK(tpm_pcr_extend(dev, 0, in, sizeof(in), out, "test"), 200);
>         TTPM_CHECK(tpm_set_global_lock(dev), 50);
>         TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100);
>         printf("done\n");
> diff --git a/include/tpm_api.h b/include/tpm_api.h
> index 11aa14eb793..8979d9d6df7 100644
> --- a/include/tpm_api.h
> +++ b/include/tpm_api.h
> @@ -81,14 +81,16 @@ u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
>   *
>   * @param dev          TPM device
>   * @param index                index of the PCR
> - * @param in_digest    160-bit value representing the event to be
> + * @param in_digest    160/256-bit value representing the event to be
>   *                     recorded
> - * @param out_digest   160-bit PCR value after execution of the
> + * @param size         size of digest in bytes
> + * @param out_digest   160/256-bit PCR value after execution of the
>   *                     command
> + * @param name         digest source, used for log output
>   * Return: return code of the operation
>   */
>  u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
> -                  void *out_digest);
> +                  uint size, void *out_digest, const char *name);
>
>  /**
>   * Issue a TPM_PCRRead command.
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index 1bf627853af..6058f2e1e4f 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -157,6 +157,8 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
>         };
>         int ret;
>
> +       if (!digest)
> +               return -EINVAL;
>         /*
>          * Fill the command structure starting from the first buffer:
>          *     - the digest
> diff --git a/lib/tpm_api.c b/lib/tpm_api.c
> index 032f383ca04..aa4a9fd406c 100644
> --- a/lib/tpm_api.c
> +++ b/lib/tpm_api.c
> @@ -140,15 +140,17 @@ u32 tpm_write_lock(struct udevice *dev, u32 index)
>  }
>
>  u32 tpm_pcr_extend(struct udevice *dev, u32 index, const void *in_digest,
> -                  void *out_digest)
> +                  uint size, void *out_digest, const char *name)
>  {
> -       if (tpm_is_v1(dev))
> +       if (tpm_is_v1(dev)) {
>                 return tpm1_extend(dev, index, in_digest, out_digest);
> -       else if (tpm_is_v2(dev))
> +       } else if (tpm_is_v2(dev)) {
>                 return tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, in_digest,
>                                        TPM2_DIGEST_LEN);
> -       else
> +               /* @name is ignored as we do not support measured boot */

This is a bit misleading, since with EFI boot, measured boot is
supported.  I can change that while merging, any alternative
suggestions?

> +       } else {
>                 return -ENOSYS;
> +       }
>  }
>
>  u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
> --
> 2.37.2.609.g9ff673ca1a-goog
>

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 2/7] tpm: Correct the permissions command in TPMv1
  2022-08-23 17:12 ` [PATCH v4 2/7] tpm: Correct the permissions command in TPMv1 Simon Glass
@ 2022-08-26  6:30   ` Ilias Apalodimas
  0 siblings, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-08-26  6:30 UTC (permalink / raw)
  To: Simon Glass; +Cc: U-Boot Mailing List, Mathew McBride

On Tue, 23 Aug 2022 at 20:12, Simon Glass <sjg@chromium.org> wrote:
>
> The offset here is incorrect. Fix it.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> (no changes since v1)
>
>  lib/tpm-v1.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c
> index 22a769c5874..d0e3ab1b21d 100644
> --- a/lib/tpm-v1.c
> +++ b/lib/tpm-v1.c
> @@ -456,12 +456,13 @@ u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
>                 0x0, 0x0, 0x0, 0x4,
>         };
>         const size_t index_offset = 18;
> -       const size_t perm_offset = 60;
> +       const size_t perm_offset = 74;
>         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
>         size_t response_length = sizeof(response);
>         u32 err;
>
> -       if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
> +       if (pack_byte_string(buf, sizeof(buf), "sd",
> +                            0, command, sizeof(command),
>                              index_offset, index))
>                 return TPM_LIB_ERROR;
>         err = tpm_sendrecv_command(dev, buf, response, &response_length);
> --
> 2.37.2.609.g9ff673ca1a-goog
>

Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 3/7] tpm: Correct the define-space command in TPMv2
  2022-08-23 17:12 ` [PATCH v4 3/7] tpm: Correct the define-space command in TPMv2 Simon Glass
@ 2022-08-26  6:31   ` Ilias Apalodimas
  0 siblings, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-08-26  6:31 UTC (permalink / raw)
  To: Simon Glass; +Cc: U-Boot Mailing List, Masahisa Kojima, Ruchika Gupta

On Tue, 23 Aug 2022 at 20:12, Simon Glass <sjg@chromium.org> wrote:
>
> The message format is incorrect. Fix it.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> (no changes since v2)
>
> Changes in v2:
> - Use constants instead of open-coded values
>
>  lib/tpm-v2.c | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index 6058f2e1e4f..3e240bb4c67 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -89,14 +89,18 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
>          * Calculate the offset of the nv_policy piece by adding each of the
>          * chunks below.
>          */
> -       uint offset = 10 + 8 + 13 + 14;
> +       const int platform_len = sizeof(u32);
> +       const int session_hdr_len = 13;
> +       const int message_len = 14;
> +       uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
> +               message_len;
>         u8 command_v2[COMMAND_BUFFER_SIZE] = {
>                 /* header 10 bytes */
>                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
> -               tpm_u32(offset + nv_policy_size),/* Length */
> +               tpm_u32(offset + nv_policy_size + 2),/* Length */
>                 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
>
> -               /* handles 8 bytes */
> +               /* handles 4 bytes */
>                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
>
>                 /* session header 13 bytes */
> @@ -107,12 +111,15 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
>                 tpm_u16(0),                     /* auth_size */
>
>                 /* message 14 bytes + policy */
> -               tpm_u16(12 + nv_policy_size),   /* size */
> +               tpm_u16(message_len + nv_policy_size),  /* size */
>                 tpm_u32(space_index),
>                 tpm_u16(TPM2_ALG_SHA256),
>                 tpm_u32(nv_attributes),
>                 tpm_u16(nv_policy_size),
> -               /* nv_policy */
> +               /*
> +                * nv_policy
> +                * space_size
> +                */
>         };
>         int ret;
>
> @@ -120,8 +127,9 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
>          * Fill the command structure starting from the first buffer:
>          *     - the password (if any)
>          */
> -       ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
> -                              offset, nv_policy, nv_policy_size);
> +       ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
> +                              offset, nv_policy, nv_policy_size,
> +                              offset + nv_policy_size, space_size);
>         if (ret)
>                 return TPM_LIB_ERROR;
>
> --
> 2.37.2.609.g9ff673ca1a-goog
>

Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 5/7] tpm: Allow reporting the internal state
  2022-08-23 17:12 ` [PATCH v4 5/7] tpm: Allow reporting the internal state Simon Glass
@ 2022-08-26  6:37   ` Ilias Apalodimas
  0 siblings, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-08-26  6:37 UTC (permalink / raw)
  To: Simon Glass; +Cc: U-Boot Mailing List, Heinrich Schuchardt, Ruchika Gupta

On Tue, 23 Aug 2022 at 20:13, Simon Glass <sjg@chromium.org> wrote:
>
> It is useful to read information about the current TPM state, where
> supported, e.g. for debugging purposes when verified boot fails.
>
> Add support for this to the TPM interface as well as Cr50. Add a simple
> sandbox test.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> (no changes since v1)
>
>  cmd/tpm-common.c               | 20 ++++++++++++++++++++
>  cmd/tpm-user-utils.h           |  2 ++
>  cmd/tpm-v2.c                   |  3 +++
>  drivers/tpm/tpm-uclass.c       | 10 ++++++++++
>  drivers/tpm/tpm2_tis_sandbox.c | 11 +++++++++++
>  include/tpm-common.h           | 20 ++++++++++++++++++++
>  test/dm/Makefile               |  1 +
>  test/dm/tpm.c                  | 34 ++++++++++++++++++++++++++++++++++
>  8 files changed, 101 insertions(+)
>  create mode 100644 test/dm/tpm.c
>
> diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c
> index 47adaffd184..d0c63cadf41 100644
> --- a/cmd/tpm-common.c
> +++ b/cmd/tpm-common.c
> @@ -333,6 +333,26 @@ int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
>         return 0;
>  }
>
> +int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
> +                       char *const argv[])
> +{
> +       struct udevice *dev;
> +       char buf[80];
> +       int rc;
> +
> +       rc = get_tpm(&dev);
> +       if (rc)
> +               return rc;
> +       rc = tpm_report_state(dev, buf, sizeof(buf));
> +       if (rc < 0) {
> +               printf("Couldn't get TPM state (%d)\n", rc);
> +               return CMD_RET_FAILURE;
> +       }
> +       printf("%s\n", buf);
> +
> +       return 0;
> +}
> +
>  int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
>  {
>         struct udevice *dev;
> diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h
> index 358ddff5761..de4a934aab6 100644
> --- a/cmd/tpm-user-utils.h
> +++ b/cmd/tpm-user-utils.h
> @@ -21,6 +21,8 @@ int do_tpm_device(struct cmd_tbl *cmdtp, int flag, int argc,
>                   char *const argv[]);
>  int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
>  int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
> +int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
> +                       char *const argv[]);
>  int do_tpm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
>
>  #endif /* __TPM_USER_UTILS_H */
> diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
> index 4ea5f9f094f..d93b83ada93 100644
> --- a/cmd/tpm-v2.c
> +++ b/cmd/tpm-v2.c
> @@ -359,6 +359,7 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
>  static struct cmd_tbl tpm2_commands[] = {
>         U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
>         U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
> +       U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""),
>         U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
>         U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""),
>         U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""),
> @@ -389,6 +390,8 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
>  "    Show all devices or set the specified device\n"
>  "info\n"
>  "    Show information about the TPM.\n"
> +"state\n"
> +"    Show internal state from the TPM (if available)\n"
>  "init\n"
>  "    Initialize the software stack. Always the first command to issue.\n"
>  "startup <mode>\n"
> diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
> index 0eb35f50c4e..5ff0cd3958c 100644
> --- a/drivers/tpm/tpm-uclass.c
> +++ b/drivers/tpm/tpm-uclass.c
> @@ -49,6 +49,16 @@ int tpm_get_desc(struct udevice *dev, char *buf, int size)
>         return ops->get_desc(dev, buf, size);
>  }
>
> +int tpm_report_state(struct udevice *dev, char *buf, int size)
> +{
> +       struct tpm_ops *ops = tpm_get_ops(dev);
> +
> +       if (!ops->report_state)
> +               return -ENOSYS;
> +
> +       return ops->report_state(dev, buf, size);
> +}
> +
>  /* Returns max number of milliseconds to wait */
>  static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
>                                                u32 ordinal)
> diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
> index c26f5d35abf..dd94bdc31fb 100644
> --- a/drivers/tpm/tpm2_tis_sandbox.c
> +++ b/drivers/tpm/tpm2_tis_sandbox.c
> @@ -795,6 +795,16 @@ static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size)
>         return snprintf(buf, size, "Sandbox TPM2.x");
>  }
>
> +static int sandbox_tpm2_report_state(struct udevice *dev, char *buf, int size)
> +{
> +       struct sandbox_tpm2 *priv = dev_get_priv(dev);
> +
> +       if (size < 40)
> +               return -ENOSPC;
> +
> +       return snprintf(buf, size, "init_done=%d", priv->init_done);
> +}
> +
>  static int sandbox_tpm2_open(struct udevice *dev)
>  {
>         struct sandbox_tpm2 *tpm = dev_get_priv(dev);
> @@ -834,6 +844,7 @@ static const struct tpm_ops sandbox_tpm2_ops = {
>         .open           = sandbox_tpm2_open,
>         .close          = sandbox_tpm2_close,
>         .get_desc       = sandbox_tpm2_get_desc,
> +       .report_state   = sandbox_tpm2_report_state,
>         .xfer           = sandbox_tpm2_xfer,
>  };
>
> diff --git a/include/tpm-common.h b/include/tpm-common.h
> index a28629e7013..b2c5404430f 100644
> --- a/include/tpm-common.h
> +++ b/include/tpm-common.h
> @@ -119,6 +119,16 @@ struct tpm_ops {
>          */
>         int (*get_desc)(struct udevice *dev, char *buf, int size);
>
> +       /**
> +        * report_state() - Collect information about the current TPM state
> +        *
> +        * @dev:        Device to check
> +        * @buf:        Buffer to put the string
> +        * @size:       Maximum size of buffer
> +        * Return: return code of the operation (0 = success)
> +        */
> +       int (*report_state)(struct udevice *dev, char *buf, int size);
> +
>         /**
>          * send() - send data to the TPM
>          *
> @@ -234,6 +244,16 @@ u32 tpm_clear_and_reenable(struct udevice *dev);
>   */
>  int tpm_get_desc(struct udevice *dev, char *buf, int size);
>
> +/**
> + * tpm_report_state() - Collect information about the current TPM state
> + *
> + * @dev:       Device to check
> + * @buf:       Buffer to put the string
> + * @size:      Maximum size of buffer
> + * Return: return code of the operation (0 = success)
> + */
> +int tpm_report_state(struct udevice *dev, char *buf, int size);
> +
>  /**
>   * tpm_xfer() - send data to the TPM and get response
>   *
> diff --git a/test/dm/Makefile b/test/dm/Makefile
> index 52fe178a828..7543df8823c 100644
> --- a/test/dm/Makefile
> +++ b/test/dm/Makefile
> @@ -107,6 +107,7 @@ obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o
>  obj-$(CONFIG_UT_DM) += tag.o
>  obj-$(CONFIG_TEE) += tee.o
>  obj-$(CONFIG_TIMER) += timer.o
> +obj-$(CONFIG_TPM_V2) += tpm.o
>  obj-$(CONFIG_DM_USB) += usb.o
>  obj-$(CONFIG_DM_VIDEO) += video.o
>  ifeq ($(CONFIG_VIRTIO_SANDBOX),y)
> diff --git a/test/dm/tpm.c b/test/dm/tpm.c
> new file mode 100644
> index 00000000000..0b46f799591
> --- /dev/null
> +++ b/test/dm/tpm.c
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2022 Google LLC
> + * Written by Simon Glass <sjg@chromium.org>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <tpm_api.h>
> +#include <dm/test.h>
> +#include <test/test.h>
> +#include <test/ut.h>
> +
> +/* Basic test of the TPM uclass */
> +static int dm_test_tpm(struct unit_test_state *uts)
> +{
> +       struct udevice *dev;
> +       char buf[50];
> +
> +       /* check probe success */
> +       ut_assertok(uclass_first_device_err(UCLASS_TPM, &dev));
> +       ut_assert(tpm_is_v2(dev));
> +
> +       ut_assert(tpm_report_state(dev, buf, sizeof(buf)));
> +       ut_asserteq_str("init_done=0", buf);
> +
> +       ut_assertok(tpm_init(dev));
> +
> +       ut_assert(tpm_report_state(dev, buf, sizeof(buf)));
> +       ut_asserteq_str("init_done=1", buf);
> +
> +       return 0;
> +}
> +DM_TEST(dm_test_tpm, UT_TESTF_SCAN_FDT);
> --
> 2.37.2.609.g9ff673ca1a-goog
>

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 6/7] tpm: Implement state command for Cr50
  2022-08-23 17:12 ` [PATCH v4 6/7] tpm: Implement state command for Cr50 Simon Glass
  2022-08-24  8:32   ` Ilias Apalodimas
@ 2022-09-03 13:51   ` Ilias Apalodimas
  1 sibling, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-09-03 13:51 UTC (permalink / raw)
  To: Simon Glass
  Cc: U-Boot Mailing List, Heinrich Schuchardt, Masahisa Kojima, Ruchika Gupta

On Tue, Aug 23, 2022 at 10:12:39AM -0700, Simon Glass wrote:
> Add a vendor-specific TPM2 command for this and implement it for Cr50.
> Note: This is not part of the TPM spec, but is a Cr50 extension.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v4:
> - Rename function and add arguments for the command/subcmd
> 
>  drivers/tpm/cr50_i2c.c | 163 +++++++++++++++++++++++++++++++++++++++++
>  include/tpm-v2.h       |  13 ++++
>  lib/tpm-v2.c           |  25 +++++++
>  3 files changed, 201 insertions(+)
> 
> diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c
> index f8c30878947..08d417a844c 100644
> --- a/drivers/tpm/cr50_i2c.c
> +++ b/drivers/tpm/cr50_i2c.c
> @@ -13,11 +13,13 @@
>  #include <irq.h>
>  #include <log.h>
>  #include <spl.h>
> +#include <tpm-common.h>
>  #include <tpm-v2.h>
>  #include <acpi/acpigen.h>
>  #include <acpi/acpi_device.h>
>  #include <asm/gpio.h>
>  #include <asm/io.h>
> +#include <asm/unaligned.h>
>  #include <linux/delay.h>
>  #include <dm/acpi.h>
>  
> @@ -37,6 +39,50 @@ enum {
>  	CR50_MAX_BUF_SIZE = 63,
>  };
>  
> +/*
> + * Operations specific to the Cr50 TPM used on Chromium OS and Android devices
> + *
> + * FIXME: below is not enough to differentiate between vendors commands
> + * of numerous devices. However, the current tpm2 APIs aren't very amenable
> + * to extending generically because the marshaling code is assuming all
> + * knowledge of all commands.
> + */
> +#define TPM2_CC_VENDOR_BIT_MASK			0x20000000
> +
> +#define TPM2_CR50_VENDOR_COMMAND		(TPM2_CC_VENDOR_BIT_MASK | 0)
> +#define TPM2_CR50_SUB_CMD_IMMEDIATE_RESET	19
> +#define TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS	21
> +#define TPM2_CR50_SUB_CMD_REPORT_TPM_STATE	23
> +#define TPM2_CR50_SUB_CMD_TURN_UPDATE_ON	24
> +#define TPM2_CR50_SUB_CMD_GET_REC_BTN		29
> +#define TPM2_CR50_SUB_CMD_TPM_MODE		40
> +#define TPM2_CR50_SUB_CMD_GET_BOOT_MODE		52
> +#define TPM2_CR50_SUB_CMD_RESET_EC		53
> +
> +/* Cr50 vendor-specific error codes. */
> +#define VENDOR_RC_ERR              0x00000500
> +enum cr50_vendor_rc {
> +	VENDOR_RC_INTERNAL_ERROR	= (VENDOR_RC_ERR | 6),
> +	VENDOR_RC_NO_SUCH_SUBCOMMAND	= (VENDOR_RC_ERR | 8),
> +	VENDOR_RC_NO_SUCH_COMMAND	= (VENDOR_RC_ERR | 127),
> +};
> +
> +enum cr50_tpm_mode {
> +	/*
> +	 * Default state: TPM is enabled, and may be set to either
> +	 * TPM_MODE_ENABLED or TPM_MODE_DISABLED.
> +	 */
> +	TPM_MODE_ENABLED_TENTATIVE = 0,
> +
> +	/* TPM is enabled, and mode may not be changed. */
> +	TPM_MODE_ENABLED = 1,
> +
> +	/* TPM is disabled, and mode may not be changed. */
> +	TPM_MODE_DISABLED = 2,
> +
> +	TPM_MODE_INVALID,
> +};
> +
>  /**
>   * struct cr50_priv - Private driver data
>   *
> @@ -54,6 +100,41 @@ struct cr50_priv {
>  	bool use_irq;
>  };
>  
> +/*
> + * The below structure represents the body of the response to the 'report tpm
> + * state' vendor command.
> + *
> + * It is transferred over the wire, so it needs to be serialized/deserialized,
> + * and it is likely to change, so its contents must be versioned.
> + */
> +#define TPM_STATE_VERSION	1
> +struct tpm_vendor_state {
> +	u32 version;
> +	/*
> +	 * The following three fields are set by the TPM in case of an assert.
> +	 * There is no other processing than setting the source code line
> +	 * number, error code and the first 4 characters of the function name.
> +	 *
> +	 * We don't expect this happening, but it is included in the report
> +	 * just in case.
> +	 */
> +	u32 fail_line;	/* s_failLIne */
> +	u32 fail_code;	/* s_failCode */
> +	char func_name[4];	/* s_failFunction, limited to 4 chars */
> +
> +	/*
> +	 * The following two fields are the current time filtered value of the
> +	 * 'failed tries' TPM counter, and the maximum allowed value of the
> +	 * counter.
> +	 *
> +	 * failed_tries == max_tries is the definition of the TPM lockout
> +	 * condition.
> +	 */
> +	u32 failed_tries;	/* gp.failedTries */
> +	u32 max_tries;	/* gp.maxTries */
> +	/* The below fields are present in version 2 and above */
> +};
> +
>  /* Wait for interrupt to indicate TPM is ready */
>  static int cr50_i2c_wait_tpm_ready(struct udevice *dev)
>  {
> @@ -573,6 +654,87 @@ static int cr50_i2c_get_desc(struct udevice *dev, char *buf, int size)
>  	return len;
>  }
>  
> +static int stringify_state(char *buf, int len, char *str, size_t max_size)
> +{
> +	struct tpm_vendor_state state;
> +	size_t text_size = 0;
> +
> +	state.version = get_unaligned_be32(buf +
> +		offsetof(struct tpm_vendor_state, version));
> +	state.fail_line = get_unaligned_be32(buf +
> +		offsetof(struct tpm_vendor_state, fail_line));
> +	state.fail_code = get_unaligned_be32(buf +
> +		offsetof(struct tpm_vendor_state, fail_code));
> +	memcpy(state.func_name,
> +	       buf + offsetof(struct tpm_vendor_state, func_name),
> +	       sizeof(state.func_name));
> +	state.failed_tries = get_unaligned_be32(buf +
> +		offsetof(struct tpm_vendor_state, failed_tries));
> +	state.max_tries = get_unaligned_be32(buf +
> +		offsetof(struct tpm_vendor_state, max_tries));
> +
> +	text_size += snprintf(str + text_size, max_size - text_size,
> +			      "v=%d", state.version);
> +	if (text_size >= max_size)
> +		return -ENOSPC;
> +
> +	if (state.version > TPM_STATE_VERSION)
> +		text_size += snprintf(str + text_size,
> +				      max_size - text_size,
> +				      " not fully supported\n");
> +	if (text_size >= max_size)
> +		return -ENOSPC;
> +
> +	if (state.version == 0)
> +		return -EINVAL;	/* This should never happen */
> +
> +	text_size += snprintf(str + text_size,
> +			      max_size - text_size,
> +			      " failed_tries=%d max_tries=%d\n",
> +			      state.failed_tries, state.max_tries);
> +	if (text_size >= max_size)
> +		return -ENOSPC;
> +
> +	if (state.fail_line) {
> +		/* make sure function name is zero terminated. */
> +		char func_name[sizeof(state.func_name) + 1];
> +
> +		memcpy(func_name, state.func_name, sizeof(state.func_name));
> +		func_name[sizeof(state.func_name)] = '\0';
> +
> +		text_size += snprintf(str + text_size,
> +				      max_size - text_size,
> +				      "tpm failed: f %s line %d code %d",
> +				      func_name,
> +				      state.fail_line,
> +				      state.fail_code);
> +		if (text_size >= max_size)
> +			return -ENOSPC;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cr50_i2c_report_state(struct udevice *dev, char *str, int str_max)
> +{
> +	char buf[50];
> +	int buf_size = sizeof(buf);
> +	int ret;
> +
> +	ret = tpm2_report_state(dev, TPM2_CR50_VENDOR_COMMAND,
> +				TPM2_CR50_SUB_CMD_REPORT_TPM_STATE,
> +				buf, &buf_size);
> +	if (ret)
> +		return ret;
> +
> +	/* TPM responded as expected */
> +	ret = stringify_state(buf, buf_size, str, str_max);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
>  static int cr50_i2c_open(struct udevice *dev)
>  {
>  	char buf[80];
> @@ -730,6 +892,7 @@ struct acpi_ops cr50_acpi_ops = {
>  static const struct tpm_ops cr50_i2c_ops = {
>  	.open		= cr50_i2c_open,
>  	.get_desc	= cr50_i2c_get_desc,
> +	.report_state	= cr50_i2c_report_state,
>  	.send		= cr50_i2c_send,
>  	.recv		= cr50_i2c_recv,
>  	.cleanup	= cr50_i2c_cleanup,
> diff --git a/include/tpm-v2.h b/include/tpm-v2.h
> index e79c90b9395..36c6ac0be6e 100644
> --- a/include/tpm-v2.h
> +++ b/include/tpm-v2.h
> @@ -658,4 +658,17 @@ u32 tpm2_disable_platform_hierarchy(struct udevice *dev);
>  u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
>  			u8 *recvbuf, size_t *recv_size);
>  
> +/**
> + * tpm_cr50_report_state() - Report the Cr50 internal state
> + *
> + * @dev:	TPM device
> + * @vendor_cmd:	Vendor command number to send
> + * @vendor_subcmd: Vendor sub-command number to send
> + * @recvbuf:	Buffer to save the response to
> + * @recv_size:	Pointer to the size of the response buffer
> + * Return: result of the operation
> + */
> +u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
> +		      u8 *recvbuf, size_t *recv_size);
> +
>  #endif /* __TPM_V2_H */
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index 3e240bb4c67..edee9854a7c 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -679,3 +679,28 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
>  {
>  	return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
>  }
> +
> +u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
> +		      u8 *recvbuf, size_t *recv_size)
> +{
> +	u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +		/* header 10 bytes */
> +		tpm_u16(TPM2_ST_NO_SESSIONS),		/* TAG */
> +		tpm_u32(10 + 2),			/* Length */
> +		tpm_u32(vendor_cmd),	/* Command code */
> +
> +		tpm_u16(vendor_subcmd),
> +	};
> +	int ret;
> +
> +	ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
> +	log_debug("ret=%s, %x\n", dev->name, ret);
> +	if (ret)
> +		return ret;
> +	if (*recv_size < 12)
> +		return -ENODATA;
> +	*recv_size -= 12;
> +	memcpy(recvbuf, recvbuf + 12, *recv_size);
> +
> +	return 0;
> +}
> -- 
> 2.37.2.609.g9ff673ca1a-goog
> 

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 7/7] tpm: Allow committing non-volatile data
  2022-08-23 17:12 ` [PATCH v4 7/7] tpm: Allow committing non-volatile data Simon Glass
@ 2022-09-03 14:05   ` Ilias Apalodimas
  0 siblings, 0 replies; 15+ messages in thread
From: Ilias Apalodimas @ 2022-09-03 14:05 UTC (permalink / raw)
  To: Simon Glass
  Cc: U-Boot Mailing List, Heinrich Schuchardt, Masahisa Kojima, Ruchika Gupta

Thanks Simon,

I'll queue up the series once the CI completes

On Tue, Aug 23, 2022 at 10:12:40AM -0700, Simon Glass wrote:
> Add an option to tell the TPM to commit non-volatile data immediately it
> is changed, rather than waiting until later. This is needed in some
> situations, since if the device reboots it may not write the data.
> 
> Add definitions for the rest of the Cr50 commands while we are here.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
> 
> Changes in v4:
> - Rename function and add arguments for the command/subcmd
> 
>  include/tpm-v2.h | 17 +++++++++++++++++
>  lib/tpm-v2.c     | 21 +++++++++++++++++++++
>  2 files changed, 38 insertions(+)
> 
> diff --git a/include/tpm-v2.h b/include/tpm-v2.h
> index 36c6ac0be6e..737e57551d7 100644
> --- a/include/tpm-v2.h
> +++ b/include/tpm-v2.h
> @@ -671,4 +671,21 @@ u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
>  u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
>  		      u8 *recvbuf, size_t *recv_size);
>  
> +/**
> + * tpm2_enable_nvcommits() - Tell TPM to commit NV data immediately
> + *
> + * For Chromium OS verified boot, we may reboot or reset at different times,
> + * possibly leaving non-volatile data unwritten by the TPM.
> + *
> + * This vendor command is used to indicate that non-volatile data should be
> + * written to its store immediately.
> + *
> + * @dev		TPM device
> + * @vendor_cmd:	Vendor command number to send
> + * @vendor_subcmd: Vendor sub-command number to send
> + * Return: result of the operation
> + */
> +u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
> +			  uint vendor_subcmd);
> +
>  #endif /* __TPM_V2_H */
> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
> index edee9854a7c..697b982e079 100644
> --- a/lib/tpm-v2.c
> +++ b/lib/tpm-v2.c
> @@ -704,3 +704,24 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
>  
>  	return 0;
>  }
> +
> +u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
> +			  uint vendor_subcmd)
> +{
> +	u8 command_v2[COMMAND_BUFFER_SIZE] = {
> +		/* header 10 bytes */
> +		tpm_u16(TPM2_ST_NO_SESSIONS),		/* TAG */
> +		tpm_u32(10 + 2),			/* Length */
> +		tpm_u32(vendor_cmd),	/* Command code */
> +
> +		tpm_u16(vendor_subcmd),
> +	};
> +	int ret;
> +
> +	ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
> +	log_debug("ret=%s, %x\n", dev->name, ret);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> -- 
> 2.37.2.609.g9ff673ca1a-goog
> 

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-09-03 14:06 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-23 17:12 [PATCH v4 0/7] tpm: Various minor fixes and enhancements Simon Glass
2022-08-23 17:12 ` [PATCH v4 1/7] tpm: Require a digest source when extending the PCR Simon Glass
2022-08-26  6:30   ` Ilias Apalodimas
2022-08-23 17:12 ` [PATCH v4 2/7] tpm: Correct the permissions command in TPMv1 Simon Glass
2022-08-26  6:30   ` Ilias Apalodimas
2022-08-23 17:12 ` [PATCH v4 3/7] tpm: Correct the define-space command in TPMv2 Simon Glass
2022-08-26  6:31   ` Ilias Apalodimas
2022-08-23 17:12 ` [PATCH v4 4/7] tpm: sandbox: Allow init of TPM in a different phase Simon Glass
2022-08-23 17:12 ` [PATCH v4 5/7] tpm: Allow reporting the internal state Simon Glass
2022-08-26  6:37   ` Ilias Apalodimas
2022-08-23 17:12 ` [PATCH v4 6/7] tpm: Implement state command for Cr50 Simon Glass
2022-08-24  8:32   ` Ilias Apalodimas
2022-09-03 13:51   ` Ilias Apalodimas
2022-08-23 17:12 ` [PATCH v4 7/7] tpm: Allow committing non-volatile data Simon Glass
2022-09-03 14:05   ` Ilias Apalodimas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).