diff options
Diffstat (limited to 'drivers/char/tpm/tpm-chip.c')
| -rw-r--r-- | drivers/char/tpm/tpm-chip.c | 139 |
1 files changed, 82 insertions, 57 deletions
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 741d8f3e8fb3..082b910ddf0d 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -28,8 +28,13 @@ DEFINE_IDR(dev_nums_idr); static DEFINE_MUTEX(idr_lock); -struct class *tpm_class; -struct class *tpmrm_class; +const struct class tpm_class = { + .name = "tpm", + .shutdown_pre = tpm_class_shutdown, +}; +const struct class tpmrm_class = { + .name = "tpmrm", +}; dev_t tpm_devt; static int tpm_request_locality(struct tpm_chip *chip) @@ -153,6 +158,9 @@ int tpm_try_get_ops(struct tpm_chip *chip) { int rc = -EIO; + if (chip->flags & TPM_CHIP_FLAG_DISABLE) + return rc; + get_device(&chip->dev); down_read(&chip->ops_sem); @@ -160,6 +168,11 @@ int tpm_try_get_ops(struct tpm_chip *chip) goto out_ops; mutex_lock(&chip->tpm_mutex); + + /* tmp_chip_start may issue IO that is denied while suspended */ + if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) + goto out_lock; + rc = tpm_chip_start(chip); if (rc) goto out_lock; @@ -218,42 +231,6 @@ struct tpm_chip *tpm_default_chip(void) EXPORT_SYMBOL_GPL(tpm_default_chip); /** - * tpm_find_get_ops() - find and reserve a TPM chip - * @chip: a &struct tpm_chip instance, %NULL for the default chip - * - * Finds a TPM chip and reserves its class device and operations. The chip must - * be released with tpm_put_ops() after use. - * This function is for internal use only. It supports existing TPM callers - * by accepting NULL, but those callers should be converted to pass in a chip - * directly. - * - * Return: - * A reserved &struct tpm_chip instance. - * %NULL if a chip is not found. - * %NULL if the chip is not available. - */ -struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) -{ - int rc; - - if (chip) { - if (!tpm_try_get_ops(chip)) - return chip; - return NULL; - } - - chip = tpm_default_chip(); - if (!chip) - return NULL; - rc = tpm_try_get_ops(chip); - /* release additional reference we got from tpm_default_chip() */ - put_device(&chip->dev); - if (rc) - return NULL; - return chip; -} - -/** * tpm_dev_release() - free chip memory and the device number * @dev: the character device for the TPM chip * @@ -267,10 +244,11 @@ static void tpm_dev_release(struct device *dev) idr_remove(&dev_nums_idr, chip->dev_num); mutex_unlock(&idr_lock); - kfree(chip->log.bios_event_log); kfree(chip->work_space.context_buf); kfree(chip->work_space.session_buf); - kfree(chip->allocated_banks); +#ifdef CONFIG_TCG_TPM2_HMAC + kfree(chip->auth); +#endif kfree(chip); } @@ -283,13 +261,14 @@ static void tpm_dev_release(struct device *dev) * * Return: always 0 (i.e. success) */ -static int tpm_class_shutdown(struct device *dev) +int tpm_class_shutdown(struct device *dev) { struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); down_write(&chip->ops_sem); if (chip->flags & TPM_CHIP_FLAG_TPM2) { if (!tpm_chip_start(chip)) { + tpm2_end_auth_session(chip); tpm2_shutdown(chip, TPM2_SU_CLEAR); tpm_chip_stop(chip); } @@ -337,8 +316,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev, device_initialize(&chip->dev); - chip->dev.class = tpm_class; - chip->dev.class->shutdown_pre = tpm_class_shutdown; + chip->dev.class = &tpm_class; chip->dev.release = tpm_dev_release; chip->dev.parent = pdev; chip->dev.groups = chip->groups; @@ -519,9 +497,20 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) return tpm_get_random(chip, data, max); } +static bool tpm_is_hwrng_enabled(struct tpm_chip *chip) +{ + if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + return false; + if (tpm_is_firmware_upgrade(chip)) + return false; + if (chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED) + return false; + return true; +} + static int tpm_add_hwrng(struct tpm_chip *chip) { - if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip)) + if (!tpm_is_hwrng_enabled(chip)) return 0; snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), @@ -549,6 +538,42 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip) } /* + * tpm_chip_bootstrap() - Boostrap TPM chip after power on + * @chip: TPM chip to use. + * + * Initialize TPM chip after power on. This a one-shot function: subsequent + * calls will have no effect. + */ +int tpm_chip_bootstrap(struct tpm_chip *chip) +{ + int rc; + + if (chip->flags & TPM_CHIP_FLAG_BOOTSTRAPPED) + return 0; + + rc = tpm_chip_start(chip); + if (rc) + return rc; + + rc = tpm_auto_startup(chip); + if (rc) + goto stop; + + rc = tpm_get_pcr_allocation(chip); +stop: + tpm_chip_stop(chip); + + /* + * Unconditionally set, as driver initialization should cease, when the + * boostrapping process fails. + */ + chip->flags |= TPM_CHIP_FLAG_BOOTSTRAPPED; + + return rc; +} +EXPORT_SYMBOL_GPL(tpm_chip_bootstrap); + +/* * tpm_chip_register() - create a character device for the TPM chip * @chip: TPM chip to use. * @@ -563,17 +588,7 @@ int tpm_chip_register(struct tpm_chip *chip) { int rc; - rc = tpm_chip_start(chip); - if (rc) - return rc; - rc = tpm_auto_startup(chip); - if (rc) { - tpm_chip_stop(chip); - return rc; - } - - rc = tpm_get_pcr_allocation(chip); - tpm_chip_stop(chip); + rc = tpm_chip_bootstrap(chip); if (rc) return rc; @@ -600,7 +615,7 @@ int tpm_chip_register(struct tpm_chip *chip) return 0; out_hwrng: - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip)) + if (tpm_is_hwrng_enabled(chip)) hwrng_unregister(&chip->hwrng); out_ppi: tpm_bios_log_teardown(chip); @@ -624,8 +639,18 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); */ void tpm_chip_unregister(struct tpm_chip *chip) { +#ifdef CONFIG_TCG_TPM2_HMAC + int rc; + + rc = tpm_try_get_ops(chip); + if (!rc) { + tpm2_end_auth_session(chip); + tpm_put_ops(chip); + } +#endif + tpm_del_legacy_sysfs(chip); - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip)) + if (tpm_is_hwrng_enabled(chip)) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) |
