TBR: reviewed in person with semenzato
diff --git a/firmware/include/load_firmware_fw.h b/firmware/include/load_firmware_fw.h
index 6bdcc6a..e377766 100644
--- a/firmware/include/load_firmware_fw.h
+++ b/firmware/include/load_firmware_fw.h
@@ -16,10 +16,12 @@
  * boot phases */
 #define LOAD_FIRMWARE_KEY_BLOB_REC_SIZE 2104
 
-/* Return codes for LoadFirmware() */
+/* Return codes for LoadFirmware() and S3Resume(). */
 #define LOAD_FIRMWARE_SUCCESS 0   /* Success */
 #define LOAD_FIRMWARE_RECOVERY 1  /* Reboot to recovery mode */
 #define LOAD_FIRMWARE_REBOOT 2    /* Reboot to same mode as current boot */
+#define LOAD_FIRMWARE_RECOVERY_TPM 3  /* Reboot to recovery mode due
+                                       * to TPM error */
 
 /* Boot flags for LoadFirmware().boot_flags */
 #define BOOT_FLAG_DEVELOPER UINT64_C(0x01)  /* Developer switch is on */
@@ -85,7 +87,9 @@
 void UpdateFirmwareBodyHash(LoadFirmwareParams* params,
                             uint8_t* data, uint64_t size);
 
-
-
+/* Handle S3 resume.
+ *
+ * Returns LOAD_FIRMWARE_SUCCESS if successful, error code on failure. */
+int S3Resume(void);
 
 #endif  /* VBOOT_REFERENCE_LOAD_FIRMWARE_FW_H_ */
diff --git a/firmware/lib/include/rollback_index.h b/firmware/lib/include/rollback_index.h
index f8f78a1..0e630db 100644
--- a/firmware/lib/include/rollback_index.h
+++ b/firmware/lib/include/rollback_index.h
@@ -83,6 +83,10 @@
   Must send in developer and recovery flags
 */
 
+/* These functions are called from S3Resume().  They cannot use
+ * global variables. */
+uint32_t RollbackS3Resume(void);
+
 /* These functions are callable from LoadFirmware().  They cannot use
  * global variables. */
 
diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c
index 0d9b23c..931e819 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -256,6 +256,17 @@
 
 /* Dummy implementations which don't support TPM rollback protection */
 
+uint32_t RollbackS3Resume(void) {
+#ifndef CHROMEOS_ENVIRONMENT
+  /* Initialize the TPM, but ignore return codes.  In ChromeOS
+   * environment, don't even talk to the TPM. */
+  TlclLibInit();
+  TlclResume();
+  TlclSelfTestFull();
+#endif
+  return TPM_SUCCESS;
+}
+
 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) {
 #ifndef CHROMEOS_ENVIRONMENT
   /* Initializes the TPM, but ignores return codes.  In ChromeOS
@@ -302,6 +313,22 @@
 }
 
 #else
+
+uint32_t RollbackS3Resume(void) {
+  TlclLibInit();
+  RETURN_ON_FAILURE(TlclResume());
+#ifdef USE_CONTINUE_SELF_TEST
+  /* TODO: ContinueSelfTest() should be faster than SelfTestFull, but
+   * may also not work properly in older TPM firmware.  For now, do
+   * the full self test. */
+  RETURN_ON_FAILURE(TlclContinueSelfTest());
+#else
+  RETURN_ON_FAILURE(TlclSelfTestFull());
+#endif
+  return TPM_SUCCESS;
+}
+
+
 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) {
   RollbackSpaceFirmware rsf;
   uint8_t out_digest[20];  /* For PCR extend output */
@@ -316,7 +343,7 @@
     RETURN_ON_FAILURE(TlclExtend(DEV_MODE_PCR, DEV_MODE_OFF_SHA1_DIGEST,
                                  out_digest));
   VBDEBUG(("TPM: RollbackFirmwareSetup dev mode PCR out_digest %02x %02x %02x "
-           "%02x", out_digest, out_digest+1, out_digest+2, out_digest+3));
+           "%02x\n", out_digest, out_digest+1, out_digest+2, out_digest+3));
 
   return TPM_SUCCESS;
 }
