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