1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2000a07b0SJason Gunthorpe /* 3000a07b0SJason Gunthorpe * Copyright (C) 2004 IBM Corporation 4000a07b0SJason Gunthorpe * Authors: 5000a07b0SJason Gunthorpe * Leendert van Doorn <leendert@watson.ibm.com> 6000a07b0SJason Gunthorpe * Dave Safford <safford@watson.ibm.com> 7000a07b0SJason Gunthorpe * Reiner Sailer <sailer@watson.ibm.com> 8000a07b0SJason Gunthorpe * Kylene Hall <kjhall@us.ibm.com> 9000a07b0SJason Gunthorpe * 101e3b73a9SJason Gunthorpe * Copyright (C) 2013 Obsidian Research Corp 111e3b73a9SJason Gunthorpe * Jason Gunthorpe <jgunthorpe@obsidianresearch.com> 121e3b73a9SJason Gunthorpe * 13000a07b0SJason Gunthorpe * sysfs filesystem inspection interface to the TPM 14000a07b0SJason Gunthorpe */ 15000a07b0SJason Gunthorpe #include <linux/device.h> 16000a07b0SJason Gunthorpe #include "tpm.h" 17000a07b0SJason Gunthorpe 18da379f3cSJarkko Sakkinen struct tpm_readpubek_out { 19da379f3cSJarkko Sakkinen u8 algorithm[4]; 20da379f3cSJarkko Sakkinen u8 encscheme[2]; 21da379f3cSJarkko Sakkinen u8 sigscheme[2]; 22da379f3cSJarkko Sakkinen __be32 paramsize; 23da379f3cSJarkko Sakkinen u8 parameters[12]; 24da379f3cSJarkko Sakkinen __be32 keysize; 25da379f3cSJarkko Sakkinen u8 modulus[256]; 26da379f3cSJarkko Sakkinen u8 checksum[20]; 27da379f3cSJarkko Sakkinen } __packed; 28da379f3cSJarkko Sakkinen 29c659af78SStefan Berger #define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256) 30a69faebfSRoberto Sassu #define TPM_ORD_READPUBEK 124 31da379f3cSJarkko Sakkinen 321e3b73a9SJason Gunthorpe static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, 33000a07b0SJason Gunthorpe char *buf) 34000a07b0SJason Gunthorpe { 35da379f3cSJarkko Sakkinen struct tpm_buf tpm_buf; 36da379f3cSJarkko Sakkinen struct tpm_readpubek_out *out; 37da379f3cSJarkko Sakkinen int i; 38000a07b0SJason Gunthorpe char *str = buf; 39062807f2SJason Gunthorpe struct tpm_chip *chip = to_tpm_chip(dev); 40da379f3cSJarkko Sakkinen char anti_replay[20]; 41000a07b0SJason Gunthorpe 42da379f3cSJarkko Sakkinen memset(&anti_replay, 0, sizeof(anti_replay)); 4313b47cfcSJarkko Sakkinen 442677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 45c6286100SJarkko Sakkinen return 0; 46da379f3cSJarkko Sakkinen 472677ca98SJarkko Sakkinen if (tpm_buf_init(&tpm_buf, TPM_TAG_RQU_COMMAND, TPM_ORD_READPUBEK)) 482677ca98SJarkko Sakkinen goto out_ops; 492677ca98SJarkko Sakkinen 50da379f3cSJarkko Sakkinen tpm_buf_append(&tpm_buf, anti_replay, sizeof(anti_replay)); 51da379f3cSJarkko Sakkinen 522677ca98SJarkko Sakkinen if (tpm_transmit_cmd(chip, &tpm_buf, READ_PUBEK_RESULT_MIN_BODY_SIZE, 5347a6c28bSJarkko Sakkinen "attempting to read the PUBEK")) 542677ca98SJarkko Sakkinen goto out_buf; 55000a07b0SJason Gunthorpe 56da379f3cSJarkko Sakkinen out = (struct tpm_readpubek_out *)&tpm_buf.data[10]; 57000a07b0SJason Gunthorpe str += 58000a07b0SJason Gunthorpe sprintf(str, 59e08c6d3bSAndy Shevchenko "Algorithm: %4ph\n" 60e08c6d3bSAndy Shevchenko "Encscheme: %2ph\n" 61e08c6d3bSAndy Shevchenko "Sigscheme: %2ph\n" 62e08c6d3bSAndy Shevchenko "Parameters: %12ph\n" 63000a07b0SJason Gunthorpe "Modulus length: %d\n" 64000a07b0SJason Gunthorpe "Modulus:\n", 65e08c6d3bSAndy Shevchenko out->algorithm, 66e08c6d3bSAndy Shevchenko out->encscheme, 67e08c6d3bSAndy Shevchenko out->sigscheme, 68e08c6d3bSAndy Shevchenko out->parameters, 69da379f3cSJarkko Sakkinen be32_to_cpu(out->keysize)); 70000a07b0SJason Gunthorpe 71e08c6d3bSAndy Shevchenko for (i = 0; i < 256; i += 16) 72e08c6d3bSAndy Shevchenko str += sprintf(str, "%16ph\n", &out->modulus[i]); 73da379f3cSJarkko Sakkinen 742677ca98SJarkko Sakkinen out_buf: 75da379f3cSJarkko Sakkinen tpm_buf_destroy(&tpm_buf); 762677ca98SJarkko Sakkinen out_ops: 772677ca98SJarkko Sakkinen tpm_put_ops(chip); 782677ca98SJarkko Sakkinen return str - buf; 79000a07b0SJason Gunthorpe } 801e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(pubek); 81000a07b0SJason Gunthorpe 821e3b73a9SJason Gunthorpe static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, 83000a07b0SJason Gunthorpe char *buf) 84000a07b0SJason Gunthorpe { 85000a07b0SJason Gunthorpe cap_t cap; 86000a07b0SJason Gunthorpe u8 digest[TPM_DIGEST_SIZE]; 8795adc6b4STomas Winkler u32 i, j, num_pcrs; 88000a07b0SJason Gunthorpe char *str = buf; 89062807f2SJason Gunthorpe struct tpm_chip *chip = to_tpm_chip(dev); 90000a07b0SJason Gunthorpe 912677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 922677ca98SJarkko Sakkinen return 0; 932677ca98SJarkko Sakkinen 9441484674SJarkko Sakkinen if (tpm1_getcap(chip, TPM_CAP_PROP_PCR, &cap, 95c659af78SStefan Berger "attempting to determine the number of PCRS", 962677ca98SJarkko Sakkinen sizeof(cap.num_pcrs))) { 972677ca98SJarkko Sakkinen tpm_put_ops(chip); 98000a07b0SJason Gunthorpe return 0; 992677ca98SJarkko Sakkinen } 100000a07b0SJason Gunthorpe 101000a07b0SJason Gunthorpe num_pcrs = be32_to_cpu(cap.num_pcrs); 102000a07b0SJason Gunthorpe for (i = 0; i < num_pcrs; i++) { 10341484674SJarkko Sakkinen if (tpm1_pcr_read(chip, i, digest)) { 10441484674SJarkko Sakkinen str = buf; 105000a07b0SJason Gunthorpe break; 10641484674SJarkko Sakkinen } 107000a07b0SJason Gunthorpe str += sprintf(str, "PCR-%02d: ", i); 108000a07b0SJason Gunthorpe for (j = 0; j < TPM_DIGEST_SIZE; j++) 109000a07b0SJason Gunthorpe str += sprintf(str, "%02X ", digest[j]); 110000a07b0SJason Gunthorpe str += sprintf(str, "\n"); 111000a07b0SJason Gunthorpe } 1122677ca98SJarkko Sakkinen tpm_put_ops(chip); 113000a07b0SJason Gunthorpe return str - buf; 114000a07b0SJason Gunthorpe } 1151e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(pcrs); 116000a07b0SJason Gunthorpe 1171e3b73a9SJason Gunthorpe static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, 118000a07b0SJason Gunthorpe char *buf) 119000a07b0SJason Gunthorpe { 1202677ca98SJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 1212677ca98SJarkko Sakkinen ssize_t rc = 0; 122000a07b0SJason Gunthorpe cap_t cap; 123000a07b0SJason Gunthorpe 1242677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 125000a07b0SJason Gunthorpe return 0; 126000a07b0SJason Gunthorpe 1272677ca98SJarkko Sakkinen if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap, 1282677ca98SJarkko Sakkinen "attempting to determine the permanent enabled state", 1292677ca98SJarkko Sakkinen sizeof(cap.perm_flags))) 1302677ca98SJarkko Sakkinen goto out_ops; 1312677ca98SJarkko Sakkinen 132000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); 1332677ca98SJarkko Sakkinen out_ops: 1342677ca98SJarkko Sakkinen tpm_put_ops(chip); 135000a07b0SJason Gunthorpe return rc; 136000a07b0SJason Gunthorpe } 1371e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(enabled); 138000a07b0SJason Gunthorpe 1395f64822dSFengguang Wu static ssize_t active_show(struct device *dev, struct device_attribute *attr, 140000a07b0SJason Gunthorpe char *buf) 141000a07b0SJason Gunthorpe { 1422677ca98SJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 1432677ca98SJarkko Sakkinen ssize_t rc = 0; 144000a07b0SJason Gunthorpe cap_t cap; 145000a07b0SJason Gunthorpe 1462677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 147000a07b0SJason Gunthorpe return 0; 148000a07b0SJason Gunthorpe 1492677ca98SJarkko Sakkinen if (tpm1_getcap(chip, TPM_CAP_FLAG_PERM, &cap, 1502677ca98SJarkko Sakkinen "attempting to determine the permanent active state", 1512677ca98SJarkko Sakkinen sizeof(cap.perm_flags))) 1522677ca98SJarkko Sakkinen goto out_ops; 1532677ca98SJarkko Sakkinen 154000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); 1552677ca98SJarkko Sakkinen out_ops: 1562677ca98SJarkko Sakkinen tpm_put_ops(chip); 157000a07b0SJason Gunthorpe return rc; 158000a07b0SJason Gunthorpe } 1591e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(active); 160000a07b0SJason Gunthorpe 1611e3b73a9SJason Gunthorpe static ssize_t owned_show(struct device *dev, struct device_attribute *attr, 162000a07b0SJason Gunthorpe char *buf) 163000a07b0SJason Gunthorpe { 1642677ca98SJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 1652677ca98SJarkko Sakkinen ssize_t rc = 0; 166000a07b0SJason Gunthorpe cap_t cap; 167000a07b0SJason Gunthorpe 1682677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 169000a07b0SJason Gunthorpe return 0; 170000a07b0SJason Gunthorpe 1712677ca98SJarkko Sakkinen if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, 1722677ca98SJarkko Sakkinen "attempting to determine the owner state", 1732677ca98SJarkko Sakkinen sizeof(cap.owned))) 1742677ca98SJarkko Sakkinen goto out_ops; 1752677ca98SJarkko Sakkinen 176000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", cap.owned); 1772677ca98SJarkko Sakkinen out_ops: 1782677ca98SJarkko Sakkinen tpm_put_ops(chip); 179000a07b0SJason Gunthorpe return rc; 180000a07b0SJason Gunthorpe } 1811e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(owned); 182000a07b0SJason Gunthorpe 1831e3b73a9SJason Gunthorpe static ssize_t temp_deactivated_show(struct device *dev, 184000a07b0SJason Gunthorpe struct device_attribute *attr, char *buf) 185000a07b0SJason Gunthorpe { 1862677ca98SJarkko Sakkinen struct tpm_chip *chip = to_tpm_chip(dev); 1872677ca98SJarkko Sakkinen ssize_t rc = 0; 188000a07b0SJason Gunthorpe cap_t cap; 189000a07b0SJason Gunthorpe 1902677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 191000a07b0SJason Gunthorpe return 0; 192000a07b0SJason Gunthorpe 1932677ca98SJarkko Sakkinen if (tpm1_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, 1942677ca98SJarkko Sakkinen "attempting to determine the temporary state", 1952677ca98SJarkko Sakkinen sizeof(cap.stclear_flags))) 1962677ca98SJarkko Sakkinen goto out_ops; 1972677ca98SJarkko Sakkinen 198000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); 1992677ca98SJarkko Sakkinen out_ops: 2002677ca98SJarkko Sakkinen tpm_put_ops(chip); 201000a07b0SJason Gunthorpe return rc; 202000a07b0SJason Gunthorpe } 2031e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(temp_deactivated); 204000a07b0SJason Gunthorpe 2051e3b73a9SJason Gunthorpe static ssize_t caps_show(struct device *dev, struct device_attribute *attr, 206000a07b0SJason Gunthorpe char *buf) 207000a07b0SJason Gunthorpe { 208062807f2SJason Gunthorpe struct tpm_chip *chip = to_tpm_chip(dev); 209f2f5820eSJarkko Sakkinen struct tpm1_version *version; 2102677ca98SJarkko Sakkinen ssize_t rc = 0; 211000a07b0SJason Gunthorpe char *str = buf; 2122677ca98SJarkko Sakkinen cap_t cap; 213000a07b0SJason Gunthorpe 2142677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 215000a07b0SJason Gunthorpe return 0; 2162677ca98SJarkko Sakkinen 2172677ca98SJarkko Sakkinen if (tpm1_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, 2182677ca98SJarkko Sakkinen "attempting to determine the manufacturer", 2192677ca98SJarkko Sakkinen sizeof(cap.manufacturer_id))) 2202677ca98SJarkko Sakkinen goto out_ops; 2212677ca98SJarkko Sakkinen 222000a07b0SJason Gunthorpe str += sprintf(str, "Manufacturer: 0x%x\n", 223000a07b0SJason Gunthorpe be32_to_cpu(cap.manufacturer_id)); 224000a07b0SJason Gunthorpe 225f2f5820eSJarkko Sakkinen /* TPM 1.2 */ 226f2f5820eSJarkko Sakkinen if (!tpm1_getcap(chip, TPM_CAP_VERSION_1_2, &cap, 227c659af78SStefan Berger "attempting to determine the 1.2 version", 228f2f5820eSJarkko Sakkinen sizeof(cap.version2))) { 229f2f5820eSJarkko Sakkinen version = &cap.version2.version; 230f2f5820eSJarkko Sakkinen goto out_print; 231f2f5820eSJarkko Sakkinen } 232f2f5820eSJarkko Sakkinen 233f2f5820eSJarkko Sakkinen /* TPM 1.1 */ 2342677ca98SJarkko Sakkinen if (tpm1_getcap(chip, TPM_CAP_VERSION_1_1, &cap, 235c659af78SStefan Berger "attempting to determine the 1.1 version", 236f2f5820eSJarkko Sakkinen sizeof(cap.version1))) { 2372677ca98SJarkko Sakkinen goto out_ops; 238f2f5820eSJarkko Sakkinen } 239f2f5820eSJarkko Sakkinen 240f2f5820eSJarkko Sakkinen version = &cap.version1; 241f2f5820eSJarkko Sakkinen 242f2f5820eSJarkko Sakkinen out_print: 243000a07b0SJason Gunthorpe str += sprintf(str, 244000a07b0SJason Gunthorpe "TCG version: %d.%d\nFirmware version: %d.%d\n", 245f2f5820eSJarkko Sakkinen version->major, version->minor, 246f2f5820eSJarkko Sakkinen version->rev_major, version->rev_minor); 247f2f5820eSJarkko Sakkinen 2482677ca98SJarkko Sakkinen rc = str - buf; 249f2f5820eSJarkko Sakkinen 2502677ca98SJarkko Sakkinen out_ops: 2512677ca98SJarkko Sakkinen tpm_put_ops(chip); 2522677ca98SJarkko Sakkinen return rc; 253000a07b0SJason Gunthorpe } 2541e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(caps); 255000a07b0SJason Gunthorpe 2561e3b73a9SJason Gunthorpe static ssize_t cancel_store(struct device *dev, struct device_attribute *attr, 257000a07b0SJason Gunthorpe const char *buf, size_t count) 258000a07b0SJason Gunthorpe { 259062807f2SJason Gunthorpe struct tpm_chip *chip = to_tpm_chip(dev); 2602677ca98SJarkko Sakkinen 2612677ca98SJarkko Sakkinen if (tpm_try_get_ops(chip)) 262000a07b0SJason Gunthorpe return 0; 263000a07b0SJason Gunthorpe 2645f82e9f0SJason Gunthorpe chip->ops->cancel(chip); 2652677ca98SJarkko Sakkinen tpm_put_ops(chip); 266000a07b0SJason Gunthorpe return count; 267000a07b0SJason Gunthorpe } 2681e3b73a9SJason Gunthorpe static DEVICE_ATTR_WO(cancel); 269000a07b0SJason Gunthorpe 2701e3b73a9SJason Gunthorpe static ssize_t durations_show(struct device *dev, struct device_attribute *attr, 271000a07b0SJason Gunthorpe char *buf) 272000a07b0SJason Gunthorpe { 273062807f2SJason Gunthorpe struct tpm_chip *chip = to_tpm_chip(dev); 274000a07b0SJason Gunthorpe 275af782f33SChristophe Ricard if (chip->duration[TPM_LONG] == 0) 276000a07b0SJason Gunthorpe return 0; 277000a07b0SJason Gunthorpe 278000a07b0SJason Gunthorpe return sprintf(buf, "%d %d %d [%s]\n", 279af782f33SChristophe Ricard jiffies_to_usecs(chip->duration[TPM_SHORT]), 280af782f33SChristophe Ricard jiffies_to_usecs(chip->duration[TPM_MEDIUM]), 281af782f33SChristophe Ricard jiffies_to_usecs(chip->duration[TPM_LONG]), 282af782f33SChristophe Ricard chip->duration_adjusted 283000a07b0SJason Gunthorpe ? "adjusted" : "original"); 284000a07b0SJason Gunthorpe } 2851e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(durations); 286000a07b0SJason Gunthorpe 2871e3b73a9SJason Gunthorpe static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr, 288000a07b0SJason Gunthorpe char *buf) 289000a07b0SJason Gunthorpe { 290062807f2SJason Gunthorpe struct tpm_chip *chip = to_tpm_chip(dev); 291000a07b0SJason Gunthorpe 292000a07b0SJason Gunthorpe return sprintf(buf, "%d %d %d %d [%s]\n", 293af782f33SChristophe Ricard jiffies_to_usecs(chip->timeout_a), 294af782f33SChristophe Ricard jiffies_to_usecs(chip->timeout_b), 295af782f33SChristophe Ricard jiffies_to_usecs(chip->timeout_c), 296af782f33SChristophe Ricard jiffies_to_usecs(chip->timeout_d), 297af782f33SChristophe Ricard chip->timeout_adjusted 298000a07b0SJason Gunthorpe ? "adjusted" : "original"); 299000a07b0SJason Gunthorpe } 3001e3b73a9SJason Gunthorpe static DEVICE_ATTR_RO(timeouts); 3011e3b73a9SJason Gunthorpe 3027084eddfSJerry Snitselaar static ssize_t tpm_version_major_show(struct device *dev, 3037084eddfSJerry Snitselaar struct device_attribute *attr, char *buf) 3047084eddfSJerry Snitselaar { 3057084eddfSJerry Snitselaar struct tpm_chip *chip = to_tpm_chip(dev); 3067084eddfSJerry Snitselaar 3077084eddfSJerry Snitselaar return sprintf(buf, "%s\n", chip->flags & TPM_CHIP_FLAG_TPM2 3087084eddfSJerry Snitselaar ? "2" : "1"); 3097084eddfSJerry Snitselaar } 3107084eddfSJerry Snitselaar static DEVICE_ATTR_RO(tpm_version_major); 3117084eddfSJerry Snitselaar 3127084eddfSJerry Snitselaar static struct attribute *tpm1_dev_attrs[] = { 3131e3b73a9SJason Gunthorpe &dev_attr_pubek.attr, 3141e3b73a9SJason Gunthorpe &dev_attr_pcrs.attr, 3151e3b73a9SJason Gunthorpe &dev_attr_enabled.attr, 3161e3b73a9SJason Gunthorpe &dev_attr_active.attr, 3171e3b73a9SJason Gunthorpe &dev_attr_owned.attr, 3181e3b73a9SJason Gunthorpe &dev_attr_temp_deactivated.attr, 3191e3b73a9SJason Gunthorpe &dev_attr_caps.attr, 3201e3b73a9SJason Gunthorpe &dev_attr_cancel.attr, 3211e3b73a9SJason Gunthorpe &dev_attr_durations.attr, 3221e3b73a9SJason Gunthorpe &dev_attr_timeouts.attr, 3237084eddfSJerry Snitselaar &dev_attr_tpm_version_major.attr, 3241e3b73a9SJason Gunthorpe NULL, 3251e3b73a9SJason Gunthorpe }; 3261e3b73a9SJason Gunthorpe 3277084eddfSJerry Snitselaar static struct attribute *tpm2_dev_attrs[] = { 3287084eddfSJerry Snitselaar &dev_attr_tpm_version_major.attr, 3297084eddfSJerry Snitselaar NULL 3307084eddfSJerry Snitselaar }; 3317084eddfSJerry Snitselaar 3327084eddfSJerry Snitselaar static const struct attribute_group tpm1_dev_group = { 3337084eddfSJerry Snitselaar .attrs = tpm1_dev_attrs, 3347084eddfSJerry Snitselaar }; 3357084eddfSJerry Snitselaar 3367084eddfSJerry Snitselaar static const struct attribute_group tpm2_dev_group = { 3377084eddfSJerry Snitselaar .attrs = tpm2_dev_attrs, 3381e3b73a9SJason Gunthorpe }; 3391e3b73a9SJason Gunthorpe 340*aab73d95SJames Bottomley struct tpm_pcr_attr { 341*aab73d95SJames Bottomley int alg_id; 342*aab73d95SJames Bottomley int pcr; 343*aab73d95SJames Bottomley struct device_attribute attr; 344*aab73d95SJames Bottomley }; 345*aab73d95SJames Bottomley 346*aab73d95SJames Bottomley #define to_tpm_pcr_attr(a) container_of(a, struct tpm_pcr_attr, attr) 347*aab73d95SJames Bottomley 348*aab73d95SJames Bottomley static ssize_t pcr_value_show(struct device *dev, 349*aab73d95SJames Bottomley struct device_attribute *attr, 350*aab73d95SJames Bottomley char *buf) 351*aab73d95SJames Bottomley { 352*aab73d95SJames Bottomley struct tpm_pcr_attr *ha = to_tpm_pcr_attr(attr); 353*aab73d95SJames Bottomley struct tpm_chip *chip = to_tpm_chip(dev); 354*aab73d95SJames Bottomley struct tpm_digest digest; 355*aab73d95SJames Bottomley int i; 356*aab73d95SJames Bottomley int digest_size = 0; 357*aab73d95SJames Bottomley int rc; 358*aab73d95SJames Bottomley char *str = buf; 359*aab73d95SJames Bottomley 360*aab73d95SJames Bottomley for (i = 0; i < chip->nr_allocated_banks; i++) 361*aab73d95SJames Bottomley if (ha->alg_id == chip->allocated_banks[i].alg_id) 362*aab73d95SJames Bottomley digest_size = chip->allocated_banks[i].digest_size; 363*aab73d95SJames Bottomley /* should never happen */ 364*aab73d95SJames Bottomley if (!digest_size) 365*aab73d95SJames Bottomley return -EINVAL; 366*aab73d95SJames Bottomley 367*aab73d95SJames Bottomley digest.alg_id = ha->alg_id; 368*aab73d95SJames Bottomley rc = tpm_pcr_read(chip, ha->pcr, &digest); 369*aab73d95SJames Bottomley if (rc) 370*aab73d95SJames Bottomley return rc; 371*aab73d95SJames Bottomley for (i = 0; i < digest_size; i++) 372*aab73d95SJames Bottomley str += sprintf(str, "%02X", digest.digest[i]); 373*aab73d95SJames Bottomley str += sprintf(str, "\n"); 374*aab73d95SJames Bottomley 375*aab73d95SJames Bottomley return str - buf; 376*aab73d95SJames Bottomley } 377*aab73d95SJames Bottomley 378*aab73d95SJames Bottomley /* 379*aab73d95SJames Bottomley * The following set of defines represents all the magic to build 380*aab73d95SJames Bottomley * the per hash attribute groups for displaying each bank of PCRs. 381*aab73d95SJames Bottomley * The only slight problem with this approach is that every PCR is 382*aab73d95SJames Bottomley * hard coded to be present, so you don't know if an PCR is missing 383*aab73d95SJames Bottomley * until a cat of the file returns -EINVAL 384*aab73d95SJames Bottomley * 385*aab73d95SJames Bottomley * Also note you must ignore checkpatch warnings in this macro 386*aab73d95SJames Bottomley * code. This is deep macro magic that checkpatch.pl doesn't 387*aab73d95SJames Bottomley * understand. 388*aab73d95SJames Bottomley */ 389*aab73d95SJames Bottomley 390*aab73d95SJames Bottomley /* Note, this must match TPM2_PLATFORM_PCR which is fixed at 24. */ 391*aab73d95SJames Bottomley #define _TPM_HELPER(_alg, _hash, F) \ 392*aab73d95SJames Bottomley F(_alg, _hash, 0) \ 393*aab73d95SJames Bottomley F(_alg, _hash, 1) \ 394*aab73d95SJames Bottomley F(_alg, _hash, 2) \ 395*aab73d95SJames Bottomley F(_alg, _hash, 3) \ 396*aab73d95SJames Bottomley F(_alg, _hash, 4) \ 397*aab73d95SJames Bottomley F(_alg, _hash, 5) \ 398*aab73d95SJames Bottomley F(_alg, _hash, 6) \ 399*aab73d95SJames Bottomley F(_alg, _hash, 7) \ 400*aab73d95SJames Bottomley F(_alg, _hash, 8) \ 401*aab73d95SJames Bottomley F(_alg, _hash, 9) \ 402*aab73d95SJames Bottomley F(_alg, _hash, 10) \ 403*aab73d95SJames Bottomley F(_alg, _hash, 11) \ 404*aab73d95SJames Bottomley F(_alg, _hash, 12) \ 405*aab73d95SJames Bottomley F(_alg, _hash, 13) \ 406*aab73d95SJames Bottomley F(_alg, _hash, 14) \ 407*aab73d95SJames Bottomley F(_alg, _hash, 15) \ 408*aab73d95SJames Bottomley F(_alg, _hash, 16) \ 409*aab73d95SJames Bottomley F(_alg, _hash, 17) \ 410*aab73d95SJames Bottomley F(_alg, _hash, 18) \ 411*aab73d95SJames Bottomley F(_alg, _hash, 19) \ 412*aab73d95SJames Bottomley F(_alg, _hash, 20) \ 413*aab73d95SJames Bottomley F(_alg, _hash, 21) \ 414*aab73d95SJames Bottomley F(_alg, _hash, 22) \ 415*aab73d95SJames Bottomley F(_alg, _hash, 23) 416*aab73d95SJames Bottomley 417*aab73d95SJames Bottomley /* ignore checkpatch warning about trailing ; in macro. */ 418*aab73d95SJames Bottomley #define PCR_ATTR(_alg, _hash, _pcr) \ 419*aab73d95SJames Bottomley static struct tpm_pcr_attr dev_attr_pcr_##_hash##_##_pcr = { \ 420*aab73d95SJames Bottomley .alg_id = _alg, \ 421*aab73d95SJames Bottomley .pcr = _pcr, \ 422*aab73d95SJames Bottomley .attr = { \ 423*aab73d95SJames Bottomley .attr = { \ 424*aab73d95SJames Bottomley .name = __stringify(_pcr), \ 425*aab73d95SJames Bottomley .mode = 0444 \ 426*aab73d95SJames Bottomley }, \ 427*aab73d95SJames Bottomley .show = pcr_value_show \ 428*aab73d95SJames Bottomley } \ 429*aab73d95SJames Bottomley }; 430*aab73d95SJames Bottomley 431*aab73d95SJames Bottomley #define PCR_ATTRS(_alg, _hash) \ 432*aab73d95SJames Bottomley _TPM_HELPER(_alg, _hash, PCR_ATTR) 433*aab73d95SJames Bottomley 434*aab73d95SJames Bottomley /* ignore checkpatch warning about trailing , in macro. */ 435*aab73d95SJames Bottomley #define PCR_ATTR_VAL(_alg, _hash, _pcr) \ 436*aab73d95SJames Bottomley &dev_attr_pcr_##_hash##_##_pcr.attr.attr, 437*aab73d95SJames Bottomley 438*aab73d95SJames Bottomley #define PCR_ATTR_GROUP_ARRAY(_alg, _hash) \ 439*aab73d95SJames Bottomley static struct attribute *pcr_group_attrs_##_hash[] = { \ 440*aab73d95SJames Bottomley _TPM_HELPER(_alg, _hash, PCR_ATTR_VAL) \ 441*aab73d95SJames Bottomley NULL \ 442*aab73d95SJames Bottomley } 443*aab73d95SJames Bottomley 444*aab73d95SJames Bottomley #define PCR_ATTR_GROUP(_alg, _hash) \ 445*aab73d95SJames Bottomley static struct attribute_group pcr_group_##_hash = { \ 446*aab73d95SJames Bottomley .name = "pcr-" __stringify(_hash), \ 447*aab73d95SJames Bottomley .attrs = pcr_group_attrs_##_hash \ 448*aab73d95SJames Bottomley } 449*aab73d95SJames Bottomley 450*aab73d95SJames Bottomley #define PCR_ATTR_BUILD(_alg, _hash) \ 451*aab73d95SJames Bottomley PCR_ATTRS(_alg, _hash) \ 452*aab73d95SJames Bottomley PCR_ATTR_GROUP_ARRAY(_alg, _hash); \ 453*aab73d95SJames Bottomley PCR_ATTR_GROUP(_alg, _hash) 454*aab73d95SJames Bottomley /* 455*aab73d95SJames Bottomley * End of macro structure to build an attribute group containing 24 456*aab73d95SJames Bottomley * PCR value files for each supported hash algorithm 457*aab73d95SJames Bottomley */ 458*aab73d95SJames Bottomley 459*aab73d95SJames Bottomley /* 460*aab73d95SJames Bottomley * The next set of macros implements the cleverness for each hash to 461*aab73d95SJames Bottomley * build a static attribute group called pcr_group_<hash> which can be 462*aab73d95SJames Bottomley * added to chip->groups[]. 463*aab73d95SJames Bottomley * 464*aab73d95SJames Bottomley * The first argument is the TPM algorithm id and the second is the 465*aab73d95SJames Bottomley * hash used as both the suffix and the group name. Note: the group 466*aab73d95SJames Bottomley * name is a directory in the top level tpm class with the name 467*aab73d95SJames Bottomley * pcr-<hash>, so it must not clash with any other names already 468*aab73d95SJames Bottomley * in the sysfs directory. 469*aab73d95SJames Bottomley */ 470*aab73d95SJames Bottomley PCR_ATTR_BUILD(TPM_ALG_SHA1, sha1); 471*aab73d95SJames Bottomley PCR_ATTR_BUILD(TPM_ALG_SHA256, sha256); 472*aab73d95SJames Bottomley PCR_ATTR_BUILD(TPM_ALG_SHA384, sha384); 473*aab73d95SJames Bottomley PCR_ATTR_BUILD(TPM_ALG_SHA512, sha512); 474*aab73d95SJames Bottomley PCR_ATTR_BUILD(TPM_ALG_SM3_256, sm3); 475*aab73d95SJames Bottomley 476*aab73d95SJames Bottomley 477062807f2SJason Gunthorpe void tpm_sysfs_add_device(struct tpm_chip *chip) 4781e3b73a9SJason Gunthorpe { 479*aab73d95SJames Bottomley int i; 480*aab73d95SJames Bottomley 481062807f2SJason Gunthorpe WARN_ON(chip->groups_cnt != 0); 482*aab73d95SJames Bottomley 4837084eddfSJerry Snitselaar if (chip->flags & TPM_CHIP_FLAG_TPM2) 4847084eddfSJerry Snitselaar chip->groups[chip->groups_cnt++] = &tpm2_dev_group; 4857084eddfSJerry Snitselaar else 4867084eddfSJerry Snitselaar chip->groups[chip->groups_cnt++] = &tpm1_dev_group; 487*aab73d95SJames Bottomley 488*aab73d95SJames Bottomley /* add one group for each bank hash */ 489*aab73d95SJames Bottomley for (i = 0; i < chip->nr_allocated_banks; i++) { 490*aab73d95SJames Bottomley switch (chip->allocated_banks[i].alg_id) { 491*aab73d95SJames Bottomley case TPM_ALG_SHA1: 492*aab73d95SJames Bottomley chip->groups[chip->groups_cnt++] = &pcr_group_sha1; 493*aab73d95SJames Bottomley break; 494*aab73d95SJames Bottomley case TPM_ALG_SHA256: 495*aab73d95SJames Bottomley chip->groups[chip->groups_cnt++] = &pcr_group_sha256; 496*aab73d95SJames Bottomley break; 497*aab73d95SJames Bottomley case TPM_ALG_SHA384: 498*aab73d95SJames Bottomley chip->groups[chip->groups_cnt++] = &pcr_group_sha384; 499*aab73d95SJames Bottomley break; 500*aab73d95SJames Bottomley case TPM_ALG_SHA512: 501*aab73d95SJames Bottomley chip->groups[chip->groups_cnt++] = &pcr_group_sha512; 502*aab73d95SJames Bottomley break; 503*aab73d95SJames Bottomley case TPM_ALG_SM3_256: 504*aab73d95SJames Bottomley chip->groups[chip->groups_cnt++] = &pcr_group_sm3; 505*aab73d95SJames Bottomley break; 506*aab73d95SJames Bottomley default: 507*aab73d95SJames Bottomley /* 508*aab73d95SJames Bottomley * If triggers, send a patch to add both a 509*aab73d95SJames Bottomley * PCR_ATTR_BUILD() macro above for the 510*aab73d95SJames Bottomley * missing algorithm as well as an additional 511*aab73d95SJames Bottomley * case in this switch statement. 512*aab73d95SJames Bottomley */ 513*aab73d95SJames Bottomley dev_err(&chip->dev, 514*aab73d95SJames Bottomley "TPM with unsupported bank algorithm 0x%04x", 515*aab73d95SJames Bottomley chip->allocated_banks[i].alg_id); 516*aab73d95SJames Bottomley break; 517*aab73d95SJames Bottomley } 518*aab73d95SJames Bottomley } 519*aab73d95SJames Bottomley 520*aab73d95SJames Bottomley /* 521*aab73d95SJames Bottomley * This will only trigger if someone has added an additional 522*aab73d95SJames Bottomley * hash to the tpm_algorithms enum without incrementing 523*aab73d95SJames Bottomley * TPM_MAX_HASHES. 524*aab73d95SJames Bottomley */ 525*aab73d95SJames Bottomley WARN_ON(chip->groups_cnt > TPM_MAX_HASHES + 1); 5261e3b73a9SJason Gunthorpe } 527