Index: firmware/lib/tpm_lite/tlcl.c |
diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c |
index 12742d8eb3fe44439cfa4fcf09a2e0aa834ce939..f36f46330c257017107bdad271b1ab2569453a14 100644 |
--- a/firmware/lib/tpm_lite/tlcl.c |
+++ b/firmware/lib/tpm_lite/tlcl.c |
@@ -44,11 +44,11 @@ static INLINE int TpmReturnCode(const uint8_t* buffer) { |
return TpmCommandCode(buffer); |
} |
-/* Sends a TPM command and gets a response. Returns 0 if success or the TPM |
- * error code if error. */ |
-static uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response, |
- int max_length) { |
- |
+/* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or |
+ * DOING_SELFTEST errors are returned. |
+ */ |
+static uint32_t TlclSendReceiveNoRetry(const uint8_t* request, |
+ uint8_t* response, int max_length) { |
uint32_t result; |
#ifdef EXTRA_LOGGING |
@@ -83,6 +83,40 @@ static uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response, |
} |
+/* Sends a TPM command and gets a response. Returns 0 if success or the TPM |
+ * error code if error. In the firmware, waits for the self test to complete |
+ * if needed. In the host, reports the first error without retries. */ |
+static uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response, |
+ int max_length) { |
+ uint32_t result = TlclSendReceiveNoRetry(request, response, max_length); |
+ /* When compiling for the firmware, hide command failures due to the self |
+ * test not having run or completed. */ |
+#ifndef CHROMEOS_ENVIRONMENT |
+ /* If the command fails because the self test has not completed, try it |
+ * again after attempting to ensure that the self test has completed. */ |
+ if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) { |
+ result = TlclContinueSelfTest(); |
+ if (result != TPM_SUCCESS) { |
+ return result; |
+ } |
+#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE) |
+ /* Retry only once */ |
+ result = TlclSendReceiveNoRetry(request, response, max_length); |
+#else |
+ /* This needs serious testing. The TPM specification says: "iii. The |
+ * caller MUST wait for the actions of TPM_ContinueSelfTest to complete |
+ * before reissuing the command C1." But, if ContinueSelfTest is |
+ * non-blocking, how do we know that the actions have completed other than |
+ * trying again? */ |
+ do { |
+ result = TlclSendReceiveNoRetry(request, response, max_length); |
+ } while (result == TPM_E_DOING_SELFTEST); |
+#endif |
+ } |
+#endif /* ! defined(CHROMEOS_ENVIRONMENT) */ |
+ return result; |
+} |
+ |
/* Sends a command and returns the error code. */ |
static uint32_t Send(const uint8_t* command) { |
uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; |
@@ -100,6 +134,11 @@ uint32_t TlclStartup(void) { |
return Send(tpm_startup_cmd.buffer); |
} |
+uint32_t TlclSaveState(void) { |
+ VBDEBUG(("TPM: SaveState\n")); |
+ return Send(tpm_savestate_cmd.buffer); |
+} |
+ |
uint32_t TlclResume(void) { |
VBDEBUG(("TPM: Resume\n")); |
return Send(tpm_resume_cmd.buffer); |
@@ -111,8 +150,11 @@ uint32_t TlclSelfTestFull(void) { |
} |
uint32_t TlclContinueSelfTest(void) { |
+ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; |
VBDEBUG(("TPM: Continue self test\n")); |
- return Send(tpm_continueselftest_cmd.buffer); |
+ /* Call the No Retry version of SendReceive to avoid recursion. */ |
+ return TlclSendReceiveNoRetry(tpm_continueselftest_cmd.buffer, |
+ response, sizeof(response)); |
} |
uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) { |
@@ -291,7 +333,8 @@ uint32_t TlclSetGlobalLock(void) { |
return TlclWrite(TPM_NV_INDEX0, (uint8_t*) &x, 0); |
} |
-uint32_t TlclExtend(int pcr_num, uint8_t* in_digest, uint8_t* out_digest) { |
+uint32_t TlclExtend(int pcr_num, const uint8_t* in_digest, |
+ uint8_t* out_digest) { |
struct s_tpm_extend_cmd cmd; |
uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; |
uint32_t result; |