1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29deb0eb7SJason Gunthorpe /* 39deb0eb7SJason Gunthorpe * Copyright (C) 2004 IBM Corporation 4afb5abc2SJarkko Sakkinen * Copyright (C) 2014 Intel Corporation 59deb0eb7SJason Gunthorpe * 69deb0eb7SJason Gunthorpe * Authors: 79deb0eb7SJason Gunthorpe * Leendert van Doorn <leendert@watson.ibm.com> 89deb0eb7SJason Gunthorpe * Dave Safford <safford@watson.ibm.com> 99deb0eb7SJason Gunthorpe * Reiner Sailer <sailer@watson.ibm.com> 109deb0eb7SJason Gunthorpe * Kylene Hall <kjhall@us.ibm.com> 119deb0eb7SJason Gunthorpe * 129deb0eb7SJason Gunthorpe * Maintained by: <tpmdd-devel@lists.sourceforge.net> 139deb0eb7SJason Gunthorpe * 149deb0eb7SJason Gunthorpe * Device driver for TCG/TCPA TPM (trusted platform module). 159deb0eb7SJason Gunthorpe * Specifications at www.trustedcomputinggroup.org 169deb0eb7SJason Gunthorpe * 179deb0eb7SJason Gunthorpe * Note, the TPM chip is not interrupt driven (only polling) 189deb0eb7SJason Gunthorpe * and can have very long timeouts (minutes!). Hence the unusual 199deb0eb7SJason Gunthorpe * calls to msleep. 209deb0eb7SJason Gunthorpe */ 219deb0eb7SJason Gunthorpe 229deb0eb7SJason Gunthorpe #include <linux/poll.h> 239deb0eb7SJason Gunthorpe #include <linux/slab.h> 249deb0eb7SJason Gunthorpe #include <linux/mutex.h> 259deb0eb7SJason Gunthorpe #include <linux/spinlock.h> 26*2e2ee5a2SStephen Boyd #include <linux/suspend.h> 279deb0eb7SJason Gunthorpe #include <linux/freezer.h> 28fd3ec366SThiebaud Weksteen #include <linux/tpm_eventlog.h> 299deb0eb7SJason Gunthorpe 309deb0eb7SJason Gunthorpe #include "tpm.h" 319deb0eb7SJason Gunthorpe 329deb0eb7SJason Gunthorpe /* 339deb0eb7SJason Gunthorpe * Bug workaround - some TPM's don't flush the most 349deb0eb7SJason Gunthorpe * recently changed pcr on suspend, so force the flush 359deb0eb7SJason Gunthorpe * with an extend to the selected _unused_ non-volatile pcr. 369deb0eb7SJason Gunthorpe */ 3795adc6b4STomas Winkler static u32 tpm_suspend_pcr; 389deb0eb7SJason Gunthorpe module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); 399deb0eb7SJason Gunthorpe MODULE_PARM_DESC(suspend_pcr, 4039f5712bSDmitry Torokhov "PCR to use for dummy writes to facilitate flush on suspend."); 419deb0eb7SJason Gunthorpe 42d856c00fSTomas Winkler /** 43d856c00fSTomas Winkler * tpm_calc_ordinal_duration() - calculate the maximum command duration 44d856c00fSTomas Winkler * @chip: TPM chip to use. 45d856c00fSTomas Winkler * @ordinal: TPM command ordinal. 46d856c00fSTomas Winkler * 47d856c00fSTomas Winkler * The function returns the maximum amount of time the chip could take 48d856c00fSTomas Winkler * to return the result for a particular ordinal in jiffies. 49d856c00fSTomas Winkler * 50d856c00fSTomas Winkler * Return: A maximal duration time for an ordinal in jiffies. 51d856c00fSTomas Winkler */ 52d856c00fSTomas Winkler unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) 53d856c00fSTomas Winkler { 54d856c00fSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 55d856c00fSTomas Winkler return tpm2_calc_ordinal_duration(chip, ordinal); 56d856c00fSTomas Winkler else 57d856c00fSTomas Winkler return tpm1_calc_ordinal_duration(chip, ordinal); 58d856c00fSTomas Winkler } 59d856c00fSTomas Winkler EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); 60d856c00fSTomas Winkler 6147a6c28bSJarkko Sakkinen static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz) 629deb0eb7SJason Gunthorpe { 63b34b77a9SJarkko Sakkinen struct tpm_header *header = buf; 64745b361eSJarkko Sakkinen int rc; 65745b361eSJarkko Sakkinen ssize_t len = 0; 669deb0eb7SJason Gunthorpe u32 count, ordinal; 679deb0eb7SJason Gunthorpe unsigned long stop; 689deb0eb7SJason Gunthorpe 69c3465a37SJarkko Sakkinen if (bufsiz < TPM_HEADER_SIZE) 70c3465a37SJarkko Sakkinen return -EINVAL; 71ebfd7532SJarkko Sakkinen 729deb0eb7SJason Gunthorpe if (bufsiz > TPM_BUFSIZE) 739deb0eb7SJason Gunthorpe bufsiz = TPM_BUFSIZE; 749deb0eb7SJason Gunthorpe 75720b0711SJarkko Sakkinen count = be32_to_cpu(header->length); 76720b0711SJarkko Sakkinen ordinal = be32_to_cpu(header->ordinal); 779deb0eb7SJason Gunthorpe if (count == 0) 789deb0eb7SJason Gunthorpe return -ENODATA; 799deb0eb7SJason Gunthorpe if (count > bufsiz) { 808cfffc9dSJason Gunthorpe dev_err(&chip->dev, 819deb0eb7SJason Gunthorpe "invalid count value %x %zx\n", count, bufsiz); 829deb0eb7SJason Gunthorpe return -E2BIG; 839deb0eb7SJason Gunthorpe } 849deb0eb7SJason Gunthorpe 8562c09e12SWinkler, Tomas rc = chip->ops->send(chip, buf, count); 869deb0eb7SJason Gunthorpe if (rc < 0) { 87402149c6SStefan Berger if (rc != -EPIPE) 888cfffc9dSJason Gunthorpe dev_err(&chip->dev, 89f5595f5bSJarkko Sakkinen "%s: send(): error %d\n", __func__, rc); 9029b47ce9SJarkko Sakkinen return rc; 919deb0eb7SJason Gunthorpe } 929deb0eb7SJason Gunthorpe 93f5595f5bSJarkko Sakkinen /* A sanity check. send() should just return zero on success e.g. 94f5595f5bSJarkko Sakkinen * not the command length. 95f5595f5bSJarkko Sakkinen */ 96f5595f5bSJarkko Sakkinen if (rc > 0) { 97f5595f5bSJarkko Sakkinen dev_warn(&chip->dev, 98f5595f5bSJarkko Sakkinen "%s: send(): invalid value %d\n", __func__, rc); 99f5595f5bSJarkko Sakkinen rc = 0; 100f5595f5bSJarkko Sakkinen } 101f5595f5bSJarkko Sakkinen 102570a3609SChristophe Ricard if (chip->flags & TPM_CHIP_FLAG_IRQ) 1039deb0eb7SJason Gunthorpe goto out_recv; 1049deb0eb7SJason Gunthorpe 105d856c00fSTomas Winkler stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); 1069deb0eb7SJason Gunthorpe do { 1075f82e9f0SJason Gunthorpe u8 status = chip->ops->status(chip); 1085f82e9f0SJason Gunthorpe if ((status & chip->ops->req_complete_mask) == 1095f82e9f0SJason Gunthorpe chip->ops->req_complete_val) 1109deb0eb7SJason Gunthorpe goto out_recv; 1119deb0eb7SJason Gunthorpe 1125f82e9f0SJason Gunthorpe if (chip->ops->req_canceled(chip, status)) { 1138cfffc9dSJason Gunthorpe dev_err(&chip->dev, "Operation Canceled\n"); 11429b47ce9SJarkko Sakkinen return -ECANCELED; 1159deb0eb7SJason Gunthorpe } 1169deb0eb7SJason Gunthorpe 11759f5a6b0SNayna Jain tpm_msleep(TPM_TIMEOUT_POLL); 1189deb0eb7SJason Gunthorpe rmb(); 1199deb0eb7SJason Gunthorpe } while (time_before(jiffies, stop)); 1209deb0eb7SJason Gunthorpe 1215f82e9f0SJason Gunthorpe chip->ops->cancel(chip); 1228cfffc9dSJason Gunthorpe dev_err(&chip->dev, "Operation Timed out\n"); 12329b47ce9SJarkko Sakkinen return -ETIME; 1249deb0eb7SJason Gunthorpe 1259deb0eb7SJason Gunthorpe out_recv: 12662c09e12SWinkler, Tomas len = chip->ops->recv(chip, buf, bufsiz); 127745b361eSJarkko Sakkinen if (len < 0) { 128745b361eSJarkko Sakkinen rc = len; 129304ff672SJarkko Sakkinen dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc); 130304ff672SJarkko Sakkinen } else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length)) 131a147918eSJarkko Sakkinen rc = -EFAULT; 132a147918eSJarkko Sakkinen 133745b361eSJarkko Sakkinen return rc ? rc : len; 1349deb0eb7SJason Gunthorpe } 1359deb0eb7SJason Gunthorpe 136f865c196SWinkler, Tomas /** 137e2fb992dSJames Bottomley * tpm_transmit - Internal kernel interface to transmit TPM commands. 138412eb585SJarkko Sakkinen * @chip: a TPM chip to use 139412eb585SJarkko Sakkinen * @buf: a TPM command buffer 140e2fb992dSJames Bottomley * @bufsiz: length of the TPM command buffer 141e2fb992dSJames Bottomley * 142412eb585SJarkko Sakkinen * A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from 143412eb585SJarkko Sakkinen * the TPM and retransmits the command after a delay up to a maximum wait of 144412eb585SJarkko Sakkinen * TPM2_DURATION_LONG. 145e2fb992dSJames Bottomley * 146412eb585SJarkko Sakkinen * Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0 147412eb585SJarkko Sakkinen * only. 148e2fb992dSJames Bottomley * 149e2fb992dSJames Bottomley * Return: 150412eb585SJarkko Sakkinen * * The response length - OK 151412eb585SJarkko Sakkinen * * -errno - A system error 152e2fb992dSJames Bottomley */ 15347a6c28bSJarkko Sakkinen ssize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz) 154e2fb992dSJames Bottomley { 155b34b77a9SJarkko Sakkinen struct tpm_header *header = (struct tpm_header *)buf; 156e2fb992dSJames Bottomley /* space for header and handles */ 157e2fb992dSJames Bottomley u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; 158e2fb992dSJames Bottomley unsigned int delay_msec = TPM2_DURATION_SHORT; 159e2fb992dSJames Bottomley u32 rc = 0; 160e2fb992dSJames Bottomley ssize_t ret; 1615faafbabSJarkko Sakkinen const size_t save_size = min(sizeof(save), bufsiz); 1622be8ffedSJames Bottomley /* the command code is where the return code will be */ 1632be8ffedSJames Bottomley u32 cc = be32_to_cpu(header->return_code); 164e2fb992dSJames Bottomley 165e2fb992dSJames Bottomley /* 166e2fb992dSJames Bottomley * Subtlety here: if we have a space, the handles will be 167e2fb992dSJames Bottomley * transformed, so when we restore the header we also have to 168e2fb992dSJames Bottomley * restore the handles. 169e2fb992dSJames Bottomley */ 170e2fb992dSJames Bottomley memcpy(save, buf, save_size); 171e2fb992dSJames Bottomley 172e2fb992dSJames Bottomley for (;;) { 17347a6c28bSJarkko Sakkinen ret = tpm_try_transmit(chip, buf, bufsiz); 174e2fb992dSJames Bottomley if (ret < 0) 175e2fb992dSJames Bottomley break; 176e2fb992dSJames Bottomley rc = be32_to_cpu(header->return_code); 1772be8ffedSJames Bottomley if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING) 1782be8ffedSJames Bottomley break; 1792be8ffedSJames Bottomley /* 1802be8ffedSJames Bottomley * return immediately if self test returns test 1812be8ffedSJames Bottomley * still running to shorten boot time. 1822be8ffedSJames Bottomley */ 1832be8ffedSJames Bottomley if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST) 184e2fb992dSJames Bottomley break; 18592980756SNayna Jain 186e2fb992dSJames Bottomley if (delay_msec > TPM2_DURATION_LONG) { 1872be8ffedSJames Bottomley if (rc == TPM2_RC_RETRY) 1882be8ffedSJames Bottomley dev_err(&chip->dev, "in retry loop\n"); 1892be8ffedSJames Bottomley else 1902be8ffedSJames Bottomley dev_err(&chip->dev, 1912be8ffedSJames Bottomley "self test is still running\n"); 192e2fb992dSJames Bottomley break; 193e2fb992dSJames Bottomley } 194e2fb992dSJames Bottomley tpm_msleep(delay_msec); 19592980756SNayna Jain delay_msec *= 2; 196e2fb992dSJames Bottomley memcpy(buf, save, save_size); 197e2fb992dSJames Bottomley } 198e2fb992dSJames Bottomley return ret; 199e2fb992dSJames Bottomley } 200412eb585SJarkko Sakkinen 201e2fb992dSJames Bottomley /** 20265520d46SWinkler, Tomas * tpm_transmit_cmd - send a tpm command to the device 203412eb585SJarkko Sakkinen * @chip: a TPM chip to use 204412eb585SJarkko Sakkinen * @buf: a TPM command buffer 205c659af78SStefan Berger * @min_rsp_body_length: minimum expected length of response body 206f865c196SWinkler, Tomas * @desc: command description used in the error message 207f865c196SWinkler, Tomas * 208f865c196SWinkler, Tomas * Return: 209412eb585SJarkko Sakkinen * * 0 - OK 210412eb585SJarkko Sakkinen * * -errno - A system error 211412eb585SJarkko Sakkinen * * TPM_RC - A TPM error 212f865c196SWinkler, Tomas */ 2135faafbabSJarkko Sakkinen ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf, 21447a6c28bSJarkko Sakkinen size_t min_rsp_body_length, const char *desc) 2159deb0eb7SJason Gunthorpe { 216b34b77a9SJarkko Sakkinen const struct tpm_header *header = (struct tpm_header *)buf->data; 2179deb0eb7SJason Gunthorpe int err; 218c659af78SStefan Berger ssize_t len; 2199deb0eb7SJason Gunthorpe 22047a6c28bSJarkko Sakkinen len = tpm_transmit(chip, buf->data, PAGE_SIZE); 2219deb0eb7SJason Gunthorpe if (len < 0) 2229deb0eb7SJason Gunthorpe return len; 22387155b73SJarkko Sakkinen 22487155b73SJarkko Sakkinen err = be32_to_cpu(header->return_code); 2250d6d0d62SJavier Martinez Canillas if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED 22608a8112aSJerry Snitselaar && err != TPM2_RC_TESTING && desc) 2278cfffc9dSJason Gunthorpe dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, 22871ed848fSJarkko Sakkinen desc); 229c659af78SStefan Berger if (err) 2309deb0eb7SJason Gunthorpe return err; 231c659af78SStefan Berger 232c659af78SStefan Berger if (len < min_rsp_body_length + TPM_HEADER_SIZE) 233c659af78SStefan Berger return -EFAULT; 234c659af78SStefan Berger 235c659af78SStefan Berger return 0; 2369deb0eb7SJason Gunthorpe } 237be4c9acfSStefan Berger EXPORT_SYMBOL_GPL(tpm_transmit_cmd); 2389deb0eb7SJason Gunthorpe 2399deb0eb7SJason Gunthorpe int tpm_get_timeouts(struct tpm_chip *chip) 2409deb0eb7SJason Gunthorpe { 241d1d253cfSJason Gunthorpe if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) 242d1d253cfSJason Gunthorpe return 0; 243d1d253cfSJason Gunthorpe 24470a3199aSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 24570a3199aSTomas Winkler return tpm2_get_timeouts(chip); 24670a3199aSTomas Winkler else 24770a3199aSTomas Winkler return tpm1_get_timeouts(chip); 2489deb0eb7SJason Gunthorpe } 2499deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_get_timeouts); 2509deb0eb7SJason Gunthorpe 2519deb0eb7SJason Gunthorpe /** 252aad887f6SJarkko Sakkinen * tpm_is_tpm2 - do we a have a TPM2 chip? 253aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 254954650efSJarkko Sakkinen * 255aad887f6SJarkko Sakkinen * Return: 256aad887f6SJarkko Sakkinen * 1 if we have a TPM2 chip. 257aad887f6SJarkko Sakkinen * 0 if we don't have a TPM2 chip. 258aad887f6SJarkko Sakkinen * A negative number for system errors (errno). 259954650efSJarkko Sakkinen */ 260aad887f6SJarkko Sakkinen int tpm_is_tpm2(struct tpm_chip *chip) 261954650efSJarkko Sakkinen { 262954650efSJarkko Sakkinen int rc; 263954650efSJarkko Sakkinen 264fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 265aad887f6SJarkko Sakkinen if (!chip) 266954650efSJarkko Sakkinen return -ENODEV; 267954650efSJarkko Sakkinen 268954650efSJarkko Sakkinen rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; 269954650efSJarkko Sakkinen 2704e26195fSJason Gunthorpe tpm_put_ops(chip); 271954650efSJarkko Sakkinen 272954650efSJarkko Sakkinen return rc; 273954650efSJarkko Sakkinen } 274954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_is_tpm2); 275954650efSJarkko Sakkinen 276954650efSJarkko Sakkinen /** 277aad887f6SJarkko Sakkinen * tpm_pcr_read - read a PCR value from SHA1 bank 278aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 279aad887f6SJarkko Sakkinen * @pcr_idx: the PCR to be retrieved 280879b5892SRoberto Sassu * @digest: the PCR bank and buffer current PCR value is written to 2819deb0eb7SJason Gunthorpe * 282aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 2839deb0eb7SJason Gunthorpe */ 284879b5892SRoberto Sassu int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, 285879b5892SRoberto Sassu struct tpm_digest *digest) 2869deb0eb7SJason Gunthorpe { 2879deb0eb7SJason Gunthorpe int rc; 2889deb0eb7SJason Gunthorpe 289fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 290aad887f6SJarkko Sakkinen if (!chip) 2919deb0eb7SJason Gunthorpe return -ENODEV; 292d4a31756STomas Winkler 2937a1d7e6dSJarkko Sakkinen if (chip->flags & TPM_CHIP_FLAG_TPM2) 294879b5892SRoberto Sassu rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); 2957a1d7e6dSJarkko Sakkinen else 296879b5892SRoberto Sassu rc = tpm1_pcr_read(chip, pcr_idx, digest->digest); 297d4a31756STomas Winkler 2984e26195fSJason Gunthorpe tpm_put_ops(chip); 2999deb0eb7SJason Gunthorpe return rc; 3009deb0eb7SJason Gunthorpe } 3019deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pcr_read); 3029deb0eb7SJason Gunthorpe 3039deb0eb7SJason Gunthorpe /** 304aad887f6SJarkko Sakkinen * tpm_pcr_extend - extend a PCR value in SHA1 bank. 305aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 306aad887f6SJarkko Sakkinen * @pcr_idx: the PCR to be retrieved 3070b6cf6b9SRoberto Sassu * @digests: array of tpm_digest structures used to extend PCRs 3089deb0eb7SJason Gunthorpe * 3090b6cf6b9SRoberto Sassu * Note: callers must pass a digest for every allocated PCR bank, in the same 3100b6cf6b9SRoberto Sassu * order of the banks in chip->allocated_banks. 311aad887f6SJarkko Sakkinen * 312aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 3139deb0eb7SJason Gunthorpe */ 3140b6cf6b9SRoberto Sassu int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, 3150b6cf6b9SRoberto Sassu struct tpm_digest *digests) 3169deb0eb7SJason Gunthorpe { 3179deb0eb7SJason Gunthorpe int rc; 318c1f92b4bSNayna Jain int i; 3199deb0eb7SJason Gunthorpe 320fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 321aad887f6SJarkko Sakkinen if (!chip) 3229deb0eb7SJason Gunthorpe return -ENODEV; 3239deb0eb7SJason Gunthorpe 3249f75c822SRoberto Sassu for (i = 0; i < chip->nr_allocated_banks; i++) { 3259f75c822SRoberto Sassu if (digests[i].alg_id != chip->allocated_banks[i].alg_id) { 3269f75c822SRoberto Sassu rc = EINVAL; 3279f75c822SRoberto Sassu goto out; 3289f75c822SRoberto Sassu } 3299f75c822SRoberto Sassu } 3300b6cf6b9SRoberto Sassu 3317a1d7e6dSJarkko Sakkinen if (chip->flags & TPM_CHIP_FLAG_TPM2) { 3320b6cf6b9SRoberto Sassu rc = tpm2_pcr_extend(chip, pcr_idx, digests); 3339f75c822SRoberto Sassu goto out; 3347a1d7e6dSJarkko Sakkinen } 3357a1d7e6dSJarkko Sakkinen 3360b6cf6b9SRoberto Sassu rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest, 3379deb0eb7SJason Gunthorpe "attempting extend a PCR value"); 3389f75c822SRoberto Sassu 3399f75c822SRoberto Sassu out: 3404e26195fSJason Gunthorpe tpm_put_ops(chip); 3419deb0eb7SJason Gunthorpe return rc; 3429deb0eb7SJason Gunthorpe } 3439deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pcr_extend); 3449deb0eb7SJason Gunthorpe 3459deb0eb7SJason Gunthorpe /** 346aad887f6SJarkko Sakkinen * tpm_send - send a TPM command 347aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 348aad887f6SJarkko Sakkinen * @cmd: a TPM command buffer 349aad887f6SJarkko Sakkinen * @buflen: the length of the TPM command buffer 350aad887f6SJarkko Sakkinen * 351aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 352aad887f6SJarkko Sakkinen */ 353aad887f6SJarkko Sakkinen int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) 3549deb0eb7SJason Gunthorpe { 355412eb585SJarkko Sakkinen struct tpm_buf buf; 3569deb0eb7SJason Gunthorpe int rc; 3579deb0eb7SJason Gunthorpe 358fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 359aad887f6SJarkko Sakkinen if (!chip) 3609deb0eb7SJason Gunthorpe return -ENODEV; 3619deb0eb7SJason Gunthorpe 362e13cd21fSJarkko Sakkinen buf.data = cmd; 36347a6c28bSJarkko Sakkinen rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command"); 364e13cd21fSJarkko Sakkinen 3654e26195fSJason Gunthorpe tpm_put_ops(chip); 3669deb0eb7SJason Gunthorpe return rc; 3679deb0eb7SJason Gunthorpe } 3689deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_send); 3699deb0eb7SJason Gunthorpe 370b03c4370STomas Winkler int tpm_auto_startup(struct tpm_chip *chip) 371b03c4370STomas Winkler { 372b03c4370STomas Winkler int rc; 373b03c4370STomas Winkler 374b03c4370STomas Winkler if (!(chip->ops->flags & TPM_OPS_AUTO_STARTUP)) 375b03c4370STomas Winkler return 0; 376b03c4370STomas Winkler 377b03c4370STomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 378b03c4370STomas Winkler rc = tpm2_auto_startup(chip); 379b03c4370STomas Winkler else 380b03c4370STomas Winkler rc = tpm1_auto_startup(chip); 381b03c4370STomas Winkler 382b03c4370STomas Winkler return rc; 383b03c4370STomas Winkler } 384b03c4370STomas Winkler 3859deb0eb7SJason Gunthorpe /* 3869deb0eb7SJason Gunthorpe * We are about to suspend. Save the TPM state 3879deb0eb7SJason Gunthorpe * so that it can be restored. 3889deb0eb7SJason Gunthorpe */ 3899deb0eb7SJason Gunthorpe int tpm_pm_suspend(struct device *dev) 3909deb0eb7SJason Gunthorpe { 391ec03c50bSStefan Berger struct tpm_chip *chip = dev_get_drvdata(dev); 392c82a330cSTomas Winkler int rc = 0; 3939deb0eb7SJason Gunthorpe 394c82a330cSTomas Winkler if (!chip) 3959deb0eb7SJason Gunthorpe return -ENODEV; 3969deb0eb7SJason Gunthorpe 397b5d0ebc9SEnric Balletbo i Serra if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) 398*2e2ee5a2SStephen Boyd goto suspended; 399*2e2ee5a2SStephen Boyd 400*2e2ee5a2SStephen Boyd if ((chip->flags & TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED) && 401*2e2ee5a2SStephen Boyd !pm_suspend_via_firmware()) 402*2e2ee5a2SStephen Boyd goto suspended; 403b5d0ebc9SEnric Balletbo i Serra 40447a6c28bSJarkko Sakkinen if (!tpm_chip_start(chip)) { 405e891db1aSJarkko Sakkinen if (chip->flags & TPM_CHIP_FLAG_TPM2) 40674d6b3ceSJarkko Sakkinen tpm2_shutdown(chip, TPM2_SU_STATE); 407e891db1aSJarkko Sakkinen else 408c82a330cSTomas Winkler rc = tpm1_pm_suspend(chip, tpm_suspend_pcr); 409e891db1aSJarkko Sakkinen 410e891db1aSJarkko Sakkinen tpm_chip_stop(chip); 411a3fbfae8SJarkko Sakkinen } 4129deb0eb7SJason Gunthorpe 413*2e2ee5a2SStephen Boyd suspended: 4149deb0eb7SJason Gunthorpe return rc; 4159deb0eb7SJason Gunthorpe } 4169deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pm_suspend); 4179deb0eb7SJason Gunthorpe 4189deb0eb7SJason Gunthorpe /* 4199deb0eb7SJason Gunthorpe * Resume from a power safe. The BIOS already restored 4209deb0eb7SJason Gunthorpe * the TPM state. 4219deb0eb7SJason Gunthorpe */ 4229deb0eb7SJason Gunthorpe int tpm_pm_resume(struct device *dev) 4239deb0eb7SJason Gunthorpe { 424ec03c50bSStefan Berger struct tpm_chip *chip = dev_get_drvdata(dev); 4259deb0eb7SJason Gunthorpe 4269deb0eb7SJason Gunthorpe if (chip == NULL) 4279deb0eb7SJason Gunthorpe return -ENODEV; 4289deb0eb7SJason Gunthorpe 4299deb0eb7SJason Gunthorpe return 0; 4309deb0eb7SJason Gunthorpe } 4319deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pm_resume); 4329deb0eb7SJason Gunthorpe 4339deb0eb7SJason Gunthorpe /** 434aad887f6SJarkko Sakkinen * tpm_get_random() - get random bytes from the TPM's RNG 435aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 4369deb0eb7SJason Gunthorpe * @out: destination buffer for the random bytes 4379deb0eb7SJason Gunthorpe * @max: the max number of bytes to write to @out 4389deb0eb7SJason Gunthorpe * 4397aee9c52STomas Winkler * Return: number of random bytes read or a negative error value. 4409deb0eb7SJason Gunthorpe */ 441aad887f6SJarkko Sakkinen int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) 4429deb0eb7SJason Gunthorpe { 443433d390fSTomas Winkler int rc; 4449deb0eb7SJason Gunthorpe 445433d390fSTomas Winkler if (!out || max > TPM_MAX_RNG_DATA) 4463e14d83eSJarkko Sakkinen return -EINVAL; 4473e14d83eSJarkko Sakkinen 448fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 449aad887f6SJarkko Sakkinen if (!chip) 4509deb0eb7SJason Gunthorpe return -ENODEV; 4519deb0eb7SJason Gunthorpe 452433d390fSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 453433d390fSTomas Winkler rc = tpm2_get_random(chip, out, max); 454433d390fSTomas Winkler else 455433d390fSTomas Winkler rc = tpm1_get_random(chip, out, max); 4569deb0eb7SJason Gunthorpe 4574e26195fSJason Gunthorpe tpm_put_ops(chip); 458433d390fSTomas Winkler return rc; 4599deb0eb7SJason Gunthorpe } 4609deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_get_random); 4619deb0eb7SJason Gunthorpe 462954650efSJarkko Sakkinen /** 463aad887f6SJarkko Sakkinen * tpm_seal_trusted() - seal a trusted key payload 464aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 465954650efSJarkko Sakkinen * @options: authentication values and other options 466954650efSJarkko Sakkinen * @payload: the key data in clear and encrypted form 467954650efSJarkko Sakkinen * 468aad887f6SJarkko Sakkinen * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in 469aad887f6SJarkko Sakkinen * the keyring subsystem. 470aad887f6SJarkko Sakkinen * 471aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 472954650efSJarkko Sakkinen */ 473aad887f6SJarkko Sakkinen int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, 474954650efSJarkko Sakkinen struct trusted_key_options *options) 475954650efSJarkko Sakkinen { 476954650efSJarkko Sakkinen int rc; 477954650efSJarkko Sakkinen 478fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 479aad887f6SJarkko Sakkinen if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) 480954650efSJarkko Sakkinen return -ENODEV; 481954650efSJarkko Sakkinen 482954650efSJarkko Sakkinen rc = tpm2_seal_trusted(chip, payload, options); 483954650efSJarkko Sakkinen 4844e26195fSJason Gunthorpe tpm_put_ops(chip); 485954650efSJarkko Sakkinen return rc; 486954650efSJarkko Sakkinen } 487954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_seal_trusted); 488954650efSJarkko Sakkinen 489954650efSJarkko Sakkinen /** 490954650efSJarkko Sakkinen * tpm_unseal_trusted() - unseal a trusted key 491aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 492954650efSJarkko Sakkinen * @options: authentication values and other options 493954650efSJarkko Sakkinen * @payload: the key data in clear and encrypted form 494954650efSJarkko Sakkinen * 495aad887f6SJarkko Sakkinen * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in 496aad887f6SJarkko Sakkinen * the keyring subsystem. 497aad887f6SJarkko Sakkinen * 498aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 499954650efSJarkko Sakkinen */ 500aad887f6SJarkko Sakkinen int tpm_unseal_trusted(struct tpm_chip *chip, 501aad887f6SJarkko Sakkinen struct trusted_key_payload *payload, 502954650efSJarkko Sakkinen struct trusted_key_options *options) 503954650efSJarkko Sakkinen { 504954650efSJarkko Sakkinen int rc; 505954650efSJarkko Sakkinen 506fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 507aad887f6SJarkko Sakkinen if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) 508954650efSJarkko Sakkinen return -ENODEV; 509954650efSJarkko Sakkinen 510954650efSJarkko Sakkinen rc = tpm2_unseal_trusted(chip, payload, options); 511954650efSJarkko Sakkinen 5124e26195fSJason Gunthorpe tpm_put_ops(chip); 5134e26195fSJason Gunthorpe 514954650efSJarkko Sakkinen return rc; 515954650efSJarkko Sakkinen } 516954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_unseal_trusted); 517954650efSJarkko Sakkinen 518313d21eeSJarkko Sakkinen static int __init tpm_init(void) 519313d21eeSJarkko Sakkinen { 520313d21eeSJarkko Sakkinen int rc; 521313d21eeSJarkko Sakkinen 522313d21eeSJarkko Sakkinen tpm_class = class_create(THIS_MODULE, "tpm"); 523313d21eeSJarkko Sakkinen if (IS_ERR(tpm_class)) { 524313d21eeSJarkko Sakkinen pr_err("couldn't create tpm class\n"); 525313d21eeSJarkko Sakkinen return PTR_ERR(tpm_class); 526313d21eeSJarkko Sakkinen } 527313d21eeSJarkko Sakkinen 528fdc915f7SJames Bottomley tpmrm_class = class_create(THIS_MODULE, "tpmrm"); 529fdc915f7SJames Bottomley if (IS_ERR(tpmrm_class)) { 530fdc915f7SJames Bottomley pr_err("couldn't create tpmrm class\n"); 5319e1b74a6STadeusz Struk rc = PTR_ERR(tpmrm_class); 5329e1b74a6STadeusz Struk goto out_destroy_tpm_class; 533fdc915f7SJames Bottomley } 534fdc915f7SJames Bottomley 535fdc915f7SJames Bottomley rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm"); 536313d21eeSJarkko Sakkinen if (rc < 0) { 537313d21eeSJarkko Sakkinen pr_err("tpm: failed to allocate char dev region\n"); 5389e1b74a6STadeusz Struk goto out_destroy_tpmrm_class; 5399e1b74a6STadeusz Struk } 5409e1b74a6STadeusz Struk 5419e1b74a6STadeusz Struk rc = tpm_dev_common_init(); 5429e1b74a6STadeusz Struk if (rc) { 5439e1b74a6STadeusz Struk pr_err("tpm: failed to allocate char dev region\n"); 5449e1b74a6STadeusz Struk goto out_unreg_chrdev; 545313d21eeSJarkko Sakkinen } 546313d21eeSJarkko Sakkinen 547313d21eeSJarkko Sakkinen return 0; 5489e1b74a6STadeusz Struk 5499e1b74a6STadeusz Struk out_unreg_chrdev: 5509e1b74a6STadeusz Struk unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES); 5519e1b74a6STadeusz Struk out_destroy_tpmrm_class: 5529e1b74a6STadeusz Struk class_destroy(tpmrm_class); 5539e1b74a6STadeusz Struk out_destroy_tpm_class: 5549e1b74a6STadeusz Struk class_destroy(tpm_class); 5559e1b74a6STadeusz Struk 5569e1b74a6STadeusz Struk return rc; 557313d21eeSJarkko Sakkinen } 558313d21eeSJarkko Sakkinen 559313d21eeSJarkko Sakkinen static void __exit tpm_exit(void) 560313d21eeSJarkko Sakkinen { 56115516788SStefan Berger idr_destroy(&dev_nums_idr); 562313d21eeSJarkko Sakkinen class_destroy(tpm_class); 563fdc915f7SJames Bottomley class_destroy(tpmrm_class); 564fdc915f7SJames Bottomley unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); 5659e1b74a6STadeusz Struk tpm_dev_common_exit(); 566313d21eeSJarkko Sakkinen } 567313d21eeSJarkko Sakkinen 568313d21eeSJarkko Sakkinen subsys_initcall(tpm_init); 569313d21eeSJarkko Sakkinen module_exit(tpm_exit); 570313d21eeSJarkko Sakkinen 5719deb0eb7SJason Gunthorpe MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 5729deb0eb7SJason Gunthorpe MODULE_DESCRIPTION("TPM Driver"); 5739deb0eb7SJason Gunthorpe MODULE_VERSION("2.0"); 5749deb0eb7SJason Gunthorpe MODULE_LICENSE("GPL"); 575