git: 38a4995eb52d - main - tpm20: fix suspend/resume and entropy harvesting
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 05 Feb 2026 03:36:18 UTC
The branch main has been updated by kevans:
URL: https://cgit.FreeBSD.org/src/commit/?id=38a4995eb52db21116f8b37ed942e66a8c2f050f
commit 38a4995eb52db21116f8b37ed942e66a8c2f050f
Author: Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2026-02-05 03:35:01 +0000
Commit: Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-02-05 03:35:10 +0000
tpm20: fix suspend/resume and entropy harvesting
There were a few problem here:
- TPM2_Shutdown results in a response that we need to either process
or ignore, otherwise any tpm20_write or tpm20_harvest call will
trivially hang on an `sc->pending_data_length != 0`
- We should have a matching TPM2_Startup upon resume to restore any
state that should have persisted
- We must drain the harvest task before we suspend to avoid problems
there
This commit is sufficient to avoid breaking suspend/resume.
PR: 291067
Fixes: a2d5ed9442bb ("Introduce driver for TPM 2.0 in CRB and [...]")
Fixes: 4ee7d3b0118c ("Allow using TPM as entropy source.")
Co-authored-by: markj (D53835)
Tested by: garga
Differential Revision: https://reviews.freebsd.org/D55074
---
sys/dev/tpm/tpm20.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
sys/dev/tpm/tpm20.h | 1 +
sys/dev/tpm/tpm_crb.c | 1 +
sys/dev/tpm/tpm_tis_core.c | 1 +
4 files changed, 68 insertions(+)
diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c
index 6c587818058d..c521ca9dda9d 100644
--- a/sys/dev/tpm/tpm20.c
+++ b/sys/dev/tpm/tpm20.c
@@ -45,6 +45,7 @@ static void tpm20_discard_buffer(void *arg);
#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
static void tpm20_harvest(void *arg, int unused);
#endif
+static int tpm20_restart(device_t dev, bool clear);
static int tpm20_save_state(device_t dev, bool suspend);
static d_open_t tpm20_open;
@@ -242,9 +243,31 @@ tpm20_release(struct tpm_sc *sc)
destroy_dev(sc->sc_cdev);
}
+int
+tpm20_resume(device_t dev)
+{
+
+ tpm20_restart(dev, false);
+
+#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
+ struct tpm_sc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task,
+ hz * TPM_HARVEST_INTERVAL);
+#endif
+ return (0);
+}
+
int
tpm20_suspend(device_t dev)
{
+#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
+ struct tpm_sc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task);
+#endif
return (tpm20_save_state(dev, true));
}
@@ -307,6 +330,43 @@ tpm20_harvest(void *arg, int unused)
}
#endif /* TPM_HARVEST */
+static int
+tpm20_restart(device_t dev, bool clear)
+{
+ struct tpm_sc *sc;
+ uint8_t startup_cmd[] = {
+ 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/
+ 0x00, 0x00, 0x00, 0x0C, /* cmd length */
+ 0x00, 0x00, 0x01, 0x44, /* cmd TPM_CC_Startup */
+ 0x00, 0x01 /* TPM_SU_STATE */
+ };
+
+ sc = device_get_softc(dev);
+
+ /*
+ * Inform the TPM whether we are resetting or resuming.
+ */
+ if (clear)
+ startup_cmd[11] = 0; /* TPM_SU_CLEAR */
+
+ if (sc == NULL || sc->buf == NULL)
+ return (0);
+
+ sx_xlock(&sc->dev_lock);
+
+ MPASS(sc->pending_data_length == 0);
+ memcpy(sc->buf, startup_cmd, sizeof(startup_cmd));
+
+ /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */
+ TPM_TRANSMIT(sc->dev, sizeof(startup_cmd));
+ sc->pending_data_length = 0;
+ sc->total_length = 0;
+
+ sx_xunlock(&sc->dev_lock);
+
+ return (0);
+}
+
static int
tpm20_save_state(device_t dev, bool suspend)
{
@@ -331,8 +391,13 @@ tpm20_save_state(device_t dev, bool suspend)
sx_xlock(&sc->dev_lock);
+ MPASS(sc->pending_data_length == 0);
memcpy(sc->buf, save_cmd, sizeof(save_cmd));
+
+ /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */
TPM_TRANSMIT(sc->dev, sizeof(save_cmd));
+ sc->pending_data_length = 0;
+ sc->total_length = 0;
sx_xunlock(&sc->dev_lock);
diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h
index b2cfcd4f25bd..96b2920283b6 100644
--- a/sys/dev/tpm/tpm20.h
+++ b/sys/dev/tpm/tpm20.h
@@ -136,6 +136,7 @@ struct tpm_sc {
};
int tpm20_suspend(device_t dev);
+int tpm20_resume(device_t dev);
int tpm20_shutdown(device_t dev);
int32_t tpm20_get_timeout(uint32_t command);
int tpm20_init(struct tpm_sc *sc);
diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c
index 26b53e7a621d..18414a6c799b 100644
--- a/sys/dev/tpm/tpm_crb.c
+++ b/sys/dev/tpm/tpm_crb.c
@@ -651,6 +651,7 @@ static device_method_t tpmcrb_methods[] = {
DEVMETHOD(device_detach, tpmcrb_detach),
DEVMETHOD(device_shutdown, tpm20_shutdown),
DEVMETHOD(device_suspend, tpm20_suspend),
+ DEVMETHOD(device_resume, tpm20_resume),
DEVMETHOD(tpm_transmit, tpmcrb_transmit),
{0, 0}
};
diff --git a/sys/dev/tpm/tpm_tis_core.c b/sys/dev/tpm/tpm_tis_core.c
index 4159de4daf3b..34ecfcc283b1 100644
--- a/sys/dev/tpm/tpm_tis_core.c
+++ b/sys/dev/tpm/tpm_tis_core.c
@@ -487,6 +487,7 @@ static device_method_t tpmtis_methods[] = {
DEVMETHOD(device_detach, tpmtis_detach),
DEVMETHOD(device_shutdown, tpm20_shutdown),
DEVMETHOD(device_suspend, tpm20_suspend),
+ DEVMETHOD(device_resume, tpm20_resume),
DEVMETHOD(tpm_transmit, tpmtis_transmit),
DEVMETHOD_END
};