aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/tpm/tpm.c411
-rw-r--r--drivers/char/tpm/tpm.h124
2 files changed, 266 insertions, 269 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 9c47dc48c9fd..9b9eb761cba9 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -429,134 +429,148 @@ out:
429#define TPM_DIGEST_SIZE 20 429#define TPM_DIGEST_SIZE 20
430#define TPM_ERROR_SIZE 10 430#define TPM_ERROR_SIZE 10
431#define TPM_RET_CODE_IDX 6 431#define TPM_RET_CODE_IDX 6
432#define TPM_GET_CAP_RET_SIZE_IDX 10
433#define TPM_GET_CAP_RET_UINT32_1_IDX 14
434#define TPM_GET_CAP_RET_UINT32_2_IDX 18
435#define TPM_GET_CAP_RET_UINT32_3_IDX 22
436#define TPM_GET_CAP_RET_UINT32_4_IDX 26
437#define TPM_GET_CAP_PERM_DISABLE_IDX 16
438#define TPM_GET_CAP_PERM_INACTIVE_IDX 18
439#define TPM_GET_CAP_RET_BOOL_1_IDX 14
440#define TPM_GET_CAP_TEMP_INACTIVE_IDX 16
441
442#define TPM_CAP_IDX 13
443#define TPM_CAP_SUBCAP_IDX 21
444 432
445enum tpm_capabilities { 433enum tpm_capabilities {
446 TPM_CAP_FLAG = 4, 434 TPM_CAP_FLAG = cpu_to_be32(4),
447 TPM_CAP_PROP = 5, 435 TPM_CAP_PROP = cpu_to_be32(5),
436 CAP_VERSION_1_1 = cpu_to_be32(0x06),
437 CAP_VERSION_1_2 = cpu_to_be32(0x1A)
448}; 438};
449 439
450enum tpm_sub_capabilities { 440enum tpm_sub_capabilities {
451 TPM_CAP_PROP_PCR = 0x1, 441 TPM_CAP_PROP_PCR = cpu_to_be32(0x101),
452 TPM_CAP_PROP_MANUFACTURER = 0x3, 442 TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103),
453 TPM_CAP_FLAG_PERM = 0x8, 443 TPM_CAP_FLAG_PERM = cpu_to_be32(0x108),
454 TPM_CAP_FLAG_VOL = 0x9, 444 TPM_CAP_FLAG_VOL = cpu_to_be32(0x109),
455 TPM_CAP_PROP_OWNER = 0x11, 445 TPM_CAP_PROP_OWNER = cpu_to_be32(0x111),
456 TPM_CAP_PROP_TIS_TIMEOUT = 0x15, 446 TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
457 TPM_CAP_PROP_TIS_DURATION = 0x20, 447 TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
458};
459 448
460/*
461 * This is a semi generic GetCapability command for use
462 * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG
463 * and their associated sub_capabilities.
464 */
465
466static const u8 tpm_cap[] = {
467 0, 193, /* TPM_TAG_RQU_COMMAND */
468 0, 0, 0, 22, /* length */
469 0, 0, 0, 101, /* TPM_ORD_GetCapability */
470 0, 0, 0, 0, /* TPM_CAP_<TYPE> */
471 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */
472 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */
473}; 449};
474 450
475static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, 451static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
476 char *desc) 452 int len, const char *desc)
477{ 453{
478 int err; 454 int err;
479 455
480 len = tpm_transmit(chip, data, len); 456 len = tpm_transmit(chip,(u8 *) cmd, len);
481 if (len < 0) 457 if (len < 0)
482 return len; 458 return len;
483 if (len == TPM_ERROR_SIZE) { 459 if (len == TPM_ERROR_SIZE) {
484 err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); 460 err = be32_to_cpu(cmd->header.out.return_code);
485 dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); 461 dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
486 return err; 462 return err;
487 } 463 }
488 return 0; 464 return 0;
489} 465}
490 466
467#define TPM_INTERNAL_RESULT_SIZE 200
468#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
469#define TPM_ORD_GET_CAP cpu_to_be32(101)
470
471static const struct tpm_input_header tpm_getcap_header = {
472 .tag = TPM_TAG_RQU_COMMAND,
473 .length = cpu_to_be32(22),
474 .ordinal = TPM_ORD_GET_CAP
475};
476
477ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
478 const char *desc)
479{
480 struct tpm_cmd_t tpm_cmd;
481 int rc;
482 struct tpm_chip *chip = dev_get_drvdata(dev);
483
484 tpm_cmd.header.in = tpm_getcap_header;
485 if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) {
486 tpm_cmd.params.getcap_in.cap = subcap_id;
487 /*subcap field not necessary */
488 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
489 tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
490 } else {
491 if (subcap_id == TPM_CAP_FLAG_PERM ||
492 subcap_id == TPM_CAP_FLAG_VOL)
493 tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG;
494 else
495 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
496 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
497 tpm_cmd.params.getcap_in.subcap = subcap_id;
498 }
499 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
500 if (!rc)
501 *cap = tpm_cmd.params.getcap_out.cap;
502 return rc;
503}
504
491void tpm_gen_interrupt(struct tpm_chip *chip) 505void tpm_gen_interrupt(struct tpm_chip *chip)
492{ 506{
493 u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; 507 struct tpm_cmd_t tpm_cmd;
494 ssize_t rc; 508 ssize_t rc;
495 509
496 memcpy(data, tpm_cap, sizeof(tpm_cap)); 510 tpm_cmd.header.in = tpm_getcap_header;
497 data[TPM_CAP_IDX] = TPM_CAP_PROP; 511 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
498 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; 512 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
513 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
499 514
500 rc = transmit_cmd(chip, data, sizeof(data), 515 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
501 "attempting to determine the timeouts"); 516 "attempting to determine the timeouts");
502} 517}
503EXPORT_SYMBOL_GPL(tpm_gen_interrupt); 518EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
504 519
505void tpm_get_timeouts(struct tpm_chip *chip) 520void tpm_get_timeouts(struct tpm_chip *chip)
506{ 521{
507 u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; 522 struct tpm_cmd_t tpm_cmd;
523 struct timeout_t *timeout_cap;
524 struct duration_t *duration_cap;
508 ssize_t rc; 525 ssize_t rc;
509 u32 timeout; 526 u32 timeout;
510 527
511 memcpy(data, tpm_cap, sizeof(tpm_cap)); 528 tpm_cmd.header.in = tpm_getcap_header;
512 data[TPM_CAP_IDX] = TPM_CAP_PROP; 529 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
513 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; 530 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
531 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
514 532
515 rc = transmit_cmd(chip, data, sizeof(data), 533 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
516 "attempting to determine the timeouts"); 534 "attempting to determine the timeouts");
517 if (rc) 535 if (rc)
518 goto duration; 536 goto duration;
519 537
520 if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) 538 if (be32_to_cpu(tpm_cmd.header.out.length)
521 != 4 * sizeof(u32)) 539 != 4 * sizeof(u32))
522 goto duration; 540 goto duration;
523 541
542 timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
524 /* Don't overwrite default if value is 0 */ 543 /* Don't overwrite default if value is 0 */
525 timeout = 544 timeout = be32_to_cpu(timeout_cap->a);
526 be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
527 if (timeout) 545 if (timeout)
528 chip->vendor.timeout_a = usecs_to_jiffies(timeout); 546 chip->vendor.timeout_a = usecs_to_jiffies(timeout);
529 timeout = 547 timeout = be32_to_cpu(timeout_cap->b);
530 be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
531 if (timeout) 548 if (timeout)
532 chip->vendor.timeout_b = usecs_to_jiffies(timeout); 549 chip->vendor.timeout_b = usecs_to_jiffies(timeout);
533 timeout = 550 timeout = be32_to_cpu(timeout_cap->c);
534 be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
535 if (timeout) 551 if (timeout)
536 chip->vendor.timeout_c = usecs_to_jiffies(timeout); 552 chip->vendor.timeout_c = usecs_to_jiffies(timeout);
537 timeout = 553 timeout = be32_to_cpu(timeout_cap->d);
538 be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
539 if (timeout) 554 if (timeout)
540 chip->vendor.timeout_d = usecs_to_jiffies(timeout); 555 chip->vendor.timeout_d = usecs_to_jiffies(timeout);
541 556
542duration: 557duration:
543 memcpy(data, tpm_cap, sizeof(tpm_cap)); 558 tpm_cmd.header.in = tpm_getcap_header;
544 data[TPM_CAP_IDX] = TPM_CAP_PROP; 559 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
545 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; 560 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
561 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
546 562
547 rc = transmit_cmd(chip, data, sizeof(data), 563 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
548 "attempting to determine the durations"); 564 "attempting to determine the durations");
549 if (rc) 565 if (rc)
550 return; 566 return;
551 567
552 if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) 568 if (be32_to_cpu(tpm_cmd.header.out.return_code)
553 != 3 * sizeof(u32)) 569 != 3 * sizeof(u32))
554 return; 570 return;
555 571 duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
556 chip->vendor.duration[TPM_SHORT] = 572 chip->vendor.duration[TPM_SHORT] =
557 usecs_to_jiffies(be32_to_cpu 573 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
558 (*((__be32 *) (data +
559 TPM_GET_CAP_RET_UINT32_1_IDX))));
560 /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above 574 /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
561 * value wrong and apparently reports msecs rather than usecs. So we 575 * value wrong and apparently reports msecs rather than usecs. So we
562 * fix up the resulting too-small TPM_SHORT value to make things work. 576 * fix up the resulting too-small TPM_SHORT value to make things work.
@@ -565,13 +579,9 @@ duration:
565 chip->vendor.duration[TPM_SHORT] = HZ; 579 chip->vendor.duration[TPM_SHORT] = HZ;
566 580
567 chip->vendor.duration[TPM_MEDIUM] = 581 chip->vendor.duration[TPM_MEDIUM] =
568 usecs_to_jiffies(be32_to_cpu 582 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
569 (*((__be32 *) (data +
570 TPM_GET_CAP_RET_UINT32_2_IDX))));
571 chip->vendor.duration[TPM_LONG] = 583 chip->vendor.duration[TPM_LONG] =
572 usecs_to_jiffies(be32_to_cpu 584 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
573 (*((__be32 *) (data +
574 TPM_GET_CAP_RET_UINT32_3_IDX))));
575} 585}
576EXPORT_SYMBOL_GPL(tpm_get_timeouts); 586EXPORT_SYMBOL_GPL(tpm_get_timeouts);
577 587
@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip)
587} 597}
588EXPORT_SYMBOL_GPL(tpm_continue_selftest); 598EXPORT_SYMBOL_GPL(tpm_continue_selftest);
589 599
590#define TPM_INTERNAL_RESULT_SIZE 200
591
592ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, 600ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
593 char *buf) 601 char *buf)
594{ 602{
595 u8 *data; 603 cap_t cap;
596 ssize_t rc; 604 ssize_t rc;
597 605
598 struct tpm_chip *chip = dev_get_drvdata(dev); 606 rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
599 if (chip == NULL) 607 "attempting to determine the permanent enabled state");
600 return -ENODEV; 608 if (rc)
601
602 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
603 if (!data)
604 return -ENOMEM;
605
606 memcpy(data, tpm_cap, sizeof(tpm_cap));
607 data[TPM_CAP_IDX] = TPM_CAP_FLAG;
608 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
609
610 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
611 "attemtping to determine the permanent enabled state");
612 if (rc) {
613 kfree(data);
614 return 0; 609 return 0;
615 }
616
617 rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]);
618 610
619 kfree(data); 611 rc = sprintf(buf, "%d\n", !cap.perm_flags.disable);
620 return rc; 612 return rc;
621} 613}
622EXPORT_SYMBOL_GPL(tpm_show_enabled); 614EXPORT_SYMBOL_GPL(tpm_show_enabled);
@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled);
624ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, 616ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr,
625 char *buf) 617 char *buf)
626{ 618{
627 u8 *data; 619 cap_t cap;
628 ssize_t rc; 620 ssize_t rc;
629 621
630 struct tpm_chip *chip = dev_get_drvdata(dev); 622 rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap,
631 if (chip == NULL) 623 "attempting to determine the permanent active state");
632 return -ENODEV; 624 if (rc)
633
634 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
635 if (!data)
636 return -ENOMEM;
637
638 memcpy(data, tpm_cap, sizeof(tpm_cap));
639 data[TPM_CAP_IDX] = TPM_CAP_FLAG;
640 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM;
641
642 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
643 "attemtping to determine the permanent active state");
644 if (rc) {
645 kfree(data);
646 return 0; 625 return 0;
647 }
648 626
649 rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); 627 rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated);
650
651 kfree(data);
652 return rc; 628 return rc;
653} 629}
654EXPORT_SYMBOL_GPL(tpm_show_active); 630EXPORT_SYMBOL_GPL(tpm_show_active);
@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active);
656ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, 632ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr,
657 char *buf) 633 char *buf)
658{ 634{
659 u8 *data; 635 cap_t cap;
660 ssize_t rc; 636 ssize_t rc;
661 637
662 struct tpm_chip *chip = dev_get_drvdata(dev); 638 rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap,
663 if (chip == NULL) 639 "attempting to determine the owner state");
664 return -ENODEV; 640 if (rc)
665
666 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
667 if (!data)
668 return -ENOMEM;
669
670 memcpy(data, tpm_cap, sizeof(tpm_cap));
671 data[TPM_CAP_IDX] = TPM_CAP_PROP;
672 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER;
673
674 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
675 "attempting to determine the owner state");
676 if (rc) {
677 kfree(data);
678 return 0; 641 return 0;
679 }
680
681 rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]);
682 642
683 kfree(data); 643 rc = sprintf(buf, "%d\n", cap.owned);
684 return rc; 644 return rc;
685} 645}
686EXPORT_SYMBOL_GPL(tpm_show_owned); 646EXPORT_SYMBOL_GPL(tpm_show_owned);
@@ -688,31 +648,15 @@ EXPORT_SYMBOL_GPL(tpm_show_owned);
688ssize_t tpm_show_temp_deactivated(struct device * dev, 648ssize_t tpm_show_temp_deactivated(struct device * dev,
689 struct device_attribute * attr, char *buf) 649 struct device_attribute * attr, char *buf)
690{ 650{
691 u8 *data; 651 cap_t cap;
692 ssize_t rc; 652 ssize_t rc;
693 653
694 struct tpm_chip *chip = dev_get_drvdata(dev); 654 rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap,
695 if (chip == NULL) 655 "attempting to determine the temporary state");
696 return -ENODEV; 656 if (rc)
697
698 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
699 if (!data)
700 return -ENOMEM;
701
702 memcpy(data, tpm_cap, sizeof(tpm_cap));
703 data[TPM_CAP_IDX] = TPM_CAP_FLAG;
704 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL;
705
706 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
707 "attempting to determine the temporary state");
708 if (rc) {
709 kfree(data);
710 return 0; 657 return 0;
711 }
712 658
713 rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); 659 rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated);
714
715 kfree(data);
716 return rc; 660 return rc;
717} 661}
718EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); 662EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated);
@@ -727,77 +671,64 @@ static const u8 pcrread[] = {
727ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, 671ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
728 char *buf) 672 char *buf)
729{ 673{
674 cap_t cap;
730 u8 *data; 675 u8 *data;
731 ssize_t rc; 676 ssize_t rc;
732 int i, j, num_pcrs; 677 int i, j, num_pcrs;
733 __be32 index; 678 __be32 index;
734 char *str = buf; 679 char *str = buf;
735
736 struct tpm_chip *chip = dev_get_drvdata(dev); 680 struct tpm_chip *chip = dev_get_drvdata(dev);
737 if (chip == NULL)
738 return -ENODEV;
739 681
740 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); 682 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
741 if (!data) 683 if (!data)
742 return -ENOMEM; 684 return -ENOMEM;
743 685
744 memcpy(data, tpm_cap, sizeof(tpm_cap)); 686 rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap,
745 data[TPM_CAP_IDX] = TPM_CAP_PROP;
746 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR;
747
748 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
749 "attempting to determine the number of PCRS"); 687 "attempting to determine the number of PCRS");
750 if (rc) { 688 if (rc)
751 kfree(data);
752 return 0; 689 return 0;
753 }
754 690
755 num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); 691 num_pcrs = be32_to_cpu(cap.num_pcrs);
756 for (i = 0; i < num_pcrs; i++) { 692 for (i = 0; i < num_pcrs; i++) {
757 memcpy(data, pcrread, sizeof(pcrread)); 693 memcpy(data, pcrread, sizeof(pcrread));
758 index = cpu_to_be32(i); 694 index = cpu_to_be32(i);
759 memcpy(data + 10, &index, 4); 695 memcpy(data + 10, &index, 4);
760 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, 696 rc = transmit_cmd(chip, (struct tpm_cmd_t *)data,
761 "attempting to read a PCR"); 697 TPM_INTERNAL_RESULT_SIZE,
698 "attempting to read a PCR");
762 if (rc) 699 if (rc)
763 goto out; 700 break;
764 str += sprintf(str, "PCR-%02d: ", i); 701 str += sprintf(str, "PCR-%02d: ", i);
765 for (j = 0; j < TPM_DIGEST_SIZE; j++) 702 for (j = 0; j < TPM_DIGEST_SIZE; j++)
766 str += sprintf(str, "%02X ", *(data + 10 + j)); 703 str += sprintf(str, "%02X ", *(data + 10 + j));
767 str += sprintf(str, "\n"); 704 str += sprintf(str, "\n");
768 } 705 }
769out:
770 kfree(data); 706 kfree(data);
771 return str - buf; 707 return str - buf;
772} 708}
773EXPORT_SYMBOL_GPL(tpm_show_pcrs); 709EXPORT_SYMBOL_GPL(tpm_show_pcrs);
774 710
775#define READ_PUBEK_RESULT_SIZE 314 711#define READ_PUBEK_RESULT_SIZE 314
776static const u8 readpubek[] = { 712#define TPM_ORD_READPUBEK cpu_to_be32(124)
777 0, 193, /* TPM_TAG_RQU_COMMAND */ 713struct tpm_input_header tpm_readpubek_header = {
778 0, 0, 0, 30, /* length */ 714 .tag = TPM_TAG_RQU_COMMAND,
779 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ 715 .length = cpu_to_be32(30),
716 .ordinal = TPM_ORD_READPUBEK
780}; 717};
781 718
782ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, 719ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
783 char *buf) 720 char *buf)
784{ 721{
785 u8 *data; 722 u8 *data;
723 struct tpm_cmd_t tpm_cmd;
786 ssize_t err; 724 ssize_t err;
787 int i, rc; 725 int i, rc;
788 char *str = buf; 726 char *str = buf;
789 727
790 struct tpm_chip *chip = dev_get_drvdata(dev); 728 struct tpm_chip *chip = dev_get_drvdata(dev);
791 if (chip == NULL)
792 return -ENODEV;
793 729
794 data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); 730 tpm_cmd.header.in = tpm_readpubek_header;
795 if (!data) 731 err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
796 return -ENOMEM;
797
798 memcpy(data, readpubek, sizeof(readpubek));
799
800 err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE,
801 "attempting to read the PUBEK"); 732 "attempting to read the PUBEK");
802 if (err) 733 if (err)
803 goto out; 734 goto out;
@@ -812,7 +743,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
812 256 byte modulus 743 256 byte modulus
813 ignore checksum 20 bytes 744 ignore checksum 20 bytes
814 */ 745 */
815 746 data = tpm_cmd.params.readpubek_out_buffer;
816 str += 747 str +=
817 sprintf(str, 748 sprintf(str,
818 "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" 749 "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@@ -832,65 +763,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
832 } 763 }
833out: 764out:
834 rc = str - buf; 765 rc = str - buf;
835 kfree(data);
836 return rc; 766 return rc;
837} 767}
838EXPORT_SYMBOL_GPL(tpm_show_pubek); 768EXPORT_SYMBOL_GPL(tpm_show_pubek);
839 769
840#define CAP_VERSION_1_1 6
841#define CAP_VERSION_1_2 0x1A
842#define CAP_VERSION_IDX 13
843static const u8 cap_version[] = {
844 0, 193, /* TPM_TAG_RQU_COMMAND */
845 0, 0, 0, 18, /* length */
846 0, 0, 0, 101, /* TPM_ORD_GetCapability */
847 0, 0, 0, 0,
848 0, 0, 0, 0
849};
850 770
851ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, 771ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
852 char *buf) 772 char *buf)
853{ 773{
854 u8 *data; 774 cap_t cap;
855 ssize_t rc; 775 ssize_t rc;
856 char *str = buf; 776 char *str = buf;
857 777
858 struct tpm_chip *chip = dev_get_drvdata(dev); 778 rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
859 if (chip == NULL)
860 return -ENODEV;
861
862 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
863 if (!data)
864 return -ENOMEM;
865
866 memcpy(data, tpm_cap, sizeof(tpm_cap));
867 data[TPM_CAP_IDX] = TPM_CAP_PROP;
868 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
869
870 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
871 "attempting to determine the manufacturer"); 779 "attempting to determine the manufacturer");
872 if (rc) { 780 if (rc)
873 kfree(data);
874 return 0; 781 return 0;
875 }
876
877 str += sprintf(str, "Manufacturer: 0x%x\n", 782 str += sprintf(str, "Manufacturer: 0x%x\n",
878 be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); 783 be32_to_cpu(cap.manufacturer_id));
879 784
880 memcpy(data, cap_version, sizeof(cap_version)); 785 rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap,
881 data[CAP_VERSION_IDX] = CAP_VERSION_1_1; 786 "attempting to determine the 1.1 version");
882 rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE,
883 "attempting to determine the 1.1 version");
884 if (rc) 787 if (rc)
885 goto out; 788 return 0;
886
887 str += sprintf(str, 789 str += sprintf(str,
888 "TCG version: %d.%d\nFirmware version: %d.%d\n", 790 "TCG version: %d.%d\nFirmware version: %d.%d\n",
889 (int) data[14], (int) data[15], (int) data[16], 791 cap.tpm_version.Major, cap.tpm_version.Minor,
890 (int) data[17]); 792 cap.tpm_version.revMajor, cap.tpm_version.revMinor);
891
892out:
893 kfree(data);
894 return str - buf; 793 return str - buf;
895} 794}
896EXPORT_SYMBOL_GPL(tpm_show_caps); 795EXPORT_SYMBOL_GPL(tpm_show_caps);
@@ -898,51 +797,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps);
898ssize_t tpm_show_caps_1_2(struct device * dev, 797ssize_t tpm_show_caps_1_2(struct device * dev,
899 struct device_attribute * attr, char *buf) 798 struct device_attribute * attr, char *buf)
900{ 799{
901 u8 *data; 800 cap_t cap;
902 ssize_t len; 801 ssize_t rc;
903 char *str = buf; 802 char *str = buf;
904 803
905 struct tpm_chip *chip = dev_get_drvdata(dev); 804 rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap,
906 if (chip == NULL) 805 "attempting to determine the manufacturer");
907 return -ENODEV; 806 if (rc)
908
909 data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL);
910 if (!data)
911 return -ENOMEM;
912
913 memcpy(data, tpm_cap, sizeof(tpm_cap));
914 data[TPM_CAP_IDX] = TPM_CAP_PROP;
915 data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER;
916
917 len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
918 if (len <= TPM_ERROR_SIZE) {
919 dev_dbg(chip->dev, "A TPM error (%d) occurred "
920 "attempting to determine the manufacturer\n",
921 be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
922 kfree(data);
923 return 0; 807 return 0;
924 }
925
926 str += sprintf(str, "Manufacturer: 0x%x\n", 808 str += sprintf(str, "Manufacturer: 0x%x\n",
927 be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); 809 be32_to_cpu(cap.manufacturer_id));
928 810 rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap,
929 memcpy(data, cap_version, sizeof(cap_version)); 811 "attempting to determine the 1.2 version");
930 data[CAP_VERSION_IDX] = CAP_VERSION_1_2; 812 if (rc)
931 813 return 0;
932 len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE);
933 if (len <= TPM_ERROR_SIZE) {
934 dev_err(chip->dev, "A TPM error (%d) occurred "
935 "attempting to determine the 1.2 version\n",
936 be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))));
937 goto out;
938 }
939 str += sprintf(str, 814 str += sprintf(str,
940 "TCG version: %d.%d\nFirmware version: %d.%d\n", 815 "TCG version: %d.%d\nFirmware version: %d.%d\n",
941 (int) data[16], (int) data[17], (int) data[18], 816 cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor,
942 (int) data[19]); 817 cap.tpm_version_1_2.revMajor,
943 818 cap.tpm_version_1_2.revMinor);
944out:
945 kfree(data);
946 return str - buf; 819 return str - buf;
947} 820}
948EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); 821EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 8e30df4a4388..d64f6b7e5b82 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -123,6 +123,130 @@ static inline void tpm_write_index(int base, int index, int value)
123 outb(index, base); 123 outb(index, base);
124 outb(value & 0xFF, base+1); 124 outb(value & 0xFF, base+1);
125} 125}
126struct tpm_input_header {
127 __be16 tag;
128 __be32 length;
129 __be32 ordinal;
130}__attribute__((packed));
131
132struct tpm_output_header {
133 __be16 tag;
134 __be32 length;
135 __be32 return_code;
136}__attribute__((packed));
137
138struct stclear_flags_t {
139 __be16 tag;
140 u8 deactivated;
141 u8 disableForceClear;
142 u8 physicalPresence;
143 u8 physicalPresenceLock;
144 u8 bGlobalLock;
145}__attribute__((packed));
146
147struct tpm_version_t {
148 u8 Major;
149 u8 Minor;
150 u8 revMajor;
151 u8 revMinor;
152}__attribute__((packed));
153
154struct tpm_version_1_2_t {
155 __be16 tag;
156 u8 Major;
157 u8 Minor;
158 u8 revMajor;
159 u8 revMinor;
160}__attribute__((packed));
161
162struct timeout_t {
163 __be32 a;
164 __be32 b;
165 __be32 c;
166 __be32 d;
167}__attribute__((packed));
168
169struct duration_t {
170 __be32 tpm_short;
171 __be32 tpm_medium;
172 __be32 tpm_long;
173}__attribute__((packed));
174
175struct permanent_flags_t {
176 __be16 tag;
177 u8 disable;
178 u8 ownership;
179 u8 deactivated;
180 u8 readPubek;
181 u8 disableOwnerClear;
182 u8 allowMaintenance;
183 u8 physicalPresenceLifetimeLock;
184 u8 physicalPresenceHWEnable;
185 u8 physicalPresenceCMDEnable;
186 u8 CEKPUsed;
187 u8 TPMpost;
188 u8 TPMpostLock;
189 u8 FIPS;
190 u8 operator;
191 u8 enableRevokeEK;
192 u8 nvLocked;
193 u8 readSRKPub;
194 u8 tpmEstablished;
195 u8 maintenanceDone;
196 u8 disableFullDALogicInfo;
197}__attribute__((packed));
198
199typedef union {
200 struct permanent_flags_t perm_flags;
201 struct stclear_flags_t stclear_flags;
202 bool owned;
203 __be32 num_pcrs;
204 struct tpm_version_t tpm_version;
205 struct tpm_version_1_2_t tpm_version_1_2;
206 __be32 manufacturer_id;
207 struct timeout_t timeout;
208 struct duration_t duration;
209} cap_t;
210
211struct tpm_getcap_params_in {
212 __be32 cap;
213 __be32 subcap_size;
214 __be32 subcap;
215}__attribute__((packed));
216
217struct tpm_getcap_params_out {
218 __be32 cap_size;
219 cap_t cap;
220}__attribute__((packed));
221
222struct tpm_readpubek_params_out {
223 u8 algorithm[4];
224 u8 encscheme[2];
225 u8 sigscheme[2];
226 u8 parameters[12]; /*assuming RSA*/
227 __be32 keysize;
228 u8 modulus[256];
229 u8 checksum[20];
230}__attribute__((packed));
231
232typedef union {
233 struct tpm_input_header in;
234 struct tpm_output_header out;
235} tpm_cmd_header;
236
237typedef union {
238 struct tpm_getcap_params_out getcap_out;
239 struct tpm_readpubek_params_out readpubek_out;
240 u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
241 struct tpm_getcap_params_in getcap_in;
242} tpm_cmd_params;
243
244struct tpm_cmd_t {
245 tpm_cmd_header header;
246 tpm_cmd_params params;
247}__attribute__((packed));
248
249ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
126 250
127extern void tpm_get_timeouts(struct tpm_chip *); 251extern void tpm_get_timeouts(struct tpm_chip *);
128extern void tpm_gen_interrupt(struct tpm_chip *); 252extern void tpm_gen_interrupt(struct tpm_chip *);