diff options
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/tpm.c | 235 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 14 |
2 files changed, 247 insertions, 2 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index e54bcb4e4e3e..24c4423d4851 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -430,17 +430,27 @@ out: | |||
430 | #define TPM_GET_CAP_RET_UINT32_2_IDX 18 | 430 | #define TPM_GET_CAP_RET_UINT32_2_IDX 18 |
431 | #define TPM_GET_CAP_RET_UINT32_3_IDX 22 | 431 | #define TPM_GET_CAP_RET_UINT32_3_IDX 22 |
432 | #define TPM_GET_CAP_RET_UINT32_4_IDX 26 | 432 | #define TPM_GET_CAP_RET_UINT32_4_IDX 26 |
433 | #define TPM_GET_CAP_PERM_DISABLE_IDX 16 | ||
434 | #define TPM_GET_CAP_PERM_INACTIVE_IDX 18 | ||
435 | #define TPM_GET_CAP_RET_BOOL_1_IDX 14 | ||
436 | #define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 | ||
433 | 437 | ||
434 | #define TPM_CAP_IDX 13 | 438 | #define TPM_CAP_IDX 13 |
435 | #define TPM_CAP_SUBCAP_IDX 21 | 439 | #define TPM_CAP_SUBCAP_IDX 21 |
436 | 440 | ||
437 | enum tpm_capabilities { | 441 | enum tpm_capabilities { |
442 | TPM_CAP_FLAG = 4, | ||
438 | TPM_CAP_PROP = 5, | 443 | TPM_CAP_PROP = 5, |
439 | }; | 444 | }; |
440 | 445 | ||
441 | enum tpm_sub_capabilities { | 446 | enum tpm_sub_capabilities { |
442 | TPM_CAP_PROP_PCR = 0x1, | 447 | TPM_CAP_PROP_PCR = 0x1, |
443 | TPM_CAP_PROP_MANUFACTURER = 0x3, | 448 | TPM_CAP_PROP_MANUFACTURER = 0x3, |
449 | TPM_CAP_FLAG_PERM = 0x8, | ||
450 | TPM_CAP_FLAG_VOL = 0x9, | ||
451 | TPM_CAP_PROP_OWNER = 0x11, | ||
452 | TPM_CAP_PROP_TIS_TIMEOUT = 0x15, | ||
453 | TPM_CAP_PROP_TIS_DURATION = 0x20, | ||
444 | }; | 454 | }; |
445 | 455 | ||
446 | /* | 456 | /* |
@@ -474,6 +484,180 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, | |||
474 | return 0; | 484 | return 0; |
475 | } | 485 | } |
476 | 486 | ||
487 | void tpm_gen_interrupt(struct tpm_chip *chip) | ||
488 | { | ||
489 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | ||
490 | ssize_t rc; | ||
491 | |||
492 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
493 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
494 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | ||
495 | |||
496 | rc = transmit_cmd(chip, data, sizeof(data), | ||
497 | "attempting to determine the timeouts"); | ||
498 | } | ||
499 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | ||
500 | |||
501 | void tpm_get_timeouts(struct tpm_chip *chip) | ||
502 | { | ||
503 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | ||
504 | ssize_t rc; | ||
505 | u32 timeout; | ||
506 | |||
507 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
508 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
509 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | ||
510 | |||
511 | rc = transmit_cmd(chip, data, sizeof(data), | ||
512 | "attempting to determine the timeouts"); | ||
513 | if (rc) | ||
514 | goto duration; | ||
515 | |||
516 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | ||
517 | != 4 * sizeof(u32)) | ||
518 | goto duration; | ||
519 | |||
520 | /* Don't overwrite default if value is 0 */ | ||
521 | timeout = | ||
522 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); | ||
523 | if (timeout) | ||
524 | chip->vendor.timeout_a = timeout; | ||
525 | timeout = | ||
526 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); | ||
527 | if (timeout) | ||
528 | chip->vendor.timeout_b = timeout; | ||
529 | timeout = | ||
530 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); | ||
531 | if (timeout) | ||
532 | chip->vendor.timeout_c = timeout; | ||
533 | timeout = | ||
534 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); | ||
535 | if (timeout) | ||
536 | chip->vendor.timeout_d = timeout; | ||
537 | |||
538 | duration: | ||
539 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
540 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
541 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; | ||
542 | |||
543 | rc = transmit_cmd(chip, data, sizeof(data), | ||
544 | "attempting to determine the durations"); | ||
545 | if (rc) | ||
546 | return; | ||
547 | |||
548 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | ||
549 | != 3 * sizeof(u32)) | ||
550 | return; | ||
551 | |||
552 | chip->vendor.duration[TPM_SHORT] = | ||
553 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); | ||
554 | chip->vendor.duration[TPM_MEDIUM] = | ||
555 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); | ||
556 | chip->vendor.duration[TPM_LONG] = | ||
557 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); | ||
558 | } | ||
559 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | ||
560 | |||
561 | void tpm_continue_selftest(struct tpm_chip *chip) | ||
562 | { | ||
563 | u8 data[] = { | ||
564 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
565 | 0, 0, 0, 10, /* length */ | ||
566 | 0, 0, 0, 83, /* TPM_ORD_GetCapability */ | ||
567 | }; | ||
568 | |||
569 | tpm_transmit(chip, data, sizeof(data)); | ||
570 | } | ||
571 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | ||
572 | |||
573 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | ||
574 | char *buf) | ||
575 | { | ||
576 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; | ||
577 | ssize_t rc; | ||
578 | |||
579 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
580 | if (chip == NULL) | ||
581 | return -ENODEV; | ||
582 | |||
583 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
584 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
585 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
586 | |||
587 | rc = transmit_cmd(chip, data, sizeof(data), | ||
588 | "attemtping to determine the permanent state"); | ||
589 | if (rc) | ||
590 | return 0; | ||
591 | return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); | ||
592 | } | ||
593 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | ||
594 | |||
595 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, | ||
596 | char *buf) | ||
597 | { | ||
598 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; | ||
599 | ssize_t rc; | ||
600 | |||
601 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
602 | if (chip == NULL) | ||
603 | return -ENODEV; | ||
604 | |||
605 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
606 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
607 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
608 | |||
609 | rc = transmit_cmd(chip, data, sizeof(data), | ||
610 | "attemtping to determine the permanent state"); | ||
611 | if (rc) | ||
612 | return 0; | ||
613 | return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); | ||
614 | } | ||
615 | EXPORT_SYMBOL_GPL(tpm_show_active); | ||
616 | |||
617 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, | ||
618 | char *buf) | ||
619 | { | ||
620 | u8 data[sizeof(tpm_cap)]; | ||
621 | ssize_t rc; | ||
622 | |||
623 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
624 | if (chip == NULL) | ||
625 | return -ENODEV; | ||
626 | |||
627 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
628 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
629 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; | ||
630 | |||
631 | rc = transmit_cmd(chip, data, sizeof(data), | ||
632 | "attempting to determine the owner state"); | ||
633 | if (rc) | ||
634 | return 0; | ||
635 | return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); | ||
636 | } | ||
637 | EXPORT_SYMBOL_GPL(tpm_show_owned); | ||
638 | |||
639 | ssize_t tpm_show_temp_deactivated(struct device * dev, | ||
640 | struct device_attribute * attr, char *buf) | ||
641 | { | ||
642 | u8 data[sizeof(tpm_cap)]; | ||
643 | ssize_t rc; | ||
644 | |||
645 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
646 | if (chip == NULL) | ||
647 | return -ENODEV; | ||
648 | |||
649 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
650 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
651 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; | ||
652 | |||
653 | rc = transmit_cmd(chip, data, sizeof(data), | ||
654 | "attempting to determine the temporary state"); | ||
655 | if (rc) | ||
656 | return 0; | ||
657 | return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | ||
658 | } | ||
659 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
660 | |||
477 | static const u8 pcrread[] = { | 661 | static const u8 pcrread[] = { |
478 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 662 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
479 | 0, 0, 0, 14, /* length */ | 663 | 0, 0, 0, 14, /* length */ |
@@ -484,7 +668,7 @@ static const u8 pcrread[] = { | |||
484 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 668 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
485 | char *buf) | 669 | char *buf) |
486 | { | 670 | { |
487 | u8 data[30]; | 671 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)]; |
488 | ssize_t rc; | 672 | ssize_t rc; |
489 | int i, j, num_pcrs; | 673 | int i, j, num_pcrs; |
490 | __be32 index; | 674 | __be32 index; |
@@ -588,6 +772,7 @@ out: | |||
588 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | 772 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
589 | 773 | ||
590 | #define CAP_VERSION_1_1 6 | 774 | #define CAP_VERSION_1_1 6 |
775 | #define CAP_VERSION_1_2 0x1A | ||
591 | #define CAP_VERSION_IDX 13 | 776 | #define CAP_VERSION_IDX 13 |
592 | static const u8 cap_version[] = { | 777 | static const u8 cap_version[] = { |
593 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 778 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
@@ -600,7 +785,7 @@ static const u8 cap_version[] = { | |||
600 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 785 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
601 | char *buf) | 786 | char *buf) |
602 | { | 787 | { |
603 | u8 data[30]; | 788 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; |
604 | ssize_t rc; | 789 | ssize_t rc; |
605 | char *str = buf; | 790 | char *str = buf; |
606 | 791 | ||
@@ -637,6 +822,52 @@ out: | |||
637 | } | 822 | } |
638 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 823 | EXPORT_SYMBOL_GPL(tpm_show_caps); |
639 | 824 | ||
825 | ssize_t tpm_show_caps_1_2(struct device * dev, | ||
826 | struct device_attribute * attr, char *buf) | ||
827 | { | ||
828 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; | ||
829 | ssize_t len; | ||
830 | char *str = buf; | ||
831 | |||
832 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
833 | if (chip == NULL) | ||
834 | return -ENODEV; | ||
835 | |||
836 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
837 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
838 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
839 | |||
840 | if ((len = tpm_transmit(chip, data, sizeof(data))) <= | ||
841 | TPM_ERROR_SIZE) { | ||
842 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | ||
843 | "attempting to determine the manufacturer\n", | ||
844 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | str += sprintf(str, "Manufacturer: 0x%x\n", | ||
849 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | ||
850 | |||
851 | memcpy(data, cap_version, sizeof(cap_version)); | ||
852 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; | ||
853 | |||
854 | if ((len = tpm_transmit(chip, data, sizeof(data))) <= | ||
855 | TPM_ERROR_SIZE) { | ||
856 | dev_err(chip->dev, "A TPM error (%d) occurred " | ||
857 | "attempting to determine the 1.2 version\n", | ||
858 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
859 | goto out; | ||
860 | } | ||
861 | str += sprintf(str, | ||
862 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
863 | (int) data[16], (int) data[17], (int) data[18], | ||
864 | (int) data[19]); | ||
865 | |||
866 | out: | ||
867 | return str - buf; | ||
868 | } | ||
869 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | ||
870 | |||
640 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | 871 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, |
641 | const char *buf, size_t count) | 872 | const char *buf, size_t count) |
642 | { | 873 | { |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 1d28485b8fb3..75d105c4e65d 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -42,8 +42,18 @@ extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, | |||
42 | char *); | 42 | char *); |
43 | extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, | 43 | extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, |
44 | char *); | 44 | char *); |
45 | extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr, | ||
46 | char *); | ||
45 | extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, | 47 | extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, |
46 | const char *, size_t); | 48 | const char *, size_t); |
49 | extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, | ||
50 | char *); | ||
51 | extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr, | ||
52 | char *); | ||
53 | extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, | ||
54 | char *); | ||
55 | extern ssize_t tpm_show_temp_deactivated(struct device *, | ||
56 | struct device_attribute *attr, char *); | ||
47 | 57 | ||
48 | struct tpm_chip; | 58 | struct tpm_chip; |
49 | 59 | ||
@@ -63,6 +73,7 @@ struct tpm_vendor_specific { | |||
63 | u8 (*status) (struct tpm_chip *); | 73 | u8 (*status) (struct tpm_chip *); |
64 | struct miscdevice miscdev; | 74 | struct miscdevice miscdev; |
65 | struct attribute_group *attr_group; | 75 | struct attribute_group *attr_group; |
76 | u32 timeout_a, timeout_b, timeout_c, timeout_d; | ||
66 | u32 duration[3]; | 77 | u32 duration[3]; |
67 | }; | 78 | }; |
68 | 79 | ||
@@ -101,6 +112,9 @@ static inline void tpm_write_index(int base, int index, int value) | |||
101 | outb(value & 0xFF, base+1); | 112 | outb(value & 0xFF, base+1); |
102 | } | 113 | } |
103 | 114 | ||
115 | extern void tpm_get_timeouts(struct tpm_chip *); | ||
116 | extern void tpm_gen_interrupt(struct tpm_chip *); | ||
117 | extern void tpm_continue_selftest(struct tpm_chip *); | ||
104 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); | 118 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); |
105 | extern struct tpm_chip* tpm_register_hardware(struct device *, | 119 | extern struct tpm_chip* tpm_register_hardware(struct device *, |
106 | const struct tpm_vendor_specific *); | 120 | const struct tpm_vendor_specific *); |