diff options
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 102 |
1 files changed, 76 insertions, 26 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 7beb0e25f1e1..caf8012ef47c 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -534,6 +534,7 @@ void tpm_get_timeouts(struct tpm_chip *chip) | |||
534 | struct duration_t *duration_cap; | 534 | struct duration_t *duration_cap; |
535 | ssize_t rc; | 535 | ssize_t rc; |
536 | u32 timeout; | 536 | u32 timeout; |
537 | unsigned int scale = 1; | ||
537 | 538 | ||
538 | tpm_cmd.header.in = tpm_getcap_header; | 539 | tpm_cmd.header.in = tpm_getcap_header; |
539 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 540 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
@@ -545,24 +546,30 @@ void tpm_get_timeouts(struct tpm_chip *chip) | |||
545 | if (rc) | 546 | if (rc) |
546 | goto duration; | 547 | goto duration; |
547 | 548 | ||
548 | if (be32_to_cpu(tpm_cmd.header.out.length) | 549 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
549 | != 4 * sizeof(u32)) | 550 | be32_to_cpu(tpm_cmd.header.out.length) |
550 | goto duration; | 551 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) |
552 | return; | ||
551 | 553 | ||
552 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; | 554 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; |
553 | /* Don't overwrite default if value is 0 */ | 555 | /* Don't overwrite default if value is 0 */ |
554 | timeout = be32_to_cpu(timeout_cap->a); | 556 | timeout = be32_to_cpu(timeout_cap->a); |
557 | if (timeout && timeout < 1000) { | ||
558 | /* timeouts in msec rather usec */ | ||
559 | scale = 1000; | ||
560 | chip->vendor.timeout_adjusted = true; | ||
561 | } | ||
555 | if (timeout) | 562 | if (timeout) |
556 | chip->vendor.timeout_a = usecs_to_jiffies(timeout); | 563 | chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale); |
557 | timeout = be32_to_cpu(timeout_cap->b); | 564 | timeout = be32_to_cpu(timeout_cap->b); |
558 | if (timeout) | 565 | if (timeout) |
559 | chip->vendor.timeout_b = usecs_to_jiffies(timeout); | 566 | chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale); |
560 | timeout = be32_to_cpu(timeout_cap->c); | 567 | timeout = be32_to_cpu(timeout_cap->c); |
561 | if (timeout) | 568 | if (timeout) |
562 | chip->vendor.timeout_c = usecs_to_jiffies(timeout); | 569 | chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale); |
563 | timeout = be32_to_cpu(timeout_cap->d); | 570 | timeout = be32_to_cpu(timeout_cap->d); |
564 | if (timeout) | 571 | if (timeout) |
565 | chip->vendor.timeout_d = usecs_to_jiffies(timeout); | 572 | chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale); |
566 | 573 | ||
567 | duration: | 574 | duration: |
568 | tpm_cmd.header.in = tpm_getcap_header; | 575 | tpm_cmd.header.in = tpm_getcap_header; |
@@ -575,23 +582,31 @@ duration: | |||
575 | if (rc) | 582 | if (rc) |
576 | return; | 583 | return; |
577 | 584 | ||
578 | if (be32_to_cpu(tpm_cmd.header.out.return_code) | 585 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
579 | != 3 * sizeof(u32)) | 586 | be32_to_cpu(tpm_cmd.header.out.length) |
587 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) | ||
580 | return; | 588 | return; |
589 | |||
581 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; | 590 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; |
582 | chip->vendor.duration[TPM_SHORT] = | 591 | chip->vendor.duration[TPM_SHORT] = |
583 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); | 592 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); |
593 | chip->vendor.duration[TPM_MEDIUM] = | ||
594 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); | ||
595 | chip->vendor.duration[TPM_LONG] = | ||
596 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); | ||
597 | |||
584 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above | 598 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above |
585 | * value wrong and apparently reports msecs rather than usecs. So we | 599 | * value wrong and apparently reports msecs rather than usecs. So we |
586 | * fix up the resulting too-small TPM_SHORT value to make things work. | 600 | * fix up the resulting too-small TPM_SHORT value to make things work. |
601 | * We also scale the TPM_MEDIUM and -_LONG values by 1000. | ||
587 | */ | 602 | */ |
588 | if (chip->vendor.duration[TPM_SHORT] < (HZ/100)) | 603 | if (chip->vendor.duration[TPM_SHORT] < (HZ / 100)) { |
589 | chip->vendor.duration[TPM_SHORT] = HZ; | 604 | chip->vendor.duration[TPM_SHORT] = HZ; |
590 | 605 | chip->vendor.duration[TPM_MEDIUM] *= 1000; | |
591 | chip->vendor.duration[TPM_MEDIUM] = | 606 | chip->vendor.duration[TPM_LONG] *= 1000; |
592 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); | 607 | chip->vendor.duration_adjusted = true; |
593 | chip->vendor.duration[TPM_LONG] = | 608 | dev_info(chip->dev, "Adjusting TPM timeout parameters."); |
594 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); | 609 | } |
595 | } | 610 | } |
596 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 611 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
597 | 612 | ||
@@ -600,7 +615,7 @@ void tpm_continue_selftest(struct tpm_chip *chip) | |||
600 | u8 data[] = { | 615 | u8 data[] = { |
601 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 616 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
602 | 0, 0, 0, 10, /* length */ | 617 | 0, 0, 0, 10, /* length */ |
603 | 0, 0, 0, 83, /* TPM_ORD_GetCapability */ | 618 | 0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */ |
604 | }; | 619 | }; |
605 | 620 | ||
606 | tpm_transmit(chip, data, sizeof(data)); | 621 | tpm_transmit(chip, data, sizeof(data)); |
@@ -863,18 +878,24 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
863 | data = tpm_cmd.params.readpubek_out_buffer; | 878 | data = tpm_cmd.params.readpubek_out_buffer; |
864 | str += | 879 | str += |
865 | sprintf(str, | 880 | sprintf(str, |
866 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" | 881 | "Algorithm: %02X %02X %02X %02X\n" |
867 | "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X" | 882 | "Encscheme: %02X %02X\n" |
868 | " %02X %02X %02X %02X %02X %02X %02X %02X\n" | 883 | "Sigscheme: %02X %02X\n" |
869 | "Modulus length: %d\nModulus: \n", | 884 | "Parameters: %02X %02X %02X %02X " |
870 | data[10], data[11], data[12], data[13], data[14], | 885 | "%02X %02X %02X %02X " |
871 | data[15], data[16], data[17], data[22], data[23], | 886 | "%02X %02X %02X %02X\n" |
872 | data[24], data[25], data[26], data[27], data[28], | 887 | "Modulus length: %d\n" |
873 | data[29], data[30], data[31], data[32], data[33], | 888 | "Modulus:\n", |
874 | be32_to_cpu(*((__be32 *) (data + 34)))); | 889 | data[0], data[1], data[2], data[3], |
890 | data[4], data[5], | ||
891 | data[6], data[7], | ||
892 | data[12], data[13], data[14], data[15], | ||
893 | data[16], data[17], data[18], data[19], | ||
894 | data[20], data[21], data[22], data[23], | ||
895 | be32_to_cpu(*((__be32 *) (data + 24)))); | ||
875 | 896 | ||
876 | for (i = 0; i < 256; i++) { | 897 | for (i = 0; i < 256; i++) { |
877 | str += sprintf(str, "%02X ", data[i + 38]); | 898 | str += sprintf(str, "%02X ", data[i + 28]); |
878 | if ((i + 1) % 16 == 0) | 899 | if ((i + 1) % 16 == 0) |
879 | str += sprintf(str, "\n"); | 900 | str += sprintf(str, "\n"); |
880 | } | 901 | } |
@@ -937,6 +958,35 @@ ssize_t tpm_show_caps_1_2(struct device * dev, | |||
937 | } | 958 | } |
938 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | 959 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); |
939 | 960 | ||
961 | ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, | ||
962 | char *buf) | ||
963 | { | ||
964 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
965 | |||
966 | return sprintf(buf, "%d %d %d [%s]\n", | ||
967 | jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), | ||
968 | jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), | ||
969 | jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), | ||
970 | chip->vendor.duration_adjusted | ||
971 | ? "adjusted" : "original"); | ||
972 | } | ||
973 | EXPORT_SYMBOL_GPL(tpm_show_durations); | ||
974 | |||
975 | ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, | ||
976 | char *buf) | ||
977 | { | ||
978 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
979 | |||
980 | return sprintf(buf, "%d %d %d %d [%s]\n", | ||
981 | jiffies_to_usecs(chip->vendor.timeout_a), | ||
982 | jiffies_to_usecs(chip->vendor.timeout_b), | ||
983 | jiffies_to_usecs(chip->vendor.timeout_c), | ||
984 | jiffies_to_usecs(chip->vendor.timeout_d), | ||
985 | chip->vendor.timeout_adjusted | ||
986 | ? "adjusted" : "original"); | ||
987 | } | ||
988 | EXPORT_SYMBOL_GPL(tpm_show_timeouts); | ||
989 | |||
940 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | 990 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, |
941 | const char *buf, size_t count) | 991 | const char *buf, size_t count) |
942 | { | 992 | { |