18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2004 IBM Corporation 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Intel Corporation 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Leendert van Doorn <leendert@watson.ibm.com> 88c2ecf20Sopenharmony_ci * Dave Safford <safford@watson.ibm.com> 98c2ecf20Sopenharmony_ci * Reiner Sailer <sailer@watson.ibm.com> 108c2ecf20Sopenharmony_ci * Kylene Hall <kjhall@us.ibm.com> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Maintained by: <tpmdd-devel@lists.sourceforge.net> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Device driver for TCG/TCPA TPM (trusted platform module). 158c2ecf20Sopenharmony_ci * Specifications at www.trustedcomputinggroup.org 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Note, the TPM chip is not interrupt driven (only polling) 188c2ecf20Sopenharmony_ci * and can have very long timeouts (minutes!). Hence the unusual 198c2ecf20Sopenharmony_ci * calls to msleep. 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/poll.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/mutex.h> 258c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 268c2ecf20Sopenharmony_ci#include <linux/suspend.h> 278c2ecf20Sopenharmony_ci#include <linux/freezer.h> 288c2ecf20Sopenharmony_ci#include <linux/tpm_eventlog.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "tpm.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Bug workaround - some TPM's don't flush the most 348c2ecf20Sopenharmony_ci * recently changed pcr on suspend, so force the flush 358c2ecf20Sopenharmony_ci * with an extend to the selected _unused_ non-volatile pcr. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic u32 tpm_suspend_pcr; 388c2ecf20Sopenharmony_cimodule_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); 398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(suspend_pcr, 408c2ecf20Sopenharmony_ci "PCR to use for dummy writes to facilitate flush on suspend."); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * tpm_calc_ordinal_duration() - calculate the maximum command duration 448c2ecf20Sopenharmony_ci * @chip: TPM chip to use. 458c2ecf20Sopenharmony_ci * @ordinal: TPM command ordinal. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * The function returns the maximum amount of time the chip could take 488c2ecf20Sopenharmony_ci * to return the result for a particular ordinal in jiffies. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Return: A maximal duration time for an ordinal in jiffies. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ciunsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) 558c2ecf20Sopenharmony_ci return tpm2_calc_ordinal_duration(chip, ordinal); 568c2ecf20Sopenharmony_ci else 578c2ecf20Sopenharmony_ci return tpm1_calc_ordinal_duration(chip, ordinal); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct tpm_header *header = buf; 648c2ecf20Sopenharmony_ci int rc; 658c2ecf20Sopenharmony_ci ssize_t len = 0; 668c2ecf20Sopenharmony_ci u32 count, ordinal; 678c2ecf20Sopenharmony_ci unsigned long stop; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (bufsiz < TPM_HEADER_SIZE) 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (bufsiz > TPM_BUFSIZE) 738c2ecf20Sopenharmony_ci bufsiz = TPM_BUFSIZE; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci count = be32_to_cpu(header->length); 768c2ecf20Sopenharmony_ci ordinal = be32_to_cpu(header->ordinal); 778c2ecf20Sopenharmony_ci if (count == 0) 788c2ecf20Sopenharmony_ci return -ENODATA; 798c2ecf20Sopenharmony_ci if (count > bufsiz) { 808c2ecf20Sopenharmony_ci dev_err(&chip->dev, 818c2ecf20Sopenharmony_ci "invalid count value %x %zx\n", count, bufsiz); 828c2ecf20Sopenharmony_ci return -E2BIG; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rc = chip->ops->send(chip, buf, count); 868c2ecf20Sopenharmony_ci if (rc < 0) { 878c2ecf20Sopenharmony_ci if (rc != -EPIPE) 888c2ecf20Sopenharmony_ci dev_err(&chip->dev, 898c2ecf20Sopenharmony_ci "%s: send(): error %d\n", __func__, rc); 908c2ecf20Sopenharmony_ci return rc; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* A sanity check. send() should just return zero on success e.g. 948c2ecf20Sopenharmony_ci * not the command length. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci if (rc > 0) { 978c2ecf20Sopenharmony_ci dev_warn(&chip->dev, 988c2ecf20Sopenharmony_ci "%s: send(): invalid value %d\n", __func__, rc); 998c2ecf20Sopenharmony_ci rc = 0; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_IRQ) 1038c2ecf20Sopenharmony_ci goto out_recv; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); 1068c2ecf20Sopenharmony_ci do { 1078c2ecf20Sopenharmony_ci u8 status = chip->ops->status(chip); 1088c2ecf20Sopenharmony_ci if ((status & chip->ops->req_complete_mask) == 1098c2ecf20Sopenharmony_ci chip->ops->req_complete_val) 1108c2ecf20Sopenharmony_ci goto out_recv; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (chip->ops->req_canceled(chip, status)) { 1138c2ecf20Sopenharmony_ci dev_err(&chip->dev, "Operation Canceled\n"); 1148c2ecf20Sopenharmony_ci return -ECANCELED; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci tpm_msleep(TPM_TIMEOUT_POLL); 1188c2ecf20Sopenharmony_ci rmb(); 1198c2ecf20Sopenharmony_ci } while (time_before(jiffies, stop)); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci chip->ops->cancel(chip); 1228c2ecf20Sopenharmony_ci dev_err(&chip->dev, "Operation Timed out\n"); 1238c2ecf20Sopenharmony_ci return -ETIME; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciout_recv: 1268c2ecf20Sopenharmony_ci len = chip->ops->recv(chip, buf, bufsiz); 1278c2ecf20Sopenharmony_ci if (len < 0) { 1288c2ecf20Sopenharmony_ci rc = len; 1298c2ecf20Sopenharmony_ci dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %d\n", rc); 1308c2ecf20Sopenharmony_ci } else if (len < TPM_HEADER_SIZE || len != be32_to_cpu(header->length)) 1318c2ecf20Sopenharmony_ci rc = -EFAULT; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return rc ? rc : len; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/** 1378c2ecf20Sopenharmony_ci * tpm_transmit - Internal kernel interface to transmit TPM commands. 1388c2ecf20Sopenharmony_ci * @chip: a TPM chip to use 1398c2ecf20Sopenharmony_ci * @buf: a TPM command buffer 1408c2ecf20Sopenharmony_ci * @bufsiz: length of the TPM command buffer 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * A wrapper around tpm_try_transmit() that handles TPM2_RC_RETRY returns from 1438c2ecf20Sopenharmony_ci * the TPM and retransmits the command after a delay up to a maximum wait of 1448c2ecf20Sopenharmony_ci * TPM2_DURATION_LONG. 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * Note that TPM 1.x never returns TPM2_RC_RETRY so the retry logic is TPM 2.0 1478c2ecf20Sopenharmony_ci * only. 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * Return: 1508c2ecf20Sopenharmony_ci * * The response length - OK 1518c2ecf20Sopenharmony_ci * * -errno - A system error 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_cissize_t tpm_transmit(struct tpm_chip *chip, u8 *buf, size_t bufsiz) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct tpm_header *header = (struct tpm_header *)buf; 1568c2ecf20Sopenharmony_ci /* space for header and handles */ 1578c2ecf20Sopenharmony_ci u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; 1588c2ecf20Sopenharmony_ci unsigned int delay_msec = TPM2_DURATION_SHORT; 1598c2ecf20Sopenharmony_ci u32 rc = 0; 1608c2ecf20Sopenharmony_ci ssize_t ret; 1618c2ecf20Sopenharmony_ci const size_t save_size = min(sizeof(save), bufsiz); 1628c2ecf20Sopenharmony_ci /* the command code is where the return code will be */ 1638c2ecf20Sopenharmony_ci u32 cc = be32_to_cpu(header->return_code); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * Subtlety here: if we have a space, the handles will be 1678c2ecf20Sopenharmony_ci * transformed, so when we restore the header we also have to 1688c2ecf20Sopenharmony_ci * restore the handles. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci memcpy(save, buf, save_size); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (;;) { 1738c2ecf20Sopenharmony_ci ret = tpm_try_transmit(chip, buf, bufsiz); 1748c2ecf20Sopenharmony_ci if (ret < 0) 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci rc = be32_to_cpu(header->return_code); 1778c2ecf20Sopenharmony_ci if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING) 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * return immediately if self test returns test 1818c2ecf20Sopenharmony_ci * still running to shorten boot time. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST) 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (delay_msec > TPM2_DURATION_LONG) { 1878c2ecf20Sopenharmony_ci if (rc == TPM2_RC_RETRY) 1888c2ecf20Sopenharmony_ci dev_err(&chip->dev, "in retry loop\n"); 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci dev_err(&chip->dev, 1918c2ecf20Sopenharmony_ci "self test is still running\n"); 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci tpm_msleep(delay_msec); 1958c2ecf20Sopenharmony_ci delay_msec *= 2; 1968c2ecf20Sopenharmony_ci memcpy(buf, save, save_size); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * tpm_transmit_cmd - send a tpm command to the device 2038c2ecf20Sopenharmony_ci * @chip: a TPM chip to use 2048c2ecf20Sopenharmony_ci * @buf: a TPM command buffer 2058c2ecf20Sopenharmony_ci * @min_rsp_body_length: minimum expected length of response body 2068c2ecf20Sopenharmony_ci * @desc: command description used in the error message 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * Return: 2098c2ecf20Sopenharmony_ci * * 0 - OK 2108c2ecf20Sopenharmony_ci * * -errno - A system error 2118c2ecf20Sopenharmony_ci * * TPM_RC - A TPM error 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_cissize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf, 2148c2ecf20Sopenharmony_ci size_t min_rsp_body_length, const char *desc) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci const struct tpm_header *header = (struct tpm_header *)buf->data; 2178c2ecf20Sopenharmony_ci int err; 2188c2ecf20Sopenharmony_ci ssize_t len; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci len = tpm_transmit(chip, buf->data, PAGE_SIZE); 2218c2ecf20Sopenharmony_ci if (len < 0) 2228c2ecf20Sopenharmony_ci return len; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci err = be32_to_cpu(header->return_code); 2258c2ecf20Sopenharmony_ci if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED 2268c2ecf20Sopenharmony_ci && err != TPM2_RC_TESTING && desc) 2278c2ecf20Sopenharmony_ci dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, 2288c2ecf20Sopenharmony_ci desc); 2298c2ecf20Sopenharmony_ci if (err) 2308c2ecf20Sopenharmony_ci return err; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (len < min_rsp_body_length + TPM_HEADER_SIZE) 2338c2ecf20Sopenharmony_ci return -EFAULT; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_transmit_cmd); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciint tpm_get_timeouts(struct tpm_chip *chip) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) 2458c2ecf20Sopenharmony_ci return tpm2_get_timeouts(chip); 2468c2ecf20Sopenharmony_ci else 2478c2ecf20Sopenharmony_ci return tpm1_get_timeouts(chip); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_get_timeouts); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/** 2528c2ecf20Sopenharmony_ci * tpm_is_tpm2 - do we a have a TPM2 chip? 2538c2ecf20Sopenharmony_ci * @chip: a &struct tpm_chip instance, %NULL for the default chip 2548c2ecf20Sopenharmony_ci * 2558c2ecf20Sopenharmony_ci * Return: 2568c2ecf20Sopenharmony_ci * 1 if we have a TPM2 chip. 2578c2ecf20Sopenharmony_ci * 0 if we don't have a TPM2 chip. 2588c2ecf20Sopenharmony_ci * A negative number for system errors (errno). 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ciint tpm_is_tpm2(struct tpm_chip *chip) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int rc; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci chip = tpm_find_get_ops(chip); 2658c2ecf20Sopenharmony_ci if (!chip) 2668c2ecf20Sopenharmony_ci return -ENODEV; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci tpm_put_ops(chip); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return rc; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_is_tpm2); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * tpm_pcr_read - read a PCR value from SHA1 bank 2788c2ecf20Sopenharmony_ci * @chip: a &struct tpm_chip instance, %NULL for the default chip 2798c2ecf20Sopenharmony_ci * @pcr_idx: the PCR to be retrieved 2808c2ecf20Sopenharmony_ci * @digest: the PCR bank and buffer current PCR value is written to 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Return: same as with tpm_transmit_cmd() 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ciint tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, 2858c2ecf20Sopenharmony_ci struct tpm_digest *digest) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int rc; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci chip = tpm_find_get_ops(chip); 2908c2ecf20Sopenharmony_ci if (!chip) 2918c2ecf20Sopenharmony_ci return -ENODEV; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) 2948c2ecf20Sopenharmony_ci rc = tpm2_pcr_read(chip, pcr_idx, digest, NULL); 2958c2ecf20Sopenharmony_ci else 2968c2ecf20Sopenharmony_ci rc = tpm1_pcr_read(chip, pcr_idx, digest->digest); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci tpm_put_ops(chip); 2998c2ecf20Sopenharmony_ci return rc; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_pcr_read); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/** 3048c2ecf20Sopenharmony_ci * tpm_pcr_extend - extend a PCR value in SHA1 bank. 3058c2ecf20Sopenharmony_ci * @chip: a &struct tpm_chip instance, %NULL for the default chip 3068c2ecf20Sopenharmony_ci * @pcr_idx: the PCR to be retrieved 3078c2ecf20Sopenharmony_ci * @digests: array of tpm_digest structures used to extend PCRs 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Note: callers must pass a digest for every allocated PCR bank, in the same 3108c2ecf20Sopenharmony_ci * order of the banks in chip->allocated_banks. 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * Return: same as with tpm_transmit_cmd() 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ciint tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, 3158c2ecf20Sopenharmony_ci struct tpm_digest *digests) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci int rc; 3188c2ecf20Sopenharmony_ci int i; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci chip = tpm_find_get_ops(chip); 3218c2ecf20Sopenharmony_ci if (!chip) 3228c2ecf20Sopenharmony_ci return -ENODEV; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci for (i = 0; i < chip->nr_allocated_banks; i++) { 3258c2ecf20Sopenharmony_ci if (digests[i].alg_id != chip->allocated_banks[i].alg_id) { 3268c2ecf20Sopenharmony_ci rc = -EINVAL; 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) { 3328c2ecf20Sopenharmony_ci rc = tpm2_pcr_extend(chip, pcr_idx, digests); 3338c2ecf20Sopenharmony_ci goto out; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci rc = tpm1_pcr_extend(chip, pcr_idx, digests[0].digest, 3378c2ecf20Sopenharmony_ci "attempting extend a PCR value"); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciout: 3408c2ecf20Sopenharmony_ci tpm_put_ops(chip); 3418c2ecf20Sopenharmony_ci return rc; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_pcr_extend); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/** 3468c2ecf20Sopenharmony_ci * tpm_send - send a TPM command 3478c2ecf20Sopenharmony_ci * @chip: a &struct tpm_chip instance, %NULL for the default chip 3488c2ecf20Sopenharmony_ci * @cmd: a TPM command buffer 3498c2ecf20Sopenharmony_ci * @buflen: the length of the TPM command buffer 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * Return: same as with tpm_transmit_cmd() 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ciint tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct tpm_buf buf; 3568c2ecf20Sopenharmony_ci int rc; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci chip = tpm_find_get_ops(chip); 3598c2ecf20Sopenharmony_ci if (!chip) 3608c2ecf20Sopenharmony_ci return -ENODEV; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci buf.data = cmd; 3638c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to a send a command"); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci tpm_put_ops(chip); 3668c2ecf20Sopenharmony_ci return rc; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_send); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciint tpm_auto_startup(struct tpm_chip *chip) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci int rc; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (!(chip->ops->flags & TPM_OPS_AUTO_STARTUP)) 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) 3788c2ecf20Sopenharmony_ci rc = tpm2_auto_startup(chip); 3798c2ecf20Sopenharmony_ci else 3808c2ecf20Sopenharmony_ci rc = tpm1_auto_startup(chip); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return rc; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/* 3868c2ecf20Sopenharmony_ci * We are about to suspend. Save the TPM state 3878c2ecf20Sopenharmony_ci * so that it can be restored. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ciint tpm_pm_suspend(struct device *dev) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct tpm_chip *chip = dev_get_drvdata(dev); 3928c2ecf20Sopenharmony_ci int rc = 0; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!chip) 3958c2ecf20Sopenharmony_ci return -ENODEV; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) 3988c2ecf20Sopenharmony_ci goto suspended; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if ((chip->flags & TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED) && 4018c2ecf20Sopenharmony_ci !pm_suspend_via_firmware()) 4028c2ecf20Sopenharmony_ci goto suspended; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci rc = tpm_try_get_ops(chip); 4058c2ecf20Sopenharmony_ci if (!rc) { 4068c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) 4078c2ecf20Sopenharmony_ci tpm2_shutdown(chip, TPM2_SU_STATE); 4088c2ecf20Sopenharmony_ci else 4098c2ecf20Sopenharmony_ci rc = tpm1_pm_suspend(chip, tpm_suspend_pcr); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci tpm_put_ops(chip); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cisuspended: 4158c2ecf20Sopenharmony_ci return rc; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_pm_suspend); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* 4208c2ecf20Sopenharmony_ci * Resume from a power safe. The BIOS already restored 4218c2ecf20Sopenharmony_ci * the TPM state. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_ciint tpm_pm_resume(struct device *dev) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct tpm_chip *chip = dev_get_drvdata(dev); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (chip == NULL) 4288c2ecf20Sopenharmony_ci return -ENODEV; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_pm_resume); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci/** 4358c2ecf20Sopenharmony_ci * tpm_get_random() - get random bytes from the TPM's RNG 4368c2ecf20Sopenharmony_ci * @chip: a &struct tpm_chip instance, %NULL for the default chip 4378c2ecf20Sopenharmony_ci * @out: destination buffer for the random bytes 4388c2ecf20Sopenharmony_ci * @max: the max number of bytes to write to @out 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * Return: number of random bytes read or a negative error value. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ciint tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int rc; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!out || max > TPM_MAX_RNG_DATA) 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci chip = tpm_find_get_ops(chip); 4508c2ecf20Sopenharmony_ci if (!chip) 4518c2ecf20Sopenharmony_ci return -ENODEV; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (chip->flags & TPM_CHIP_FLAG_TPM2) 4548c2ecf20Sopenharmony_ci rc = tpm2_get_random(chip, out, max); 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci rc = tpm1_get_random(chip, out, max); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci tpm_put_ops(chip); 4598c2ecf20Sopenharmony_ci return rc; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm_get_random); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int __init tpm_init(void) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci int rc; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci tpm_class = class_create(THIS_MODULE, "tpm"); 4688c2ecf20Sopenharmony_ci if (IS_ERR(tpm_class)) { 4698c2ecf20Sopenharmony_ci pr_err("couldn't create tpm class\n"); 4708c2ecf20Sopenharmony_ci return PTR_ERR(tpm_class); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci tpmrm_class = class_create(THIS_MODULE, "tpmrm"); 4748c2ecf20Sopenharmony_ci if (IS_ERR(tpmrm_class)) { 4758c2ecf20Sopenharmony_ci pr_err("couldn't create tpmrm class\n"); 4768c2ecf20Sopenharmony_ci rc = PTR_ERR(tpmrm_class); 4778c2ecf20Sopenharmony_ci goto out_destroy_tpm_class; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm"); 4818c2ecf20Sopenharmony_ci if (rc < 0) { 4828c2ecf20Sopenharmony_ci pr_err("tpm: failed to allocate char dev region\n"); 4838c2ecf20Sopenharmony_ci goto out_destroy_tpmrm_class; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci rc = tpm_dev_common_init(); 4878c2ecf20Sopenharmony_ci if (rc) { 4888c2ecf20Sopenharmony_ci pr_err("tpm: failed to allocate char dev region\n"); 4898c2ecf20Sopenharmony_ci goto out_unreg_chrdev; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ciout_unreg_chrdev: 4958c2ecf20Sopenharmony_ci unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES); 4968c2ecf20Sopenharmony_ciout_destroy_tpmrm_class: 4978c2ecf20Sopenharmony_ci class_destroy(tpmrm_class); 4988c2ecf20Sopenharmony_ciout_destroy_tpm_class: 4998c2ecf20Sopenharmony_ci class_destroy(tpm_class); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return rc; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void __exit tpm_exit(void) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci idr_destroy(&dev_nums_idr); 5078c2ecf20Sopenharmony_ci class_destroy(tpm_class); 5088c2ecf20Sopenharmony_ci class_destroy(tpmrm_class); 5098c2ecf20Sopenharmony_ci unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES); 5108c2ecf20Sopenharmony_ci tpm_dev_common_exit(); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cisubsys_initcall(tpm_init); 5148c2ecf20Sopenharmony_cimodule_exit(tpm_exit); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 5178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TPM Driver"); 5188c2ecf20Sopenharmony_ciMODULE_VERSION("2.0"); 5198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 520