diff options
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 530 |
1 files changed, 248 insertions, 282 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 9c47dc48c9f..ccdd828adce 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 | ||
445 | enum tpm_capabilities { | 433 | enum 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 | ||
450 | enum tpm_sub_capabilities { | 440 | enum 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 | |||
466 | static 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 | ||
475 | static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, | 451 | static 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 | |||
471 | static 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 | |||
477 | ssize_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 | |||
491 | void tpm_gen_interrupt(struct tpm_chip *chip) | 505 | void 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 | } |
503 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | 518 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); |
504 | 519 | ||
505 | void tpm_get_timeouts(struct tpm_chip *chip) | 520 | void 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 | ||
542 | duration: | 557 | duration: |
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 | } |
576 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 586 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
577 | 587 | ||
@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip) | |||
587 | } | 597 | } |
588 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | 598 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); |
589 | 599 | ||
590 | #define TPM_INTERNAL_RESULT_SIZE 200 | ||
591 | |||
592 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | 600 | ssize_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 | } |
622 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | 614 | EXPORT_SYMBOL_GPL(tpm_show_enabled); |
@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled); | |||
624 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, | 616 | ssize_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 | } |
654 | EXPORT_SYMBOL_GPL(tpm_show_active); | 630 | EXPORT_SYMBOL_GPL(tpm_show_active); |
@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active); | |||
656 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, | 632 | ssize_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 | } |
686 | EXPORT_SYMBOL_GPL(tpm_show_owned); | 646 | EXPORT_SYMBOL_GPL(tpm_show_owned); |
@@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned); | |||
688 | ssize_t tpm_show_temp_deactivated(struct device * dev, | 648 | ssize_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) |
657 | return 0; | ||
697 | 658 | ||
698 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | 659 | rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); |
699 | if (!data) | 660 | return rc; |
700 | return -ENOMEM; | 661 | } |
662 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
701 | 663 | ||
702 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 664 | /* |
703 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | 665 | * tpm_chip_find_get - return tpm_chip for given chip number |
704 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; | 666 | */ |
667 | static struct tpm_chip *tpm_chip_find_get(int chip_num) | ||
668 | { | ||
669 | struct tpm_chip *pos, *chip = NULL; | ||
705 | 670 | ||
706 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | 671 | rcu_read_lock(); |
707 | "attempting to determine the temporary state"); | 672 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { |
708 | if (rc) { | 673 | if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) |
709 | kfree(data); | 674 | continue; |
710 | return 0; | 675 | |
676 | if (try_module_get(pos->dev->driver->owner)) { | ||
677 | chip = pos; | ||
678 | break; | ||
679 | } | ||
711 | } | 680 | } |
681 | rcu_read_unlock(); | ||
682 | return chip; | ||
683 | } | ||
712 | 684 | ||
713 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | 685 | #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) |
686 | #define READ_PCR_RESULT_SIZE 30 | ||
687 | static struct tpm_input_header pcrread_header = { | ||
688 | .tag = TPM_TAG_RQU_COMMAND, | ||
689 | .length = cpu_to_be32(14), | ||
690 | .ordinal = TPM_ORDINAL_PCRREAD | ||
691 | }; | ||
714 | 692 | ||
715 | kfree(data); | 693 | int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) |
694 | { | ||
695 | int rc; | ||
696 | struct tpm_cmd_t cmd; | ||
697 | |||
698 | cmd.header.in = pcrread_header; | ||
699 | cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); | ||
700 | BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE); | ||
701 | rc = transmit_cmd(chip, &cmd, cmd.header.in.length, | ||
702 | "attempting to read a pcr value"); | ||
703 | |||
704 | if (rc == 0) | ||
705 | memcpy(res_buf, cmd.params.pcrread_out.pcr_result, | ||
706 | TPM_DIGEST_SIZE); | ||
716 | return rc; | 707 | return rc; |
717 | } | 708 | } |
718 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
719 | 709 | ||
720 | static const u8 pcrread[] = { | 710 | /** |
721 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 711 | * tpm_pcr_read - read a pcr value |
722 | 0, 0, 0, 14, /* length */ | 712 | * @chip_num: tpm idx # or ANY |
723 | 0, 0, 0, 21, /* TPM_ORD_PcrRead */ | 713 | * @pcr_idx: pcr idx to retrieve |
724 | 0, 0, 0, 0 /* PCR index */ | 714 | * @res_buf: TPM_PCR value |
715 | * size of res_buf is 20 bytes (or NULL if you don't care) | ||
716 | * | ||
717 | * The TPM driver should be built-in, but for whatever reason it | ||
718 | * isn't, protect against the chip disappearing, by incrementing | ||
719 | * the module usage count. | ||
720 | */ | ||
721 | int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) | ||
722 | { | ||
723 | struct tpm_chip *chip; | ||
724 | int rc; | ||
725 | |||
726 | chip = tpm_chip_find_get(chip_num); | ||
727 | if (chip == NULL) | ||
728 | return -ENODEV; | ||
729 | rc = __tpm_pcr_read(chip, pcr_idx, res_buf); | ||
730 | module_put(chip->dev->driver->owner); | ||
731 | return rc; | ||
732 | } | ||
733 | EXPORT_SYMBOL_GPL(tpm_pcr_read); | ||
734 | |||
735 | /** | ||
736 | * tpm_pcr_extend - extend pcr value with hash | ||
737 | * @chip_num: tpm idx # or AN& | ||
738 | * @pcr_idx: pcr idx to extend | ||
739 | * @hash: hash value used to extend pcr value | ||
740 | * | ||
741 | * The TPM driver should be built-in, but for whatever reason it | ||
742 | * isn't, protect against the chip disappearing, by incrementing | ||
743 | * the module usage count. | ||
744 | */ | ||
745 | #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) | ||
746 | #define EXTEND_PCR_SIZE 34 | ||
747 | static struct tpm_input_header pcrextend_header = { | ||
748 | .tag = TPM_TAG_RQU_COMMAND, | ||
749 | .length = cpu_to_be32(34), | ||
750 | .ordinal = TPM_ORD_PCR_EXTEND | ||
725 | }; | 751 | }; |
726 | 752 | ||
753 | int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) | ||
754 | { | ||
755 | struct tpm_cmd_t cmd; | ||
756 | int rc; | ||
757 | struct tpm_chip *chip; | ||
758 | |||
759 | chip = tpm_chip_find_get(chip_num); | ||
760 | if (chip == NULL) | ||
761 | return -ENODEV; | ||
762 | |||
763 | cmd.header.in = pcrextend_header; | ||
764 | BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE); | ||
765 | cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); | ||
766 | memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); | ||
767 | rc = transmit_cmd(chip, &cmd, cmd.header.in.length, | ||
768 | "attempting extend a PCR value"); | ||
769 | |||
770 | module_put(chip->dev->driver->owner); | ||
771 | return rc; | ||
772 | } | ||
773 | EXPORT_SYMBOL_GPL(tpm_pcr_extend); | ||
774 | |||
727 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 775 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
728 | char *buf) | 776 | char *buf) |
729 | { | 777 | { |
730 | u8 *data; | 778 | cap_t cap; |
779 | u8 digest[TPM_DIGEST_SIZE]; | ||
731 | ssize_t rc; | 780 | ssize_t rc; |
732 | int i, j, num_pcrs; | 781 | int i, j, num_pcrs; |
733 | __be32 index; | ||
734 | char *str = buf; | 782 | char *str = buf; |
735 | |||
736 | struct tpm_chip *chip = dev_get_drvdata(dev); | 783 | struct tpm_chip *chip = dev_get_drvdata(dev); |
737 | if (chip == NULL) | ||
738 | return -ENODEV; | ||
739 | 784 | ||
740 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | 785 | rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, |
741 | if (!data) | ||
742 | return -ENOMEM; | ||
743 | |||
744 | memcpy(data, tpm_cap, sizeof(tpm_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"); | 786 | "attempting to determine the number of PCRS"); |
750 | if (rc) { | 787 | if (rc) |
751 | kfree(data); | ||
752 | return 0; | 788 | return 0; |
753 | } | ||
754 | 789 | ||
755 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); | 790 | num_pcrs = be32_to_cpu(cap.num_pcrs); |
756 | for (i = 0; i < num_pcrs; i++) { | 791 | for (i = 0; i < num_pcrs; i++) { |
757 | memcpy(data, pcrread, sizeof(pcrread)); | 792 | rc = __tpm_pcr_read(chip, i, digest); |
758 | index = cpu_to_be32(i); | ||
759 | memcpy(data + 10, &index, 4); | ||
760 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
761 | "attempting to read a PCR"); | ||
762 | if (rc) | 793 | if (rc) |
763 | goto out; | 794 | break; |
764 | str += sprintf(str, "PCR-%02d: ", i); | 795 | str += sprintf(str, "PCR-%02d: ", i); |
765 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | 796 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
766 | str += sprintf(str, "%02X ", *(data + 10 + j)); | 797 | str += sprintf(str, "%02X ", digest[j]); |
767 | str += sprintf(str, "\n"); | 798 | str += sprintf(str, "\n"); |
768 | } | 799 | } |
769 | out: | ||
770 | kfree(data); | ||
771 | return str - buf; | 800 | return str - buf; |
772 | } | 801 | } |
773 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | 802 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); |
774 | 803 | ||
775 | #define READ_PUBEK_RESULT_SIZE 314 | 804 | #define READ_PUBEK_RESULT_SIZE 314 |
776 | static const u8 readpubek[] = { | 805 | #define TPM_ORD_READPUBEK cpu_to_be32(124) |
777 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 806 | struct tpm_input_header tpm_readpubek_header = { |
778 | 0, 0, 0, 30, /* length */ | 807 | .tag = TPM_TAG_RQU_COMMAND, |
779 | 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ | 808 | .length = cpu_to_be32(30), |
809 | .ordinal = TPM_ORD_READPUBEK | ||
780 | }; | 810 | }; |
781 | 811 | ||
782 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | 812 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, |
783 | char *buf) | 813 | char *buf) |
784 | { | 814 | { |
785 | u8 *data; | 815 | u8 *data; |
816 | struct tpm_cmd_t tpm_cmd; | ||
786 | ssize_t err; | 817 | ssize_t err; |
787 | int i, rc; | 818 | int i, rc; |
788 | char *str = buf; | 819 | char *str = buf; |
789 | 820 | ||
790 | struct tpm_chip *chip = dev_get_drvdata(dev); | 821 | struct tpm_chip *chip = dev_get_drvdata(dev); |
791 | if (chip == NULL) | ||
792 | return -ENODEV; | ||
793 | 822 | ||
794 | data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); | 823 | tpm_cmd.header.in = tpm_readpubek_header; |
795 | if (!data) | 824 | 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"); | 825 | "attempting to read the PUBEK"); |
802 | if (err) | 826 | if (err) |
803 | goto out; | 827 | goto out; |
@@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
812 | 256 byte modulus | 836 | 256 byte modulus |
813 | ignore checksum 20 bytes | 837 | ignore checksum 20 bytes |
814 | */ | 838 | */ |
815 | 839 | data = tpm_cmd.params.readpubek_out_buffer; | |
816 | str += | 840 | str += |
817 | sprintf(str, | 841 | sprintf(str, |
818 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" | 842 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" |
@@ -832,65 +856,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
832 | } | 856 | } |
833 | out: | 857 | out: |
834 | rc = str - buf; | 858 | rc = str - buf; |
835 | kfree(data); | ||
836 | return rc; | 859 | return rc; |
837 | } | 860 | } |
838 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | 861 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
839 | 862 | ||
840 | #define CAP_VERSION_1_1 6 | ||
841 | #define CAP_VERSION_1_2 0x1A | ||
842 | #define CAP_VERSION_IDX 13 | ||
843 | static 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 | 863 | ||
851 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 864 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
852 | char *buf) | 865 | char *buf) |
853 | { | 866 | { |
854 | u8 *data; | 867 | cap_t cap; |
855 | ssize_t rc; | 868 | ssize_t rc; |
856 | char *str = buf; | 869 | char *str = buf; |
857 | 870 | ||
858 | struct tpm_chip *chip = dev_get_drvdata(dev); | 871 | 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"); | 872 | "attempting to determine the manufacturer"); |
872 | if (rc) { | 873 | if (rc) |
873 | kfree(data); | ||
874 | return 0; | 874 | return 0; |
875 | } | ||
876 | |||
877 | str += sprintf(str, "Manufacturer: 0x%x\n", | 875 | str += sprintf(str, "Manufacturer: 0x%x\n", |
878 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 876 | be32_to_cpu(cap.manufacturer_id)); |
879 | 877 | ||
880 | memcpy(data, cap_version, sizeof(cap_version)); | 878 | rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, |
881 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; | 879 | "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) | 880 | if (rc) |
885 | goto out; | 881 | return 0; |
886 | |||
887 | str += sprintf(str, | 882 | str += sprintf(str, |
888 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | 883 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
889 | (int) data[14], (int) data[15], (int) data[16], | 884 | cap.tpm_version.Major, cap.tpm_version.Minor, |
890 | (int) data[17]); | 885 | cap.tpm_version.revMajor, cap.tpm_version.revMinor); |
891 | |||
892 | out: | ||
893 | kfree(data); | ||
894 | return str - buf; | 886 | return str - buf; |
895 | } | 887 | } |
896 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 888 | EXPORT_SYMBOL_GPL(tpm_show_caps); |
@@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps); | |||
898 | ssize_t tpm_show_caps_1_2(struct device * dev, | 890 | ssize_t tpm_show_caps_1_2(struct device * dev, |
899 | struct device_attribute * attr, char *buf) | 891 | struct device_attribute * attr, char *buf) |
900 | { | 892 | { |
901 | u8 *data; | 893 | cap_t cap; |
902 | ssize_t len; | 894 | ssize_t rc; |
903 | char *str = buf; | 895 | char *str = buf; |
904 | 896 | ||
905 | struct tpm_chip *chip = dev_get_drvdata(dev); | 897 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, |
906 | if (chip == NULL) | 898 | "attempting to determine the manufacturer"); |
907 | return -ENODEV; | 899 | 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; | 900 | return 0; |
924 | } | ||
925 | |||
926 | str += sprintf(str, "Manufacturer: 0x%x\n", | 901 | str += sprintf(str, "Manufacturer: 0x%x\n", |
927 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 902 | be32_to_cpu(cap.manufacturer_id)); |
928 | 903 | rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, | |
929 | memcpy(data, cap_version, sizeof(cap_version)); | 904 | "attempting to determine the 1.2 version"); |
930 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; | 905 | if (rc) |
931 | 906 | 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, | 907 | str += sprintf(str, |
940 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | 908 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
941 | (int) data[16], (int) data[17], (int) data[18], | 909 | cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor, |
942 | (int) data[19]); | 910 | cap.tpm_version_1_2.revMajor, |
943 | 911 | cap.tpm_version_1_2.revMinor); | |
944 | out: | ||
945 | kfree(data); | ||
946 | return str - buf; | 912 | return str - buf; |
947 | } | 913 | } |
948 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | 914 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); |