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();