19deb0eb7SJason Gunthorpe /* 29deb0eb7SJason Gunthorpe * Copyright (C) 2004 IBM Corporation 3afb5abc2SJarkko Sakkinen * Copyright (C) 2014 Intel Corporation 49deb0eb7SJason Gunthorpe * 59deb0eb7SJason Gunthorpe * Authors: 69deb0eb7SJason Gunthorpe * Leendert van Doorn <leendert@watson.ibm.com> 79deb0eb7SJason Gunthorpe * Dave Safford <safford@watson.ibm.com> 89deb0eb7SJason Gunthorpe * Reiner Sailer <sailer@watson.ibm.com> 99deb0eb7SJason Gunthorpe * Kylene Hall <kjhall@us.ibm.com> 109deb0eb7SJason Gunthorpe * 119deb0eb7SJason Gunthorpe * Maintained by: <tpmdd-devel@lists.sourceforge.net> 129deb0eb7SJason Gunthorpe * 139deb0eb7SJason Gunthorpe * Device driver for TCG/TCPA TPM (trusted platform module). 149deb0eb7SJason Gunthorpe * Specifications at www.trustedcomputinggroup.org 159deb0eb7SJason Gunthorpe * 169deb0eb7SJason Gunthorpe * This program is free software; you can redistribute it and/or 179deb0eb7SJason Gunthorpe * modify it under the terms of the GNU General Public License as 189deb0eb7SJason Gunthorpe * published by the Free Software Foundation, version 2 of the 199deb0eb7SJason Gunthorpe * License. 209deb0eb7SJason Gunthorpe * 219deb0eb7SJason Gunthorpe * Note, the TPM chip is not interrupt driven (only polling) 229deb0eb7SJason Gunthorpe * and can have very long timeouts (minutes!). Hence the unusual 239deb0eb7SJason Gunthorpe * calls to msleep. 249deb0eb7SJason Gunthorpe * 259deb0eb7SJason Gunthorpe */ 269deb0eb7SJason Gunthorpe 279deb0eb7SJason Gunthorpe #include <linux/poll.h> 289deb0eb7SJason Gunthorpe #include <linux/slab.h> 299deb0eb7SJason Gunthorpe #include <linux/mutex.h> 309deb0eb7SJason Gunthorpe #include <linux/spinlock.h> 319deb0eb7SJason Gunthorpe #include <linux/freezer.h> 32fd3ec366SThiebaud Weksteen #include <linux/tpm_eventlog.h> 339deb0eb7SJason Gunthorpe 349deb0eb7SJason Gunthorpe #include "tpm.h" 359deb0eb7SJason Gunthorpe 369deb0eb7SJason Gunthorpe /* 379deb0eb7SJason Gunthorpe * Bug workaround - some TPM's don't flush the most 389deb0eb7SJason Gunthorpe * recently changed pcr on suspend, so force the flush 399deb0eb7SJason Gunthorpe * with an extend to the selected _unused_ non-volatile pcr. 409deb0eb7SJason Gunthorpe */ 4195adc6b4STomas Winkler static u32 tpm_suspend_pcr; 429deb0eb7SJason Gunthorpe module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); 439deb0eb7SJason Gunthorpe MODULE_PARM_DESC(suspend_pcr, 4439f5712bSDmitry Torokhov "PCR to use for dummy writes to facilitate flush on suspend."); 459deb0eb7SJason Gunthorpe 46d856c00fSTomas Winkler /** 47d856c00fSTomas Winkler * tpm_calc_ordinal_duration() - calculate the maximum command duration 48d856c00fSTomas Winkler * @chip: TPM chip to use. 49d856c00fSTomas Winkler * @ordinal: TPM command ordinal. 50d856c00fSTomas Winkler * 51d856c00fSTomas Winkler * The function returns the maximum amount of time the chip could take 52d856c00fSTomas Winkler * to return the result for a particular ordinal in jiffies. 53d856c00fSTomas Winkler * 54d856c00fSTomas Winkler * Return: A maximal duration time for an ordinal in jiffies. 55d856c00fSTomas Winkler */ 56d856c00fSTomas Winkler unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) 57d856c00fSTomas Winkler { 58d856c00fSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 59d856c00fSTomas Winkler return tpm2_calc_ordinal_duration(chip, ordinal); 60d856c00fSTomas Winkler else 61d856c00fSTomas Winkler return tpm1_calc_ordinal_duration(chip, ordinal); 62d856c00fSTomas Winkler } 63d856c00fSTomas Winkler EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); 64d856c00fSTomas Winkler 65627448e8STomas Winkler static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags) 66888d867dSTomas Winkler { 67888d867dSTomas Winkler int rc; 68888d867dSTomas Winkler 6958bac8ccSJarkko Sakkinen if (flags & TPM_TRANSMIT_NESTED) 70627448e8STomas Winkler return 0; 71627448e8STomas Winkler 72888d867dSTomas Winkler if (!chip->ops->request_locality) 73888d867dSTomas Winkler return 0; 74888d867dSTomas Winkler 75888d867dSTomas Winkler rc = chip->ops->request_locality(chip, 0); 76888d867dSTomas Winkler if (rc < 0) 77888d867dSTomas Winkler return rc; 78888d867dSTomas Winkler 79888d867dSTomas Winkler chip->locality = rc; 80888d867dSTomas Winkler 81888d867dSTomas Winkler return 0; 82888d867dSTomas Winkler } 83888d867dSTomas Winkler 84627448e8STomas Winkler static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags) 85888d867dSTomas Winkler { 86888d867dSTomas Winkler int rc; 87888d867dSTomas Winkler 8858bac8ccSJarkko Sakkinen if (flags & TPM_TRANSMIT_NESTED) 89627448e8STomas Winkler return; 90627448e8STomas Winkler 91888d867dSTomas Winkler if (!chip->ops->relinquish_locality) 92888d867dSTomas Winkler return; 93888d867dSTomas Winkler 94888d867dSTomas Winkler rc = chip->ops->relinquish_locality(chip, chip->locality); 95888d867dSTomas Winkler if (rc) 96888d867dSTomas Winkler dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); 97888d867dSTomas Winkler 98888d867dSTomas Winkler chip->locality = -1; 99888d867dSTomas Winkler } 100888d867dSTomas Winkler 101627448e8STomas Winkler static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags) 102627448e8STomas Winkler { 10358bac8ccSJarkko Sakkinen if (flags & TPM_TRANSMIT_NESTED) 104627448e8STomas Winkler return 0; 105627448e8STomas Winkler 106627448e8STomas Winkler if (!chip->ops->cmd_ready) 107627448e8STomas Winkler return 0; 108627448e8STomas Winkler 109627448e8STomas Winkler return chip->ops->cmd_ready(chip); 110627448e8STomas Winkler } 111627448e8STomas Winkler 112627448e8STomas Winkler static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags) 113627448e8STomas Winkler { 11458bac8ccSJarkko Sakkinen if (flags & TPM_TRANSMIT_NESTED) 115627448e8STomas Winkler return 0; 116627448e8STomas Winkler 117627448e8STomas Winkler if (!chip->ops->go_idle) 118627448e8STomas Winkler return 0; 119627448e8STomas Winkler 120627448e8STomas Winkler return chip->ops->go_idle(chip); 121627448e8STomas Winkler } 122627448e8STomas Winkler 123b34b77a9SJarkko Sakkinen static ssize_t tpm_try_transmit(struct tpm_chip *chip, struct tpm_space *space, 124b34b77a9SJarkko Sakkinen void *buf, size_t bufsiz, unsigned int flags) 1259deb0eb7SJason Gunthorpe { 126b34b77a9SJarkko Sakkinen struct tpm_header *header = buf; 127745b361eSJarkko Sakkinen int rc; 128745b361eSJarkko Sakkinen ssize_t len = 0; 1299deb0eb7SJason Gunthorpe u32 count, ordinal; 1309deb0eb7SJason Gunthorpe unsigned long stop; 1319deb0eb7SJason Gunthorpe 132*c3465a37SJarkko Sakkinen if (bufsiz < TPM_HEADER_SIZE) 133*c3465a37SJarkko Sakkinen return -EINVAL; 134ebfd7532SJarkko Sakkinen 1359deb0eb7SJason Gunthorpe if (bufsiz > TPM_BUFSIZE) 1369deb0eb7SJason Gunthorpe bufsiz = TPM_BUFSIZE; 1379deb0eb7SJason Gunthorpe 138720b0711SJarkko Sakkinen count = be32_to_cpu(header->length); 139720b0711SJarkko Sakkinen ordinal = be32_to_cpu(header->ordinal); 1409deb0eb7SJason Gunthorpe if (count == 0) 1419deb0eb7SJason Gunthorpe return -ENODATA; 1429deb0eb7SJason Gunthorpe if (count > bufsiz) { 1438cfffc9dSJason Gunthorpe dev_err(&chip->dev, 1449deb0eb7SJason Gunthorpe "invalid count value %x %zx\n", count, bufsiz); 1459deb0eb7SJason Gunthorpe return -E2BIG; 1469deb0eb7SJason Gunthorpe } 1479deb0eb7SJason Gunthorpe 148*c3465a37SJarkko Sakkinen rc = tpm2_prepare_space(chip, space, buf, bufsiz); 149*c3465a37SJarkko Sakkinen /* 150*c3465a37SJarkko Sakkinen * If the command is not implemented by the TPM, synthesize a 151*c3465a37SJarkko Sakkinen * response with a TPM2_RC_COMMAND_CODE return for user-space. 152*c3465a37SJarkko Sakkinen */ 153*c3465a37SJarkko Sakkinen if (rc == -EOPNOTSUPP) { 154*c3465a37SJarkko Sakkinen header->length = cpu_to_be32(sizeof(*header)); 155*c3465a37SJarkko Sakkinen header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); 156*c3465a37SJarkko Sakkinen header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | 157*c3465a37SJarkko Sakkinen TSS2_RESMGR_TPM_RC_LAYER); 158*c3465a37SJarkko Sakkinen return sizeof(*header); 159*c3465a37SJarkko Sakkinen } 160745b361eSJarkko Sakkinen if (rc) 161304ff672SJarkko Sakkinen return rc; 162745b361eSJarkko Sakkinen 16362c09e12SWinkler, Tomas rc = chip->ops->send(chip, buf, count); 1649deb0eb7SJason Gunthorpe if (rc < 0) { 165402149c6SStefan Berger if (rc != -EPIPE) 1668cfffc9dSJason Gunthorpe dev_err(&chip->dev, 167f5595f5bSJarkko Sakkinen "%s: send(): error %d\n", __func__, rc); 168304ff672SJarkko Sakkinen goto out_rc; 1699deb0eb7SJason Gunthorpe } 1709deb0eb7SJason Gunthorpe 171f5595f5bSJarkko Sakkinen /* A sanity check. send() should just return zero on success e.g. 172f5595f5bSJarkko Sakkinen * not the command length. 173f5595f5bSJarkko Sakkinen */ 174f5595f5bSJarkko Sakkinen if (rc > 0) { 175f5595f5bSJarkko Sakkinen dev_warn(&chip->dev, 176f5595f5bSJarkko Sakkinen "%s: send(): invalid value %d\n", __func__, rc); 177f5595f5bSJarkko Sakkinen rc = 0; 178f5595f5bSJarkko Sakkinen } 179f5595f5bSJarkko Sakkinen 180570a3609SChristophe Ricard if (chip->flags & TPM_CHIP_FLAG_IRQ) 1819deb0eb7SJason Gunthorpe goto out_recv; 1829deb0eb7SJason Gunthorpe 183d856c00fSTomas Winkler stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); 1849deb0eb7SJason Gunthorpe do { 1855f82e9f0SJason Gunthorpe u8 status = chip->ops->status(chip); 1865f82e9f0SJason Gunthorpe if ((status & chip->ops->req_complete_mask) == 1875f82e9f0SJason Gunthorpe chip->ops->req_complete_val) 1889deb0eb7SJason Gunthorpe goto out_recv; 1899deb0eb7SJason Gunthorpe 1905f82e9f0SJason Gunthorpe if (chip->ops->req_canceled(chip, status)) { 1918cfffc9dSJason Gunthorpe dev_err(&chip->dev, "Operation Canceled\n"); 1929deb0eb7SJason Gunthorpe rc = -ECANCELED; 193304ff672SJarkko Sakkinen goto out_rc; 1949deb0eb7SJason Gunthorpe } 1959deb0eb7SJason Gunthorpe 19659f5a6b0SNayna Jain tpm_msleep(TPM_TIMEOUT_POLL); 1979deb0eb7SJason Gunthorpe rmb(); 1989deb0eb7SJason Gunthorpe } while (time_before(jiffies, stop)); 1999deb0eb7SJason Gunthorpe 2005f82e9f0SJason Gunthorpe chip->ops->cancel(chip); 2018cfffc9dSJason Gunthorpe dev_err(&chip->dev, "Operation Timed out\n"); 2029deb0eb7SJason Gunthorpe rc = -ETIME; 203304ff672SJarkko Sakkinen goto out_rc; 2049deb0eb7SJason Gunthorpe 2059deb0eb7SJason Gunthorpe out_recv: 20662c09e12SWinkler, Tomas len = chip->ops->recv(chip, buf, bufsiz); 207745b361eSJarkko Sakkinen if (len < 0) { 208745b361eSJarkko Sakkinen rc = len; 209304ff672SJarkko Sakkinen dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc); 210304ff672SJarkko Sakkinen } else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length)) 211a147918eSJarkko Sakkinen rc = -EFAULT; 212a147918eSJarkko Sakkinen 213304ff672SJarkko Sakkinen out_rc: 214304ff672SJarkko Sakkinen if (!rc) 215*c3465a37SJarkko Sakkinen rc = tpm2_commit_space(chip, space, buf, &len); 216a147918eSJarkko Sakkinen 217745b361eSJarkko Sakkinen return rc ? rc : len; 2189deb0eb7SJason Gunthorpe } 2199deb0eb7SJason Gunthorpe 220f865c196SWinkler, Tomas /** 221e2fb992dSJames Bottomley * tpm_transmit - Internal kernel interface to transmit TPM commands. 222412eb585SJarkko Sakkinen * @chip: a TPM chip to use 223412eb585SJarkko Sakkinen * @space: a TPM space 224412eb585SJarkko Sakkinen * @buf: a TPM command buffer 225e2fb992dSJames Bottomley * @bufsiz: length of the TPM command buffer 226412eb585SJarkko Sakkinen * @flags: TPM transmit flags 227e2fb992dSJames Bottomley * 228412eb585SJarkko Sakkinen * A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from 229412eb585SJarkko Sakkinen * the TPM and retransmits the command after a delay up to a maximum wait of 230412eb585SJarkko Sakkinen * TPM2_DURATION_LONG. 231e2fb992dSJames Bottomley * 232412eb585SJarkko Sakkinen * Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0 233412eb585SJarkko Sakkinen * only. 234e2fb992dSJames Bottomley * 235e2fb992dSJames Bottomley * Return: 236412eb585SJarkko Sakkinen * * The response length - OK 237412eb585SJarkko Sakkinen * * -errno - A system error 238e2fb992dSJames Bottomley */ 239e2fb992dSJames Bottomley ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, 240e2fb992dSJames Bottomley u8 *buf, size_t bufsiz, unsigned int flags) 241e2fb992dSJames Bottomley { 242b34b77a9SJarkko Sakkinen struct tpm_header *header = (struct tpm_header *)buf; 243e2fb992dSJames Bottomley /* space for header and handles */ 244e2fb992dSJames Bottomley u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; 245e2fb992dSJames Bottomley unsigned int delay_msec = TPM2_DURATION_SHORT; 246304ff672SJarkko Sakkinen bool has_locality = false; 247e2fb992dSJames Bottomley u32 rc = 0; 248e2fb992dSJames Bottomley ssize_t ret; 249e2fb992dSJames Bottomley const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE, 250e2fb992dSJames Bottomley bufsiz); 2512be8ffedSJames Bottomley /* the command code is where the return code will be */ 2522be8ffedSJames Bottomley u32 cc = be32_to_cpu(header->return_code); 253e2fb992dSJames Bottomley 254e2fb992dSJames Bottomley /* 255e2fb992dSJames Bottomley * Subtlety here: if we have a space, the handles will be 256e2fb992dSJames Bottomley * transformed, so when we restore the header we also have to 257e2fb992dSJames Bottomley * restore the handles. 258e2fb992dSJames Bottomley */ 259e2fb992dSJames Bottomley memcpy(save, buf, save_size); 260e2fb992dSJames Bottomley 261e2fb992dSJames Bottomley for (;;) { 262304ff672SJarkko Sakkinen if (!(flags & TPM_TRANSMIT_UNLOCKED) && 263304ff672SJarkko Sakkinen !(flags & TPM_TRANSMIT_NESTED)) 264304ff672SJarkko Sakkinen mutex_lock(&chip->tpm_mutex); 265304ff672SJarkko Sakkinen 266304ff672SJarkko Sakkinen if (chip->ops->clk_enable != NULL) 267304ff672SJarkko Sakkinen chip->ops->clk_enable(chip, true); 268304ff672SJarkko Sakkinen 269304ff672SJarkko Sakkinen if (chip->locality == -1) { 270304ff672SJarkko Sakkinen ret = tpm_request_locality(chip, flags); 271304ff672SJarkko Sakkinen if (ret) 272304ff672SJarkko Sakkinen goto out_locality; 273304ff672SJarkko Sakkinen has_locality = true; 274304ff672SJarkko Sakkinen } 275304ff672SJarkko Sakkinen 276304ff672SJarkko Sakkinen ret = tpm_cmd_ready(chip, flags); 277304ff672SJarkko Sakkinen if (ret) 278304ff672SJarkko Sakkinen goto out_locality; 279304ff672SJarkko Sakkinen 280e2fb992dSJames Bottomley ret = tpm_try_transmit(chip, space, buf, bufsiz, flags); 281304ff672SJarkko Sakkinen 282304ff672SJarkko Sakkinen /* This may fail but do not override ret. */ 283304ff672SJarkko Sakkinen tpm_go_idle(chip, flags); 284304ff672SJarkko Sakkinen 285304ff672SJarkko Sakkinen out_locality: 286304ff672SJarkko Sakkinen if (has_locality) 287304ff672SJarkko Sakkinen tpm_relinquish_locality(chip, flags); 288304ff672SJarkko Sakkinen 289304ff672SJarkko Sakkinen if (chip->ops->clk_enable != NULL) 290304ff672SJarkko Sakkinen chip->ops->clk_enable(chip, false); 291304ff672SJarkko Sakkinen 292304ff672SJarkko Sakkinen if (!(flags & TPM_TRANSMIT_UNLOCKED) && 293304ff672SJarkko Sakkinen !(flags & TPM_TRANSMIT_NESTED)) 294304ff672SJarkko Sakkinen mutex_unlock(&chip->tpm_mutex); 295304ff672SJarkko Sakkinen 296e2fb992dSJames Bottomley if (ret < 0) 297e2fb992dSJames Bottomley break; 298e2fb992dSJames Bottomley rc = be32_to_cpu(header->return_code); 2992be8ffedSJames Bottomley if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING) 3002be8ffedSJames Bottomley break; 3012be8ffedSJames Bottomley /* 3022be8ffedSJames Bottomley * return immediately if self test returns test 3032be8ffedSJames Bottomley * still running to shorten boot time. 3042be8ffedSJames Bottomley */ 3052be8ffedSJames Bottomley if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST) 306e2fb992dSJames Bottomley break; 30792980756SNayna Jain 308e2fb992dSJames Bottomley if (delay_msec > TPM2_DURATION_LONG) { 3092be8ffedSJames Bottomley if (rc == TPM2_RC_RETRY) 3102be8ffedSJames Bottomley dev_err(&chip->dev, "in retry loop\n"); 3112be8ffedSJames Bottomley else 3122be8ffedSJames Bottomley dev_err(&chip->dev, 3132be8ffedSJames Bottomley "self test is still running\n"); 314e2fb992dSJames Bottomley break; 315e2fb992dSJames Bottomley } 316e2fb992dSJames Bottomley tpm_msleep(delay_msec); 31792980756SNayna Jain delay_msec *= 2; 318e2fb992dSJames Bottomley memcpy(buf, save, save_size); 319e2fb992dSJames Bottomley } 320e2fb992dSJames Bottomley return ret; 321e2fb992dSJames Bottomley } 322412eb585SJarkko Sakkinen 323e2fb992dSJames Bottomley /** 32465520d46SWinkler, Tomas * tpm_transmit_cmd - send a tpm command to the device 325412eb585SJarkko Sakkinen * @chip: a TPM chip to use 326412eb585SJarkko Sakkinen * @space: a TPM space 327412eb585SJarkko Sakkinen * @buf: a TPM command buffer 328c659af78SStefan Berger * @min_rsp_body_length: minimum expected length of response body 329412eb585SJarkko Sakkinen * @flags: TPM transmit flags 330f865c196SWinkler, Tomas * @desc: command description used in the error message 331f865c196SWinkler, Tomas * 332f865c196SWinkler, Tomas * Return: 333412eb585SJarkko Sakkinen * * 0 - OK 334412eb585SJarkko Sakkinen * * -errno - A system error 335412eb585SJarkko Sakkinen * * TPM_RC - A TPM error 336f865c196SWinkler, Tomas */ 337745b361eSJarkko Sakkinen ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, 338412eb585SJarkko Sakkinen struct tpm_buf *buf, size_t min_rsp_body_length, 339412eb585SJarkko Sakkinen unsigned int flags, const char *desc) 3409deb0eb7SJason Gunthorpe { 341b34b77a9SJarkko Sakkinen const struct tpm_header *header = (struct tpm_header *)buf->data; 3429deb0eb7SJason Gunthorpe int err; 343c659af78SStefan Berger ssize_t len; 3449deb0eb7SJason Gunthorpe 345412eb585SJarkko Sakkinen len = tpm_transmit(chip, space, buf->data, PAGE_SIZE, flags); 3469deb0eb7SJason Gunthorpe if (len < 0) 3479deb0eb7SJason Gunthorpe return len; 34887155b73SJarkko Sakkinen 34987155b73SJarkko Sakkinen err = be32_to_cpu(header->return_code); 3500d6d0d62SJavier Martinez Canillas if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED 35108a8112aSJerry Snitselaar && err != TPM2_RC_TESTING && desc) 3528cfffc9dSJason Gunthorpe dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, 35371ed848fSJarkko Sakkinen desc); 354c659af78SStefan Berger if (err) 3559deb0eb7SJason Gunthorpe return err; 356c659af78SStefan Berger 357c659af78SStefan Berger if (len < min_rsp_body_length + TPM_HEADER_SIZE) 358c659af78SStefan Berger return -EFAULT; 359c659af78SStefan Berger 360c659af78SStefan Berger return 0; 3619deb0eb7SJason Gunthorpe } 362be4c9acfSStefan Berger EXPORT_SYMBOL_GPL(tpm_transmit_cmd); 3639deb0eb7SJason Gunthorpe 3649deb0eb7SJason Gunthorpe int tpm_get_timeouts(struct tpm_chip *chip) 3659deb0eb7SJason Gunthorpe { 366d1d253cfSJason Gunthorpe if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) 367d1d253cfSJason Gunthorpe return 0; 368d1d253cfSJason Gunthorpe 36970a3199aSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 37070a3199aSTomas Winkler return tpm2_get_timeouts(chip); 37170a3199aSTomas Winkler else 37270a3199aSTomas Winkler return tpm1_get_timeouts(chip); 3739deb0eb7SJason Gunthorpe } 3749deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_get_timeouts); 3759deb0eb7SJason Gunthorpe 3769deb0eb7SJason Gunthorpe /** 377aad887f6SJarkko Sakkinen * tpm_is_tpm2 - do we a have a TPM2 chip? 378aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 379954650efSJarkko Sakkinen * 380aad887f6SJarkko Sakkinen * Return: 381aad887f6SJarkko Sakkinen * 1 if we have a TPM2 chip. 382aad887f6SJarkko Sakkinen * 0 if we don't have a TPM2 chip. 383aad887f6SJarkko Sakkinen * A negative number for system errors (errno). 384954650efSJarkko Sakkinen */ 385aad887f6SJarkko Sakkinen int tpm_is_tpm2(struct tpm_chip *chip) 386954650efSJarkko Sakkinen { 387954650efSJarkko Sakkinen int rc; 388954650efSJarkko Sakkinen 389fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 390aad887f6SJarkko Sakkinen if (!chip) 391954650efSJarkko Sakkinen return -ENODEV; 392954650efSJarkko Sakkinen 393954650efSJarkko Sakkinen rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; 394954650efSJarkko Sakkinen 3954e26195fSJason Gunthorpe tpm_put_ops(chip); 396954650efSJarkko Sakkinen 397954650efSJarkko Sakkinen return rc; 398954650efSJarkko Sakkinen } 399954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_is_tpm2); 400954650efSJarkko Sakkinen 401954650efSJarkko Sakkinen /** 402aad887f6SJarkko Sakkinen * tpm_pcr_read - read a PCR value from SHA1 bank 403aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 404aad887f6SJarkko Sakkinen * @pcr_idx: the PCR to be retrieved 405aad887f6SJarkko Sakkinen * @res_buf: the value of the PCR 4069deb0eb7SJason Gunthorpe * 407aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 4089deb0eb7SJason Gunthorpe */ 40995adc6b4STomas Winkler int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, u8 *res_buf) 4109deb0eb7SJason Gunthorpe { 4119deb0eb7SJason Gunthorpe int rc; 4129deb0eb7SJason Gunthorpe 413fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 414aad887f6SJarkko Sakkinen if (!chip) 4159deb0eb7SJason Gunthorpe return -ENODEV; 416d4a31756STomas Winkler 4177a1d7e6dSJarkko Sakkinen if (chip->flags & TPM_CHIP_FLAG_TPM2) 4187a1d7e6dSJarkko Sakkinen rc = tpm2_pcr_read(chip, pcr_idx, res_buf); 4197a1d7e6dSJarkko Sakkinen else 420cfddcb05STomas Winkler rc = tpm1_pcr_read(chip, pcr_idx, res_buf); 421d4a31756STomas Winkler 4224e26195fSJason Gunthorpe tpm_put_ops(chip); 4239deb0eb7SJason Gunthorpe return rc; 4249deb0eb7SJason Gunthorpe } 4259deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pcr_read); 4269deb0eb7SJason Gunthorpe 4279deb0eb7SJason Gunthorpe /** 428aad887f6SJarkko Sakkinen * tpm_pcr_extend - extend a PCR value in SHA1 bank. 429aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 430aad887f6SJarkko Sakkinen * @pcr_idx: the PCR to be retrieved 431aad887f6SJarkko Sakkinen * @hash: the hash value used to extend the PCR value 4329deb0eb7SJason Gunthorpe * 433aad887f6SJarkko Sakkinen * Note: with TPM 2.0 extends also those banks with a known digest size to the 434aad887f6SJarkko Sakkinen * cryto subsystem in order to prevent malicious use of those PCR banks. In the 435aad887f6SJarkko Sakkinen * future we should dynamically determine digest sizes. 436aad887f6SJarkko Sakkinen * 437aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 4389deb0eb7SJason Gunthorpe */ 43995adc6b4STomas Winkler int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash) 4409deb0eb7SJason Gunthorpe { 4419deb0eb7SJason Gunthorpe int rc; 442c1f92b4bSNayna Jain struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; 443c1f92b4bSNayna Jain u32 count = 0; 444c1f92b4bSNayna Jain int i; 4459deb0eb7SJason Gunthorpe 446fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 447aad887f6SJarkko Sakkinen if (!chip) 4489deb0eb7SJason Gunthorpe return -ENODEV; 4499deb0eb7SJason Gunthorpe 4507a1d7e6dSJarkko Sakkinen if (chip->flags & TPM_CHIP_FLAG_TPM2) { 451c1f92b4bSNayna Jain memset(digest_list, 0, sizeof(digest_list)); 452c1f92b4bSNayna Jain 45370ea1636SDan Carpenter for (i = 0; i < ARRAY_SIZE(chip->active_banks) && 45470ea1636SDan Carpenter chip->active_banks[i] != TPM2_ALG_ERROR; i++) { 455c1f92b4bSNayna Jain digest_list[i].alg_id = chip->active_banks[i]; 456c1f92b4bSNayna Jain memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE); 457c1f92b4bSNayna Jain count++; 458c1f92b4bSNayna Jain } 459c1f92b4bSNayna Jain 460c1f92b4bSNayna Jain rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list); 4614e26195fSJason Gunthorpe tpm_put_ops(chip); 4627a1d7e6dSJarkko Sakkinen return rc; 4637a1d7e6dSJarkko Sakkinen } 4647a1d7e6dSJarkko Sakkinen 465175d5b2aSRoberto Sassu rc = tpm1_pcr_extend(chip, pcr_idx, hash, 4669deb0eb7SJason Gunthorpe "attempting extend a PCR value"); 4674e26195fSJason Gunthorpe tpm_put_ops(chip); 4689deb0eb7SJason Gunthorpe return rc; 4699deb0eb7SJason Gunthorpe } 4709deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pcr_extend); 4719deb0eb7SJason Gunthorpe 4729deb0eb7SJason Gunthorpe /** 473aad887f6SJarkko Sakkinen * tpm_send - send a TPM command 474aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 475aad887f6SJarkko Sakkinen * @cmd: a TPM command buffer 476aad887f6SJarkko Sakkinen * @buflen: the length of the TPM command buffer 477aad887f6SJarkko Sakkinen * 478aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 479aad887f6SJarkko Sakkinen */ 480aad887f6SJarkko Sakkinen int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) 4819deb0eb7SJason Gunthorpe { 482412eb585SJarkko Sakkinen struct tpm_buf buf; 4839deb0eb7SJason Gunthorpe int rc; 4849deb0eb7SJason Gunthorpe 485fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 486aad887f6SJarkko Sakkinen if (!chip) 4879deb0eb7SJason Gunthorpe return -ENODEV; 4889deb0eb7SJason Gunthorpe 489412eb585SJarkko Sakkinen rc = tpm_buf_init(&buf, 0, 0); 490412eb585SJarkko Sakkinen if (rc) 491412eb585SJarkko Sakkinen goto out; 492412eb585SJarkko Sakkinen 493412eb585SJarkko Sakkinen memcpy(buf.data, cmd, buflen); 494412eb585SJarkko Sakkinen rc = tpm_transmit_cmd(chip, NULL, &buf, 0, 0, 495aad887f6SJarkko Sakkinen "attempting to a send a command"); 496412eb585SJarkko Sakkinen tpm_buf_destroy(&buf); 497412eb585SJarkko Sakkinen out: 4984e26195fSJason Gunthorpe tpm_put_ops(chip); 4999deb0eb7SJason Gunthorpe return rc; 5009deb0eb7SJason Gunthorpe } 5019deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_send); 5029deb0eb7SJason Gunthorpe 503b03c4370STomas Winkler int tpm_auto_startup(struct tpm_chip *chip) 504b03c4370STomas Winkler { 505b03c4370STomas Winkler int rc; 506b03c4370STomas Winkler 507b03c4370STomas Winkler if (!(chip->ops->flags & TPM_OPS_AUTO_STARTUP)) 508b03c4370STomas Winkler return 0; 509b03c4370STomas Winkler 510b03c4370STomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 511b03c4370STomas Winkler rc = tpm2_auto_startup(chip); 512b03c4370STomas Winkler else 513b03c4370STomas Winkler rc = tpm1_auto_startup(chip); 514b03c4370STomas Winkler 515b03c4370STomas Winkler return rc; 516b03c4370STomas Winkler } 517b03c4370STomas Winkler 5189deb0eb7SJason Gunthorpe /* 5199deb0eb7SJason Gunthorpe * We are about to suspend. Save the TPM state 5209deb0eb7SJason Gunthorpe * so that it can be restored. 5219deb0eb7SJason Gunthorpe */ 5229deb0eb7SJason Gunthorpe int tpm_pm_suspend(struct device *dev) 5239deb0eb7SJason Gunthorpe { 524ec03c50bSStefan Berger struct tpm_chip *chip = dev_get_drvdata(dev); 525c82a330cSTomas Winkler int rc = 0; 5269deb0eb7SJason Gunthorpe 527c82a330cSTomas Winkler if (!chip) 5289deb0eb7SJason Gunthorpe return -ENODEV; 5299deb0eb7SJason Gunthorpe 530b5d0ebc9SEnric Balletbo i Serra if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) 531b5d0ebc9SEnric Balletbo i Serra return 0; 532b5d0ebc9SEnric Balletbo i Serra 533c82a330cSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 53474d6b3ceSJarkko Sakkinen tpm2_shutdown(chip, TPM2_SU_STATE); 535c82a330cSTomas Winkler else 536c82a330cSTomas Winkler rc = tpm1_pm_suspend(chip, tpm_suspend_pcr); 5379deb0eb7SJason Gunthorpe 5389deb0eb7SJason Gunthorpe return rc; 5399deb0eb7SJason Gunthorpe } 5409deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pm_suspend); 5419deb0eb7SJason Gunthorpe 5429deb0eb7SJason Gunthorpe /* 5439deb0eb7SJason Gunthorpe * Resume from a power safe. The BIOS already restored 5449deb0eb7SJason Gunthorpe * the TPM state. 5459deb0eb7SJason Gunthorpe */ 5469deb0eb7SJason Gunthorpe int tpm_pm_resume(struct device *dev) 5479deb0eb7SJason Gunthorpe { 548ec03c50bSStefan Berger struct tpm_chip *chip = dev_get_drvdata(dev); 5499deb0eb7SJason Gunthorpe 5509deb0eb7SJason Gunthorpe if (chip == NULL) 5519deb0eb7SJason Gunthorpe return -ENODEV; 5529deb0eb7SJason Gunthorpe 5539deb0eb7SJason Gunthorpe return 0; 5549deb0eb7SJason Gunthorpe } 5559deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pm_resume); 5569deb0eb7SJason Gunthorpe 5579deb0eb7SJason Gunthorpe /** 558aad887f6SJarkko Sakkinen * tpm_get_random() - get random bytes from the TPM's RNG 559aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 5609deb0eb7SJason Gunthorpe * @out: destination buffer for the random bytes 5619deb0eb7SJason Gunthorpe * @max: the max number of bytes to write to @out 5629deb0eb7SJason Gunthorpe * 5637aee9c52STomas Winkler * Return: number of random bytes read or a negative error value. 5649deb0eb7SJason Gunthorpe */ 565aad887f6SJarkko Sakkinen int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) 5669deb0eb7SJason Gunthorpe { 567433d390fSTomas Winkler int rc; 5689deb0eb7SJason Gunthorpe 569433d390fSTomas Winkler if (!out || max > TPM_MAX_RNG_DATA) 5703e14d83eSJarkko Sakkinen return -EINVAL; 5713e14d83eSJarkko Sakkinen 572fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 573aad887f6SJarkko Sakkinen if (!chip) 5749deb0eb7SJason Gunthorpe return -ENODEV; 5759deb0eb7SJason Gunthorpe 576433d390fSTomas Winkler if (chip->flags & TPM_CHIP_FLAG_TPM2) 577433d390fSTomas Winkler rc = tpm2_get_random(chip, out, max); 578433d390fSTomas Winkler else 579433d390fSTomas Winkler rc = tpm1_get_random(chip, out, max); 5809deb0eb7SJason Gunthorpe 5814e26195fSJason Gunthorpe tpm_put_ops(chip); 582433d390fSTomas Winkler return rc; 5839deb0eb7SJason Gunthorpe } 5849deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_get_random); 5859deb0eb7SJason Gunthorpe 586954650efSJarkko Sakkinen /** 587aad887f6SJarkko Sakkinen * tpm_seal_trusted() - seal a trusted key payload 588aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 589954650efSJarkko Sakkinen * @options: authentication values and other options 590954650efSJarkko Sakkinen * @payload: the key data in clear and encrypted form 591954650efSJarkko Sakkinen * 592aad887f6SJarkko Sakkinen * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in 593aad887f6SJarkko Sakkinen * the keyring subsystem. 594aad887f6SJarkko Sakkinen * 595aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 596954650efSJarkko Sakkinen */ 597aad887f6SJarkko Sakkinen int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, 598954650efSJarkko Sakkinen struct trusted_key_options *options) 599954650efSJarkko Sakkinen { 600954650efSJarkko Sakkinen int rc; 601954650efSJarkko Sakkinen 602fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 603aad887f6SJarkko Sakkinen if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) 604954650efSJarkko Sakkinen return -ENODEV; 605954650efSJarkko Sakkinen 606954650efSJarkko Sakkinen rc = tpm2_seal_trusted(chip, payload, options); 607954650efSJarkko Sakkinen 6084e26195fSJason Gunthorpe tpm_put_ops(chip); 609954650efSJarkko Sakkinen return rc; 610954650efSJarkko Sakkinen } 611954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_seal_trusted); 612954650efSJarkko Sakkinen 613954650efSJarkko Sakkinen /** 614954650efSJarkko Sakkinen * tpm_unseal_trusted() - unseal a trusted key 615aad887f6SJarkko Sakkinen * @chip: a &struct tpm_chip instance, %NULL for the default chip 616954650efSJarkko Sakkinen * @options: authentication values and other options 617954650efSJarkko Sakkinen * @payload: the key data in clear and encrypted form 618954650efSJarkko Sakkinen * 619aad887f6SJarkko Sakkinen * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in 620aad887f6SJarkko Sakkinen * the keyring subsystem. 621aad887f6SJarkko Sakkinen * 622aad887f6SJarkko Sakkinen * Return: same as with tpm_transmit_cmd() 623954650efSJarkko Sakkinen */ 624aad887f6SJarkko Sakkinen int tpm_unseal_trusted(struct tpm_chip *chip, 625aad887f6SJarkko Sakkinen struct trusted_key_payload *payload, 626954650efSJarkko Sakkinen struct trusted_key_options *options) 627954650efSJarkko Sakkinen { 628954650efSJarkko Sakkinen int rc; 629954650efSJarkko Sakkinen 630fc1d52b7SStefan Berger chip = tpm_find_get_ops(chip); 631aad887f6SJarkko Sakkinen if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) 632954650efSJarkko Sakkinen return -ENODEV; 633954650efSJarkko Sakkinen 634954650efSJarkko Sakkinen rc = tpm2_unseal_trusted(chip, payload, options); 635954650efSJarkko Sakkinen 6364e26195fSJason Gunthorpe tpm_put_ops(chip); 6374e26195fSJason Gunthorpe 638954650efSJarkko Sakkinen return rc; 639954650efSJarkko Sakkinen } 640954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_unseal_trusted); 641954650efSJarkko Sakkinen 642313d21eeSJarkko Sakkinen static int __init tpm_init(void) 643313d21eeSJarkko Sakkinen { 644313d21eeSJarkko Sakkinen int rc; 645313d21eeSJarkko Sakkinen 646313d21eeSJarkko Sakkinen tpm_class = class_create(THIS_MODULE, "tpm"); 647313d21eeSJarkko Sakkinen if (IS_ERR(tpm_class)) { 648313d21eeSJarkko Sakkinen pr_err("couldn't create tpm class\n"); 649313d21eeSJarkko Sakkinen return PTR_ERR(tpm_class); 650313d21eeSJarkko Sakkinen } 651313d21eeSJarkko Sakkinen 652fdc915f7SJames Bottomley tpmrm_class = class_create(THIS_MODULE, "tpmrm"); 653fdc915f7SJames Bottomley if (IS_ERR(tpmrm_class)) { 654fdc915f7SJames Bottomley pr_err("couldn't create tpmrm class\n"); 6559e1b74a6STadeusz Struk rc = PTR_ERR(tpmrm_class); 6569e1b74a6STadeusz Struk goto out_destroy_tpm_class; 657fdc915f7SJames Bottomley } 658fdc915f7SJames Bottomley 659fdc915f7SJames Bottomley rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm"); 660313d21eeSJarkko Sakkinen if (rc < 0) { 661313d21eeSJarkko Sakkinen pr_err("tpm: failed to allocate char dev region\n"); 6629e1b74a6STadeusz Struk goto out_destroy_tpmrm_class; 6639e1b74a6STadeusz Struk } 6649e1b74a6STadeusz Struk 6659e1b74a6STadeusz Struk rc = tpm_dev_common_init(); 6669e1b74a6STadeusz Struk if (rc) { 6679e1b74a6STadeusz Struk pr_err("tpm: failed to allocate char dev region\n"); 6689e1b74a6STadeusz Struk goto out_unreg_chrdev; 669313d21eeSJarkko Sakkinen } 670313d21eeSJarkko Sakkinen 671313d21eeSJarkko Sakkinen return 0; 6729e1b74a6STadeusz Struk 6739e1b74a6STadeusz Struk out_unreg_chrdev: 6749e1b74a6STadeusz Struk unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES); 6759e1b74a6STadeusz Struk out_destroy_tpmrm_class: 6769e1b74a6STadeusz Struk class_destroy(tpmrm_class); 6779e1b74a6STadeusz Struk out_destroy_tpm_class: 6789e1b74a6STadeusz Struk class_destroy(tpm_class); 6799e1b74a6STadeusz Struk 6809e1b74a6STadeusz Struk return rc; 681313d21eeSJarkko Sakkinen } 682313d21eeSJarkko Sakkinen 683313d21eeSJarkko Sakkinen static void __exit tpm_exit(void) 684313d21eeSJarkko Sakkinen { 68515516788SStefan Berger idr_destroy(&dev_nums_idr); 686313d21eeSJarkko Sakkinen class_destroy(tpm_class); 687fdc915f7SJames Bottomley class_destroy(tpmrm_class); 688fdc915f7SJames Bottomley unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); 6899e1b74a6STadeusz Struk tpm_dev_common_exit(); 690313d21eeSJarkko Sakkinen } 691313d21eeSJarkko Sakkinen 692313d21eeSJarkko Sakkinen subsys_initcall(tpm_init); 693313d21eeSJarkko Sakkinen module_exit(tpm_exit); 694313d21eeSJarkko Sakkinen 6959deb0eb7SJason Gunthorpe MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 6969deb0eb7SJason Gunthorpe MODULE_DESCRIPTION("TPM Driver"); 6979deb0eb7SJason Gunthorpe MODULE_VERSION("2.0"); 6989deb0eb7SJason Gunthorpe MODULE_LICENSE("GPL"); 699