Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux...
[linux-block.git] / drivers / char / tpm / tpm-sysfs.c
CommitLineData
000a07b0
JG
1/*
2 * Copyright (C) 2004 IBM Corporation
3 * Authors:
4 * Leendert van Doorn <leendert@watson.ibm.com>
5 * Dave Safford <safford@watson.ibm.com>
6 * Reiner Sailer <sailer@watson.ibm.com>
7 * Kylene Hall <kjhall@us.ibm.com>
8 *
1e3b73a9
JG
9 * Copyright (C) 2013 Obsidian Research Corp
10 * Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
11 *
000a07b0
JG
12 * sysfs filesystem inspection interface to the TPM
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation, version 2 of the
17 * License.
18 *
19 */
20#include <linux/device.h>
21#include "tpm.h"
22
000a07b0 23#define READ_PUBEK_RESULT_SIZE 314
c659af78 24#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
a69faebf 25#define TPM_ORD_READPUBEK 124
0014777f 26static const struct tpm_input_header tpm_readpubek_header = {
06e93279 27 .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
000a07b0 28 .length = cpu_to_be32(30),
a69faebf 29 .ordinal = cpu_to_be32(TPM_ORD_READPUBEK)
000a07b0 30};
1e3b73a9
JG
31static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
32 char *buf)
000a07b0
JG
33{
34 u8 *data;
35 struct tpm_cmd_t tpm_cmd;
36 ssize_t err;
37 int i, rc;
38 char *str = buf;
39
062807f2 40 struct tpm_chip *chip = to_tpm_chip(dev);
000a07b0
JG
41
42 tpm_cmd.header.in = tpm_readpubek_header;
745b361e 43 err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
c659af78 44 READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
87155b73 45 "attempting to read the PUBEK");
000a07b0
JG
46 if (err)
47 goto out;
48
49 /*
50 ignore header 10 bytes
51 algorithm 32 bits (1 == RSA )
52 encscheme 16 bits
53 sigscheme 16 bits
54 parameters (RSA 12->bytes: keybit, #primes, expbit)
55 keylenbytes 32 bits
56 256 byte modulus
57 ignore checksum 20 bytes
58 */
59 data = tpm_cmd.params.readpubek_out_buffer;
60 str +=
61 sprintf(str,
62 "Algorithm: %02X %02X %02X %02X\n"
63 "Encscheme: %02X %02X\n"
64 "Sigscheme: %02X %02X\n"
65 "Parameters: %02X %02X %02X %02X "
66 "%02X %02X %02X %02X "
67 "%02X %02X %02X %02X\n"
68 "Modulus length: %d\n"
69 "Modulus:\n",
70 data[0], data[1], data[2], data[3],
71 data[4], data[5],
72 data[6], data[7],
73 data[12], data[13], data[14], data[15],
74 data[16], data[17], data[18], data[19],
75 data[20], data[21], data[22], data[23],
76 be32_to_cpu(*((__be32 *) (data + 24))));
77
78 for (i = 0; i < 256; i++) {
79 str += sprintf(str, "%02X ", data[i + 28]);
80 if ((i + 1) % 16 == 0)
81 str += sprintf(str, "\n");
82 }
83out:
84 rc = str - buf;
85 return rc;
86}
1e3b73a9 87static DEVICE_ATTR_RO(pubek);
000a07b0 88
1e3b73a9
JG
89static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
90 char *buf)
000a07b0
JG
91{
92 cap_t cap;
93 u8 digest[TPM_DIGEST_SIZE];
94 ssize_t rc;
95 int i, j, num_pcrs;
96 char *str = buf;
062807f2 97 struct tpm_chip *chip = to_tpm_chip(dev);
000a07b0 98
062807f2 99 rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap,
c659af78
SB
100 "attempting to determine the number of PCRS",
101 sizeof(cap.num_pcrs));
000a07b0
JG
102 if (rc)
103 return 0;
104
105 num_pcrs = be32_to_cpu(cap.num_pcrs);
106 for (i = 0; i < num_pcrs; i++) {
107 rc = tpm_pcr_read_dev(chip, i, digest);
108 if (rc)
109 break;
110 str += sprintf(str, "PCR-%02d: ", i);
111 for (j = 0; j < TPM_DIGEST_SIZE; j++)
112 str += sprintf(str, "%02X ", digest[j]);
113 str += sprintf(str, "\n");
114 }
115 return str - buf;
116}
1e3b73a9 117static DEVICE_ATTR_RO(pcrs);
000a07b0 118
1e3b73a9
JG
119static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
120 char *buf)
000a07b0
JG
121{
122 cap_t cap;
123 ssize_t rc;
124
062807f2 125 rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
c659af78
SB
126 "attempting to determine the permanent enabled state",
127 sizeof(cap.perm_flags));
000a07b0
JG
128 if (rc)
129 return 0;
130
131 rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
132 return rc;
133}
1e3b73a9 134static DEVICE_ATTR_RO(enabled);
000a07b0 135
5f64822d 136static ssize_t active_show(struct device *dev, struct device_attribute *attr,
1e3b73a9 137 char *buf)
000a07b0
JG
138{
139 cap_t cap;
140 ssize_t rc;
141
062807f2 142 rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
c659af78
SB
143 "attempting to determine the permanent active state",
144 sizeof(cap.perm_flags));
000a07b0
JG
145 if (rc)
146 return 0;
147
148 rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
149 return rc;
150}
1e3b73a9 151static DEVICE_ATTR_RO(active);
000a07b0 152
1e3b73a9
JG
153static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
154 char *buf)
000a07b0
JG
155{
156 cap_t cap;
157 ssize_t rc;
158
062807f2 159 rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
c659af78
SB
160 "attempting to determine the owner state",
161 sizeof(cap.owned));
000a07b0
JG
162 if (rc)
163 return 0;
164
165 rc = sprintf(buf, "%d\n", cap.owned);
166 return rc;
167}
1e3b73a9 168static DEVICE_ATTR_RO(owned);
000a07b0 169
1e3b73a9
JG
170static ssize_t temp_deactivated_show(struct device *dev,
171 struct device_attribute *attr, char *buf)
000a07b0
JG
172{
173 cap_t cap;
174 ssize_t rc;
175
062807f2 176 rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
c659af78
SB
177 "attempting to determine the temporary state",
178 sizeof(cap.stclear_flags));
000a07b0
JG
179 if (rc)
180 return 0;
181
182 rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
183 return rc;
184}
1e3b73a9 185static DEVICE_ATTR_RO(temp_deactivated);
000a07b0 186
1e3b73a9
JG
187static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
188 char *buf)
000a07b0 189{
062807f2 190 struct tpm_chip *chip = to_tpm_chip(dev);
000a07b0
JG
191 cap_t cap;
192 ssize_t rc;
193 char *str = buf;
194
062807f2 195 rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
c659af78
SB
196 "attempting to determine the manufacturer",
197 sizeof(cap.manufacturer_id));
000a07b0
JG
198 if (rc)
199 return 0;
200 str += sprintf(str, "Manufacturer: 0x%x\n",
201 be32_to_cpu(cap.manufacturer_id));
202
203 /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
84fda152 204 rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap,
c659af78
SB
205 "attempting to determine the 1.2 version",
206 sizeof(cap.tpm_version_1_2));
000a07b0
JG
207 if (!rc) {
208 str += sprintf(str,
209 "TCG version: %d.%d\nFirmware version: %d.%d\n",
210 cap.tpm_version_1_2.Major,
211 cap.tpm_version_1_2.Minor,
212 cap.tpm_version_1_2.revMajor,
213 cap.tpm_version_1_2.revMinor);
214 } else {
215 /* Otherwise just use TPM_STRUCT_VER */
84fda152 216 rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
c659af78
SB
217 "attempting to determine the 1.1 version",
218 sizeof(cap.tpm_version));
000a07b0
JG
219 if (rc)
220 return 0;
221 str += sprintf(str,
222 "TCG version: %d.%d\nFirmware version: %d.%d\n",
223 cap.tpm_version.Major,
224 cap.tpm_version.Minor,
225 cap.tpm_version.revMajor,
226 cap.tpm_version.revMinor);
227 }
228
229 return str - buf;
230}
1e3b73a9 231static DEVICE_ATTR_RO(caps);
000a07b0 232
1e3b73a9
JG
233static ssize_t cancel_store(struct device *dev, struct device_attribute *attr,
234 const char *buf, size_t count)
000a07b0 235{
062807f2 236 struct tpm_chip *chip = to_tpm_chip(dev);
000a07b0
JG
237 if (chip == NULL)
238 return 0;
239
5f82e9f0 240 chip->ops->cancel(chip);
000a07b0
JG
241 return count;
242}
1e3b73a9 243static DEVICE_ATTR_WO(cancel);
000a07b0 244
1e3b73a9
JG
245static ssize_t durations_show(struct device *dev, struct device_attribute *attr,
246 char *buf)
000a07b0 247{
062807f2 248 struct tpm_chip *chip = to_tpm_chip(dev);
000a07b0 249
af782f33 250 if (chip->duration[TPM_LONG] == 0)
000a07b0
JG
251 return 0;
252
253 return sprintf(buf, "%d %d %d [%s]\n",
af782f33
CR
254 jiffies_to_usecs(chip->duration[TPM_SHORT]),
255 jiffies_to_usecs(chip->duration[TPM_MEDIUM]),
256 jiffies_to_usecs(chip->duration[TPM_LONG]),
257 chip->duration_adjusted
000a07b0
JG
258 ? "adjusted" : "original");
259}
1e3b73a9 260static DEVICE_ATTR_RO(durations);
000a07b0 261
1e3b73a9
JG
262static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
263 char *buf)
000a07b0 264{
062807f2 265 struct tpm_chip *chip = to_tpm_chip(dev);
000a07b0
JG
266
267 return sprintf(buf, "%d %d %d %d [%s]\n",
af782f33
CR
268 jiffies_to_usecs(chip->timeout_a),
269 jiffies_to_usecs(chip->timeout_b),
270 jiffies_to_usecs(chip->timeout_c),
271 jiffies_to_usecs(chip->timeout_d),
272 chip->timeout_adjusted
000a07b0
JG
273 ? "adjusted" : "original");
274}
1e3b73a9
JG
275static DEVICE_ATTR_RO(timeouts);
276
277static struct attribute *tpm_dev_attrs[] = {
278 &dev_attr_pubek.attr,
279 &dev_attr_pcrs.attr,
280 &dev_attr_enabled.attr,
281 &dev_attr_active.attr,
282 &dev_attr_owned.attr,
283 &dev_attr_temp_deactivated.attr,
284 &dev_attr_caps.attr,
285 &dev_attr_cancel.attr,
286 &dev_attr_durations.attr,
287 &dev_attr_timeouts.attr,
288 NULL,
289};
290
291static const struct attribute_group tpm_dev_group = {
292 .attrs = tpm_dev_attrs,
293};
294
062807f2 295void tpm_sysfs_add_device(struct tpm_chip *chip)
1e3b73a9 296{
7518a21a
JS
297 if (chip->flags & TPM_CHIP_FLAG_TPM2)
298 return;
299
062807f2
JG
300 /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del
301 * is called before ops is null'd and the sysfs core synchronizes this
302 * removal so that no callbacks are running or can run again
4e26195f 303 */
062807f2
JG
304 WARN_ON(chip->groups_cnt != 0);
305 chip->groups[chip->groups_cnt++] = &tpm_dev_group;
1e3b73a9 306}