/* * Internal kernel interface to transmit TPM commands */ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz) { ssize_t rc; u32 count, ordinal; unsigned long stop; count = be32_to_cpu(*((__be32 *) (buf + 2))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); if (count == 0) return -ENODATA; if (count > bufsiz) { dev_err(chip->dev, "invalid count value %x %zx \n", count, bufsiz); return -E2BIG; } mutex_lock(&chip->tpm_mutex); if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } if (chip->vendor.irq) goto out_recv; stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->vendor.status(chip); if ((status & chip->vendor.req_complete_mask) == chip->vendor.req_complete_val) goto out_recv; if ((status == chip->vendor.req_canceled)) { dev_err(chip->dev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } msleep(TPM_TIMEOUT); /* CHECK */ rmb(); } while (time_before(jiffies, stop)); chip->vendor.cancel(chip); dev_err(chip->dev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz); if (rc < 0) dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: mutex_unlock(&chip->tpm_mutex); return rc; }
/* * Internal kernel interface to transmit TPM commands */ static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf, size_t bufsiz) { ssize_t rc; uint32_t count, ordinal; s_time_t stop; count = be32_to_cpu(*((uint32_t *) (buf + 2))); ordinal = be32_to_cpu(*((uint32_t *) (buf + 6))); if (count == 0) return -ENODATA; if (count > bufsiz) { printk("Error: invalid count value %x %zx \n", count, bufsiz); return -E2BIG; } //down(&chip->tpm_mutex); if ((rc = tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) { printk("tpm_transmit: tpm_send: error %ld\n", rc); goto out; } if (chip->irq) goto out_recv; stop = NOW() + tpm_calc_ordinal_duration(chip, ordinal); do { uint8_t status = tpm_tis_status(chip); if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) == (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) goto out_recv; if ((status == TPM_STS_COMMAND_READY)) { printk("TPM Error: Operation Canceled\n"); rc = -ECANCELED; goto out; } msleep(TPM_TIMEOUT); /* CHECK */ rmb(); } while (NOW() < stop); /* Cancel the command */ tpm_tis_cancel_cmd(chip); printk("TPM Operation Timed out\n"); rc = -ETIME; goto out; out_recv: if((rc = tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) { printk("tpm_transmit: tpm_recv: error %d\n", rc); } out: //up(&chip->tpm_mutex); return rc; }
/** * tpm_do_selftest - have the TPM continue its selftest and wait until it * can receive further commands * @chip: TPM chip to use * * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing * a TPM error code. */ int tpm_do_selftest(struct tpm_chip *chip) { int rc; unsigned int loops; unsigned int delay_msec = 100; unsigned long duration; struct tpm_cmd_t cmd; duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST); loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ if (rc) return rc; do { /* Attempt to read a PCR value */ cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0); rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE); /* Some buggy TPMs will not respond to tpm_tis_ready() for * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ if (rc == -ETIME) { dev_info( &chip->dev, HW_ERR "TPM command timed out during continue self test"); msleep(delay_msec); continue; } if (rc < TPM_HEADER_SIZE) return -EFAULT; rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { dev_info(&chip->dev, "TPM is disabled/deactivated (0x%X)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for * suspend/resume correctly */ return 0; } if (rc != TPM_WARN_DOING_SELFTEST) return rc; msleep(delay_msec); } while (--loops > 0); return rc; }
/** * tpm_do_selftest - have the TPM continue its selftest and wait until it * can receive further commands * @chip: TPM chip to use * * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing * a TPM error code. */ int tpm_do_selftest(struct tpm_chip *chip) { int rc; unsigned int loops; unsigned int delay_msec = 100; unsigned long duration; u8 dummy[TPM_DIGEST_SIZE]; duration = tpm_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST); loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ if (rc) return rc; do { /* Attempt to read a PCR value */ rc = tpm_pcr_read_dev(chip, 0, dummy); /* Some buggy TPMs will not respond to tpm_tis_ready() for * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ if (rc == -ETIME) { dev_info( &chip->dev, HW_ERR "TPM command timed out during continue self test"); msleep(delay_msec); continue; } if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { dev_info(&chip->dev, "TPM is disabled/deactivated (0x%X)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for * suspend/resume correctly */ return 0; } if (rc != TPM_WARN_DOING_SELFTEST) return rc; msleep(delay_msec); } while (--loops > 0); return rc; }
static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct tpm_private *priv = dev_get_drvdata(&chip->dev); struct vtpm_shared_page *shr = priv->shr; unsigned int offset = shr_data_offset(shr); u32 ordinal; unsigned long duration; if (offset > PAGE_SIZE) return -EINVAL; if (offset + count > PAGE_SIZE) return -EINVAL; /* Wait for completion of any existing command or cancellation */ if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->timeout_c, &priv->read_queue, true) < 0) { vtpm_cancel(chip); return -ETIME; } memcpy(offset + (u8 *)shr, buf, count); shr->length = count; barrier(); shr->state = VTPM_STATE_SUBMIT; wmb(); notify_remote_via_evtchn(priv->evtchn); ordinal = be32_to_cpu(((struct tpm_header *)buf)->ordinal); duration = tpm_calc_ordinal_duration(chip, ordinal); if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration, &priv->read_queue, true) < 0) { /* got a signal or timeout, try to cancel */ vtpm_cancel(chip); return -ETIME; } return 0; }
/* * Internal kernel interface to transmit TPM commands */ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags) { ssize_t rc; u32 count, ordinal; unsigned long stop; if (bufsiz < TPM_HEADER_SIZE) return -EINVAL; if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; count = be32_to_cpu(*((__be32 *) (buf + 2))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); if (count == 0) return -ENODATA; if (count > bufsiz) { dev_err(&chip->dev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(&chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } if (chip->flags & TPM_CHIP_FLAG_IRQ) goto out_recv; if (chip->flags & TPM_CHIP_FLAG_TPM2) stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal); else 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"); rc = -ECANCELED; goto out; } msleep(TPM_TIMEOUT); /* CHECK */ rmb(); } while (time_before(jiffies, stop)); chip->ops->cancel(chip); dev_err(&chip->dev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc; }
ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) { ssize_t rc; u32 count, ordinal; unsigned long start, stop; struct tpm_chip *chip = &g_chip; /* switch endianess: big->little */ count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE); ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE); if (count == 0) { dev_err(chip->dev, "no data\n"); return -ENODATA; } if (count > bufsiz) { dev_err(chip->dev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } rc = chip->vendor.send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } if (chip->vendor.irq) goto out_recv; start = get_timer(0); stop = tpm_calc_ordinal_duration(chip, ordinal); do { dbg_printf("waiting for status...\n"); u8 status = chip->vendor.status(chip); if ((status & chip->vendor.req_complete_mask) == chip->vendor.req_complete_val) { dbg_printf("...got it;\n"); goto out_recv; } if ((status == chip->vendor.req_canceled)) { dev_err(chip->dev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } msleep(TPM_TIMEOUT); } while (get_timer(start) < stop); chip->vendor.cancel(chip); dev_err(chip->dev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: dbg_printf("out_recv: reading response...\n"); rc = chip->vendor.recv(chip, (u8 *) buf, TPM_BUFSIZE); if (rc < 0) dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: return rc; }
/* * st33zp24_send send TPM commands through the I2C bus. * * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h * @param: buf, the buffer to send. * @param: count, the number of bytes to send. * @return: In case of success the number of bytes sent. * In other case, a < 0 value describing the issue. */ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, size_t len) { struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); u32 status, i, size, ordinal; int burstcnt = 0; int ret; u8 data; if (!chip) return -EBUSY; if (len < TPM_HEADER_SIZE) return -EBUSY; ret = request_locality(chip); if (ret < 0) return ret; status = st33zp24_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { st33zp24_cancel(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->timeout_b, &tpm_dev->read_queue, false) < 0) { ret = -ETIME; goto out_err; } } for (i = 0; i < len - 1;) { burstcnt = get_burstcount(chip); if (burstcnt < 0) return burstcnt; size = min_t(int, len - i - 1, burstcnt); ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, buf + i, size); if (ret < 0) goto out_err; i += size; } status = st33zp24_status(chip); if ((status & TPM_STS_DATA_EXPECT) == 0) { ret = -EIO; goto out_err; } ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO, buf + len - 1, 1); if (ret < 0) goto out_err; status = st33zp24_status(chip); if ((status & TPM_STS_DATA_EXPECT) != 0) { ret = -EIO; goto out_err; } data = TPM_STS_GO; ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); if (ret < 0) goto out_err; if (chip->flags & TPM_CHIP_FLAG_IRQ) { ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); ret = wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, tpm_calc_ordinal_duration(chip, ordinal), &tpm_dev->read_queue, false); if (ret < 0) goto out_err; } return len; out_err: st33zp24_cancel(chip); release_locality(chip); return ret; }
int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) { int rc; int status, burstcnt = 0; int count = 0; uint32_t ordinal; if(tpm_tis_request_locality(tpm, tpm->locality) < 0) { return -EBUSY; } status = tpm_tis_status(tpm); if((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_ready(tpm); if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b, &tpm->int_queue) < 0) { rc = -ETIME; goto out_err; } } while(count < len - 1) { burstcnt = get_burstcount(tpm); for(;burstcnt > 0 && count < len -1; --burstcnt) { iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]); } wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue); status = tpm_tis_status(tpm); if((status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; goto out_err; } } /*Write last byte*/ iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]); wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue); status = tpm_tis_status(tpm); if((status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; goto out_err; } /*go and do it*/ iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO); if(tpm->irq) { /*Wait for interrupt */ ordinal = be32_to_cpu(*(buf + 6)); if(wait_for_stat(tpm, TPM_STS_DATA_AVAIL | TPM_STS_VALID, tpm_calc_ordinal_duration(tpm, ordinal), &tpm->read_queue) < 0) { rc = -ETIME; goto out_err; } } #ifdef HAVE_LIBC if(tpm->fd >= 0) { files[tpm->fd].read = 0; files[tpm->fd].tpm_tis.respgot = 0; files[tpm->fd].tpm_tis.offset = 0; } #endif return len; out_err: tpm_tis_ready(tpm); release_locality(tpm, tpm->locality, 0); return rc; }
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; }