diff --git a/firmware/lib/tpm_lite/include/tss_constants.h b/firmware/lib/tpm_lite/include/tss_constants.h
index 6475adb..d1d2f22 100644
--- a/firmware/lib/tpm_lite/include/tss_constants.h
+++ b/firmware/lib/tpm_lite/include/tss_constants.h
@@ -13,6 +13,7 @@
 
 #define TPM_MAX_COMMAND_SIZE 4096
 #define TPM_LARGE_ENOUGH_COMMAND_SIZE 256  /* saves space in the firmware */
+#define TPM_PUBEK_SIZE 256
 
 #define TPM_E_NON_FATAL 0x800
 
diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c
index 39c92e6..cc0c373 100644
--- a/firmware/lib/tpm_lite/tlcl.c
+++ b/firmware/lib/tpm_lite/tlcl.c
@@ -18,7 +18,6 @@
 #include "tlcl.h"
 #include "tlcl_internal.h"
 #include "tlcl_structures.h"
-#include "tpmextras.h"
 #include "utility.h"
 
 /* Sets the size field of a TPM command. */
diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c
index ac16246..4a0c74a 100644
--- a/firmware/lib/vboot_firmware.c
+++ b/firmware/lib/vboot_firmware.c
@@ -64,7 +64,7 @@
   if (0 != status) {
     VBDEBUG(("Unable to setup TPM and read stored versions.\n"));
     return (status == TPM_E_MUST_REBOOT ?
-            LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY);
+            LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM);
   }
 
   /* Allocate our internal data */
@@ -214,7 +214,7 @@
       if (0 != status) {
         VBDEBUG(("Unable to write stored versions.\n"));
         return (status == TPM_E_MUST_REBOOT ?
-                LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY);
+                LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM);
       }
     }
 
@@ -223,7 +223,7 @@
     if (0 != status) {
       VBDEBUG(("Unable to lock firmware versions.\n"));
       return (status == TPM_E_MUST_REBOOT ?
-              LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY);
+              LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM);
     }
 
     /* Success */
@@ -235,3 +235,16 @@
   VBDEBUG(("Alas, no good firmware.\n"));
   return LOAD_FIRMWARE_RECOVERY;
 }
+
+
+int S3Resume(void) {
+  /* Resume the TPM */
+  uint32_t status = RollbackS3Resume();
+
+  if (status == TPM_SUCCESS)
+    return LOAD_FIRMWARE_SUCCESS;
+  else if (status == TPM_E_MUST_REBOOT)
+    return LOAD_FIRMWARE_REBOOT;
+  else
+    return LOAD_FIRMWARE_RECOVERY_TPM;
+}
diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c
index daa4247..fbf4a2f 100644
--- a/firmware/linktest/main.c
+++ b/firmware/linktest/main.c
@@ -27,6 +27,7 @@
   LoadKernel(0);
 
   /* rollback_index.h */
+  RollbackS3Resume();
   RollbackFirmwareSetup(0, 0);
   RollbackFirmwareWrite(0);
   RollbackFirmwareLock();
@@ -40,6 +41,7 @@
   TlclCloseDevice();
   TlclOpenDevice();
   TlclStartup();
+  TlclResume();
   TlclSelfTestFull();
   TlclContinueSelfTest();
   TlclDefineSpace(0, 0, 0);
diff --git a/firmware/stub/tpm_lite_stub.c b/firmware/stub/tpm_lite_stub.c
index 6df8464..a302dcc 100644
--- a/firmware/stub/tpm_lite_stub.c
+++ b/firmware/stub/tpm_lite_stub.c
@@ -22,7 +22,6 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include "tpmextras.h"
 #define TPM_DEVICE_PATH "/dev/tpm0"
 
 /* TODO: these functions should pass errors back rather than returning void */
diff --git a/firmware/version.c b/firmware/version.c
index 85a841d..551bdcf 100644
--- a/firmware/version.c
+++ b/firmware/version.c
@@ -1 +1 @@
-char* VbootVersion = "VBOOv=fc764233";
+char* VbootVersion = "VBOOv=54e1e8b5";
diff --git a/firmware/stub/include/tpmextras.h b/utility/include/tpmextras.h
similarity index 100%
rename from firmware/stub/include/tpmextras.h
rename to utility/include/tpmextras.h