18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2014, 2015 Intel Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: 68c2ecf20Sopenharmony_ci * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Maintained by: <tpmdd-devel@lists.sourceforge.net> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This file contains TPM2 protocol implementations of the commands 118c2ecf20Sopenharmony_ci * used by the kernel internally. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "tpm.h" 158c2ecf20Sopenharmony_ci#include <crypto/hash_info.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic struct tpm2_hash tpm2_hash_map[] = { 188c2ecf20Sopenharmony_ci {HASH_ALGO_SHA1, TPM_ALG_SHA1}, 198c2ecf20Sopenharmony_ci {HASH_ALGO_SHA256, TPM_ALG_SHA256}, 208c2ecf20Sopenharmony_ci {HASH_ALGO_SHA384, TPM_ALG_SHA384}, 218c2ecf20Sopenharmony_ci {HASH_ALGO_SHA512, TPM_ALG_SHA512}, 228c2ecf20Sopenharmony_ci {HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciint tpm2_get_timeouts(struct tpm_chip *chip) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci /* Fixed timeouts for TPM2 */ 288c2ecf20Sopenharmony_ci chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); 298c2ecf20Sopenharmony_ci chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); 308c2ecf20Sopenharmony_ci chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C); 318c2ecf20Sopenharmony_ci chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* PTP spec timeouts */ 348c2ecf20Sopenharmony_ci chip->duration[TPM_SHORT] = msecs_to_jiffies(TPM2_DURATION_SHORT); 358c2ecf20Sopenharmony_ci chip->duration[TPM_MEDIUM] = msecs_to_jiffies(TPM2_DURATION_MEDIUM); 368c2ecf20Sopenharmony_ci chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* Key creation commands long timeouts */ 398c2ecf20Sopenharmony_ci chip->duration[TPM_LONG_LONG] = 408c2ecf20Sopenharmony_ci msecs_to_jiffies(TPM2_DURATION_LONG_LONG); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * tpm2_ordinal_duration_index() - returns an index to the chip duration table 498c2ecf20Sopenharmony_ci * @ordinal: TPM command ordinal. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * The function returns an index to the chip duration table 528c2ecf20Sopenharmony_ci * (enum tpm_duration), that describes the maximum amount of 538c2ecf20Sopenharmony_ci * time the chip could take to return the result for a particular ordinal. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * The values of the MEDIUM, and LONG durations are taken 568c2ecf20Sopenharmony_ci * from the PC Client Profile (PTP) specification (750, 2000 msec) 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * LONG_LONG is for commands that generates keys which empirically takes 598c2ecf20Sopenharmony_ci * a longer time on some systems. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Return: 628c2ecf20Sopenharmony_ci * * TPM_MEDIUM 638c2ecf20Sopenharmony_ci * * TPM_LONG 648c2ecf20Sopenharmony_ci * * TPM_LONG_LONG 658c2ecf20Sopenharmony_ci * * TPM_UNDEFINED 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic u8 tpm2_ordinal_duration_index(u32 ordinal) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci switch (ordinal) { 708c2ecf20Sopenharmony_ci /* Startup */ 718c2ecf20Sopenharmony_ci case TPM2_CC_STARTUP: /* 144 */ 728c2ecf20Sopenharmony_ci return TPM_MEDIUM; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci case TPM2_CC_SELF_TEST: /* 143 */ 758c2ecf20Sopenharmony_ci return TPM_LONG; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci case TPM2_CC_GET_RANDOM: /* 17B */ 788c2ecf20Sopenharmony_ci return TPM_LONG; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci case TPM2_CC_SEQUENCE_UPDATE: /* 15C */ 818c2ecf20Sopenharmony_ci return TPM_MEDIUM; 828c2ecf20Sopenharmony_ci case TPM2_CC_SEQUENCE_COMPLETE: /* 13E */ 838c2ecf20Sopenharmony_ci return TPM_MEDIUM; 848c2ecf20Sopenharmony_ci case TPM2_CC_EVENT_SEQUENCE_COMPLETE: /* 185 */ 858c2ecf20Sopenharmony_ci return TPM_MEDIUM; 868c2ecf20Sopenharmony_ci case TPM2_CC_HASH_SEQUENCE_START: /* 186 */ 878c2ecf20Sopenharmony_ci return TPM_MEDIUM; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci case TPM2_CC_VERIFY_SIGNATURE: /* 177 */ 908c2ecf20Sopenharmony_ci return TPM_LONG; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci case TPM2_CC_PCR_EXTEND: /* 182 */ 938c2ecf20Sopenharmony_ci return TPM_MEDIUM; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci case TPM2_CC_HIERARCHY_CONTROL: /* 121 */ 968c2ecf20Sopenharmony_ci return TPM_LONG; 978c2ecf20Sopenharmony_ci case TPM2_CC_HIERARCHY_CHANGE_AUTH: /* 129 */ 988c2ecf20Sopenharmony_ci return TPM_LONG; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci case TPM2_CC_GET_CAPABILITY: /* 17A */ 1018c2ecf20Sopenharmony_ci return TPM_MEDIUM; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci case TPM2_CC_NV_READ: /* 14E */ 1048c2ecf20Sopenharmony_ci return TPM_LONG; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci case TPM2_CC_CREATE_PRIMARY: /* 131 */ 1078c2ecf20Sopenharmony_ci return TPM_LONG_LONG; 1088c2ecf20Sopenharmony_ci case TPM2_CC_CREATE: /* 153 */ 1098c2ecf20Sopenharmony_ci return TPM_LONG_LONG; 1108c2ecf20Sopenharmony_ci case TPM2_CC_CREATE_LOADED: /* 191 */ 1118c2ecf20Sopenharmony_ci return TPM_LONG_LONG; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci default: 1148c2ecf20Sopenharmony_ci return TPM_UNDEFINED; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * tpm2_calc_ordinal_duration() - calculate the maximum command duration 1208c2ecf20Sopenharmony_ci * @chip: TPM chip to use. 1218c2ecf20Sopenharmony_ci * @ordinal: TPM command ordinal. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * The function returns the maximum amount of time the chip could take 1248c2ecf20Sopenharmony_ci * to return the result for a particular ordinal in jiffies. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Return: A maximal duration time for an ordinal in jiffies. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ciunsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci unsigned int index; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci index = tpm2_ordinal_duration_index(ordinal); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (index != TPM_UNDEFINED) 1358c2ecf20Sopenharmony_ci return chip->duration[index]; 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci return msecs_to_jiffies(TPM2_DURATION_DEFAULT); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistruct tpm2_pcr_read_out { 1428c2ecf20Sopenharmony_ci __be32 update_cnt; 1438c2ecf20Sopenharmony_ci __be32 pcr_selects_cnt; 1448c2ecf20Sopenharmony_ci __be16 hash_alg; 1458c2ecf20Sopenharmony_ci u8 pcr_select_size; 1468c2ecf20Sopenharmony_ci u8 pcr_select[TPM2_PCR_SELECT_MIN]; 1478c2ecf20Sopenharmony_ci __be32 digests_cnt; 1488c2ecf20Sopenharmony_ci __be16 digest_size; 1498c2ecf20Sopenharmony_ci u8 digest[]; 1508c2ecf20Sopenharmony_ci} __packed; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/** 1538c2ecf20Sopenharmony_ci * tpm2_pcr_read() - read a PCR value 1548c2ecf20Sopenharmony_ci * @chip: TPM chip to use. 1558c2ecf20Sopenharmony_ci * @pcr_idx: index of the PCR to read. 1568c2ecf20Sopenharmony_ci * @digest: PCR bank and buffer current PCR value is written to. 1578c2ecf20Sopenharmony_ci * @digest_size_ptr: pointer to variable that stores the digest size. 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * Return: Same as with tpm_transmit_cmd. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ciint tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, 1628c2ecf20Sopenharmony_ci struct tpm_digest *digest, u16 *digest_size_ptr) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci int i; 1658c2ecf20Sopenharmony_ci int rc; 1668c2ecf20Sopenharmony_ci struct tpm_buf buf; 1678c2ecf20Sopenharmony_ci struct tpm2_pcr_read_out *out; 1688c2ecf20Sopenharmony_ci u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0}; 1698c2ecf20Sopenharmony_ci u16 digest_size; 1708c2ecf20Sopenharmony_ci u16 expected_digest_size = 0; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (pcr_idx >= TPM2_PLATFORM_PCR) 1738c2ecf20Sopenharmony_ci return -EINVAL; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!digest_size_ptr) { 1768c2ecf20Sopenharmony_ci for (i = 0; i < chip->nr_allocated_banks && 1778c2ecf20Sopenharmony_ci chip->allocated_banks[i].alg_id != digest->alg_id; i++) 1788c2ecf20Sopenharmony_ci ; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (i == chip->nr_allocated_banks) 1818c2ecf20Sopenharmony_ci return -EINVAL; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci expected_digest_size = chip->allocated_banks[i].digest_size; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ); 1878c2ecf20Sopenharmony_ci if (rc) 1888c2ecf20Sopenharmony_ci return rc; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, 1); 1938c2ecf20Sopenharmony_ci tpm_buf_append_u16(&buf, digest->alg_id); 1948c2ecf20Sopenharmony_ci tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN); 1958c2ecf20Sopenharmony_ci tpm_buf_append(&buf, (const unsigned char *)pcr_select, 1968c2ecf20Sopenharmony_ci sizeof(pcr_select)); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value"); 1998c2ecf20Sopenharmony_ci if (rc) 2008c2ecf20Sopenharmony_ci goto out; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE]; 2038c2ecf20Sopenharmony_ci digest_size = be16_to_cpu(out->digest_size); 2048c2ecf20Sopenharmony_ci if (digest_size > sizeof(digest->digest) || 2058c2ecf20Sopenharmony_ci (!digest_size_ptr && digest_size != expected_digest_size)) { 2068c2ecf20Sopenharmony_ci rc = -EINVAL; 2078c2ecf20Sopenharmony_ci goto out; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (digest_size_ptr) 2118c2ecf20Sopenharmony_ci *digest_size_ptr = digest_size; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci memcpy(digest->digest, out->digest, digest_size); 2148c2ecf20Sopenharmony_ciout: 2158c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 2168c2ecf20Sopenharmony_ci return rc; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistruct tpm2_null_auth_area { 2208c2ecf20Sopenharmony_ci __be32 handle; 2218c2ecf20Sopenharmony_ci __be16 nonce_size; 2228c2ecf20Sopenharmony_ci u8 attributes; 2238c2ecf20Sopenharmony_ci __be16 auth_size; 2248c2ecf20Sopenharmony_ci} __packed; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/** 2278c2ecf20Sopenharmony_ci * tpm2_pcr_extend() - extend a PCR value 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * @chip: TPM chip to use. 2308c2ecf20Sopenharmony_ci * @pcr_idx: index of the PCR. 2318c2ecf20Sopenharmony_ci * @digests: list of pcr banks and corresponding digest values to extend. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * Return: Same as with tpm_transmit_cmd. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ciint tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, 2368c2ecf20Sopenharmony_ci struct tpm_digest *digests) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct tpm_buf buf; 2398c2ecf20Sopenharmony_ci struct tpm2_null_auth_area auth_area; 2408c2ecf20Sopenharmony_ci int rc; 2418c2ecf20Sopenharmony_ci int i; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); 2448c2ecf20Sopenharmony_ci if (rc) 2458c2ecf20Sopenharmony_ci return rc; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, pcr_idx); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci auth_area.handle = cpu_to_be32(TPM2_RS_PW); 2508c2ecf20Sopenharmony_ci auth_area.nonce_size = 0; 2518c2ecf20Sopenharmony_ci auth_area.attributes = 0; 2528c2ecf20Sopenharmony_ci auth_area.auth_size = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area)); 2558c2ecf20Sopenharmony_ci tpm_buf_append(&buf, (const unsigned char *)&auth_area, 2568c2ecf20Sopenharmony_ci sizeof(auth_area)); 2578c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, chip->nr_allocated_banks); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci for (i = 0; i < chip->nr_allocated_banks; i++) { 2608c2ecf20Sopenharmony_ci tpm_buf_append_u16(&buf, digests[i].alg_id); 2618c2ecf20Sopenharmony_ci tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest, 2628c2ecf20Sopenharmony_ci chip->allocated_banks[i].digest_size); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return rc; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistruct tpm2_get_random_out { 2738c2ecf20Sopenharmony_ci __be16 size; 2748c2ecf20Sopenharmony_ci u8 buffer[TPM_MAX_RNG_DATA]; 2758c2ecf20Sopenharmony_ci} __packed; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/** 2788c2ecf20Sopenharmony_ci * tpm2_get_random() - get random bytes from the TPM RNG 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * @chip: a &tpm_chip instance 2818c2ecf20Sopenharmony_ci * @dest: destination buffer 2828c2ecf20Sopenharmony_ci * @max: the max number of random bytes to pull 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci * Return: 2858c2ecf20Sopenharmony_ci * size of the buffer on success, 2868c2ecf20Sopenharmony_ci * -errno otherwise (positive TPM return codes are masked to -EIO) 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ciint tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct tpm2_get_random_out *out; 2918c2ecf20Sopenharmony_ci struct tpm_buf buf; 2928c2ecf20Sopenharmony_ci u32 recd; 2938c2ecf20Sopenharmony_ci u32 num_bytes = max; 2948c2ecf20Sopenharmony_ci int err; 2958c2ecf20Sopenharmony_ci int total = 0; 2968c2ecf20Sopenharmony_ci int retries = 5; 2978c2ecf20Sopenharmony_ci u8 *dest_ptr = dest; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (!num_bytes || max > TPM_MAX_RNG_DATA) 3008c2ecf20Sopenharmony_ci return -EINVAL; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci err = tpm_buf_init(&buf, 0, 0); 3038c2ecf20Sopenharmony_ci if (err) 3048c2ecf20Sopenharmony_ci return err; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci do { 3078c2ecf20Sopenharmony_ci tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM); 3088c2ecf20Sopenharmony_ci tpm_buf_append_u16(&buf, num_bytes); 3098c2ecf20Sopenharmony_ci err = tpm_transmit_cmd(chip, &buf, 3108c2ecf20Sopenharmony_ci offsetof(struct tpm2_get_random_out, 3118c2ecf20Sopenharmony_ci buffer), 3128c2ecf20Sopenharmony_ci "attempting get random"); 3138c2ecf20Sopenharmony_ci if (err) { 3148c2ecf20Sopenharmony_ci if (err > 0) 3158c2ecf20Sopenharmony_ci err = -EIO; 3168c2ecf20Sopenharmony_ci goto out; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci out = (struct tpm2_get_random_out *) 3208c2ecf20Sopenharmony_ci &buf.data[TPM_HEADER_SIZE]; 3218c2ecf20Sopenharmony_ci recd = min_t(u32, be16_to_cpu(out->size), num_bytes); 3228c2ecf20Sopenharmony_ci if (tpm_buf_length(&buf) < 3238c2ecf20Sopenharmony_ci TPM_HEADER_SIZE + 3248c2ecf20Sopenharmony_ci offsetof(struct tpm2_get_random_out, buffer) + 3258c2ecf20Sopenharmony_ci recd) { 3268c2ecf20Sopenharmony_ci err = -EFAULT; 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci memcpy(dest_ptr, out->buffer, recd); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci dest_ptr += recd; 3328c2ecf20Sopenharmony_ci total += recd; 3338c2ecf20Sopenharmony_ci num_bytes -= recd; 3348c2ecf20Sopenharmony_ci } while (retries-- && total < max); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 3378c2ecf20Sopenharmony_ci return total ? total : -EIO; 3388c2ecf20Sopenharmony_ciout: 3398c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 3408c2ecf20Sopenharmony_ci return err; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * tpm2_flush_context() - execute a TPM2_FlushContext command 3458c2ecf20Sopenharmony_ci * @chip: TPM chip to use 3468c2ecf20Sopenharmony_ci * @handle: context handle 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_civoid tpm2_flush_context(struct tpm_chip *chip, u32 handle) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct tpm_buf buf; 3518c2ecf20Sopenharmony_ci int rc; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); 3548c2ecf20Sopenharmony_ci if (rc) { 3558c2ecf20Sopenharmony_ci dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n", 3568c2ecf20Sopenharmony_ci handle); 3578c2ecf20Sopenharmony_ci return; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, handle); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci tpm_transmit_cmd(chip, &buf, 0, "flushing context"); 3638c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm2_flush_context); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistruct tpm2_get_cap_out { 3688c2ecf20Sopenharmony_ci u8 more_data; 3698c2ecf20Sopenharmony_ci __be32 subcap_id; 3708c2ecf20Sopenharmony_ci __be32 property_cnt; 3718c2ecf20Sopenharmony_ci __be32 property_id; 3728c2ecf20Sopenharmony_ci __be32 value; 3738c2ecf20Sopenharmony_ci} __packed; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/** 3768c2ecf20Sopenharmony_ci * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property 3778c2ecf20Sopenharmony_ci * @chip: a &tpm_chip instance 3788c2ecf20Sopenharmony_ci * @property_id: property ID. 3798c2ecf20Sopenharmony_ci * @value: output variable. 3808c2ecf20Sopenharmony_ci * @desc: passed to tpm_transmit_cmd() 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * Return: 3838c2ecf20Sopenharmony_ci * 0 on success, 3848c2ecf20Sopenharmony_ci * -errno or a TPM return code otherwise 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_cissize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, 3878c2ecf20Sopenharmony_ci const char *desc) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct tpm2_get_cap_out *out; 3908c2ecf20Sopenharmony_ci struct tpm_buf buf; 3918c2ecf20Sopenharmony_ci int rc; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); 3948c2ecf20Sopenharmony_ci if (rc) 3958c2ecf20Sopenharmony_ci return rc; 3968c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); 3978c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, property_id); 3988c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, 1); 3998c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, NULL); 4008c2ecf20Sopenharmony_ci if (!rc) { 4018c2ecf20Sopenharmony_ci out = (struct tpm2_get_cap_out *) 4028c2ecf20Sopenharmony_ci &buf.data[TPM_HEADER_SIZE]; 4038c2ecf20Sopenharmony_ci /* 4048c2ecf20Sopenharmony_ci * To prevent failing boot up of some systems, Infineon TPM2.0 4058c2ecf20Sopenharmony_ci * returns SUCCESS on TPM2_Startup in field upgrade mode. Also 4068c2ecf20Sopenharmony_ci * the TPM2_Getcapability command returns a zero length list 4078c2ecf20Sopenharmony_ci * in field upgrade mode. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci if (be32_to_cpu(out->property_cnt) > 0) 4108c2ecf20Sopenharmony_ci *value = be32_to_cpu(out->value); 4118c2ecf20Sopenharmony_ci else 4128c2ecf20Sopenharmony_ci rc = -ENODATA; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 4158c2ecf20Sopenharmony_ci return rc; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/** 4208c2ecf20Sopenharmony_ci * tpm2_shutdown() - send a TPM shutdown command 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * Sends a TPM shutdown command. The shutdown command is used in call 4238c2ecf20Sopenharmony_ci * sites where the system is going down. If it fails, there is not much 4248c2ecf20Sopenharmony_ci * that can be done except print an error message. 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * @chip: a &tpm_chip instance 4278c2ecf20Sopenharmony_ci * @shutdown_type: TPM_SU_CLEAR or TPM_SU_STATE. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_civoid tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct tpm_buf buf; 4328c2ecf20Sopenharmony_ci int rc; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN); 4358c2ecf20Sopenharmony_ci if (rc) 4368c2ecf20Sopenharmony_ci return; 4378c2ecf20Sopenharmony_ci tpm_buf_append_u16(&buf, shutdown_type); 4388c2ecf20Sopenharmony_ci tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM"); 4398c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/** 4438c2ecf20Sopenharmony_ci * tpm2_do_selftest() - ensure that all self tests have passed 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * @chip: TPM chip to use 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * Return: Same as with tpm_transmit_cmd. 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * The TPM can either run all self tests synchronously and then return 4508c2ecf20Sopenharmony_ci * RC_SUCCESS once all tests were successful. Or it can choose to run the tests 4518c2ecf20Sopenharmony_ci * asynchronously and return RC_TESTING immediately while the self tests still 4528c2ecf20Sopenharmony_ci * execute in the background. This function handles both cases and waits until 4538c2ecf20Sopenharmony_ci * all tests have completed. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_cistatic int tpm2_do_selftest(struct tpm_chip *chip) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct tpm_buf buf; 4588c2ecf20Sopenharmony_ci int full; 4598c2ecf20Sopenharmony_ci int rc; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci for (full = 0; full < 2; full++) { 4628c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST); 4638c2ecf20Sopenharmony_ci if (rc) 4648c2ecf20Sopenharmony_ci return rc; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci tpm_buf_append_u8(&buf, full); 4678c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, 4688c2ecf20Sopenharmony_ci "attempting the self test"); 4698c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (rc == TPM2_RC_TESTING) 4728c2ecf20Sopenharmony_ci rc = TPM2_RC_SUCCESS; 4738c2ecf20Sopenharmony_ci if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS) 4748c2ecf20Sopenharmony_ci return rc; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return rc; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci/** 4818c2ecf20Sopenharmony_ci * tpm2_probe() - probe for the TPM 2.0 protocol 4828c2ecf20Sopenharmony_ci * @chip: a &tpm_chip instance 4838c2ecf20Sopenharmony_ci * 4848c2ecf20Sopenharmony_ci * Send an idempotent TPM 2.0 command and see whether there is TPM2 chip in the 4858c2ecf20Sopenharmony_ci * other end based on the response tag. The flag TPM_CHIP_FLAG_TPM2 is set by 4868c2ecf20Sopenharmony_ci * this function if this is the case. 4878c2ecf20Sopenharmony_ci * 4888c2ecf20Sopenharmony_ci * Return: 4898c2ecf20Sopenharmony_ci * 0 on success, 4908c2ecf20Sopenharmony_ci * -errno otherwise 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ciint tpm2_probe(struct tpm_chip *chip) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct tpm_header *out; 4958c2ecf20Sopenharmony_ci struct tpm_buf buf; 4968c2ecf20Sopenharmony_ci int rc; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); 4998c2ecf20Sopenharmony_ci if (rc) 5008c2ecf20Sopenharmony_ci return rc; 5018c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); 5028c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS); 5038c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, 1); 5048c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, NULL); 5058c2ecf20Sopenharmony_ci /* We ignore TPM return codes on purpose. */ 5068c2ecf20Sopenharmony_ci if (rc >= 0) { 5078c2ecf20Sopenharmony_ci out = (struct tpm_header *)buf.data; 5088c2ecf20Sopenharmony_ci if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS) 5098c2ecf20Sopenharmony_ci chip->flags |= TPM_CHIP_FLAG_TPM2; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm2_probe); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct tpm_bank_info *bank = chip->allocated_banks + bank_index; 5198c2ecf20Sopenharmony_ci struct tpm_digest digest = { .alg_id = bank->alg_id }; 5208c2ecf20Sopenharmony_ci int i; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* 5238c2ecf20Sopenharmony_ci * Avoid unnecessary PCR read operations to reduce overhead 5248c2ecf20Sopenharmony_ci * and obtain identifiers of the crypto subsystem. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { 5278c2ecf20Sopenharmony_ci enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (bank->alg_id != tpm2_hash_map[i].tpm_id) 5308c2ecf20Sopenharmony_ci continue; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci bank->digest_size = hash_digest_size[crypto_algo]; 5338c2ecf20Sopenharmony_ci bank->crypto_id = crypto_algo; 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci bank->crypto_id = HASH_ALGO__LAST; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistruct tpm2_pcr_selection { 5438c2ecf20Sopenharmony_ci __be16 hash_alg; 5448c2ecf20Sopenharmony_ci u8 size_of_select; 5458c2ecf20Sopenharmony_ci u8 pcr_select[3]; 5468c2ecf20Sopenharmony_ci} __packed; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cissize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct tpm2_pcr_selection pcr_selection; 5518c2ecf20Sopenharmony_ci struct tpm_buf buf; 5528c2ecf20Sopenharmony_ci void *marker; 5538c2ecf20Sopenharmony_ci void *end; 5548c2ecf20Sopenharmony_ci void *pcr_select_offset; 5558c2ecf20Sopenharmony_ci u32 sizeof_pcr_selection; 5568c2ecf20Sopenharmony_ci u32 nr_possible_banks; 5578c2ecf20Sopenharmony_ci u32 nr_alloc_banks = 0; 5588c2ecf20Sopenharmony_ci u16 hash_alg; 5598c2ecf20Sopenharmony_ci u32 rsp_len; 5608c2ecf20Sopenharmony_ci int rc; 5618c2ecf20Sopenharmony_ci int i = 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); 5648c2ecf20Sopenharmony_ci if (rc) 5658c2ecf20Sopenharmony_ci return rc; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, TPM2_CAP_PCRS); 5688c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, 0); 5698c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, 1); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation"); 5728c2ecf20Sopenharmony_ci if (rc) 5738c2ecf20Sopenharmony_ci goto out; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci nr_possible_banks = be32_to_cpup( 5768c2ecf20Sopenharmony_ci (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci chip->allocated_banks = kcalloc(nr_possible_banks, 5798c2ecf20Sopenharmony_ci sizeof(*chip->allocated_banks), 5808c2ecf20Sopenharmony_ci GFP_KERNEL); 5818c2ecf20Sopenharmony_ci if (!chip->allocated_banks) { 5828c2ecf20Sopenharmony_ci rc = -ENOMEM; 5838c2ecf20Sopenharmony_ci goto out; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci marker = &buf.data[TPM_HEADER_SIZE + 9]; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci rsp_len = be32_to_cpup((__be32 *)&buf.data[2]); 5898c2ecf20Sopenharmony_ci end = &buf.data[rsp_len]; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci for (i = 0; i < nr_possible_banks; i++) { 5928c2ecf20Sopenharmony_ci pcr_select_offset = marker + 5938c2ecf20Sopenharmony_ci offsetof(struct tpm2_pcr_selection, size_of_select); 5948c2ecf20Sopenharmony_ci if (pcr_select_offset >= end) { 5958c2ecf20Sopenharmony_ci rc = -EFAULT; 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci memcpy(&pcr_selection, marker, sizeof(pcr_selection)); 6008c2ecf20Sopenharmony_ci hash_alg = be16_to_cpu(pcr_selection.hash_alg); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0, 6038c2ecf20Sopenharmony_ci pcr_selection.size_of_select); 6048c2ecf20Sopenharmony_ci if (pcr_select_offset) { 6058c2ecf20Sopenharmony_ci chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci rc = tpm2_init_bank_info(chip, nr_alloc_banks); 6088c2ecf20Sopenharmony_ci if (rc < 0) 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci nr_alloc_banks++; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + 6158c2ecf20Sopenharmony_ci sizeof(pcr_selection.size_of_select) + 6168c2ecf20Sopenharmony_ci pcr_selection.size_of_select; 6178c2ecf20Sopenharmony_ci marker = marker + sizeof_pcr_selection; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci chip->nr_allocated_banks = nr_alloc_banks; 6218c2ecf20Sopenharmony_ciout: 6228c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return rc; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ciint tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct tpm_buf buf; 6308c2ecf20Sopenharmony_ci u32 nr_commands; 6318c2ecf20Sopenharmony_ci __be32 *attrs; 6328c2ecf20Sopenharmony_ci u32 cc; 6338c2ecf20Sopenharmony_ci int i; 6348c2ecf20Sopenharmony_ci int rc; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL); 6378c2ecf20Sopenharmony_ci if (rc) 6388c2ecf20Sopenharmony_ci goto out; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (nr_commands > 0xFFFFF) { 6418c2ecf20Sopenharmony_ci rc = -EFAULT; 6428c2ecf20Sopenharmony_ci goto out; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands, 6468c2ecf20Sopenharmony_ci GFP_KERNEL); 6478c2ecf20Sopenharmony_ci if (!chip->cc_attrs_tbl) { 6488c2ecf20Sopenharmony_ci rc = -ENOMEM; 6498c2ecf20Sopenharmony_ci goto out; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); 6538c2ecf20Sopenharmony_ci if (rc) 6548c2ecf20Sopenharmony_ci goto out; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS); 6578c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, TPM2_CC_FIRST); 6588c2ecf20Sopenharmony_ci tpm_buf_append_u32(&buf, nr_commands); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL); 6618c2ecf20Sopenharmony_ci if (rc) { 6628c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 6638c2ecf20Sopenharmony_ci goto out; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (nr_commands != 6678c2ecf20Sopenharmony_ci be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) { 6688c2ecf20Sopenharmony_ci rc = -EFAULT; 6698c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 6708c2ecf20Sopenharmony_ci goto out; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci chip->nr_commands = nr_commands; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9]; 6768c2ecf20Sopenharmony_ci for (i = 0; i < nr_commands; i++, attrs++) { 6778c2ecf20Sopenharmony_ci chip->cc_attrs_tbl[i] = be32_to_cpup(attrs); 6788c2ecf20Sopenharmony_ci cc = chip->cc_attrs_tbl[i] & 0xFFFF; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) { 6818c2ecf20Sopenharmony_ci chip->cc_attrs_tbl[i] &= 6828c2ecf20Sopenharmony_ci ~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES); 6838c2ecf20Sopenharmony_ci chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ciout: 6908c2ecf20Sopenharmony_ci if (rc > 0) 6918c2ecf20Sopenharmony_ci rc = -ENODEV; 6928c2ecf20Sopenharmony_ci return rc; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/** 6978c2ecf20Sopenharmony_ci * tpm2_startup - turn on the TPM 6988c2ecf20Sopenharmony_ci * @chip: TPM chip to use 6998c2ecf20Sopenharmony_ci * 7008c2ecf20Sopenharmony_ci * Normally the firmware should start the TPM. This function is provided as a 7018c2ecf20Sopenharmony_ci * workaround if this does not happen. A legal case for this could be for 7028c2ecf20Sopenharmony_ci * example when a TPM emulator is used. 7038c2ecf20Sopenharmony_ci * 7048c2ecf20Sopenharmony_ci * Return: same as tpm_transmit_cmd() 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic int tpm2_startup(struct tpm_chip *chip) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct tpm_buf buf; 7108c2ecf20Sopenharmony_ci int rc; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci dev_info(&chip->dev, "starting up the TPM manually\n"); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP); 7158c2ecf20Sopenharmony_ci if (rc < 0) 7168c2ecf20Sopenharmony_ci return rc; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci tpm_buf_append_u16(&buf, TPM2_SU_CLEAR); 7198c2ecf20Sopenharmony_ci rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM"); 7208c2ecf20Sopenharmony_ci tpm_buf_destroy(&buf); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return rc; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci/** 7268c2ecf20Sopenharmony_ci * tpm2_auto_startup - Perform the standard automatic TPM initialization 7278c2ecf20Sopenharmony_ci * sequence 7288c2ecf20Sopenharmony_ci * @chip: TPM chip to use 7298c2ecf20Sopenharmony_ci * 7308c2ecf20Sopenharmony_ci * Returns 0 on success, < 0 in case of fatal error. 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ciint tpm2_auto_startup(struct tpm_chip *chip) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci int rc; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci rc = tpm2_get_timeouts(chip); 7378c2ecf20Sopenharmony_ci if (rc) 7388c2ecf20Sopenharmony_ci goto out; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci rc = tpm2_do_selftest(chip); 7418c2ecf20Sopenharmony_ci if (rc && rc != TPM2_RC_INITIALIZE) 7428c2ecf20Sopenharmony_ci goto out; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (rc == TPM2_RC_INITIALIZE) { 7458c2ecf20Sopenharmony_ci rc = tpm2_startup(chip); 7468c2ecf20Sopenharmony_ci if (rc) 7478c2ecf20Sopenharmony_ci goto out; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci rc = tpm2_do_selftest(chip); 7508c2ecf20Sopenharmony_ci if (rc) 7518c2ecf20Sopenharmony_ci goto out; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci rc = tpm2_get_cc_attrs_tbl(chip); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ciout: 7578c2ecf20Sopenharmony_ci if (rc > 0) 7588c2ecf20Sopenharmony_ci rc = -ENODEV; 7598c2ecf20Sopenharmony_ci return rc; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ciint tpm2_find_cc(struct tpm_chip *chip, u32 cc) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci int i; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci for (i = 0; i < chip->nr_commands; i++) 7678c2ecf20Sopenharmony_ci if (cc == (chip->cc_attrs_tbl[i] & GENMASK(15, 0))) 7688c2ecf20Sopenharmony_ci return i; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return -1; 7718c2ecf20Sopenharmony_ci} 772