From a595be3a4af116a9559a3868f81dcad55d01b8dd Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 25 Jan 2023 12:18:36 +0200 Subject: tpm: add a function that performs selftest + startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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-Architecture-01.07-2014-03-13.pdf ยง12.3 Self-test modes Reviewed-by: Simon Glass Signed-off-by: Ilias Apalodimas --- include/tpm-v2.h | 16 ++++++++++++++++ include/tpm_api.h | 8 ++++++++ 2 files changed, 24 insertions(+) (limited to 'include') diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 2df3dad5532..2b6980e441d 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -690,4 +690,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 8979d9d6df7..022a8bbaeca 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 */ -- cgit v1.3.1 From a11be4c303eabb142e074c7ca14b6ae0d293f0cb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 21 Feb 2023 06:24:52 -0700 Subject: tpm: Implement tpm_auto_start() for TPMv1.2 Add an implementation of this, moving the common call to tpm_init() up into the common API implementation. Add a test. Reviewed-by: Ilias Apalodimas Signed-off-by: Simon Glass Signed-off-by: Ilias Apalodimas --- include/tpm-common.h | 2 +- include/tpm-v1.h | 11 +++++++++++ lib/tpm-v1.c | 14 ++++++++++++++ lib/tpm-v2.c | 8 -------- lib/tpm_api.c | 19 ++++++++++++++++--- test/dm/tpm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/tpm-common.h b/include/tpm-common.h index b2c5404430f..1ba81386ce1 100644 --- a/include/tpm-common.h +++ b/include/tpm-common.h @@ -94,7 +94,7 @@ struct tpm_ops { * close(). * * @dev: Device to open - * @return 0 ok OK, -ve on error + * @return 0 ok OK, -EBUSY if already opened, other -ve on other error */ int (*open)(struct udevice *dev); diff --git a/include/tpm-v1.h b/include/tpm-v1.h index 33d53fb695e..60b71e2a4b6 100644 --- a/include/tpm-v1.h +++ b/include/tpm-v1.h @@ -591,4 +591,15 @@ u32 tpm_set_global_lock(struct udevice *dev); */ u32 tpm1_resume(struct udevice *dev); +/** + * tpm1_auto_start() - start up the TPM + * + * This does not do a self test. + * + * @dev TPM device + * Return: TPM2_RC_SUCCESS, on success, or when the TPM returns + * TPM_INVALID_POSTINIT; TPM_FAILEDSELFTEST, if the TPM is in failure state + */ +u32 tpm1_auto_start(struct udevice *dev); + #endif /* __TPM_V1_H */ diff --git a/lib/tpm-v1.c b/lib/tpm-v1.c index d0e3ab1b21d..60a18ca5040 100644 --- a/lib/tpm-v1.c +++ b/lib/tpm-v1.c @@ -69,6 +69,20 @@ u32 tpm1_continue_self_test(struct udevice *dev) return tpm_sendrecv_command(dev, command, NULL, NULL); } +u32 tpm1_auto_start(struct udevice *dev) +{ + u32 rc; + + rc = tpm1_startup(dev, TPM_ST_CLEAR); + /* continue on if the TPM is already inited */ + if (rc && rc != TPM_INVALID_POSTINIT) + return rc; + + rc = tpm1_self_test_full(dev); + + return rc; +} + u32 tpm1_clear_and_reenable(struct udevice *dev) { u32 ret; diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 895b093bcb1..9ab5b46df17 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -48,14 +48,6 @@ 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) { diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 5b2c11a277c..3ef5e811794 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -37,10 +37,23 @@ 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); + u32 rc; - return -ENOSYS; + /* + * 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; + + if (tpm_is_v1(dev)) + return tpm1_auto_start(dev); + else if (tpm_is_v2(dev)) + return tpm2_auto_start(dev); + else + return -ENOSYS; } u32 tpm_resume(struct udevice *dev) diff --git a/test/dm/tpm.c b/test/dm/tpm.c index 7d880012090..3defb3c3da1 100644 --- a/test/dm/tpm.c +++ b/test/dm/tpm.c @@ -79,3 +79,48 @@ static int dm_test_tpm_report_state(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_tpm_report_state, UT_TESTF_SCAN_FDT); + +/** + * test_tpm_autostart() - check the tpm_auto_start() call + * + * @uts: Unit test state + * @version: TPM version to use + * @reinit: true to call tpm_init() first + * Returns 0 if OK, non-zero on failure + */ +static int test_tpm_autostart(struct unit_test_state *uts, + enum tpm_version version, bool reinit) +{ + struct udevice *dev; + + /* check probe success */ + ut_assertok(get_tpm_version(version, &dev)); + + if (reinit) + ut_assertok(tpm_init(dev)); + /* + * tpm_auto_start will rerun tpm_init() if reinit, but handles the + * -EBUSY return code internally. + */ + ut_assertok(tpm_auto_start(dev)); + + return 0; +} + +static int dm_test_tpm_autostart(struct unit_test_state *uts) +{ + ut_assertok(test_tpm_autostart(uts, TPM_V1, false)); + ut_assertok(test_tpm_autostart(uts, TPM_V2, false)); + + return 0; +} +DM_TEST(dm_test_tpm_autostart, UT_TESTF_SCAN_FDT); + +static int dm_test_tpm_autostart_reinit(struct unit_test_state *uts) +{ + ut_assertok(test_tpm_autostart(uts, TPM_V1, true)); + ut_assertok(test_tpm_autostart(uts, TPM_V2, true)); + + return 0; +} +DM_TEST(dm_test_tpm_autostart_reinit, UT_TESTF_SCAN_FDT); -- cgit v1.3.1