blob: 677c6e26593ffc94ae23f166e7fc049c1d69218e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2004 IBM Corporation
3 *
4 * Authors:
5 * Leendert van Doorn <leendert@watson.ibm.com>
6 * Dave Safford <safford@watson.ibm.com>
7 * Reiner Sailer <sailer@watson.ibm.com>
8 * Kylene Hall <kjhall@us.ibm.com>
9 *
Kent Yoder8e81cc12007-08-22 14:01:04 -070010 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
12 * Device driver for TCG/TCPA TPM (trusted platform module).
13 * Specifications at www.trustedcomputinggroup.org
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation, version 2 of the
18 * License.
19 *
20 * Note, the TPM chip is not interrupt driven (only polling)
21 * and can have very long timeouts (minutes!). Hence the unusual
Nishanth Aravamudan700d8bd2005-06-23 22:01:47 -070022 * calls to msleep.
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 *
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/poll.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Matthias Kaehlcked081d472007-05-08 00:32:02 -070028#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/spinlock.h>
Rajiv Andradefd048862011-09-16 14:39:40 -030030#include <linux/freezer.h>
Matthias Kaehlcked081d472007-05-08 00:32:02 -070031
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "tpm.h"
Kent Yodere5dcd872012-07-11 10:08:12 -050033#include "tpm_eventlog.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Kylene Hall3122a882005-06-23 22:01:48 -070035enum tpm_const {
36 TPM_MINOR = 224, /* officially assigned */
Rajiv Andrade7f366782009-09-24 16:27:46 -030037 TPM_BUFSIZE = 4096,
Kylene Hall3122a882005-06-23 22:01:48 -070038 TPM_NUM_DEVICES = 256,
Kylene Hall3122a882005-06-23 22:01:48 -070039};
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -070041enum tpm_duration {
42 TPM_SHORT = 0,
43 TPM_MEDIUM = 1,
44 TPM_LONG = 2,
45 TPM_UNDEFINED,
46};
47
48#define TPM_MAX_ORDINAL 243
49#define TPM_MAX_PROTECTED_ORDINAL 12
50#define TPM_PROTECTED_ORDINAL_MASK 0xFF
51
Dmitry Torokhov9b3056c2010-10-01 14:16:39 -070052/*
53 * Bug workaround - some TPM's don't flush the most
54 * recently changed pcr on suspend, so force the flush
55 * with an extend to the selected _unused_ non-volatile pcr.
56 */
57static int tpm_suspend_pcr;
58module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
59MODULE_PARM_DESC(suspend_pcr,
60 "PCR to use for dummy writes to faciltate flush on suspend.");
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062static LIST_HEAD(tpm_chip_list);
63static DEFINE_SPINLOCK(driver_lock);
Kylene Jo Hall10685a92006-04-22 02:38:32 -070064static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -070066/*
67 * Array with one entry per ordinal defining the maximum amount
68 * of time the chip could take to return the result. The ordinal
69 * designation of short, medium or long is defined in a table in
70 * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
71 * values of the SHORT, MEDIUM, and LONG durations are retrieved
72 * from the chip during initialization with a call to tpm_get_timeouts.
73 */
74static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
75 TPM_UNDEFINED, /* 0 */
76 TPM_UNDEFINED,
77 TPM_UNDEFINED,
78 TPM_UNDEFINED,
79 TPM_UNDEFINED,
80 TPM_UNDEFINED, /* 5 */
81 TPM_UNDEFINED,
82 TPM_UNDEFINED,
83 TPM_UNDEFINED,
84 TPM_UNDEFINED,
85 TPM_SHORT, /* 10 */
86 TPM_SHORT,
87};
88
89static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
90 TPM_UNDEFINED, /* 0 */
91 TPM_UNDEFINED,
92 TPM_UNDEFINED,
93 TPM_UNDEFINED,
94 TPM_UNDEFINED,
95 TPM_UNDEFINED, /* 5 */
96 TPM_UNDEFINED,
97 TPM_UNDEFINED,
98 TPM_UNDEFINED,
99 TPM_UNDEFINED,
100 TPM_SHORT, /* 10 */
101 TPM_SHORT,
102 TPM_MEDIUM,
103 TPM_LONG,
104 TPM_LONG,
105 TPM_MEDIUM, /* 15 */
106 TPM_SHORT,
107 TPM_SHORT,
108 TPM_MEDIUM,
109 TPM_LONG,
110 TPM_SHORT, /* 20 */
111 TPM_SHORT,
112 TPM_MEDIUM,
113 TPM_MEDIUM,
114 TPM_MEDIUM,
115 TPM_SHORT, /* 25 */
116 TPM_SHORT,
117 TPM_MEDIUM,
118 TPM_SHORT,
119 TPM_SHORT,
120 TPM_MEDIUM, /* 30 */
121 TPM_LONG,
122 TPM_MEDIUM,
123 TPM_SHORT,
124 TPM_SHORT,
125 TPM_SHORT, /* 35 */
126 TPM_MEDIUM,
127 TPM_MEDIUM,
128 TPM_UNDEFINED,
129 TPM_UNDEFINED,
130 TPM_MEDIUM, /* 40 */
131 TPM_LONG,
132 TPM_MEDIUM,
133 TPM_SHORT,
134 TPM_SHORT,
135 TPM_SHORT, /* 45 */
136 TPM_SHORT,
137 TPM_SHORT,
138 TPM_SHORT,
139 TPM_LONG,
140 TPM_MEDIUM, /* 50 */
141 TPM_MEDIUM,
142 TPM_UNDEFINED,
143 TPM_UNDEFINED,
144 TPM_UNDEFINED,
145 TPM_UNDEFINED, /* 55 */
146 TPM_UNDEFINED,
147 TPM_UNDEFINED,
148 TPM_UNDEFINED,
149 TPM_UNDEFINED,
150 TPM_MEDIUM, /* 60 */
151 TPM_MEDIUM,
152 TPM_MEDIUM,
153 TPM_SHORT,
154 TPM_SHORT,
155 TPM_MEDIUM, /* 65 */
156 TPM_UNDEFINED,
157 TPM_UNDEFINED,
158 TPM_UNDEFINED,
159 TPM_UNDEFINED,
160 TPM_SHORT, /* 70 */
161 TPM_SHORT,
162 TPM_UNDEFINED,
163 TPM_UNDEFINED,
164 TPM_UNDEFINED,
165 TPM_UNDEFINED, /* 75 */
166 TPM_UNDEFINED,
167 TPM_UNDEFINED,
168 TPM_UNDEFINED,
169 TPM_UNDEFINED,
170 TPM_LONG, /* 80 */
171 TPM_UNDEFINED,
172 TPM_MEDIUM,
173 TPM_LONG,
174 TPM_SHORT,
175 TPM_UNDEFINED, /* 85 */
176 TPM_UNDEFINED,
177 TPM_UNDEFINED,
178 TPM_UNDEFINED,
179 TPM_UNDEFINED,
180 TPM_SHORT, /* 90 */
181 TPM_SHORT,
182 TPM_SHORT,
183 TPM_SHORT,
184 TPM_SHORT,
185 TPM_UNDEFINED, /* 95 */
186 TPM_UNDEFINED,
187 TPM_UNDEFINED,
188 TPM_UNDEFINED,
189 TPM_UNDEFINED,
190 TPM_MEDIUM, /* 100 */
191 TPM_SHORT,
192 TPM_SHORT,
193 TPM_UNDEFINED,
194 TPM_UNDEFINED,
195 TPM_UNDEFINED, /* 105 */
196 TPM_UNDEFINED,
197 TPM_UNDEFINED,
198 TPM_UNDEFINED,
199 TPM_UNDEFINED,
200 TPM_SHORT, /* 110 */
201 TPM_SHORT,
202 TPM_SHORT,
203 TPM_SHORT,
204 TPM_SHORT,
205 TPM_SHORT, /* 115 */
206 TPM_SHORT,
207 TPM_SHORT,
208 TPM_UNDEFINED,
209 TPM_UNDEFINED,
210 TPM_LONG, /* 120 */
211 TPM_LONG,
212 TPM_MEDIUM,
213 TPM_UNDEFINED,
214 TPM_SHORT,
215 TPM_SHORT, /* 125 */
216 TPM_SHORT,
217 TPM_LONG,
218 TPM_SHORT,
219 TPM_SHORT,
220 TPM_SHORT, /* 130 */
221 TPM_MEDIUM,
222 TPM_UNDEFINED,
223 TPM_SHORT,
224 TPM_MEDIUM,
225 TPM_UNDEFINED, /* 135 */
226 TPM_UNDEFINED,
227 TPM_UNDEFINED,
228 TPM_UNDEFINED,
229 TPM_UNDEFINED,
230 TPM_SHORT, /* 140 */
231 TPM_SHORT,
232 TPM_UNDEFINED,
233 TPM_UNDEFINED,
234 TPM_UNDEFINED,
235 TPM_UNDEFINED, /* 145 */
236 TPM_UNDEFINED,
237 TPM_UNDEFINED,
238 TPM_UNDEFINED,
239 TPM_UNDEFINED,
240 TPM_SHORT, /* 150 */
241 TPM_MEDIUM,
242 TPM_MEDIUM,
243 TPM_SHORT,
244 TPM_SHORT,
245 TPM_UNDEFINED, /* 155 */
246 TPM_UNDEFINED,
247 TPM_UNDEFINED,
248 TPM_UNDEFINED,
249 TPM_UNDEFINED,
250 TPM_SHORT, /* 160 */
251 TPM_SHORT,
252 TPM_SHORT,
253 TPM_SHORT,
254 TPM_UNDEFINED,
255 TPM_UNDEFINED, /* 165 */
256 TPM_UNDEFINED,
257 TPM_UNDEFINED,
258 TPM_UNDEFINED,
259 TPM_UNDEFINED,
260 TPM_LONG, /* 170 */
261 TPM_UNDEFINED,
262 TPM_UNDEFINED,
263 TPM_UNDEFINED,
264 TPM_UNDEFINED,
265 TPM_UNDEFINED, /* 175 */
266 TPM_UNDEFINED,
267 TPM_UNDEFINED,
268 TPM_UNDEFINED,
269 TPM_UNDEFINED,
270 TPM_MEDIUM, /* 180 */
271 TPM_SHORT,
272 TPM_MEDIUM,
273 TPM_MEDIUM,
274 TPM_MEDIUM,
275 TPM_MEDIUM, /* 185 */
276 TPM_SHORT,
277 TPM_UNDEFINED,
278 TPM_UNDEFINED,
279 TPM_UNDEFINED,
280 TPM_UNDEFINED, /* 190 */
281 TPM_UNDEFINED,
282 TPM_UNDEFINED,
283 TPM_UNDEFINED,
284 TPM_UNDEFINED,
285 TPM_UNDEFINED, /* 195 */
286 TPM_UNDEFINED,
287 TPM_UNDEFINED,
288 TPM_UNDEFINED,
289 TPM_UNDEFINED,
290 TPM_SHORT, /* 200 */
291 TPM_UNDEFINED,
292 TPM_UNDEFINED,
293 TPM_UNDEFINED,
294 TPM_SHORT,
295 TPM_SHORT, /* 205 */
296 TPM_SHORT,
297 TPM_SHORT,
298 TPM_SHORT,
299 TPM_SHORT,
300 TPM_MEDIUM, /* 210 */
301 TPM_UNDEFINED,
302 TPM_MEDIUM,
303 TPM_MEDIUM,
304 TPM_MEDIUM,
305 TPM_UNDEFINED, /* 215 */
306 TPM_MEDIUM,
307 TPM_UNDEFINED,
308 TPM_UNDEFINED,
309 TPM_SHORT,
310 TPM_SHORT, /* 220 */
311 TPM_SHORT,
312 TPM_SHORT,
313 TPM_SHORT,
314 TPM_SHORT,
315 TPM_UNDEFINED, /* 225 */
316 TPM_UNDEFINED,
317 TPM_UNDEFINED,
318 TPM_UNDEFINED,
319 TPM_UNDEFINED,
320 TPM_SHORT, /* 230 */
321 TPM_LONG,
322 TPM_MEDIUM,
323 TPM_UNDEFINED,
324 TPM_UNDEFINED,
325 TPM_UNDEFINED, /* 235 */
326 TPM_UNDEFINED,
327 TPM_UNDEFINED,
328 TPM_UNDEFINED,
329 TPM_UNDEFINED,
330 TPM_SHORT, /* 240 */
331 TPM_UNDEFINED,
332 TPM_MEDIUM,
333};
334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335static void user_reader_timeout(unsigned long ptr)
336{
337 struct tpm_chip *chip = (struct tpm_chip *) ptr;
338
Kylene Jo Hall09e12f92005-11-13 16:07:43 -0800339 schedule_work(&chip->work);
340}
341
David Howellsc4028952006-11-22 14:57:56 +0000342static void timeout_work(struct work_struct *work)
Kylene Jo Hall09e12f92005-11-13 16:07:43 -0800343{
David Howellsc4028952006-11-22 14:57:56 +0000344 struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
Kylene Jo Hall09e12f92005-11-13 16:07:43 -0800345
Matthias Kaehlcked081d472007-05-08 00:32:02 -0700346 mutex_lock(&chip->buffer_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 atomic_set(&chip->data_pending, 0);
348 memset(chip->data_buffer, 0, TPM_BUFSIZE);
Matthias Kaehlcked081d472007-05-08 00:32:02 -0700349 mutex_unlock(&chip->buffer_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352/*
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -0700353 * Returns max number of jiffies to wait
354 */
355unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
356 u32 ordinal)
357{
358 int duration_idx = TPM_UNDEFINED;
359 int duration = 0;
360
361 if (ordinal < TPM_MAX_ORDINAL)
362 duration_idx = tpm_ordinal_duration[ordinal];
363 else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
364 TPM_MAX_PROTECTED_ORDINAL)
365 duration_idx =
366 tpm_protected_ordinal_duration[ordinal &
367 TPM_PROTECTED_ORDINAL_MASK];
368
Linus Torvalds8d1dc202011-03-01 13:23:27 -0800369 if (duration_idx != TPM_UNDEFINED)
Kylene Jo Hall36b20022006-04-22 02:38:19 -0700370 duration = chip->vendor.duration[duration_idx];
Linus Torvalds8d1dc202011-03-01 13:23:27 -0800371 if (duration <= 0)
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -0700372 return 2 * 60 * HZ;
Linus Torvalds8d1dc202011-03-01 13:23:27 -0800373 else
374 return duration;
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -0700375}
376EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
377
378/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 * Internal kernel interface to transmit TPM commands
380 */
381static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
382 size_t bufsiz)
383{
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700384 ssize_t rc;
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -0700385 u32 count, ordinal;
Nishanth Aravamudan700d8bd2005-06-23 22:01:47 -0700386 unsigned long stop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Peter Huewe6b07d302011-09-15 14:37:43 -0300388 if (bufsiz > TPM_BUFSIZE)
389 bufsiz = TPM_BUFSIZE;
390
Kylene Hall81179bb2005-06-23 22:01:59 -0700391 count = be32_to_cpu(*((__be32 *) (buf + 2)));
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -0700392 ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 if (count == 0)
394 return -ENODATA;
395 if (count > bufsiz) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800396 dev_err(chip->dev,
Al Virob76be682005-04-26 07:43:41 -0700397 "invalid count value %x %zx \n", count, bufsiz);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return -E2BIG;
399 }
400
Matthias Kaehlcked081d472007-05-08 00:32:02 -0700401 mutex_lock(&chip->tpm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Kylene Jo Hall90dda522006-04-22 02:37:15 -0700403 if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800404 dev_err(chip->dev,
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700405 "tpm_transmit: tpm_send: error %zd\n", rc);
406 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 }
408
Leendert van Doorn27084ef2006-04-22 02:38:03 -0700409 if (chip->vendor.irq)
410 goto out_recv;
411
Kylene Jo Hall9e18ee12006-04-22 02:37:38 -0700412 stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 do {
Kylene Jo Hall90dda522006-04-22 02:37:15 -0700414 u8 status = chip->vendor.status(chip);
415 if ((status & chip->vendor.req_complete_mask) ==
416 chip->vendor.req_complete_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 goto out_recv;
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700418
Kylene Jo Hall90dda522006-04-22 02:37:15 -0700419 if ((status == chip->vendor.req_canceled)) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800420 dev_err(chip->dev, "Operation Canceled\n");
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700421 rc = -ECANCELED;
422 goto out;
423 }
424
425 msleep(TPM_TIMEOUT); /* CHECK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 rmb();
Nishanth Aravamudan700d8bd2005-06-23 22:01:47 -0700427 } while (time_before(jiffies, stop));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Kylene Jo Hall90dda522006-04-22 02:37:15 -0700429 chip->vendor.cancel(chip);
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800430 dev_err(chip->dev, "Operation Timed out\n");
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700431 rc = -ETIME;
432 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434out_recv:
Kylene Jo Hall90dda522006-04-22 02:37:15 -0700435 rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz);
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700436 if (rc < 0)
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800437 dev_err(chip->dev,
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700438 "tpm_transmit: tpm_recv: error %zd\n", rc);
439out:
Matthias Kaehlcked081d472007-05-08 00:32:02 -0700440 mutex_unlock(&chip->tpm_mutex);
Kylene Halld9e5b6b2005-06-23 22:02:02 -0700441 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
444#define TPM_DIGEST_SIZE 20
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700445#define TPM_RET_CODE_IDX 6
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700446
447enum tpm_capabilities {
Rajiv Andrade08837432009-02-02 15:23:43 -0200448 TPM_CAP_FLAG = cpu_to_be32(4),
449 TPM_CAP_PROP = cpu_to_be32(5),
450 CAP_VERSION_1_1 = cpu_to_be32(0x06),
451 CAP_VERSION_1_2 = cpu_to_be32(0x1A)
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700452};
453
454enum tpm_sub_capabilities {
Rajiv Andrade08837432009-02-02 15:23:43 -0200455 TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
456 TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
457 TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
458 TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
459 TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
460 TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
461 TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
462
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700463};
464
Rajiv Andrade08837432009-02-02 15:23:43 -0200465static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
466 int len, const char *desc)
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700467{
468 int err;
469
Rajiv Andrade08837432009-02-02 15:23:43 -0200470 len = tpm_transmit(chip,(u8 *) cmd, len);
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700471 if (len < 0)
472 return len;
Rajiv Andradeb9e32382011-11-01 17:00:52 -0200473 else if (len < TPM_HEADER_SIZE)
474 return -EFAULT;
475
476 err = be32_to_cpu(cmd->header.out.return_code);
477 if (err != 0)
478 dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
479
480 return err;
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700481}
482
Rajiv Andrade08837432009-02-02 15:23:43 -0200483#define TPM_INTERNAL_RESULT_SIZE 200
484#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
485#define TPM_ORD_GET_CAP cpu_to_be32(101)
486
487static const struct tpm_input_header tpm_getcap_header = {
488 .tag = TPM_TAG_RQU_COMMAND,
489 .length = cpu_to_be32(22),
490 .ordinal = TPM_ORD_GET_CAP
491};
492
493ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
494 const char *desc)
495{
496 struct tpm_cmd_t tpm_cmd;
497 int rc;
498 struct tpm_chip *chip = dev_get_drvdata(dev);
499
500 tpm_cmd.header.in = tpm_getcap_header;
501 if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
502 tpm_cmd.params.getcap_in.cap = subcap_id;
503 /*subcap field not necessary */
504 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
505 tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
506 } else {
507 if (subcap_id == TPM_CAP_FLAG_PERM ||
508 subcap_id == TPM_CAP_FLAG_VOL)
509 tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
510 else
511 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
512 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
513 tpm_cmd.params.getcap_in.subcap = subcap_id;
514 }
515 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
516 if (!rc)
517 *cap = tpm_cmd.params.getcap_out.cap;
518 return rc;
519}
520
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700521void tpm_gen_interrupt(struct tpm_chip *chip)
522{
Rajiv Andrade08837432009-02-02 15:23:43 -0200523 struct tpm_cmd_t tpm_cmd;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700524 ssize_t rc;
525
Rajiv Andrade08837432009-02-02 15:23:43 -0200526 tpm_cmd.header.in = tpm_getcap_header;
527 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
528 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
529 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700530
Rajiv Andrade08837432009-02-02 15:23:43 -0200531 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700532 "attempting to determine the timeouts");
533}
534EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
535
Stefan Berger2b30a902011-11-11 12:57:02 -0500536int tpm_get_timeouts(struct tpm_chip *chip)
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700537{
Rajiv Andrade08837432009-02-02 15:23:43 -0200538 struct tpm_cmd_t tpm_cmd;
539 struct timeout_t *timeout_cap;
540 struct duration_t *duration_cap;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700541 ssize_t rc;
542 u32 timeout;
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400543 unsigned int scale = 1;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700544
Rajiv Andrade08837432009-02-02 15:23:43 -0200545 tpm_cmd.header.in = tpm_getcap_header;
546 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
547 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
548 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700549
Rajiv Andrade08837432009-02-02 15:23:43 -0200550 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700551 "attempting to determine the timeouts");
552 if (rc)
553 goto duration;
554
Stefan Berger829bf062011-03-30 12:13:26 -0400555 if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
556 be32_to_cpu(tpm_cmd.header.out.length)
557 != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
Stefan Berger2b30a902011-11-11 12:57:02 -0500558 return -EINVAL;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700559
Rajiv Andrade08837432009-02-02 15:23:43 -0200560 timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700561 /* Don't overwrite default if value is 0 */
Rajiv Andrade08837432009-02-02 15:23:43 -0200562 timeout = be32_to_cpu(timeout_cap->a);
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400563 if (timeout && timeout < 1000) {
564 /* timeouts in msec rather usec */
565 scale = 1000;
Stefan Berger62592102011-03-30 12:13:28 -0400566 chip->vendor.timeout_adjusted = true;
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400567 }
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700568 if (timeout)
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400569 chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale);
Rajiv Andrade08837432009-02-02 15:23:43 -0200570 timeout = be32_to_cpu(timeout_cap->b);
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700571 if (timeout)
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400572 chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale);
Rajiv Andrade08837432009-02-02 15:23:43 -0200573 timeout = be32_to_cpu(timeout_cap->c);
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700574 if (timeout)
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400575 chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale);
Rajiv Andrade08837432009-02-02 15:23:43 -0200576 timeout = be32_to_cpu(timeout_cap->d);
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700577 if (timeout)
Stefan Bergere3e1a1e2011-03-30 12:13:27 -0400578 chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale);
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700579
580duration:
Rajiv Andrade08837432009-02-02 15:23:43 -0200581 tpm_cmd.header.in = tpm_getcap_header;
582 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
583 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
584 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700585
Rajiv Andrade08837432009-02-02 15:23:43 -0200586 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700587 "attempting to determine the durations");
588 if (rc)
Stefan Berger2b30a902011-11-11 12:57:02 -0500589 return rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700590
Stefan Berger979b1402011-03-30 12:13:23 -0400591 if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
592 be32_to_cpu(tpm_cmd.header.out.length)
593 != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
Stefan Berger2b30a902011-11-11 12:57:02 -0500594 return -EINVAL;
Stefan Berger979b1402011-03-30 12:13:23 -0400595
Rajiv Andrade08837432009-02-02 15:23:43 -0200596 duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700597 chip->vendor.duration[TPM_SHORT] =
Rajiv Andrade08837432009-02-02 15:23:43 -0200598 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700599 chip->vendor.duration[TPM_MEDIUM] =
Rajiv Andrade08837432009-02-02 15:23:43 -0200600 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700601 chip->vendor.duration[TPM_LONG] =
Rajiv Andrade08837432009-02-02 15:23:43 -0200602 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
Stefan Bergere934acc2011-03-30 12:13:24 -0400603
604 /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
605 * value wrong and apparently reports msecs rather than usecs. So we
606 * fix up the resulting too-small TPM_SHORT value to make things work.
607 * We also scale the TPM_MEDIUM and -_LONG values by 1000.
608 */
609 if (chip->vendor.duration[TPM_SHORT] < (HZ / 100)) {
610 chip->vendor.duration[TPM_SHORT] = HZ;
611 chip->vendor.duration[TPM_MEDIUM] *= 1000;
612 chip->vendor.duration[TPM_LONG] *= 1000;
Stefan Berger04ab2292011-03-30 12:13:25 -0400613 chip->vendor.duration_adjusted = true;
Stefan Bergere934acc2011-03-30 12:13:24 -0400614 dev_info(chip->dev, "Adjusting TPM timeout parameters.");
615 }
Stefan Berger2b30a902011-11-11 12:57:02 -0500616 return 0;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700617}
618EXPORT_SYMBOL_GPL(tpm_get_timeouts);
619
Stefan Bergerd97c6ad2011-11-11 12:57:03 -0500620#define TPM_ORD_CONTINUE_SELFTEST 83
621#define CONTINUE_SELFTEST_RESULT_SIZE 10
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700622
Stefan Bergerd97c6ad2011-11-11 12:57:03 -0500623static struct tpm_input_header continue_selftest_header = {
624 .tag = TPM_TAG_RQU_COMMAND,
625 .length = cpu_to_be32(10),
626 .ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
627};
628
629/**
630 * tpm_continue_selftest -- run TPM's selftest
631 * @chip: TPM chip to use
632 *
633 * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
634 * a TPM error code.
635 */
Stefan Berger68d6e672011-11-11 12:57:04 -0500636static int tpm_continue_selftest(struct tpm_chip *chip)
Stefan Bergerd97c6ad2011-11-11 12:57:03 -0500637{
638 int rc;
639 struct tpm_cmd_t cmd;
640
641 cmd.header.in = continue_selftest_header;
642 rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
643 "continue selftest");
644 return rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700645}
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700646
647ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
648 char *buf)
649{
Rajiv Andrade08837432009-02-02 15:23:43 -0200650 cap_t cap;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700651 ssize_t rc;
652
Rajiv Andrade08837432009-02-02 15:23:43 -0200653 rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
654 "attempting to determine the permanent enabled state");
655 if (rc)
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700656 return 0;
Marcin Obaraec288bd2008-07-25 19:44:59 -0700657
Rajiv Andrade08837432009-02-02 15:23:43 -0200658 rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
Marcin Obaraec288bd2008-07-25 19:44:59 -0700659 return rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700660}
661EXPORT_SYMBOL_GPL(tpm_show_enabled);
662
663ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
664 char *buf)
665{
Rajiv Andrade08837432009-02-02 15:23:43 -0200666 cap_t cap;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700667 ssize_t rc;
668
Rajiv Andrade08837432009-02-02 15:23:43 -0200669 rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
670 "attempting to determine the permanent active state");
671 if (rc)
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700672 return 0;
Marcin Obaraec288bd2008-07-25 19:44:59 -0700673
Rajiv Andrade08837432009-02-02 15:23:43 -0200674 rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
Marcin Obaraec288bd2008-07-25 19:44:59 -0700675 return rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700676}
677EXPORT_SYMBOL_GPL(tpm_show_active);
678
679ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
680 char *buf)
681{
Rajiv Andrade08837432009-02-02 15:23:43 -0200682 cap_t cap;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700683 ssize_t rc;
684
Rajiv Andrade08837432009-02-02 15:23:43 -0200685 rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
686 "attempting to determine the owner state");
687 if (rc)
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700688 return 0;
Marcin Obaraec288bd2008-07-25 19:44:59 -0700689
Rajiv Andrade08837432009-02-02 15:23:43 -0200690 rc = sprintf(buf, "%d\n", cap.owned);
Marcin Obaraec288bd2008-07-25 19:44:59 -0700691 return rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700692}
693EXPORT_SYMBOL_GPL(tpm_show_owned);
694
695ssize_t tpm_show_temp_deactivated(struct device * dev,
696 struct device_attribute * attr, char *buf)
697{
Rajiv Andrade08837432009-02-02 15:23:43 -0200698 cap_t cap;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700699 ssize_t rc;
700
Rajiv Andrade08837432009-02-02 15:23:43 -0200701 rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
702 "attempting to determine the temporary state");
703 if (rc)
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700704 return 0;
Marcin Obaraec288bd2008-07-25 19:44:59 -0700705
Rajiv Andrade08837432009-02-02 15:23:43 -0200706 rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
Marcin Obaraec288bd2008-07-25 19:44:59 -0700707 return rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -0700708}
709EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
710
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200711/*
712 * tpm_chip_find_get - return tpm_chip for given chip number
713 */
714static struct tpm_chip *tpm_chip_find_get(int chip_num)
715{
Rajiv Andrade8920d5a2009-02-05 13:06:30 -0200716 struct tpm_chip *pos, *chip = NULL;
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200717
718 rcu_read_lock();
719 list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
720 if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
721 continue;
722
Rajiv Andrade8920d5a2009-02-05 13:06:30 -0200723 if (try_module_get(pos->dev->driver->owner)) {
724 chip = pos;
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200725 break;
Rajiv Andrade8920d5a2009-02-05 13:06:30 -0200726 }
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200727 }
728 rcu_read_unlock();
Rajiv Andrade8920d5a2009-02-05 13:06:30 -0200729 return chip;
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200730}
731
732#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
733#define READ_PCR_RESULT_SIZE 30
734static struct tpm_input_header pcrread_header = {
735 .tag = TPM_TAG_RQU_COMMAND,
736 .length = cpu_to_be32(14),
737 .ordinal = TPM_ORDINAL_PCRREAD
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738};
739
Stefan Berger68d6e672011-11-11 12:57:04 -0500740static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200741{
742 int rc;
743 struct tpm_cmd_t cmd;
744
745 cmd.header.in = pcrread_header;
746 cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
Rajiv Andrade23acb982009-09-30 12:26:55 -0300747 rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200748 "attempting to read a pcr value");
749
750 if (rc == 0)
751 memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
752 TPM_DIGEST_SIZE);
753 return rc;
754}
755
756/**
757 * tpm_pcr_read - read a pcr value
758 * @chip_num: tpm idx # or ANY
759 * @pcr_idx: pcr idx to retrieve
760 * @res_buf: TPM_PCR value
761 * size of res_buf is 20 bytes (or NULL if you don't care)
762 *
763 * The TPM driver should be built-in, but for whatever reason it
764 * isn't, protect against the chip disappearing, by incrementing
765 * the module usage count.
766 */
767int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
768{
769 struct tpm_chip *chip;
770 int rc;
771
772 chip = tpm_chip_find_get(chip_num);
773 if (chip == NULL)
774 return -ENODEV;
775 rc = __tpm_pcr_read(chip, pcr_idx, res_buf);
Mimi Zohara0e39342010-11-23 17:50:32 -0500776 tpm_chip_put(chip);
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200777 return rc;
778}
779EXPORT_SYMBOL_GPL(tpm_pcr_read);
780
781/**
782 * tpm_pcr_extend - extend pcr value with hash
783 * @chip_num: tpm idx # or AN&
784 * @pcr_idx: pcr idx to extend
785 * @hash: hash value used to extend pcr value
786 *
787 * The TPM driver should be built-in, but for whatever reason it
788 * isn't, protect against the chip disappearing, by incrementing
789 * the module usage count.
790 */
791#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
Jason Gunthorpe0afd9052009-09-18 12:54:24 -0700792#define EXTEND_PCR_RESULT_SIZE 34
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200793static struct tpm_input_header pcrextend_header = {
794 .tag = TPM_TAG_RQU_COMMAND,
795 .length = cpu_to_be32(34),
796 .ordinal = TPM_ORD_PCR_EXTEND
797};
798
799int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
800{
801 struct tpm_cmd_t cmd;
802 int rc;
803 struct tpm_chip *chip;
804
805 chip = tpm_chip_find_get(chip_num);
806 if (chip == NULL)
807 return -ENODEV;
808
809 cmd.header.in = pcrextend_header;
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200810 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
811 memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
Jason Gunthorpe0afd9052009-09-18 12:54:24 -0700812 rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200813 "attempting extend a PCR value");
814
Mimi Zohara0e39342010-11-23 17:50:32 -0500815 tpm_chip_put(chip);
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200816 return rc;
817}
818EXPORT_SYMBOL_GPL(tpm_pcr_extend);
819
Stefan Berger68d6e672011-11-11 12:57:04 -0500820/**
821 * tpm_do_selftest - have the TPM continue its selftest and wait until it
822 * can receive further commands
823 * @chip: TPM chip to use
824 *
825 * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
826 * a TPM error code.
827 */
828int tpm_do_selftest(struct tpm_chip *chip)
829{
830 int rc;
Stefan Berger68d6e672011-11-11 12:57:04 -0500831 unsigned int loops;
832 unsigned int delay_msec = 1000;
833 unsigned long duration;
Rajiv Andrade24ebe662012-04-24 17:38:17 -0300834 struct tpm_cmd_t cmd;
Stefan Berger68d6e672011-11-11 12:57:04 -0500835
836 duration = tpm_calc_ordinal_duration(chip,
837 TPM_ORD_CONTINUE_SELFTEST);
838
839 loops = jiffies_to_msecs(duration) / delay_msec;
840
841 rc = tpm_continue_selftest(chip);
842 /* This may fail if there was no TPM driver during a suspend/resume
843 * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
844 */
845 if (rc)
846 return rc;
847
848 do {
Rajiv Andrade24ebe662012-04-24 17:38:17 -0300849 /* Attempt to read a PCR value */
850 cmd.header.in = pcrread_header;
851 cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0);
852 rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE);
853
854 if (rc < TPM_HEADER_SIZE)
855 return -EFAULT;
856
857 rc = be32_to_cpu(cmd.header.out.return_code);
Stefan Bergerbe405412012-01-17 22:07:30 -0500858 if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
859 dev_info(chip->dev,
860 "TPM is disabled/deactivated (0x%X)\n", rc);
861 /* TPM is disabled and/or deactivated; driver can
862 * proceed and TPM does handle commands for
863 * suspend/resume correctly
864 */
865 return 0;
866 }
Stefan Berger68d6e672011-11-11 12:57:04 -0500867 if (rc != TPM_WARN_DOING_SELFTEST)
868 return rc;
869 msleep(delay_msec);
870 } while (--loops > 0);
871
872 return rc;
873}
874EXPORT_SYMBOL_GPL(tpm_do_selftest);
875
Mimi Zoharc749ba92010-11-23 18:54:16 -0500876int tpm_send(u32 chip_num, void *cmd, size_t buflen)
877{
878 struct tpm_chip *chip;
879 int rc;
880
881 chip = tpm_chip_find_get(chip_num);
882 if (chip == NULL)
883 return -ENODEV;
884
885 rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
886
887 tpm_chip_put(chip);
888 return rc;
889}
890EXPORT_SYMBOL_GPL(tpm_send);
891
Kylene Hall6659ca22005-06-23 22:02:00 -0700892ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
893 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
Rajiv Andrade08837432009-02-02 15:23:43 -0200895 cap_t cap;
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200896 u8 digest[TPM_DIGEST_SIZE];
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700897 ssize_t rc;
Kylene Hall81179bb2005-06-23 22:01:59 -0700898 int i, j, num_pcrs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 char *str = buf;
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800900 struct tpm_chip *chip = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Rajiv Andrade08837432009-02-02 15:23:43 -0200902 rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700903 "attempting to determine the number of PCRS");
Rajiv Andrade08837432009-02-02 15:23:43 -0200904 if (rc)
Kylene Halle234bc92005-06-23 22:02:08 -0700905 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Rajiv Andrade08837432009-02-02 15:23:43 -0200907 num_pcrs = be32_to_cpu(cap.num_pcrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 for (i = 0; i < num_pcrs; i++) {
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200909 rc = __tpm_pcr_read(chip, i, digest);
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700910 if (rc)
Rajiv Andrade08837432009-02-02 15:23:43 -0200911 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 str += sprintf(str, "PCR-%02d: ", i);
913 for (j = 0; j < TPM_DIGEST_SIZE; j++)
Rajiv Andrade659aaf22009-02-02 15:23:44 -0200914 str += sprintf(str, "%02X ", digest[j]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 str += sprintf(str, "\n");
916 }
917 return str - buf;
918}
Kylene Hall6659ca22005-06-23 22:02:00 -0700919EXPORT_SYMBOL_GPL(tpm_show_pcrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921#define READ_PUBEK_RESULT_SIZE 314
Rajiv Andrade08837432009-02-02 15:23:43 -0200922#define TPM_ORD_READPUBEK cpu_to_be32(124)
923struct tpm_input_header tpm_readpubek_header = {
924 .tag = TPM_TAG_RQU_COMMAND,
925 .length = cpu_to_be32(30),
926 .ordinal = TPM_ORD_READPUBEK
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927};
928
Kylene Hall6659ca22005-06-23 22:02:00 -0700929ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
930 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931{
Kylene Hall2df71112005-06-23 22:01:54 -0700932 u8 *data;
Rajiv Andrade08837432009-02-02 15:23:43 -0200933 struct tpm_cmd_t tpm_cmd;
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700934 ssize_t err;
Kylene Hall81179bb2005-06-23 22:01:59 -0700935 int i, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 char *str = buf;
937
Kylene Jo Halle659a3f2005-10-30 15:03:24 -0800938 struct tpm_chip *chip = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Rajiv Andrade08837432009-02-02 15:23:43 -0200940 tpm_cmd.header.in = tpm_readpubek_header;
941 err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700942 "attempting to read the PUBEK");
943 if (err)
Kylene Jo Hall34d6e072005-06-23 22:02:10 -0700944 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 /*
947 ignore header 10 bytes
948 algorithm 32 bits (1 == RSA )
949 encscheme 16 bits
950 sigscheme 16 bits
951 parameters (RSA 12->bytes: keybit, #primes, expbit)
952 keylenbytes 32 bits
953 256 byte modulus
954 ignore checksum 20 bytes
955 */
Rajiv Andrade08837432009-02-02 15:23:43 -0200956 data = tpm_cmd.params.readpubek_out_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 str +=
958 sprintf(str,
Stefan Berger5a794442011-03-30 12:13:29 -0400959 "Algorithm: %02X %02X %02X %02X\n"
960 "Encscheme: %02X %02X\n"
961 "Sigscheme: %02X %02X\n"
962 "Parameters: %02X %02X %02X %02X "
963 "%02X %02X %02X %02X "
964 "%02X %02X %02X %02X\n"
965 "Modulus length: %d\n"
966 "Modulus:\n",
967 data[0], data[1], data[2], data[3],
968 data[4], data[5],
969 data[6], data[7],
970 data[12], data[13], data[14], data[15],
971 data[16], data[17], data[18], data[19],
972 data[20], data[21], data[22], data[23],
973 be32_to_cpu(*((__be32 *) (data + 24))));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 for (i = 0; i < 256; i++) {
Stefan Berger5a794442011-03-30 12:13:29 -0400976 str += sprintf(str, "%02X ", data[i + 28]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if ((i + 1) % 16 == 0)
978 str += sprintf(str, "\n");
979 }
Kylene Jo Hall34d6e072005-06-23 22:02:10 -0700980out:
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700981 rc = str - buf;
Kylene Hall2df71112005-06-23 22:01:54 -0700982 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
Kylene Hall6659ca22005-06-23 22:02:00 -0700984EXPORT_SYMBOL_GPL(tpm_show_pubek);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Kylene Hall6659ca22005-06-23 22:02:00 -0700987ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
988 char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
Rajiv Andrade08837432009-02-02 15:23:43 -0200990 cap_t cap;
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700991 ssize_t rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 char *str = buf;
993
Rajiv Andrade08837432009-02-02 15:23:43 -0200994 rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700995 "attempting to determine the manufacturer");
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -0700996 if (rc)
Rajiv Andrade08837432009-02-02 15:23:43 -0200997 return 0;
998 str += sprintf(str, "Manufacturer: 0x%x\n",
999 be32_to_cpu(cap.manufacturer_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Rajiv Andrade08837432009-02-02 15:23:43 -02001001 rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
1002 "attempting to determine the 1.1 version");
1003 if (rc)
1004 return 0;
Kylene Jo Hallbeed53a2006-04-22 02:37:05 -07001005 str += sprintf(str,
1006 "TCG version: %d.%d\nFirmware version: %d.%d\n",
Rajiv Andrade08837432009-02-02 15:23:43 -02001007 cap.tpm_version.Major, cap.tpm_version.Minor,
1008 cap.tpm_version.revMajor, cap.tpm_version.revMinor);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return str - buf;
1010}
Kylene Hall6659ca22005-06-23 22:02:00 -07001011EXPORT_SYMBOL_GPL(tpm_show_caps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Kylene Jo Hall08e96e42006-04-22 02:37:50 -07001013ssize_t tpm_show_caps_1_2(struct device * dev,
1014 struct device_attribute * attr, char *buf)
1015{
Rajiv Andrade08837432009-02-02 15:23:43 -02001016 cap_t cap;
1017 ssize_t rc;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -07001018 char *str = buf;
1019
Rajiv Andrade08837432009-02-02 15:23:43 -02001020 rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
1021 "attempting to determine the manufacturer");
1022 if (rc)
Kylene Jo Hall08e96e42006-04-22 02:37:50 -07001023 return 0;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -07001024 str += sprintf(str, "Manufacturer: 0x%x\n",
Rajiv Andrade08837432009-02-02 15:23:43 -02001025 be32_to_cpu(cap.manufacturer_id));
1026 rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
1027 "attempting to determine the 1.2 version");
1028 if (rc)
1029 return 0;
Kylene Jo Hall08e96e42006-04-22 02:37:50 -07001030 str += sprintf(str,
1031 "TCG version: %d.%d\nFirmware version: %d.%d\n",
Rajiv Andrade08837432009-02-02 15:23:43 -02001032 cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
1033 cap.tpm_version_1_2.revMajor,
1034 cap.tpm_version_1_2.revMinor);
Kylene Jo Hall08e96e42006-04-22 02:37:50 -07001035 return str - buf;
1036}
1037EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
1038
Stefan Berger04ab2292011-03-30 12:13:25 -04001039ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
1040 char *buf)
1041{
1042 struct tpm_chip *chip = dev_get_drvdata(dev);
1043
Stefan Berger403d1d02011-08-23 08:52:10 -04001044 if (chip->vendor.duration[TPM_LONG] == 0)
1045 return 0;
1046
Stefan Berger04ab2292011-03-30 12:13:25 -04001047 return sprintf(buf, "%d %d %d [%s]\n",
1048 jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
1049 jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
1050 jiffies_to_usecs(chip->vendor.duration[TPM_LONG]),
1051 chip->vendor.duration_adjusted
1052 ? "adjusted" : "original");
1053}
1054EXPORT_SYMBOL_GPL(tpm_show_durations);
1055
Stefan Berger62592102011-03-30 12:13:28 -04001056ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr,
1057 char *buf)
1058{
1059 struct tpm_chip *chip = dev_get_drvdata(dev);
1060
1061 return sprintf(buf, "%d %d %d %d [%s]\n",
1062 jiffies_to_usecs(chip->vendor.timeout_a),
1063 jiffies_to_usecs(chip->vendor.timeout_b),
1064 jiffies_to_usecs(chip->vendor.timeout_c),
1065 jiffies_to_usecs(chip->vendor.timeout_d),
1066 chip->vendor.timeout_adjusted
1067 ? "adjusted" : "original");
1068}
1069EXPORT_SYMBOL_GPL(tpm_show_timeouts);
1070
Kylene Hall6659ca22005-06-23 22:02:00 -07001071ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
1072 const char *buf, size_t count)
1073{
1074 struct tpm_chip *chip = dev_get_drvdata(dev);
1075 if (chip == NULL)
1076 return 0;
1077
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001078 chip->vendor.cancel(chip);
Kylene Hall6659ca22005-06-23 22:02:00 -07001079 return count;
1080}
1081EXPORT_SYMBOL_GPL(tpm_store_cancel);
1082
Rajiv Andradefd048862011-09-16 14:39:40 -03001083int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
1084 wait_queue_head_t *queue)
1085{
1086 unsigned long stop;
1087 long rc;
1088 u8 status;
1089
1090 /* check current status */
1091 status = chip->vendor.status(chip);
1092 if ((status & mask) == mask)
1093 return 0;
1094
1095 stop = jiffies + timeout;
1096
1097 if (chip->vendor.irq) {
1098again:
1099 timeout = stop - jiffies;
1100 if ((long)timeout <= 0)
1101 return -ETIME;
1102 rc = wait_event_interruptible_timeout(*queue,
1103 ((chip->vendor.status(chip)
1104 & mask) == mask),
1105 timeout);
1106 if (rc > 0)
1107 return 0;
1108 if (rc == -ERESTARTSYS && freezing(current)) {
1109 clear_thread_flag(TIF_SIGPENDING);
1110 goto again;
1111 }
1112 } else {
1113 do {
1114 msleep(TPM_TIMEOUT);
1115 status = chip->vendor.status(chip);
1116 if ((status & mask) == mask)
1117 return 0;
1118 } while (time_before(jiffies, stop));
1119 }
1120 return -ETIME;
1121}
1122EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123/*
1124 * Device file system interface to the TPM
Rajiv Andradef89c5ed2008-10-11 09:03:39 +11001125 *
1126 * It's assured that the chip will be opened just once,
1127 * by the check of is_open variable, which is protected
1128 * by driver_lock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 */
1130int tpm_open(struct inode *inode, struct file *file)
1131{
Rajiv Andradef02a9362008-10-11 09:04:23 +11001132 int minor = iminor(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 struct tpm_chip *chip = NULL, *pos;
1134
Rajiv Andradef02a9362008-10-11 09:04:23 +11001135 rcu_read_lock();
1136 list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001137 if (pos->vendor.miscdev.minor == minor) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 chip = pos;
Rajiv Andradef02a9362008-10-11 09:04:23 +11001139 get_device(chip->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 break;
1141 }
1142 }
Rajiv Andradef02a9362008-10-11 09:04:23 +11001143 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Rajiv Andradef02a9362008-10-11 09:04:23 +11001145 if (!chip)
1146 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Rajiv Andradedc36d322008-10-11 09:04:02 +11001148 if (test_and_set_bit(0, &chip->is_open)) {
Andrew Mortonb888c872005-10-30 15:03:28 -08001149 dev_dbg(chip->dev, "Another process owns this TPM\n");
Rajiv Andradef02a9362008-10-11 09:04:23 +11001150 put_device(chip->dev);
1151 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
Peter Huewe1309d7a2011-03-29 13:31:25 +02001154 chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (chip->data_buffer == NULL) {
Rajiv Andradedc36d322008-10-11 09:04:02 +11001156 clear_bit(0, &chip->is_open);
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001157 put_device(chip->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 return -ENOMEM;
1159 }
1160
1161 atomic_set(&chip->data_pending, 0);
1162
1163 file->private_data = chip;
1164 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166EXPORT_SYMBOL_GPL(tpm_open);
1167
Rajiv Andradef02a9362008-10-11 09:04:23 +11001168/*
1169 * Called on file close
1170 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171int tpm_release(struct inode *inode, struct file *file)
1172{
1173 struct tpm_chip *chip = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Rajiv Andrade4bdec112008-10-11 09:05:20 +11001175 del_singleshot_timer_sync(&chip->user_read_timer);
Tejun Heo2e5c44c2010-12-24 15:59:07 +01001176 flush_work_sync(&chip->work);
Kylene Hall5e976d52005-06-23 22:02:03 -07001177 file->private_data = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 atomic_set(&chip->data_pending, 0);
Rajiv Andradef02a9362008-10-11 09:04:23 +11001179 kfree(chip->data_buffer);
Rajiv Andradedc36d322008-10-11 09:04:02 +11001180 clear_bit(0, &chip->is_open);
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001181 put_device(chip->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return 0;
1183}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184EXPORT_SYMBOL_GPL(tpm_release);
1185
Andrew Mortonb888c872005-10-30 15:03:28 -08001186ssize_t tpm_write(struct file *file, const char __user *buf,
Kylene Jo Hall3c2f6062006-04-22 02:36:56 -07001187 size_t size, loff_t *off)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
1189 struct tpm_chip *chip = file->private_data;
Michael Halcrow01476002008-07-25 19:45:00 -07001190 size_t in_size = size, out_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 /* cannot perform a write until the read has cleared
1193 either via tpm_read or a user_read_timer timeout */
Nishanth Aravamudan700d8bd2005-06-23 22:01:47 -07001194 while (atomic_read(&chip->data_pending) != 0)
1195 msleep(TPM_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Matthias Kaehlcked081d472007-05-08 00:32:02 -07001197 mutex_lock(&chip->buffer_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 if (in_size > TPM_BUFSIZE)
1200 in_size = TPM_BUFSIZE;
1201
1202 if (copy_from_user
1203 (chip->data_buffer, (void __user *) buf, in_size)) {
Matthias Kaehlcked081d472007-05-08 00:32:02 -07001204 mutex_unlock(&chip->buffer_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 return -EFAULT;
1206 }
1207
1208 /* atomic tpm command send and result receive */
1209 out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
1210
1211 atomic_set(&chip->data_pending, out_size);
Matthias Kaehlcked081d472007-05-08 00:32:02 -07001212 mutex_unlock(&chip->buffer_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 /* Set a timeout by which the reader must come claim the result */
Kylene Hallfe3fd4832005-06-23 22:01:56 -07001215 mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 return in_size;
1218}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219EXPORT_SYMBOL_GPL(tpm_write);
1220
Kylene Jo Hall3c2f6062006-04-22 02:36:56 -07001221ssize_t tpm_read(struct file *file, char __user *buf,
1222 size_t size, loff_t *off)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
1224 struct tpm_chip *chip = file->private_data;
Michael Halcrow01476002008-07-25 19:45:00 -07001225 ssize_t ret_size;
Peter Huewe3321c072011-09-15 14:47:42 -03001226 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Kylene Hall5b44bd52005-06-23 22:01:53 -07001228 del_singleshot_timer_sync(&chip->user_read_timer);
Tejun Heo2e5c44c2010-12-24 15:59:07 +01001229 flush_work_sync(&chip->work);
Kylene Hall5b44bd52005-06-23 22:01:53 -07001230 ret_size = atomic_read(&chip->data_pending);
1231 atomic_set(&chip->data_pending, 0);
1232 if (ret_size > 0) { /* relay data */
Tim Gardner3ab1aff2011-12-06 11:29:20 -07001233 ssize_t orig_ret_size = ret_size;
Kylene Hall5b44bd52005-06-23 22:01:53 -07001234 if (size < ret_size)
1235 ret_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Matthias Kaehlcked081d472007-05-08 00:32:02 -07001237 mutex_lock(&chip->buffer_mutex);
Peter Huewe3321c072011-09-15 14:47:42 -03001238 rc = copy_to_user(buf, chip->data_buffer, ret_size);
Tim Gardner3ab1aff2011-12-06 11:29:20 -07001239 memset(chip->data_buffer, 0, orig_ret_size);
Peter Huewe3321c072011-09-15 14:47:42 -03001240 if (rc)
Kylene Hall5b44bd52005-06-23 22:01:53 -07001241 ret_size = -EFAULT;
Peter Huewe3321c072011-09-15 14:47:42 -03001242
Matthias Kaehlcked081d472007-05-08 00:32:02 -07001243 mutex_unlock(&chip->buffer_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245
1246 return ret_size;
1247}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248EXPORT_SYMBOL_GPL(tpm_read);
1249
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001250void tpm_remove_hardware(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251{
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001252 struct tpm_chip *chip = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 if (chip == NULL) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001255 dev_err(dev, "No device data found\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 return;
1257 }
1258
1259 spin_lock(&driver_lock);
Rajiv Andradef02a9362008-10-11 09:04:23 +11001260 list_del_rcu(&chip->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 spin_unlock(&driver_lock);
Rajiv Andradef02a9362008-10-11 09:04:23 +11001262 synchronize_rcu();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001264 misc_deregister(&chip->vendor.miscdev);
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001265 sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -08001266 tpm_bios_log_teardown(chip->bios_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001268 /* write it this way to be explicit (chip->dev == dev) */
1269 put_device(chip->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270}
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001271EXPORT_SYMBOL_GPL(tpm_remove_hardware);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Rajiv Andrade225a9be2010-03-25 00:55:32 -03001273#define TPM_ORD_SAVESTATE cpu_to_be32(152)
1274#define SAVESTATE_RESULT_SIZE 10
1275
1276static struct tpm_input_header savestate_header = {
1277 .tag = TPM_TAG_RQU_COMMAND,
1278 .length = cpu_to_be32(10),
1279 .ordinal = TPM_ORD_SAVESTATE
1280};
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282/*
1283 * We are about to suspend. Save the TPM state
1284 * so that it can be restored.
1285 */
Rafael J. Wysocki035e2ce2012-07-06 19:09:01 +02001286int tpm_pm_suspend(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
Kylene Jo Hallce2c87d2005-10-30 15:03:25 -08001288 struct tpm_chip *chip = dev_get_drvdata(dev);
Rajiv Andrade225a9be2010-03-25 00:55:32 -03001289 struct tpm_cmd_t cmd;
1290 int rc;
1291
1292 u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
David Smith2490c682008-01-14 00:55:12 -08001293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (chip == NULL)
1295 return -ENODEV;
1296
Rajiv Andrade225a9be2010-03-25 00:55:32 -03001297 /* for buggy tpm, flush pcrs with extend to selected dummy */
1298 if (tpm_suspend_pcr) {
1299 cmd.header.in = pcrextend_header;
1300 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
1301 memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
1302 TPM_DIGEST_SIZE);
1303 rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
1304 "extending dummy pcr before suspend");
1305 }
1306
1307 /* now do the actual savestate */
1308 cmd.header.in = savestate_header;
1309 rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
1310 "sending savestate before suspend");
1311 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313EXPORT_SYMBOL_GPL(tpm_pm_suspend);
1314
1315/*
1316 * Resume from a power safe. The BIOS already restored
1317 * the TPM state.
1318 */
Kylene Jo Hallce2c87d2005-10-30 15:03:25 -08001319int tpm_pm_resume(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
Kylene Jo Hallce2c87d2005-10-30 15:03:25 -08001321 struct tpm_chip *chip = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
1323 if (chip == NULL)
1324 return -ENODEV;
1325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 return 0;
1327}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328EXPORT_SYMBOL_GPL(tpm_pm_resume);
1329
Rajiv Andrade253115b2008-10-11 09:04:39 +11001330/* In case vendor provided release function, call it too.*/
1331
1332void tpm_dev_vendor_release(struct tpm_chip *chip)
1333{
Andi Shyti30729282012-05-28 18:42:45 +02001334 if (!chip)
1335 return;
1336
Rajiv Andrade253115b2008-10-11 09:04:39 +11001337 if (chip->vendor.release)
1338 chip->vendor.release(chip->dev);
1339
1340 clear_bit(chip->dev_num, dev_mask);
1341 kfree(chip->vendor.miscdev.name);
1342}
1343EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
1344
1345
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346/*
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001347 * Once all references to platform device are down to 0,
1348 * release all allocated structures.
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001349 */
Stephen Rothwellcbb2ed42008-10-18 20:25:46 -07001350void tpm_dev_release(struct device *dev)
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001351{
1352 struct tpm_chip *chip = dev_get_drvdata(dev);
1353
Andi Shyti30729282012-05-28 18:42:45 +02001354 if (!chip)
1355 return;
1356
Rajiv Andrade253115b2008-10-11 09:04:39 +11001357 tpm_dev_vendor_release(chip);
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001358
Rajiv Andrade253115b2008-10-11 09:04:39 +11001359 chip->release(dev);
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001360 kfree(chip);
1361}
Rajiv Andrade253115b2008-10-11 09:04:39 +11001362EXPORT_SYMBOL_GPL(tpm_dev_release);
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001363
1364/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 * Called from tpm_<specific>.c probe function only for devices
1366 * the driver has determined it should claim. Prior to calling
1367 * this function the specific probe function has called pci_enable_device
1368 * upon errant exit from this function specific probe function should call
1369 * pci_disable_device
1370 */
Rajiv Andradef02a9362008-10-11 09:04:23 +11001371struct tpm_chip *tpm_register_hardware(struct device *dev,
1372 const struct tpm_vendor_specific *entry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
Kylene Jo Hall6f9becc2005-06-25 14:55:41 -07001374#define DEVNAME_SIZE 7
1375
1376 char *devname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 struct tpm_chip *chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 /* Driver specific per-device data */
Andrew Mortonb888c872005-10-30 15:03:28 -08001380 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
Parag Warudkar8e39c932007-05-08 00:31:09 -07001381 devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
1382
Andrew Mortondd78c942008-10-15 22:04:37 -07001383 if (chip == NULL || devname == NULL)
1384 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Matthias Kaehlcked081d472007-05-08 00:32:02 -07001386 mutex_init(&chip->buffer_mutex);
1387 mutex_init(&chip->tpm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 INIT_LIST_HEAD(&chip->list);
1389
David Howellsc4028952006-11-22 14:57:56 +00001390 INIT_WORK(&chip->work, timeout_work);
Kylene Jo Hall09e12f92005-11-13 16:07:43 -08001391
Jiri Slaby40565f12007-02-12 00:52:31 -08001392 setup_timer(&chip->user_read_timer, user_reader_timeout,
1393 (unsigned long)chip);
Kylene Hallfe3fd4832005-06-23 22:01:56 -07001394
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001395 memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Kylene Jo Hall10685a92006-04-22 02:38:32 -07001397 chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Kylene Jo Hall10685a92006-04-22 02:38:32 -07001399 if (chip->dev_num >= TPM_NUM_DEVICES) {
Andrew Mortonb888c872005-10-30 15:03:28 -08001400 dev_err(dev, "No available tpm device numbers\n");
Andrew Mortondd78c942008-10-15 22:04:37 -07001401 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 } else if (chip->dev_num == 0)
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001403 chip->vendor.miscdev.minor = TPM_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 else
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001405 chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Kylene Jo Hall10685a92006-04-22 02:38:32 -07001407 set_bit(chip->dev_num, dev_mask);
1408
Kylene Jo Hall6f9becc2005-06-25 14:55:41 -07001409 scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001410 chip->vendor.miscdev.name = devname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Greg Kroah-Hartman94fbcde2006-07-27 16:16:04 -07001412 chip->vendor.miscdev.parent = dev;
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001413 chip->dev = get_device(dev);
Richard MUSIL5bd91f12008-02-06 01:37:02 -08001414 chip->release = dev->release;
1415 dev->release = tpm_dev_release;
1416 dev_set_drvdata(dev, chip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001418 if (misc_register(&chip->vendor.miscdev)) {
Kylene Jo Halle659a3f2005-10-30 15:03:24 -08001419 dev_err(chip->dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 "unable to misc_register %s, minor %d\n",
Kylene Jo Hall90dda522006-04-22 02:37:15 -07001421 chip->vendor.miscdev.name,
1422 chip->vendor.miscdev.minor);
Wanlong Gaodad79cb2012-05-16 16:24:28 +08001423 goto put_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 }
1425
Jeff Garzikf33d9bd2006-10-11 01:21:51 -07001426 if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
Neil Horman5d469ec2006-12-06 20:37:08 -08001427 misc_deregister(&chip->vendor.miscdev);
Wanlong Gaodad79cb2012-05-16 16:24:28 +08001428 goto put_device;
Jeff Garzikf33d9bd2006-10-11 01:21:51 -07001429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -08001431 chip->bios_dir = tpm_bios_log_setup(devname);
1432
Rajiv Andradef02a9362008-10-11 09:04:23 +11001433 /* Make chip available */
1434 spin_lock(&driver_lock);
1435 list_add_rcu(&chip->list, &tpm_chip_list);
1436 spin_unlock(&driver_lock);
1437
Kylene Jo Halle0dd03c2006-04-22 02:37:26 -07001438 return chip;
Andrew Mortondd78c942008-10-15 22:04:37 -07001439
Wanlong Gaodad79cb2012-05-16 16:24:28 +08001440put_device:
1441 put_device(chip->dev);
Andrew Mortondd78c942008-10-15 22:04:37 -07001442out_free:
1443 kfree(chip);
1444 kfree(devname);
1445 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447EXPORT_SYMBOL_GPL(tpm_register_hardware);
1448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
1450MODULE_DESCRIPTION("TPM Driver");
1451MODULE_VERSION("2.0");
1452MODULE_LICENSE("GPL");