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: a2d5ed9442 ("Introduce driver for TPM 2.0 in CRB and [...]")
Fixes: 4ee7d3b011 ("Allow using TPM as entropy source.")
Co-authored-by: markj (D53835)
Tested by: garga
Differential Revision: https://reviews.freebsd.org/D55074
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user