ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/char/tpm/tpm.c @ 8745:514f2585d102

Converge the TPM drivers in the Xen repository
with those coming from the 2.6.15 kernel. Some files can now be
taken from 2.6.15 directly and can therefore be removed.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author cl349@firebug.cl.cam.ac.uk
date Fri Feb 03 09:31:28 2006 +0000 (2006-02-03)
parents 2494b4e00cbb
children e9d78d8bd568
line source
1 /*
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 *
10 * Maintained by: <tpmdd_devel@lists.sourceforge.net>
11 *
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
22 * calls to msleep.
23 *
24 */
26 #include <linux/sched.h>
27 #include <linux/poll.h>
28 #include <linux/spinlock.h>
29 #include "tpm.h"
31 enum tpm_const {
32 TPM_MINOR = 224, /* officially assigned */
33 TPM_MIN_BUFSIZE = 2048,
34 TPM_MAX_BUFSIZE = 64 * 1024,
35 TPM_NUM_DEVICES = 256,
36 TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
37 };
39 static LIST_HEAD(tpm_chip_list);
40 static DEFINE_SPINLOCK(driver_lock);
41 static int dev_mask[TPM_NUM_MASK_ENTRIES];
43 static void user_reader_timeout(unsigned long ptr)
44 {
45 struct tpm_chip *chip = (struct tpm_chip *) ptr;
47 schedule_work(&chip->work);
48 }
50 static void timeout_work(void * ptr)
51 {
52 struct tpm_chip *chip = ptr;
54 down(&chip->buffer_mutex);
55 atomic_set(&chip->data_pending, 0);
56 memset(chip->data_buffer, 0, chip->vendor->buffersize);
57 up(&chip->buffer_mutex);
58 }
60 /*
61 * Internal kernel interface to transmit TPM commands
62 */
63 static ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
64 size_t bufsiz)
65 {
66 ssize_t rc;
67 u32 count;
68 unsigned long stop;
70 if (!chip)
71 return -ENODEV;
73 count = be32_to_cpu(*((__be32 *) (buf + 2)));
75 if (count == 0)
76 return -ENODATA;
77 if (count > bufsiz) {
78 dev_err(chip->dev,
79 "invalid count value %x %zx \n", count, bufsiz);
80 return -E2BIG;
81 }
83 down(&chip->tpm_mutex);
85 if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
86 dev_err(chip->dev,
87 "tpm_transmit: tpm_send: error %zd\n", rc);
88 goto out;
89 }
91 stop = jiffies + 2 * 60 * HZ;
92 do {
93 u8 status = chip->vendor->status(chip);
94 if ((status & chip->vendor->req_complete_mask) ==
95 chip->vendor->req_complete_val) {
96 goto out_recv;
97 }
99 if ((status == chip->vendor->req_canceled)) {
100 dev_err(chip->dev, "Operation Canceled\n");
101 rc = -ECANCELED;
102 goto out;
103 }
105 msleep(TPM_TIMEOUT); /* CHECK */
106 rmb();
107 } while (time_before(jiffies, stop));
110 chip->vendor->cancel(chip);
111 dev_err(chip->dev, "Operation Timed out\n");
112 rc = -ETIME;
113 goto out;
115 out_recv:
116 rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
117 if (rc < 0)
118 dev_err(chip->dev,
119 "tpm_transmit: tpm_recv: error %zd\n", rc);
120 out:
121 up(&chip->tpm_mutex);
122 return rc;
123 }
125 #define TPM_DIGEST_SIZE 20
126 #define CAP_PCR_RESULT_SIZE 18
127 static const u8 cap_pcr[] = {
128 0, 193, /* TPM_TAG_RQU_COMMAND */
129 0, 0, 0, 22, /* length */
130 0, 0, 0, 101, /* TPM_ORD_GetCapability */
131 0, 0, 0, 5,
132 0, 0, 0, 4,
133 0, 0, 1, 1
134 };
136 #define READ_PCR_RESULT_SIZE 30
137 static const u8 pcrread[] = {
138 0, 193, /* TPM_TAG_RQU_COMMAND */
139 0, 0, 0, 14, /* length */
140 0, 0, 0, 21, /* TPM_ORD_PcrRead */
141 0, 0, 0, 0 /* PCR index */
142 };
144 ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
145 char *buf)
146 {
147 u8 data[READ_PCR_RESULT_SIZE];
148 ssize_t len;
149 int i, j, num_pcrs;
150 __be32 index;
151 char *str = buf;
153 struct tpm_chip *chip = dev_get_drvdata(dev);
154 if (chip == NULL)
155 return -ENODEV;
157 memcpy(data, cap_pcr, sizeof(cap_pcr));
158 if ((len = tpm_transmit(chip, data, sizeof(data)))
159 < CAP_PCR_RESULT_SIZE) {
160 dev_dbg(chip->dev, "A TPM error (%d) occurred "
161 "attempting to determine the number of PCRS\n",
162 be32_to_cpu(*((__be32 *) (data + 6))));
163 return 0;
164 }
166 num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
168 for (i = 0; i < num_pcrs; i++) {
169 memcpy(data, pcrread, sizeof(pcrread));
170 index = cpu_to_be32(i);
171 memcpy(data + 10, &index, 4);
172 if ((len = tpm_transmit(chip, data, sizeof(data)))
173 < READ_PCR_RESULT_SIZE){
174 dev_dbg(chip->dev, "A TPM error (%d) occurred"
175 " attempting to read PCR %d of %d\n",
176 be32_to_cpu(*((__be32 *) (data + 6))),
177 i, num_pcrs);
178 goto out;
179 }
180 str += sprintf(str, "PCR-%02d: ", i);
181 for (j = 0; j < TPM_DIGEST_SIZE; j++)
182 str += sprintf(str, "%02X ", *(data + 10 + j));
183 str += sprintf(str, "\n");
184 }
185 out:
186 return str - buf;
187 }
188 EXPORT_SYMBOL_GPL(tpm_show_pcrs);
190 #define READ_PUBEK_RESULT_SIZE 314
191 static const u8 readpubek[] = {
192 0, 193, /* TPM_TAG_RQU_COMMAND */
193 0, 0, 0, 30, /* length */
194 0, 0, 0, 124, /* TPM_ORD_ReadPubek */
195 };
197 ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
198 char *buf)
199 {
200 u8 *data;
201 ssize_t len;
202 int i, rc;
203 char *str = buf;
205 struct tpm_chip *chip = dev_get_drvdata(dev);
206 if (chip == NULL)
207 return -ENODEV;
209 data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
210 if (!data)
211 return -ENOMEM;
213 memcpy(data, readpubek, sizeof(readpubek));
215 if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
216 READ_PUBEK_RESULT_SIZE) {
217 dev_dbg(chip->dev, "A TPM error (%d) occurred "
218 "attempting to read the PUBEK\n",
219 be32_to_cpu(*((__be32 *) (data + 6))));
220 rc = 0;
221 goto out;
222 }
224 /*
225 ignore header 10 bytes
226 algorithm 32 bits (1 == RSA )
227 encscheme 16 bits
228 sigscheme 16 bits
229 parameters (RSA 12->bytes: keybit, #primes, expbit)
230 keylenbytes 32 bits
231 256 byte modulus
232 ignore checksum 20 bytes
233 */
235 str +=
236 sprintf(str,
237 "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
238 "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
239 " %02X %02X %02X %02X %02X %02X %02X %02X\n"
240 "Modulus length: %d\nModulus: \n",
241 data[10], data[11], data[12], data[13], data[14],
242 data[15], data[16], data[17], data[22], data[23],
243 data[24], data[25], data[26], data[27], data[28],
244 data[29], data[30], data[31], data[32], data[33],
245 be32_to_cpu(*((__be32 *) (data + 34))));
247 for (i = 0; i < 256; i++) {
248 str += sprintf(str, "%02X ", data[i + 38]);
249 if ((i + 1) % 16 == 0)
250 str += sprintf(str, "\n");
251 }
252 rc = str - buf;
253 out:
254 kfree(data);
255 return rc;
256 }
257 EXPORT_SYMBOL_GPL(tpm_show_pubek);
259 #define CAP_VER_RESULT_SIZE 18
260 static const u8 cap_version[] = {
261 0, 193, /* TPM_TAG_RQU_COMMAND */
262 0, 0, 0, 18, /* length */
263 0, 0, 0, 101, /* TPM_ORD_GetCapability */
264 0, 0, 0, 6,
265 0, 0, 0, 0
266 };
268 #define CAP_MANUFACTURER_RESULT_SIZE 18
269 static const u8 cap_manufacturer[] = {
270 0, 193, /* TPM_TAG_RQU_COMMAND */
271 0, 0, 0, 22, /* length */
272 0, 0, 0, 101, /* TPM_ORD_GetCapability */
273 0, 0, 0, 5,
274 0, 0, 0, 4,
275 0, 0, 1, 3
276 };
278 ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
279 char *buf)
280 {
281 u8 data[sizeof(cap_manufacturer)];
282 ssize_t len;
283 char *str = buf;
285 struct tpm_chip *chip = dev_get_drvdata(dev);
286 if (chip == NULL)
287 return -ENODEV;
289 memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
291 if ((len = tpm_transmit(chip, data, sizeof(data))) <
292 CAP_MANUFACTURER_RESULT_SIZE)
293 return len;
295 str += sprintf(str, "Manufacturer: 0x%x\n",
296 be32_to_cpu(*((__be32 *) (data + 14))));
298 memcpy(data, cap_version, sizeof(cap_version));
300 if ((len = tpm_transmit(chip, data, sizeof(data))) <
301 CAP_VER_RESULT_SIZE)
302 return len;
304 str +=
305 sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
306 (int) data[14], (int) data[15], (int) data[16],
307 (int) data[17]);
309 return str - buf;
310 }
311 EXPORT_SYMBOL_GPL(tpm_show_caps);
313 ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
314 const char *buf, size_t count)
315 {
316 struct tpm_chip *chip = dev_get_drvdata(dev);
317 if (chip == NULL)
318 return 0;
320 chip->vendor->cancel(chip);
321 return count;
322 }
323 EXPORT_SYMBOL_GPL(tpm_store_cancel);
325 /*
326 * Device file system interface to the TPM
327 */
328 int tpm_open(struct inode *inode, struct file *file)
329 {
330 int rc = 0, minor = iminor(inode);
331 struct tpm_chip *chip = NULL, *pos;
333 spin_lock(&driver_lock);
335 list_for_each_entry(pos, &tpm_chip_list, list) {
336 if (pos->vendor->miscdev.minor == minor) {
337 chip = pos;
338 break;
339 }
340 }
342 if (chip == NULL) {
343 rc = -ENODEV;
344 goto err_out;
345 }
347 if (chip->num_opens) {
348 dev_dbg(chip->dev, "Another process owns this TPM\n");
349 rc = -EBUSY;
350 goto err_out;
351 }
353 chip->num_opens++;
354 get_device(chip->dev);
356 spin_unlock(&driver_lock);
358 chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8), GFP_KERNEL);
359 if (chip->data_buffer == NULL) {
360 chip->num_opens--;
361 put_device(chip->dev);
362 return -ENOMEM;
363 }
365 atomic_set(&chip->data_pending, 0);
367 file->private_data = chip;
368 return 0;
370 err_out:
371 spin_unlock(&driver_lock);
372 return rc;
373 }
374 EXPORT_SYMBOL_GPL(tpm_open);
376 int tpm_release(struct inode *inode, struct file *file)
377 {
378 struct tpm_chip *chip = file->private_data;
380 spin_lock(&driver_lock);
381 file->private_data = NULL;
382 chip->num_opens--;
383 del_singleshot_timer_sync(&chip->user_read_timer);
384 flush_scheduled_work();
385 atomic_set(&chip->data_pending, 0);
386 put_device(chip->dev);
387 kfree(chip->data_buffer);
388 spin_unlock(&driver_lock);
389 return 0;
390 }
391 EXPORT_SYMBOL_GPL(tpm_release);
393 ssize_t tpm_write(struct file *file, const char __user *buf,
394 size_t size, loff_t * off)
395 {
396 struct tpm_chip *chip = file->private_data;
397 int in_size = size, out_size;
399 /* cannot perform a write until the read has cleared
400 either via tpm_read or a user_read_timer timeout */
401 while (atomic_read(&chip->data_pending) != 0)
402 msleep(TPM_TIMEOUT);
404 down(&chip->buffer_mutex);
406 if (in_size > chip->vendor->buffersize)
407 in_size = chip->vendor->buffersize;
409 if (copy_from_user
410 (chip->data_buffer, (void __user *) buf, in_size)) {
411 up(&chip->buffer_mutex);
412 return -EFAULT;
413 }
415 /* atomic tpm command send and result receive */
416 out_size = tpm_transmit(chip, chip->data_buffer,
417 chip->vendor->buffersize);
419 atomic_set(&chip->data_pending, out_size);
420 atomic_set(&chip->data_position, 0);
421 up(&chip->buffer_mutex);
423 /* Set a timeout by which the reader must come claim the result */
424 mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
426 return in_size;
427 }
429 EXPORT_SYMBOL_GPL(tpm_write);
431 ssize_t tpm_read(struct file * file, char __user *buf,
432 size_t size, loff_t * off)
433 {
434 struct tpm_chip *chip = file->private_data;
435 int ret_size;
436 int pos, pending = 0;
438 del_singleshot_timer_sync(&chip->user_read_timer);
439 flush_scheduled_work();
440 ret_size = atomic_read(&chip->data_pending);
441 if (ret_size > 0) { /* relay data */
442 if (size < ret_size)
443 ret_size = size;
445 pos = atomic_read(&chip->data_position);
447 down(&chip->buffer_mutex);
448 if (copy_to_user(buf, &chip->data_buffer[pos], ret_size)) {
449 ret_size = -EFAULT;
450 } else {
451 pending = atomic_read(&chip->data_pending) - ret_size;
452 if ( pending ) {
453 atomic_set( &chip->data_pending, pending );
454 atomic_set( &chip->data_position, pos+ret_size );
455 }
456 }
457 up(&chip->buffer_mutex);
458 }
460 if ( ret_size <= 0 || pending == 0 ) {
461 atomic_set( &chip->data_pending, 0 );
462 del_singleshot_timer_sync(&chip->user_read_timer);
463 }
465 return ret_size;
466 }
467 EXPORT_SYMBOL_GPL(tpm_read);
469 void tpm_remove_hardware(struct device *dev)
470 {
471 struct tpm_chip *chip = dev_get_drvdata(dev);
473 if (chip == NULL) {
474 dev_err(dev, "No device data found\n");
475 return;
476 }
478 spin_lock(&driver_lock);
480 list_del(&chip->list);
482 spin_unlock(&driver_lock);
484 dev_set_drvdata(dev, NULL);
485 misc_deregister(&chip->vendor->miscdev);
486 kfree(chip->vendor->miscdev.name);
488 sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
489 tpm_bios_log_teardown(chip->bios_dir);
491 dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
492 ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
494 kfree(chip);
496 put_device(dev);
497 }
498 EXPORT_SYMBOL_GPL(tpm_remove_hardware);
500 static u8 savestate[] = {
501 0, 193, /* TPM_TAG_RQU_COMMAND */
502 0, 0, 0, 10, /* blob length (in bytes) */
503 0, 0, 0, 152 /* TPM_ORD_SaveState */
504 };
506 /*
507 * We are about to suspend. Save the TPM state
508 * so that it can be restored.
509 */
510 int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
511 {
512 struct tpm_chip *chip = dev_get_drvdata(dev);
513 if (chip == NULL)
514 return -ENODEV;
516 tpm_transmit(chip, savestate, sizeof(savestate));
517 return 0;
518 }
519 EXPORT_SYMBOL_GPL(tpm_pm_suspend);
521 /*
522 * Resume from a power safe. The BIOS already restored
523 * the TPM state.
524 */
525 int tpm_pm_resume(struct device *dev)
526 {
527 struct tpm_chip *chip = dev_get_drvdata(dev);
529 if (chip == NULL)
530 return -ENODEV;
532 return 0;
533 }
534 EXPORT_SYMBOL_GPL(tpm_pm_resume);
536 /*
537 * Called from tpm_<specific>.c probe function only for devices
538 * the driver has determined it should claim. Prior to calling
539 * this function the specific probe function has called pci_enable_device
540 * upon errant exit from this function specific probe function should call
541 * pci_disable_device
542 */
543 int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry)
544 {
545 #define DEVNAME_SIZE 7
547 char *devname;
548 struct tpm_chip *chip;
549 int i, j;
551 /* Driver specific per-device data */
552 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
553 if (chip == NULL)
554 return -ENOMEM;
556 init_MUTEX(&chip->buffer_mutex);
557 init_MUTEX(&chip->tpm_mutex);
558 INIT_LIST_HEAD(&chip->list);
560 INIT_WORK(&chip->work, timeout_work, chip);
562 init_timer(&chip->user_read_timer);
563 chip->user_read_timer.function = user_reader_timeout;
564 chip->user_read_timer.data = (unsigned long) chip;
566 chip->vendor = entry;
568 if (entry->buffersize < TPM_MIN_BUFSIZE) {
569 entry->buffersize = TPM_MIN_BUFSIZE;
570 } else if (entry->buffersize > TPM_MAX_BUFSIZE) {
571 entry->buffersize = TPM_MAX_BUFSIZE;
572 }
574 chip->dev_num = -1;
576 for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
577 for (j = 0; j < 8 * sizeof(int); j++)
578 if ((dev_mask[i] & (1 << j)) == 0) {
579 chip->dev_num =
580 i * TPM_NUM_MASK_ENTRIES + j;
581 dev_mask[i] |= 1 << j;
582 goto dev_num_search_complete;
583 }
585 dev_num_search_complete:
586 if (chip->dev_num < 0) {
587 dev_err(dev, "No available tpm device numbers\n");
588 kfree(chip);
589 return -ENODEV;
590 } else if (chip->dev_num == 0)
591 chip->vendor->miscdev.minor = TPM_MINOR;
592 else
593 chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
595 devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
596 scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
597 chip->vendor->miscdev.name = devname;
599 chip->vendor->miscdev.dev = dev;
600 chip->dev = get_device(dev);
602 if (misc_register(&chip->vendor->miscdev)) {
603 dev_err(chip->dev,
604 "unable to misc_register %s, minor %d\n",
605 chip->vendor->miscdev.name,
606 chip->vendor->miscdev.minor);
607 put_device(dev);
608 kfree(chip);
609 dev_mask[i] &= !(1 << j);
610 return -ENODEV;
611 }
613 spin_lock(&driver_lock);
615 dev_set_drvdata(dev, chip);
617 list_add(&chip->list, &tpm_chip_list);
619 spin_unlock(&driver_lock);
621 sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
623 chip->bios_dir = tpm_bios_log_setup(devname);
625 return 0;
626 }
627 EXPORT_SYMBOL_GPL(tpm_register_hardware);
629 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
630 MODULE_DESCRIPTION("TPM Driver");
631 MODULE_VERSION("2.0");
632 MODULE_LICENSE("GPL");