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
|
#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
|
||||||
static void tpm20_harvest(void *arg, int unused);
|
static void tpm20_harvest(void *arg, int unused);
|
||||||
#endif
|
#endif
|
||||||
|
static int tpm20_restart(device_t dev, bool clear);
|
||||||
static int tpm20_save_state(device_t dev, bool suspend);
|
static int tpm20_save_state(device_t dev, bool suspend);
|
||||||
|
|
||||||
static d_open_t tpm20_open;
|
static d_open_t tpm20_open;
|
||||||
@@ -242,9 +243,31 @@ tpm20_release(struct tpm_sc *sc)
|
|||||||
destroy_dev(sc->sc_cdev);
|
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
|
int
|
||||||
tpm20_suspend(device_t dev)
|
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));
|
return (tpm20_save_state(dev, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +330,43 @@ tpm20_harvest(void *arg, int unused)
|
|||||||
}
|
}
|
||||||
#endif /* TPM_HARVEST */
|
#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
|
static int
|
||||||
tpm20_save_state(device_t dev, bool suspend)
|
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);
|
sx_xlock(&sc->dev_lock);
|
||||||
|
|
||||||
|
MPASS(sc->pending_data_length == 0);
|
||||||
memcpy(sc->buf, save_cmd, sizeof(save_cmd));
|
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));
|
TPM_TRANSMIT(sc->dev, sizeof(save_cmd));
|
||||||
|
sc->pending_data_length = 0;
|
||||||
|
sc->total_length = 0;
|
||||||
|
|
||||||
sx_xunlock(&sc->dev_lock);
|
sx_xunlock(&sc->dev_lock);
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ struct tpm_sc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int tpm20_suspend(device_t dev);
|
int tpm20_suspend(device_t dev);
|
||||||
|
int tpm20_resume(device_t dev);
|
||||||
int tpm20_shutdown(device_t dev);
|
int tpm20_shutdown(device_t dev);
|
||||||
int32_t tpm20_get_timeout(uint32_t command);
|
int32_t tpm20_get_timeout(uint32_t command);
|
||||||
int tpm20_init(struct tpm_sc *sc);
|
int tpm20_init(struct tpm_sc *sc);
|
||||||
|
|||||||
@@ -651,6 +651,7 @@ static device_method_t tpmcrb_methods[] = {
|
|||||||
DEVMETHOD(device_detach, tpmcrb_detach),
|
DEVMETHOD(device_detach, tpmcrb_detach),
|
||||||
DEVMETHOD(device_shutdown, tpm20_shutdown),
|
DEVMETHOD(device_shutdown, tpm20_shutdown),
|
||||||
DEVMETHOD(device_suspend, tpm20_suspend),
|
DEVMETHOD(device_suspend, tpm20_suspend),
|
||||||
|
DEVMETHOD(device_resume, tpm20_resume),
|
||||||
DEVMETHOD(tpm_transmit, tpmcrb_transmit),
|
DEVMETHOD(tpm_transmit, tpmcrb_transmit),
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -487,6 +487,7 @@ static device_method_t tpmtis_methods[] = {
|
|||||||
DEVMETHOD(device_detach, tpmtis_detach),
|
DEVMETHOD(device_detach, tpmtis_detach),
|
||||||
DEVMETHOD(device_shutdown, tpm20_shutdown),
|
DEVMETHOD(device_shutdown, tpm20_shutdown),
|
||||||
DEVMETHOD(device_suspend, tpm20_suspend),
|
DEVMETHOD(device_suspend, tpm20_suspend),
|
||||||
|
DEVMETHOD(device_resume, tpm20_resume),
|
||||||
DEVMETHOD(tpm_transmit, tpmtis_transmit),
|
DEVMETHOD(tpm_transmit, tpmtis_transmit),
|
||||||
DEVMETHOD_END
|
DEVMETHOD_END
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user