Index: sys/conf/options =================================================================== --- sys/conf/options +++ sys/conf/options @@ -983,6 +983,9 @@ RANDOM_ENABLE_UMA opt_global.h RANDOM_ENABLE_ETHER opt_global.h +# This options turns TPM into entropy source. +TPM_HARVEST opt_tpm.h + # BHND(4) driver BHND_LOGLEVEL opt_global.h Index: sys/dev/random/random_harvestq.c =================================================================== --- sys/dev/random/random_harvestq.c +++ sys/dev/random/random_harvestq.c @@ -330,6 +330,7 @@ [RANDOM_PURE_BROADCOM] = "PURE_BROADCOM", [RANDOM_PURE_CCP] = "PURE_CCP", [RANDOM_PURE_DARN] = "PURE_DARN", + [RANDOM_PURE_TPM] = "PURE_TPM", /* "ENTROPYSOURCE" */ }; Index: sys/dev/tpm/tpm20.h =================================================================== --- sys/dev/tpm/tpm20.h +++ sys/dev/tpm/tpm20.h @@ -55,6 +55,8 @@ #include #include "opt_acpi.h" +#include "opt_tpm.h" + #define BIT(x) (1 << (x)) /* Timeouts in us */ @@ -120,6 +122,10 @@ size_t pending_data_length; struct callout discard_buffer_callout; +#ifdef TPM_HARVEST + struct callout harvest_callout; + int harvest_ticks; +#endif int (*transmit)(struct tpm_sc *, size_t); }; Index: sys/dev/tpm/tpm20.c =================================================================== --- sys/dev/tpm/tpm20.c +++ sys/dev/tpm/tpm20.c @@ -28,13 +28,27 @@ #include __FBSDID("$FreeBSD$"); +#include + #include "tpm20.h" +#define TPM_HARVEST_SIZE 16 +/* + * Perform a harvest every 10 seconds. + * Since discrete TPMs are painfully slow + * we don't want to execute this too often + * as the chip is likely to be used by others too. + */ +#define TPM_HARVEST_INTERVAL 10000000 + MALLOC_DECLARE(M_TPM20); MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver"); static void tpm20_discard_buffer(void *arg); -static int tpm20_save_state(device_t dev, bool suspend); +#ifdef TPM_HARVEST +static void tpm20_harvest(void *arg); +#endif +static int tpm20_save_state(device_t dev, bool suspend); static d_open_t tpm20_open; static d_close_t tpm20_close; @@ -175,6 +189,11 @@ sx_init(&sc->dev_lock, "TPM driver lock"); cv_init(&sc->buf_cv, "TPM buffer cv"); callout_init(&sc->discard_buffer_callout, 1); +#ifdef TPM_HARVEST + sc->harvest_ticks = TPM_HARVEST_INTERVAL / tick; + callout_init(&sc->harvest_callout, 1); + callout_reset(&sc->harvest_callout, 0, tpm20_harvest, sc); +#endif sc->pending_data_length = 0; make_dev_args_init(&args); @@ -195,6 +214,8 @@ tpm20_release(struct tpm_sc *sc) { + callout_drain(&sc->harvest_callout); + if (sc->buf != NULL) free(sc->buf, M_TPM20); @@ -217,6 +238,57 @@ return (tpm20_save_state(dev, false)); } +#ifdef TPM_HARVEST + +/* + * Get TPM_HARVEST_SIZE random bytes and add them + * into system entropy pool. + */ +static void +tpm20_harvest(void *arg) +{ + struct tpm_sc *sc; + unsigned char entropy[TPM_HARVEST_SIZE]; + uint16_t entropy_size; + int result; + uint8_t cmd[] = { + 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ + 0x00, 0x00, 0x00, 0x0c, /* cmd length */ + 0x00, 0x00, 0x01, 0x7b, /* cmd TPM_CC_GetRandom */ + 0x00, TPM_HARVEST_SIZE /* number of bytes requested */ + }; + + + sc = arg; + sx_xlock(&sc->dev_lock); + + memcpy(sc->buf, cmd, sizeof(cmd)); + result = sc->transmit(sc, sizeof(cmd)); + if (result != 0) { + sx_xunlock(&sc->dev_lock); + return; + } + + /* Ignore response size */ + sc->pending_data_length = 0; + + /* The number of random bytes we got is placed right after the header */ + entropy_size = (uint16_t) sc->buf[TPM_HEADER_SIZE + 1]; + if (entropy_size > 0) { + entropy_size = MIN(entropy_size, TPM_HARVEST_SIZE); + memcpy(entropy, + sc->buf + TPM_HEADER_SIZE + sizeof(uint16_t), + entropy_size); + } + + sx_xunlock(&sc->dev_lock); + if (entropy_size > 0) + random_harvest_queue(entropy, entropy_size, RANDOM_PURE_TPM); + + callout_reset(&sc->harvest_callout, sc->harvest_ticks, tpm20_harvest, sc); +} +#endif /* TPM_HARVEST */ + static int tpm20_save_state(device_t dev, bool suspend) { Index: sys/dev/tpm/tpm_crb.c =================================================================== --- sys/dev/tpm/tpm_crb.c +++ sys/dev/tpm/tpm_crb.c @@ -165,7 +165,8 @@ return (ENXIO); if(!tpmcrb_request_locality(sc, 0)) { - tpmcrb_detach(dev); + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); return (ENXIO); } @@ -231,12 +232,12 @@ struct tpm_sc *sc; sc = device_get_softc(dev); + tpm20_release(sc); if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - tpm20_release(sc); return (0); } Index: sys/dev/tpm/tpm_tis.c =================================================================== --- sys/dev/tpm/tpm_tis.c +++ sys/dev/tpm/tpm_tis.c @@ -163,6 +163,7 @@ struct tpm_sc *sc; sc = device_get_softc(dev); + tpm20_release(sc); if (sc->intr_cookie != NULL) bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie); @@ -175,7 +176,6 @@ bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - tpm20_release(sc); return (0); } Index: sys/sys/random.h =================================================================== --- sys/sys/random.h +++ sys/sys/random.h @@ -87,6 +87,7 @@ RANDOM_PURE_BROADCOM, RANDOM_PURE_CCP, RANDOM_PURE_DARN, + RANDOM_PURE_TPM, ENTROPYSOURCE }; _Static_assert(ENTROPYSOURCE <= 32,