aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
authorRajiv Andrade <srajiv@linux.vnet.ibm.com>2010-03-24 23:55:32 -0400
committerJames Morris <jmorris@namei.org>2010-03-25 18:30:03 -0400
commit225a9be24d799aa16d543c31fb09f0c9ed1d9caa (patch)
treee2db049524c7f153457e55506d1ef4cec0ccf39c /drivers/char/tpm
parent310de047eef6685274045db1e6b39c9f313df428 (diff)
TPM: workaround to enforce PCR updates across suspends
Add a workaround for TPM's which fail to flush last written PCR values in a TPM_SaveState, in preparation for suspend. Signed-off-by: David Safford <safford@watson.ibm.com> Acked-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'drivers/char/tpm')
-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 f06bb37defb1..5c447c991bd5 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1067,6 +1067,27 @@ void tpm_remove_hardware(struct device *dev)
1067} 1067}
1068EXPORT_SYMBOL_GPL(tpm_remove_hardware); 1068EXPORT_SYMBOL_GPL(tpm_remove_hardware);
1069 1069
1070#define TPM_ORD_SAVESTATE cpu_to_be32(152)
1071#define SAVESTATE_RESULT_SIZE 10
1072
1073static struct tpm_input_header savestate_header = {
1074 .tag = TPM_TAG_RQU_COMMAND,
1075 .length = cpu_to_be32(10),
1076 .ordinal = TPM_ORD_SAVESTATE
1077};
1078
1079/* Bug workaround - some TPM's don't flush the most
1080 * recently changed pcr on suspend, so force the flush
1081 * with an extend to the selected _unused_ non-volatile pcr.
1082 */
1083static int tpm_suspend_pcr;
1084static int __init tpm_suspend_setup(char *str)
1085{
1086 get_option(&str, &tpm_suspend_pcr);
1087 return 1;
1088}
1089__setup("tpm_suspend_pcr=", tpm_suspend_setup);
1090
1070/* 1091/*
1071 * We are about to suspend. Save the TPM state 1092 * We are about to suspend. Save the TPM state
1072 * so that it can be restored. 1093 * so that it can be restored.
@@ -1074,17 +1095,29 @@ EXPORT_SYMBOL_GPL(tpm_remove_hardware);
1074int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) 1095int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
1075{ 1096{
1076 struct tpm_chip *chip = dev_get_drvdata(dev); 1097 struct tpm_chip *chip = dev_get_drvdata(dev);
1077 u8 savestate[] = { 1098 struct tpm_cmd_t cmd;
1078 0, 193, /* TPM_TAG_RQU_COMMAND */ 1099 int rc;
1079 0, 0, 0, 10, /* blob length (in bytes) */ 1100
1080 0, 0, 0, 152 /* TPM_ORD_SaveState */ 1101 u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
1081 };
1082 1102
1083 if (chip == NULL) 1103 if (chip == NULL)
1084 return -ENODEV; 1104 return -ENODEV;
1085 1105
1086 tpm_transmit(chip, savestate, sizeof(savestate)); 1106 /* for buggy tpm, flush pcrs with extend to selected dummy */
1087 return 0; 1107 if (tpm_suspend_pcr) {
1108 cmd.header.in = pcrextend_header;
1109 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
1110 memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
1111 TPM_DIGEST_SIZE);
1112 rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
1113 "extending dummy pcr before suspend");
1114 }
1115
1116 /* now do the actual savestate */
1117 cmd.header.in = savestate_header;
1118 rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
1119 "sending savestate before suspend");
1120 return rc;
1088} 1121}
1089EXPORT_SYMBOL_GPL(tpm_pm_suspend); 1122EXPORT_SYMBOL_GPL(tpm_pm_suspend);
1090 1123