[PATCH 1/4 v4] tpm: add a function that performs selftest + startup

As described in [0] if a command requires use of an untested algorithm or functional module, the TPM performs the test and then completes the command actions.
Since we don't check for TPM_RC_NEEDS_TEST (which is the return code of the TPM in that case) and even if we would, it would complicate our TPM code for no apparent reason, add a wrapper function that performs both the selftest and the startup sequence of the TPM.
It's worth noting that this is implemented on TPMv2.0. The code for 1.2 would look similar, but I don't have a device available to test.
[0] https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Arch... §12.3 Self-test modes
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- Changes since v3: - Limit comments to 80 columns - drop extra lines from comments include/tpm-v2.h | 16 ++++++++++++++++ include/tpm_api.h | 8 ++++++++ lib/tpm-v2.c | 25 +++++++++++++++++++++++++ lib/tpm_api.c | 8 ++++++++ 4 files changed, 57 insertions(+)
diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 737e57551d73..2893783c6ceb 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -688,4 +688,20 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd, u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd);
+/** + * tpm2_auto_start() - start up the TPM and perform selftests. + * If a testable function has not been tested and is + * requested the TPM2 will return TPM_RC_NEEDS_TEST. + * + * @param dev TPM device + * Return: TPM2_RC_TESTING, if TPM2 self-test is in progress. + * TPM2_RC_SUCCESS, if testing of all functions is complete without + * functional failures. + * TPM2_RC_FAILURE, if any test failed. + * TPM2_RC_INITIALIZE, if the TPM has not gone through the Startup + * sequence + + */ +u32 tpm2_auto_start(struct udevice *dev); + #endif /* __TPM_V2_H */ diff --git a/include/tpm_api.h b/include/tpm_api.h index 8979d9d6df7e..022a8bbaeca6 100644 --- a/include/tpm_api.h +++ b/include/tpm_api.h @@ -331,4 +331,12 @@ static inline bool tpm_is_v2(struct udevice *dev) return IS_ENABLED(CONFIG_TPM_V2) && tpm_get_version(dev) == TPM_V2; }
+/** + * tpm_auto_start() - start up the TPM and perform selftests + * + * @param dev TPM device + * Return: return code of the operation (0 = success) + */ +u32 tpm_auto_start(struct udevice *dev); + #endif /* __TPM_API_H */ diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 697b982e079f..895b093bcb1a 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -44,6 +44,31 @@ u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test) return tpm_sendrecv_command(dev, command_v2, NULL, NULL); }
+u32 tpm2_auto_start(struct udevice *dev) +{ + u32 rc; + + /* + * the tpm_init() will return -EBUSY if the init has already happened + * The selftest and startup code can run multiple times with no side + * effects + */ + rc = tpm_init(dev); + if (rc && rc != -EBUSY) + return rc; + rc = tpm2_self_test(dev, TPMI_YES); + + if (rc == TPM2_RC_INITIALIZE) { + rc = tpm2_startup(dev, TPM2_SU_CLEAR); + if (rc) + return rc; + + rc = tpm2_self_test(dev, TPMI_YES); + } + + return rc; +} + u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw, const ssize_t pw_sz) { diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 7e8df8795ef3..5b2c11a277cc 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -35,6 +35,14 @@ u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode) } }
+u32 tpm_auto_start(struct udevice *dev) +{ + if (tpm_is_v2(dev)) + return tpm2_auto_start(dev); + + return -ENOSYS; +} + u32 tpm_resume(struct udevice *dev) { if (tpm_is_v1(dev)) -- 2.39.2

A previous commit is adding a new tpm startup functions which initializes the TPMv2 and performs all the needed selftests. Since the TPM selftests might be needed depending on the requested algorithm or functional module use that instead.
Reviewed-by: Simon Glass sjg@chromium.org Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- Changes since v3: - Added r-b tags by Simon lib/efi_loader/efi_tcg2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index 918e9a268641..d035a00d98ac 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -2422,7 +2422,7 @@ efi_status_t efi_tcg2_register(void) }
/* initialize the TPM as early as possible. */ - err = tpm_startup(dev, TPM_ST_CLEAR); + err = tpm_auto_start(dev); if (err) { log_err("TPM startup failed\n"); goto fail; -- 2.39.2

All the TPM drivers as well as out TCG TIS API for a TPM2.0 device return -EBUSY if the device has already been opened. Adjust the sandbox TPM do return the same error code.
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- Changes since v3: - New patch. Required for [4/4]
drivers/tpm/tpm2_tis_sandbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c index dd94bdc31fb7..e4004cfcca33 100644 --- a/drivers/tpm/tpm2_tis_sandbox.c +++ b/drivers/tpm/tpm2_tis_sandbox.c @@ -810,7 +810,7 @@ static int sandbox_tpm2_open(struct udevice *dev) struct sandbox_tpm2 *tpm = dev_get_priv(dev);
if (tpm->init_done) - return -EIO; + return -EBUSY;
tpm->init_done = true;
-- 2.39.2

On Sat, 18 Feb 2023 at 08:27, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
All the TPM drivers as well as out TCG TIS API for a TPM2.0 device return -EBUSY if the device has already been opened. Adjust the sandbox TPM do return the same error code.
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org
Changes since v3:
- New patch. Required for [4/4]
drivers/tpm/tpm2_tis_sandbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

A prior patch adds a new API function for TPM2.0, which performs the full startup sequence of the TPM. Add a selftest for that.
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- Changes since v4: - New patch
test/dm/tpm.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/test/dm/tpm.c b/test/dm/tpm.c index 0b46f799591f..8ee17f6a9bc3 100644 --- a/test/dm/tpm.c +++ b/test/dm/tpm.c @@ -25,6 +25,11 @@ static int dm_test_tpm(struct unit_test_state *uts) ut_asserteq_str("init_done=0", buf);
ut_assertok(tpm_init(dev)); + /* + * tpm_auto_start will rerun tpm_init, but handles the + * -EBUSY return code internally. + */ + ut_assertok(tpm_auto_start(dev));
ut_assert(tpm_report_state(dev, buf, sizeof(buf))); ut_asserteq_str("init_done=1", buf); -- 2.39.2

On Sat, 18 Feb 2023 at 08:27, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
A prior patch adds a new API function for TPM2.0, which performs the full startup sequence of the TPM. Add a selftest for that.
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org
Changes since v4:
- New patch
test/dm/tpm.c | 5 +++++ 1 file changed, 5 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org (with my patches on top)

On Sat, 18 Feb 2023 at 08:27, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
As described in [0] if a command requires use of an untested algorithm or functional module, the TPM performs the test and then completes the command actions.
Since we don't check for TPM_RC_NEEDS_TEST (which is the return code of the TPM in that case) and even if we would, it would complicate our TPM code for no apparent reason, add a wrapper function that performs both the selftest and the startup sequence of the TPM.
It's worth noting that this is implemented on TPMv2.0. The code for 1.2 would look similar, but I don't have a device available to test.
[0] https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Arch... §12.3 Self-test modes
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org
Changes since v3:
- Limit comments to 80 columns
- drop extra lines from comments
include/tpm-v2.h | 16 ++++++++++++++++ include/tpm_api.h | 8 ++++++++ lib/tpm-v2.c | 25 +++++++++++++++++++++++++ lib/tpm_api.c | 8 ++++++++ 4 files changed, 57 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
(with my two patches on top)
participants (2)
-
Ilias Apalodimas
-
Simon Glass