tpm2: support capturing/restoring state of orderly spaces

This CL provides utility functions for copying the current state of
RAM-backed nv indices to an alt location in RAM and restoring from there
to allow saving this state over TPM reset.

BUG=b:201101365
TEST=1) create an orderly counter
     2) increment it
     3) trigger EC reset
     4) verify that the counter value was preserved

Change-Id: Ia074e5603e4a99c7de4b71bcbeae90175ccfe861
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/tpm2/+/3417937
Reviewed-by: Mary Ruthven <mruthven@chromium.org>
Auto-Submit: Andrey Pronin <apronin@chromium.org>
Tested-by: Andrey Pronin <apronin@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Commit-Queue: Andrey Pronin <apronin@chromium.org>
diff --git a/Global.c b/Global.c
index b9f6bcd..a555a58 100644
--- a/Global.c
+++ b/Global.c
@@ -29,6 +29,7 @@
 TPM_SU                  g_prevOrderlyState;
 BOOL                    g_updateNV;
 BOOL                    g_nvOk;
+BOOL                    g_nvStatePreserved;
 TPM2B_AUTH              g_platformUniqueDetails;
 STATE_CLEAR_DATA        gc;
 STATE_RESET_DATA        gr;
diff --git a/Global.h b/Global.h
index 593686b..737c66a 100644
--- a/Global.h
+++ b/Global.h
@@ -653,6 +653,15 @@
 extern BOOL                   g_nvOk;
 //
 //
+//       g_nvStateRestored
+//
+//      This value indicates if the state of RAM-backed NV indices has been preserved over TPM reset.
+//      If that was the case, the state doesn't need to be re-read from flash and the counters don't need to be rolled
+//      up even after unorderly shutdowns.
+//
+extern BOOL                   g_nvStatePreserved;
+//
+//
 //       g_platformUnique
 //
 //      This location contains the unique value(s) used to identify the TPM. It is loaded on every
diff --git a/NV.c b/NV.c
index c97af58..6b16311 100644
--- a/NV.c
+++ b/NV.c
@@ -927,6 +927,29 @@
 }
 //
 //
+//          NvStateCapture()
+//
+//      This function is used to capture the current state of RAM backed NV Indices in an external `copy`.
+//      It doesn't need to capture s_ramIndexSize since that value is always saved to flash when it is modified.
+//
+void NvStateCapture(BYTE copy[RAM_INDEX_SPACE])
+{
+    memcpy(copy, s_ramIndex, RAM_INDEX_SPACE);
+}
+//
+//
+//          NvStateRestore()
+//
+//      This function is used to restore the current state of RAM backed NV Indices from an external `copy`.
+//      It doesn't need to restore s_ramIndexSize since that value is always saved to flash when it is modified.
+//
+void NvStateRestore(const BYTE copy[RAM_INDEX_SPACE])
+{
+    memcpy(s_ramIndex, copy, RAM_INDEX_SPACE);
+    g_nvStatePreserved = TRUE;
+}
+//
+//
 //
 //           NvEntityStartup()
 //
@@ -944,10 +967,17 @@
 {
     NV_ITER                   iter = NV_ITER_INIT;
     UINT32                    currentAddr;         // offset points to the current entity
-    // Restore RAM index data
+    BOOL                      nvStatePreserved = g_nvStatePreserved;
+
+    g_nvStatePreserved = FALSE;
+    // Restore RAM index size
     _plat__NvMemoryRead(s_ramIndexSizeAddr, sizeof(UINT32), &s_ramIndexSize);
-    _plat__NvMemoryRead(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
-    NvCleanBadFromRAM();
+    if (!nvStatePreserved)
+    {
+        // Restore RAM index data
+        _plat__NvMemoryRead(s_ramIndexAddr, RAM_INDEX_SPACE, s_ramIndex);
+        NvCleanBadFromRAM();
+    }
     // If recovering from state save, do nothing
     if(type == SU_RESUME)
         return;
@@ -998,8 +1028,10 @@
                  g_updateNV = TRUE;
          }
          // Set the lower bits in an orderly counter to 1 for a non-orderly startup
+         // unless the state was restored for them.
          if(    g_prevOrderlyState == SHUTDOWN_NONE
-             && attributes.TPMA_NV_WRITTEN == SET)
+             && attributes.TPMA_NV_WRITTEN == SET
+             && !nvStatePreserved)
          {
               if(    attributes.TPMA_NV_ORDERLY == SET
                   && attributes.TPMA_NV_COUNTER == SET)
diff --git a/NV_fp.h b/NV_fp.h
index ef821cf..1678f53 100644
--- a/NV_fp.h
+++ b/NV_fp.h
@@ -97,6 +97,8 @@
                     );
 void NvSetGlobalLock(void);
 void NvStateSave(void);
+void NvStateCapture(BYTE copy[RAM_INDEX_SPACE]);
+void NvStateRestore(const BYTE copy[RAM_INDEX_SPACE]);
 TPM_RC NvWriteIndexData(TPMI_RH_NV_INDEX handle,  //   IN: handle
                         NV_INDEX *nvIndex,        //   IN: RAM copy of NV Index
                         UINT32 offset,            //   IN: offset of NV data
diff --git a/_TPM_Init.c b/_TPM_Init.c
index 7c8fa7f..6e7a33d 100644
--- a/_TPM_Init.c
+++ b/_TPM_Init.c
@@ -14,6 +14,7 @@
    // Clear the failure mode flags
    g_inFailureMode = FALSE;
    g_forceFailureMode = FALSE;
+   g_nvStatePreserved = FALSE;
 
    // Initialize the NvEnvironment.
    g_nvOk = NvPowerOn();