310d9609566fb6dc545b9bd46d162f21c9ea60c1
[cascardo/linux.git] / drivers / char / tpm / tpm-sysfs.c
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  *
9  * sysfs filesystem inspection interface to the TPM
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation, version 2 of the
14  * License.
15  *
16  */
17 #include <linux/device.h>
18 #include "tpm.h"
19
20 /* XXX for now this helper is duplicated in tpm-interface.c */
21 static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
22                             int len, const char *desc)
23 {
24         int err;
25
26         len = tpm_transmit(chip, (u8 *) cmd, len);
27         if (len <  0)
28                 return len;
29         else if (len < TPM_HEADER_SIZE)
30                 return -EFAULT;
31
32         err = be32_to_cpu(cmd->header.out.return_code);
33         if (err != 0 && desc)
34                 dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
35
36         return err;
37 }
38
39 #define READ_PUBEK_RESULT_SIZE 314
40 #define TPM_ORD_READPUBEK cpu_to_be32(124)
41 static struct tpm_input_header tpm_readpubek_header = {
42         .tag = TPM_TAG_RQU_COMMAND,
43         .length = cpu_to_be32(30),
44         .ordinal = TPM_ORD_READPUBEK
45 };
46
47 ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
48                        char *buf)
49 {
50         u8 *data;
51         struct tpm_cmd_t tpm_cmd;
52         ssize_t err;
53         int i, rc;
54         char *str = buf;
55
56         struct tpm_chip *chip = dev_get_drvdata(dev);
57
58         tpm_cmd.header.in = tpm_readpubek_header;
59         err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
60                            "attempting to read the PUBEK");
61         if (err)
62                 goto out;
63
64         /*
65            ignore header 10 bytes
66            algorithm 32 bits (1 == RSA )
67            encscheme 16 bits
68            sigscheme 16 bits
69            parameters (RSA 12->bytes: keybit, #primes, expbit)
70            keylenbytes 32 bits
71            256 byte modulus
72            ignore checksum 20 bytes
73          */
74         data = tpm_cmd.params.readpubek_out_buffer;
75         str +=
76             sprintf(str,
77                     "Algorithm: %02X %02X %02X %02X\n"
78                     "Encscheme: %02X %02X\n"
79                     "Sigscheme: %02X %02X\n"
80                     "Parameters: %02X %02X %02X %02X "
81                     "%02X %02X %02X %02X "
82                     "%02X %02X %02X %02X\n"
83                     "Modulus length: %d\n"
84                     "Modulus:\n",
85                     data[0], data[1], data[2], data[3],
86                     data[4], data[5],
87                     data[6], data[7],
88                     data[12], data[13], data[14], data[15],
89                     data[16], data[17], data[18], data[19],
90                     data[20], data[21], data[22], data[23],
91                     be32_to_cpu(*((__be32 *) (data + 24))));
92
93         for (i = 0; i < 256; i++) {
94                 str += sprintf(str, "%02X ", data[i + 28]);
95                 if ((i + 1) % 16 == 0)
96                         str += sprintf(str, "\n");
97         }
98 out:
99         rc = str - buf;
100         return rc;
101 }
102 EXPORT_SYMBOL_GPL(tpm_show_pubek);
103
104 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
105                       char *buf)
106 {
107         cap_t cap;
108         u8 digest[TPM_DIGEST_SIZE];
109         ssize_t rc;
110         int i, j, num_pcrs;
111         char *str = buf;
112         struct tpm_chip *chip = dev_get_drvdata(dev);
113
114         rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
115                         "attempting to determine the number of PCRS");
116         if (rc)
117                 return 0;
118
119         num_pcrs = be32_to_cpu(cap.num_pcrs);
120         for (i = 0; i < num_pcrs; i++) {
121                 rc = tpm_pcr_read_dev(chip, i, digest);
122                 if (rc)
123                         break;
124                 str += sprintf(str, "PCR-%02d: ", i);
125                 for (j = 0; j < TPM_DIGEST_SIZE; j++)
126                         str += sprintf(str, "%02X ", digest[j]);
127                 str += sprintf(str, "\n");
128         }
129         return str - buf;
130 }
131 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
132
133 ssize_t tpm_show_enabled(struct device *dev, struct device_attribute *attr,
134                         char *buf)
135 {
136         cap_t cap;
137         ssize_t rc;
138
139         rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
140                          "attempting to determine the permanent enabled state");
141         if (rc)
142                 return 0;
143
144         rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
145         return rc;
146 }
147 EXPORT_SYMBOL_GPL(tpm_show_enabled);
148
149 ssize_t tpm_show_active(struct device *dev, struct device_attribute *attr,
150                         char *buf)
151 {
152         cap_t cap;
153         ssize_t rc;
154
155         rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
156                          "attempting to determine the permanent active state");
157         if (rc)
158                 return 0;
159
160         rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
161         return rc;
162 }
163 EXPORT_SYMBOL_GPL(tpm_show_active);
164
165 ssize_t tpm_show_owned(struct device *dev, struct device_attribute *attr,
166                         char *buf)
167 {
168         cap_t cap;
169         ssize_t rc;
170
171         rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
172                          "attempting to determine the owner state");
173         if (rc)
174                 return 0;
175
176         rc = sprintf(buf, "%d\n", cap.owned);
177         return rc;
178 }
179 EXPORT_SYMBOL_GPL(tpm_show_owned);
180
181 ssize_t tpm_show_temp_deactivated(struct device *dev,
182                                 struct device_attribute *attr, char *buf)
183 {
184         cap_t cap;
185         ssize_t rc;
186
187         rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
188                          "attempting to determine the temporary state");
189         if (rc)
190                 return 0;
191
192         rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
193         return rc;
194 }
195 EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
196
197 ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
198                       char *buf)
199 {
200         cap_t cap;
201         ssize_t rc;
202         char *str = buf;
203
204         rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
205                         "attempting to determine the manufacturer");
206         if (rc)
207                 return 0;
208         str += sprintf(str, "Manufacturer: 0x%x\n",
209                        be32_to_cpu(cap.manufacturer_id));
210
211         /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
212         rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
213                          "attempting to determine the 1.2 version");
214         if (!rc) {
215                 str += sprintf(str,
216                                "TCG version: %d.%d\nFirmware version: %d.%d\n",
217                                cap.tpm_version_1_2.Major,
218                                cap.tpm_version_1_2.Minor,
219                                cap.tpm_version_1_2.revMajor,
220                                cap.tpm_version_1_2.revMinor);
221         } else {
222                 /* Otherwise just use TPM_STRUCT_VER */
223                 rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
224                                 "attempting to determine the 1.1 version");
225                 if (rc)
226                         return 0;
227                 str += sprintf(str,
228                                "TCG version: %d.%d\nFirmware version: %d.%d\n",
229                                cap.tpm_version.Major,
230                                cap.tpm_version.Minor,
231                                cap.tpm_version.revMajor,
232                                cap.tpm_version.revMinor);
233         }
234
235         return str - buf;
236 }
237 EXPORT_SYMBOL_GPL(tpm_show_caps);
238
239 ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
240                         const char *buf, size_t count)
241 {
242         struct tpm_chip *chip = dev_get_drvdata(dev);
243         if (chip == NULL)
244                 return 0;
245
246         chip->vendor.cancel(chip);
247         return count;
248 }
249 EXPORT_SYMBOL_GPL(tpm_store_cancel);
250
251 ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
252                           char *buf)
253 {
254         struct tpm_chip *chip = dev_get_drvdata(dev);
255
256         if (chip->vendor.duration[TPM_LONG] == 0)
257                 return 0;
258
259         return sprintf(buf, "%d %d %d [%s]\n",
260                        jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
261                        jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
262                        jiffies_to_usecs(chip->vendor.duration[TPM_LONG]),
263                        chip->vendor.duration_adjusted
264                        ? "adjusted" : "original");
265 }
266 EXPORT_SYMBOL_GPL(tpm_show_durations);
267
268 ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr,
269                           char *buf)
270 {
271         struct tpm_chip *chip = dev_get_drvdata(dev);
272
273         return sprintf(buf, "%d %d %d %d [%s]\n",
274                        jiffies_to_usecs(chip->vendor.timeout_a),
275                        jiffies_to_usecs(chip->vendor.timeout_b),
276                        jiffies_to_usecs(chip->vendor.timeout_c),
277                        jiffies_to_usecs(chip->vendor.timeout_d),
278                        chip->vendor.timeout_adjusted
279                        ? "adjusted" : "original");
280 }
281 EXPORT_SYMBOL_GPL(tpm_show_timeouts);