// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2004 IBM Corporation * Copyright (C) 2014 Intel Corporation * * Authors: * Leendert van Doorn * Dave Safford * Reiner Sailer * Kylene Hall * * Maintained by: * * Device driver for TCG/TCPA TPM (trusted platform module). * Specifications at www.trustedcomputinggroup.org * * Note, the TPM chip is not interrupt driven (only polling) * and can have very long timeouts (minutes!). Hence the unusual * calls to msleep. */ #include #include #include #include #include #include #include #include "tpm.h" /* * Bug workaround - some TPM's don't flush the most * recently changed pcr on suspend, so force the flush * with an extend to the selected _unused_ non-volatile pcr. */ static u32 tpm_suspend_pcr; module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); MODULE_PARM_DESC(suspend_pcr, "PCR to use for dummy writes to facilitate flush on suspend."); /** * tpm_calc_ordinal_duration() - calculate the maximum command duration * @chip: TPM chip to use. * @ordinal: TPM command ordinal. * * The function returns the maximum amount of time the chip could take * to return the result for a particular ordinal in jiffies. * * Return: A maximal duration time for an ordinal in jiffies. */ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) { if (chip->flags & TPM_CHIP_FLAG_TPM2) return tpm2_calc_ordinal_duration(chip, ordinal); else return tpm1_calc_ordinal_duration(chip, ordinal); } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz) { struct tpm_header *header = buf; int rc; ssize_t len = 0; u32 count, ordinal; unsigned long stop; if (bufsiz < TPM_HEADER_SIZE) return -EINVAL; if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; count = be32_to_cpu(header->length); ordinal = be32_to_cpu(header->ordinal); if (count == 0) return -ENODATA; if (count > bufsiz) { dev_err(&chip->dev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } rc = chip->ops->send(chip, buf, count); if (rc < 0) { if (rc != -EPIPE) dev_err(&chip->dev, "%s: send(): error %d\n", __func__, rc); return rc; } /* A sanity check. send() should just return zero on success e.g. * not the command length. */ if (rc > 0) { dev_warn(&chip->dev, "%s: send(): invalid value %d\n", __func__, rc); rc = 0; } if (chip->flags & TPM_CHIP_FLAG_IRQ) goto out_recv; stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->ops->status(chip); if ((status & chip->ops->req_complete_mask) == chip->ops->req_complete_val) goto out_recv; if (chip->ops->req_canceled(chip, status)) { dev_err(&chip->dev, "Operation Canceled\n"); return -ECANCELED; } tpm_msleep(TPM_TIMEOUT_POLL); rmb(); } while (time_before(jiffies, stop)); chip->ops->cancel(chip); dev_err(&chip->dev, "Operation Timed out\n"); return -ETIME; out_recv: len = chip->ops->recv(chip, buf, bufsiz); if (len < 0) { rc = len; dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc); } else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length)) rc = -EFAULT; return rc ? rc : len; } /** * tpm_transmit - Internal kernel interface to transmit TPM commands. * @chip: a TPM chip to use * @buf: a TPM command buffer * @bufsiz: length of the TPM command buffer * * A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from * the TPM and retransmits the command after a delay up to a maximum wait of * TPM2_DURATION_LONG. * * Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0 * only. * * Return: * * The response length - OK * * -errno - A system error */ ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz) { struct tpm_header *header = (struct tpm_header *)buf; /* space for header and handles */ u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; unsigned int delay_msec = TPM2_DURATION_SHORT; u32 rc = 0; ssize_t ret; const size_t save_size = min(sizeof(save), bufsiz); /* the command code is where the return code will be */ u32 cc = be32_to_cpu(header->return_code); /* * Subtlety here: if we have a space, the handles will be * transformed, so when we restore the header we also have to * restore the handles. */ memcpy(save, buf, save_size); for (;;) { ret = tpm_try_transmit(chip, buf, bufsiz); if (ret < 0) break; rc = be32_to_cpu(header->return_code); if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING) break; /* * return immediately if self test returns test * still running to shorten boot time. */ if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST) break; if (delay_msec > TPM2_DURATION_LONG) { if (rc == TPM2_RC_RETRY) dev_err(&chip->dev, "in retry loop\n"); else dev_err(&chip->dev, "self test is still running\n"); break; } tpm_msleep(delay_msec); delay_msec *= 2; memcpy(buf, save, save_size); } return ret; } /** * tpm_transmit_cmd - send a tpm command to the device * @chip: a TPM chip to use * @buf: a TPM command buffer * @min_rsp_body_length: minimum expected length of response body * @desc: command description used in the error message * * Return: * * 0 - OK * * -errno - A system error * * TPM_RC - A TPM error */ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf, size_t min_rsp_body_length, const char *desc) { const struct tpm_header *header = (struct tpm_header *)buf->data; int err; ssize_t len; len = tpm_transmit(chip, buf->data, PAGE_SIZE); if (len < 0) return len; err = be32_to_cpu(header->return_code); if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED && err != TPM2_RC_TESTING && desc) dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, desc); if (err) return err; if (len < min_rsp_body_length + TPM_HEADER_SIZE) return -EFAULT; return 0; } EXPORT_SYMBOL_GPL(tpm_transmit_cmd); int tpm_get_timeouts(struct tpm_chip *chip) { if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2) return tpm2_get_timeouts(chip); else return tpm1_get_timeouts(chip); } EXPORT_SYMBOL_GPL(tpm_get_timeouts); /** * tpm_is_tpm2 - do we a have a TPM2 chip? * @chip: a &struct tpm_chip instance, %NULL for the default chip * * Return: * 1 if we have a TPM2 chip. * 0 if we don't have a TPM2 chip. * A negative number for system errors (errno). */ int tpm_is_tpm2(struct tpm_chip *chip) { int rc; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_is_tpm2); /** * tpm_pcr_read - read a PCR value from SHA1 bank * @chip: a &struct tpm_chip instance, %NULL for the default chip * @pcr_idx: the PCR to be retrieved * @digest: the PCR bank and buffer current PCR value is written to * * Return: same as with tpm_transmit_cmd() */ int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, struct tpm_digest *digest) { int rc; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); else rc = tpm1_pcr_read(chip, pcr_idx, digest->digest); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_read); /** * tpm_pcr_extend - extend a PCR value in SHA1 bank. * @chip: a &struct tpm_chip instance, %NULL for the default chip * @pcr_idx: the PCR to be retrieved * @digests: array of tpm_digest structures used to extend PCRs * * Note: callers must pass a digest for every allocated PCR bank, in the same * order of the banks in chip->allocated_banks. * * Return: same as with tpm_transmit_cmd() */ int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, struct tpm_digest *digests) { int rc; int i; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; for (i = 0; i < chip->nr_allocated_banks; i++) { if (digests[i].alg_id != chip->allocated_banks[i].alg_id) { rc = EINVAL; goto out; } } if (chip->flags & TPM_CHIP_FLAG_TPM2) { rc = tpm2_pcr_extend(chip, pcr_idx, digests); goto out; } rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest, "attempting extend a PCR value"); out: tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_pcr_extend); /** * tpm_send - send a TPM command * @chip: a &struct tpm_chip instance, %NULL for the default chip * @cmd: a TPM command buffer * @buflen: the length of the TPM command buffer * * Return: same as with tpm_transmit_cmd() */ int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) { struct tpm_buf buf; int rc; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; buf.data = cmd; rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command"); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_send); int tpm_auto_startup(struct tpm_chip *chip) { int rc; if (!(chip->ops->flags & TPM_OPS_AUTO_STARTUP)) return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_auto_startup(chip); else rc = tpm1_auto_startup(chip); return rc; } /* * We are about to suspend. Save the TPM state * so that it can be restored. */ int tpm_pm_suspend(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); int rc = 0; if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) goto suspended; if ((chip->flags & TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED) && !pm_suspend_via_firmware()) goto suspended; if (!tpm_chip_start(chip)) { if (chip->flags & TPM_CHIP_FLAG_TPM2) tpm2_shutdown(chip, TPM2_SU_STATE); else rc = tpm1_pm_suspend(chip, tpm_suspend_pcr); tpm_chip_stop(chip); } suspended: return rc; } EXPORT_SYMBOL_GPL(tpm_pm_suspend); /* * Resume from a power safe. The BIOS already restored * the TPM state. */ int tpm_pm_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if (chip == NULL) return -ENODEV; return 0; } EXPORT_SYMBOL_GPL(tpm_pm_resume); /** * tpm_get_random() - get random bytes from the TPM's RNG * @chip: a &struct tpm_chip instance, %NULL for the default chip * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * * Return: number of random bytes read or a negative error value. */ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) { int rc; if (!out || max > TPM_MAX_RNG_DATA) return -EINVAL; chip = tpm_find_get_ops(chip); if (!chip) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_get_random(chip, out, max); else rc = tpm1_get_random(chip, out, max); tpm_put_ops(chip); return rc; } EXPORT_SYMBOL_GPL(tpm_get_random); static int __init tpm_init(void) { int rc; tpm_class = class_create(THIS_MODULE, "tpm"); if (IS_ERR(tpm_class)) { pr_err("couldn't create tpm class\n"); return PTR_ERR(tpm_class); } tpmrm_class = class_create(THIS_MODULE, "tpmrm"); if (IS_ERR(tpmrm_class)) { pr_err("couldn't create tpmrm class\n"); rc = PTR_ERR(tpmrm_class); goto out_destroy_tpm_class; } rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm"); if (rc < 0) { pr_err("tpm: failed to allocate char dev region\n"); goto out_destroy_tpmrm_class; } rc = tpm_dev_common_init(); if (rc) { pr_err("tpm: failed to allocate char dev region\n"); goto out_unreg_chrdev; } return 0; out_unreg_chrdev: unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES); out_destroy_tpmrm_class: class_destroy(tpmrm_class); out_destroy_tpm_class: class_destroy(tpm_class); return rc; } static void __exit tpm_exit(void) { idr_destroy(&dev_nums_idr); class_destroy(tpm_class); class_destroy(tpmrm_class); unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); tpm_dev_common_exit(); } subsys_initcall(tpm_init); module_exit(tpm_exit); MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); MODULE_DESCRIPTION("TPM Driver"); MODULE_VERSION("2.0"); MODULE_LICENSE("GPL");