aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2026-02-05 03:35:01 +0000
committerKyle Evans <kevans@FreeBSD.org>2026-02-05 03:35:10 +0000
commit38a4995eb52db21116f8b37ed942e66a8c2f050f (patch)
treed7822b980e27ccacb143f1e1686cdfa23be41381
parent5c9d988d865cc4ce849507173c0a2e2f399d0f62 (diff)
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
-rw-r--r--sys/dev/tpm/tpm20.c65
-rw-r--r--sys/dev/tpm/tpm20.h1
-rw-r--r--sys/dev/tpm/tpm_crb.c1
-rw-r--r--sys/dev/tpm/tpm_tis_core.c1
4 files changed, 68 insertions, 0 deletions
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;
@@ -243,8 +244,30 @@ tpm20_release(struct tpm_sc *sc)
}
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));
}
@@ -308,6 +331,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)
{
struct tpm_sc *sc;
@@ -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
};