1000a07b0SJason Gunthorpe /* 2000a07b0SJason Gunthorpe * Copyright (C) 2004 IBM Corporation 3000a07b0SJason Gunthorpe * Authors: 4000a07b0SJason Gunthorpe * Leendert van Doorn <leendert@watson.ibm.com> 5000a07b0SJason Gunthorpe * Dave Safford <safford@watson.ibm.com> 6000a07b0SJason Gunthorpe * Reiner Sailer <sailer@watson.ibm.com> 7000a07b0SJason Gunthorpe * Kylene Hall <kjhall@us.ibm.com> 8000a07b0SJason Gunthorpe * 9000a07b0SJason Gunthorpe * sysfs filesystem inspection interface to the TPM 10000a07b0SJason Gunthorpe * 11000a07b0SJason Gunthorpe * This program is free software; you can redistribute it and/or 12000a07b0SJason Gunthorpe * modify it under the terms of the GNU General Public License as 13000a07b0SJason Gunthorpe * published by the Free Software Foundation, version 2 of the 14000a07b0SJason Gunthorpe * License. 15000a07b0SJason Gunthorpe * 16000a07b0SJason Gunthorpe */ 17000a07b0SJason Gunthorpe #include <linux/device.h> 18000a07b0SJason Gunthorpe #include "tpm.h" 19000a07b0SJason Gunthorpe 20000a07b0SJason Gunthorpe /* XXX for now this helper is duplicated in tpm-interface.c */ 21000a07b0SJason Gunthorpe static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, 22000a07b0SJason Gunthorpe int len, const char *desc) 23000a07b0SJason Gunthorpe { 24000a07b0SJason Gunthorpe int err; 25000a07b0SJason Gunthorpe 26000a07b0SJason Gunthorpe len = tpm_transmit(chip, (u8 *) cmd, len); 27000a07b0SJason Gunthorpe if (len < 0) 28000a07b0SJason Gunthorpe return len; 29000a07b0SJason Gunthorpe else if (len < TPM_HEADER_SIZE) 30000a07b0SJason Gunthorpe return -EFAULT; 31000a07b0SJason Gunthorpe 32000a07b0SJason Gunthorpe err = be32_to_cpu(cmd->header.out.return_code); 33000a07b0SJason Gunthorpe if (err != 0 && desc) 34000a07b0SJason Gunthorpe dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); 35000a07b0SJason Gunthorpe 36000a07b0SJason Gunthorpe return err; 37000a07b0SJason Gunthorpe } 38000a07b0SJason Gunthorpe 39000a07b0SJason Gunthorpe #define READ_PUBEK_RESULT_SIZE 314 40000a07b0SJason Gunthorpe #define TPM_ORD_READPUBEK cpu_to_be32(124) 41000a07b0SJason Gunthorpe static struct tpm_input_header tpm_readpubek_header = { 42000a07b0SJason Gunthorpe .tag = TPM_TAG_RQU_COMMAND, 43000a07b0SJason Gunthorpe .length = cpu_to_be32(30), 44000a07b0SJason Gunthorpe .ordinal = TPM_ORD_READPUBEK 45000a07b0SJason Gunthorpe }; 46000a07b0SJason Gunthorpe 47000a07b0SJason Gunthorpe ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, 48000a07b0SJason Gunthorpe char *buf) 49000a07b0SJason Gunthorpe { 50000a07b0SJason Gunthorpe u8 *data; 51000a07b0SJason Gunthorpe struct tpm_cmd_t tpm_cmd; 52000a07b0SJason Gunthorpe ssize_t err; 53000a07b0SJason Gunthorpe int i, rc; 54000a07b0SJason Gunthorpe char *str = buf; 55000a07b0SJason Gunthorpe 56000a07b0SJason Gunthorpe struct tpm_chip *chip = dev_get_drvdata(dev); 57000a07b0SJason Gunthorpe 58000a07b0SJason Gunthorpe tpm_cmd.header.in = tpm_readpubek_header; 59000a07b0SJason Gunthorpe err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 60000a07b0SJason Gunthorpe "attempting to read the PUBEK"); 61000a07b0SJason Gunthorpe if (err) 62000a07b0SJason Gunthorpe goto out; 63000a07b0SJason Gunthorpe 64000a07b0SJason Gunthorpe /* 65000a07b0SJason Gunthorpe ignore header 10 bytes 66000a07b0SJason Gunthorpe algorithm 32 bits (1 == RSA ) 67000a07b0SJason Gunthorpe encscheme 16 bits 68000a07b0SJason Gunthorpe sigscheme 16 bits 69000a07b0SJason Gunthorpe parameters (RSA 12->bytes: keybit, #primes, expbit) 70000a07b0SJason Gunthorpe keylenbytes 32 bits 71000a07b0SJason Gunthorpe 256 byte modulus 72000a07b0SJason Gunthorpe ignore checksum 20 bytes 73000a07b0SJason Gunthorpe */ 74000a07b0SJason Gunthorpe data = tpm_cmd.params.readpubek_out_buffer; 75000a07b0SJason Gunthorpe str += 76000a07b0SJason Gunthorpe sprintf(str, 77000a07b0SJason Gunthorpe "Algorithm: %02X %02X %02X %02X\n" 78000a07b0SJason Gunthorpe "Encscheme: %02X %02X\n" 79000a07b0SJason Gunthorpe "Sigscheme: %02X %02X\n" 80000a07b0SJason Gunthorpe "Parameters: %02X %02X %02X %02X " 81000a07b0SJason Gunthorpe "%02X %02X %02X %02X " 82000a07b0SJason Gunthorpe "%02X %02X %02X %02X\n" 83000a07b0SJason Gunthorpe "Modulus length: %d\n" 84000a07b0SJason Gunthorpe "Modulus:\n", 85000a07b0SJason Gunthorpe data[0], data[1], data[2], data[3], 86000a07b0SJason Gunthorpe data[4], data[5], 87000a07b0SJason Gunthorpe data[6], data[7], 88000a07b0SJason Gunthorpe data[12], data[13], data[14], data[15], 89000a07b0SJason Gunthorpe data[16], data[17], data[18], data[19], 90000a07b0SJason Gunthorpe data[20], data[21], data[22], data[23], 91000a07b0SJason Gunthorpe be32_to_cpu(*((__be32 *) (data + 24)))); 92000a07b0SJason Gunthorpe 93000a07b0SJason Gunthorpe for (i = 0; i < 256; i++) { 94000a07b0SJason Gunthorpe str += sprintf(str, "%02X ", data[i + 28]); 95000a07b0SJason Gunthorpe if ((i + 1) % 16 == 0) 96000a07b0SJason Gunthorpe str += sprintf(str, "\n"); 97000a07b0SJason Gunthorpe } 98000a07b0SJason Gunthorpe out: 99000a07b0SJason Gunthorpe rc = str - buf; 100000a07b0SJason Gunthorpe return rc; 101000a07b0SJason Gunthorpe } 102000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_pubek); 103000a07b0SJason Gunthorpe 104000a07b0SJason Gunthorpe ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, 105000a07b0SJason Gunthorpe char *buf) 106000a07b0SJason Gunthorpe { 107000a07b0SJason Gunthorpe cap_t cap; 108000a07b0SJason Gunthorpe u8 digest[TPM_DIGEST_SIZE]; 109000a07b0SJason Gunthorpe ssize_t rc; 110000a07b0SJason Gunthorpe int i, j, num_pcrs; 111000a07b0SJason Gunthorpe char *str = buf; 112000a07b0SJason Gunthorpe struct tpm_chip *chip = dev_get_drvdata(dev); 113000a07b0SJason Gunthorpe 114000a07b0SJason Gunthorpe rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, 115000a07b0SJason Gunthorpe "attempting to determine the number of PCRS"); 116000a07b0SJason Gunthorpe if (rc) 117000a07b0SJason Gunthorpe return 0; 118000a07b0SJason Gunthorpe 119000a07b0SJason Gunthorpe num_pcrs = be32_to_cpu(cap.num_pcrs); 120000a07b0SJason Gunthorpe for (i = 0; i < num_pcrs; i++) { 121000a07b0SJason Gunthorpe rc = tpm_pcr_read_dev(chip, i, digest); 122000a07b0SJason Gunthorpe if (rc) 123000a07b0SJason Gunthorpe break; 124000a07b0SJason Gunthorpe str += sprintf(str, "PCR-%02d: ", i); 125000a07b0SJason Gunthorpe for (j = 0; j < TPM_DIGEST_SIZE; j++) 126000a07b0SJason Gunthorpe str += sprintf(str, "%02X ", digest[j]); 127000a07b0SJason Gunthorpe str += sprintf(str, "\n"); 128000a07b0SJason Gunthorpe } 129000a07b0SJason Gunthorpe return str - buf; 130000a07b0SJason Gunthorpe } 131000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_pcrs); 132000a07b0SJason Gunthorpe 133000a07b0SJason Gunthorpe ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr, 134000a07b0SJason Gunthorpe char *buf) 135000a07b0SJason Gunthorpe { 136000a07b0SJason Gunthorpe cap_t cap; 137000a07b0SJason Gunthorpe ssize_t rc; 138000a07b0SJason Gunthorpe 139000a07b0SJason Gunthorpe rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, 140000a07b0SJason Gunthorpe "attempting to determine the permanent enabled state"); 141000a07b0SJason Gunthorpe if (rc) 142000a07b0SJason Gunthorpe return 0; 143000a07b0SJason Gunthorpe 144000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); 145000a07b0SJason Gunthorpe return rc; 146000a07b0SJason Gunthorpe } 147000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_enabled); 148000a07b0SJason Gunthorpe 149000a07b0SJason Gunthorpe ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr, 150000a07b0SJason Gunthorpe char *buf) 151000a07b0SJason Gunthorpe { 152000a07b0SJason Gunthorpe cap_t cap; 153000a07b0SJason Gunthorpe ssize_t rc; 154000a07b0SJason Gunthorpe 155000a07b0SJason Gunthorpe rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, 156000a07b0SJason Gunthorpe "attempting to determine the permanent active state"); 157000a07b0SJason Gunthorpe if (rc) 158000a07b0SJason Gunthorpe return 0; 159000a07b0SJason Gunthorpe 160000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); 161000a07b0SJason Gunthorpe return rc; 162000a07b0SJason Gunthorpe } 163000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_active); 164000a07b0SJason Gunthorpe 165000a07b0SJason Gunthorpe ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr, 166000a07b0SJason Gunthorpe char *buf) 167000a07b0SJason Gunthorpe { 168000a07b0SJason Gunthorpe cap_t cap; 169000a07b0SJason Gunthorpe ssize_t rc; 170000a07b0SJason Gunthorpe 171000a07b0SJason Gunthorpe rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, 172000a07b0SJason Gunthorpe "attempting to determine the owner state"); 173000a07b0SJason Gunthorpe if (rc) 174000a07b0SJason Gunthorpe return 0; 175000a07b0SJason Gunthorpe 176000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", cap.owned); 177000a07b0SJason Gunthorpe return rc; 178000a07b0SJason Gunthorpe } 179000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_owned); 180000a07b0SJason Gunthorpe 181000a07b0SJason Gunthorpe ssize_t tpm_show_temp_deactivated(struct device *dev, 182000a07b0SJason Gunthorpe struct device_attribute *attr, char *buf) 183000a07b0SJason Gunthorpe { 184000a07b0SJason Gunthorpe cap_t cap; 185000a07b0SJason Gunthorpe ssize_t rc; 186000a07b0SJason Gunthorpe 187000a07b0SJason Gunthorpe rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, 188000a07b0SJason Gunthorpe "attempting to determine the temporary state"); 189000a07b0SJason Gunthorpe if (rc) 190000a07b0SJason Gunthorpe return 0; 191000a07b0SJason Gunthorpe 192000a07b0SJason Gunthorpe rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); 193000a07b0SJason Gunthorpe return rc; 194000a07b0SJason Gunthorpe } 195000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); 196000a07b0SJason Gunthorpe 197000a07b0SJason Gunthorpe ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, 198000a07b0SJason Gunthorpe char *buf) 199000a07b0SJason Gunthorpe { 200000a07b0SJason Gunthorpe cap_t cap; 201000a07b0SJason Gunthorpe ssize_t rc; 202000a07b0SJason Gunthorpe char *str = buf; 203000a07b0SJason Gunthorpe 204000a07b0SJason Gunthorpe rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, 205000a07b0SJason Gunthorpe "attempting to determine the manufacturer"); 206000a07b0SJason Gunthorpe if (rc) 207000a07b0SJason Gunthorpe return 0; 208000a07b0SJason Gunthorpe str += sprintf(str, "Manufacturer: 0x%x\n", 209000a07b0SJason Gunthorpe be32_to_cpu(cap.manufacturer_id)); 210000a07b0SJason Gunthorpe 211000a07b0SJason Gunthorpe /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ 212000a07b0SJason Gunthorpe rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, 213000a07b0SJason Gunthorpe "attempting to determine the 1.2 version"); 214000a07b0SJason Gunthorpe if (!rc) { 215000a07b0SJason Gunthorpe str += sprintf(str, 216000a07b0SJason Gunthorpe "TCG version: %d.%d\nFirmware version: %d.%d\n", 217000a07b0SJason Gunthorpe cap.tpm_version_1_2.Major, 218000a07b0SJason Gunthorpe cap.tpm_version_1_2.Minor, 219000a07b0SJason Gunthorpe cap.tpm_version_1_2.revMajor, 220000a07b0SJason Gunthorpe cap.tpm_version_1_2.revMinor); 221000a07b0SJason Gunthorpe } else { 222000a07b0SJason Gunthorpe /* Otherwise just use TPM_STRUCT_VER */ 223000a07b0SJason Gunthorpe rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, 224000a07b0SJason Gunthorpe "attempting to determine the 1.1 version"); 225000a07b0SJason Gunthorpe if (rc) 226000a07b0SJason Gunthorpe return 0; 227000a07b0SJason Gunthorpe str += sprintf(str, 228000a07b0SJason Gunthorpe "TCG version: %d.%d\nFirmware version: %d.%d\n", 229000a07b0SJason Gunthorpe cap.tpm_version.Major, 230000a07b0SJason Gunthorpe cap.tpm_version.Minor, 231000a07b0SJason Gunthorpe cap.tpm_version.revMajor, 232000a07b0SJason Gunthorpe cap.tpm_version.revMinor); 233000a07b0SJason Gunthorpe } 234000a07b0SJason Gunthorpe 235000a07b0SJason Gunthorpe return str - buf; 236000a07b0SJason Gunthorpe } 237000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_caps); 238000a07b0SJason Gunthorpe 239000a07b0SJason Gunthorpe ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, 240000a07b0SJason Gunthorpe const char *buf, size_t count) 241000a07b0SJason Gunthorpe { 242000a07b0SJason Gunthorpe struct tpm_chip *chip = dev_get_drvdata(dev); 243000a07b0SJason Gunthorpe if (chip == NULL) 244000a07b0SJason Gunthorpe return 0; 245000a07b0SJason Gunthorpe 246000a07b0SJason Gunthorpe chip->vendor.cancel(chip); 247000a07b0SJason Gunthorpe return count; 248000a07b0SJason Gunthorpe } 249000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_store_cancel); 250000a07b0SJason Gunthorpe 251000a07b0SJason Gunthorpe ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, 252000a07b0SJason Gunthorpe char *buf) 253000a07b0SJason Gunthorpe { 254000a07b0SJason Gunthorpe struct tpm_chip *chip = dev_get_drvdata(dev); 255000a07b0SJason Gunthorpe 256000a07b0SJason Gunthorpe if (chip->vendor.duration[TPM_LONG] == 0) 257000a07b0SJason Gunthorpe return 0; 258000a07b0SJason Gunthorpe 259000a07b0SJason Gunthorpe return sprintf(buf, "%d %d %d [%s]\n", 260000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), 261000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), 262000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), 263000a07b0SJason Gunthorpe chip->vendor.duration_adjusted 264000a07b0SJason Gunthorpe ? "adjusted" : "original"); 265000a07b0SJason Gunthorpe } 266000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_durations); 267000a07b0SJason Gunthorpe 268000a07b0SJason Gunthorpe ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, 269000a07b0SJason Gunthorpe char *buf) 270000a07b0SJason Gunthorpe { 271000a07b0SJason Gunthorpe struct tpm_chip *chip = dev_get_drvdata(dev); 272000a07b0SJason Gunthorpe 273000a07b0SJason Gunthorpe return sprintf(buf, "%d %d %d %d [%s]\n", 274000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.timeout_a), 275000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.timeout_b), 276000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.timeout_c), 277000a07b0SJason Gunthorpe jiffies_to_usecs(chip->vendor.timeout_d), 278000a07b0SJason Gunthorpe chip->vendor.timeout_adjusted 279000a07b0SJason Gunthorpe ? "adjusted" : "original"); 280000a07b0SJason Gunthorpe } 281000a07b0SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_show_timeouts); 282