aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm/tpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r--drivers/char/tpm/tpm.c47
1 files changed, 40 insertions, 7 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 068c816e6942..05ad4a17a28f 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1068,6 +1068,27 @@ void tpm_remove_hardware(struct device *dev)
1068} 1068}
1069EXPORT_SYMBOL_GPL(tpm_remove_hardware); 1069EXPORT_SYMBOL_GPL(tpm_remove_hardware);
1070 1070
1071#define TPM_ORD_SAVESTATE cpu_to_be32(152)
1072#define SAVESTATE_RESULT_SIZE 10
1073
1074static struct tpm_input_header savestate_header = {
1075 .tag = TPM_TAG_RQU_COMMAND,
1076 .length = cpu_to_be32(10),
1077 .ordinal = TPM_ORD_SAVESTATE
1078};
1079
1080/* Bug workaround - some TPM's don't flush the most
1081 * recently changed pcr on suspend, so force the flush
1082 * with an extend to the selected _unused_ non-volatile pcr.
1083 */
1084static int tpm_suspend_pcr;
1085static int __init tpm_suspend_setup(char *str)
1086{
1087 get_option(&str, &tpm_suspend_pcr);
1088 return 1;
1089}
1090__setup("tpm_suspend_pcr=", tpm_suspend_setup);
1091
1071/* 1092/*
1072 * We are about to suspend. Save the TPM state 1093 * We are about to suspend. Save the TPM state
1073 * so that it can be restored. 1094 * so that it can be restored.
@@ -1075,17 +1096,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware);
1075int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) 1096int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
1076{ 1097{
1077 struct tpm_chip *chip = dev_get_drvdata(dev); 1098 struct tpm_chip *chip = dev_get_drvdata(dev);
1078 u8 savestate[] = { 1099 struct tpm_cmd_t cmd;
1079 0, 193, /* TPM_TAG_RQU_COMMAND */ 1100 int rc;
1080 0, 0, 0, 10, /* blob length (in bytes) */ 1101
1081 0, 0, 0, 152 /* TPM_ORD_SaveState */ 1102 u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
1082 };
1083 1103
1084 if (chip == NULL) 1104 if (chip == NULL)
1085 return -ENODEV; 1105 return -ENODEV;
1086 1106
1087 tpm_transmit(chip, savestate, sizeof(savestate)); 1107 /* for buggy tpm, flush pcrs with extend to selected dummy */
1088 return 0; 1108 if (tpm_suspend_pcr) {
1109 cmd.header.in = pcrextend_header;
1110 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
1111 memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
1112 TPM_DIGEST_SIZE);
1113 rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
1114 "extending dummy pcr before suspend");
1115 }
1116
1117 /* now do the actual savestate */
1118 cmd.header.in = savestate_header;
1119 rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
1120 "sending savestate before suspend");
1121 return rc;
1089} 1122}
1090EXPORT_SYMBOL_GPL(tpm_pm_suspend); 1123EXPORT_SYMBOL_GPL(tpm_pm_suspend);
1091 1124