Browse Source

IntelSiliconPkg/SpiFvbServiceSmm: Rewrite VariableStore header.

When invalid VariableStore FV header detected, current SpiFvbService
will erase both FV and VariableStore headers from flash, however,
it will only rewrite FV header back and cause invalid VariableStore
header.

This patch adding the support for rewriting both FV header and
VariableStore header when VariableStore corruption happened.
The Corrupted variable content should be taken care by
FaultTolerantWrite driver later.

Platform has to set PcdFlashVariableStoreType to inform SpiFvbService
which VariableStoreType should be rewritten.

Cc: Ashraf Ali S <ashraf.ali.s@intel.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Signed-off-by: Chasel Chiu <chasel.chiu@intel.com>
Reviewed-by: Michael Kubacki <michael.kubacki@microsoft.com>
Reviewed-by: S, Ashraf Ali <ashraf.ali.s@intel.com>
Reviewed-by: Isaac Oram <isaac.w.oram@intel.com>
Chasel Chiu 1 year ago
parent
commit
e95c798899

+ 65 - 5
Silicon/Intel/IntelSiliconPkg/Feature/Flash/SpiFvbService/SpiFvbServiceMm.c

@@ -12,6 +12,7 @@
 #include <Library/MmServicesTableLib.h>
 #include <Library/UefiDriverEntryPoint.h>
 #include <Protocol/SmmFirmwareVolumeBlock.h>
+#include <Guid/VariableFormat.h>
 
 /**
   The function installs EFI_FIRMWARE_VOLUME_BLOCK protocol
@@ -113,7 +114,12 @@ FvbInitialize (
   UINT32                                MaxLbaSize;
   UINT32                                BytesWritten;
   UINTN                                 BytesErased;
+  EFI_PHYSICAL_ADDRESS                  NvStorageBaseAddress;
   UINT64                                NvStorageFvSize;
+  UINT32                                ExpectedBytesWritten;
+  VARIABLE_STORE_HEADER                 *VariableStoreHeader;
+  UINT8                                 VariableStoreType;
+  UINT8                                 *NvStoreBuffer;
 
   Status = GetVariableFlashNvStorageInfo (&BaseAddress, &NvStorageFvSize);
   if (EFI_ERROR (Status)) {
@@ -129,12 +135,15 @@ FvbInitialize (
     DEBUG ((DEBUG_ERROR, "[%a] - 64-bit variable storage base address not supported.\n", __FUNCTION__));
     return;
   }
+  NvStorageBaseAddress = mPlatformFvBaseAddress[0].FvBase;
+
   Status = SafeUint64ToUint32 (NvStorageFvSize, &mPlatformFvBaseAddress[0].FvSize);
   if (EFI_ERROR (Status)) {
     ASSERT_EFI_ERROR (Status);
     DEBUG ((DEBUG_ERROR, "[%a] - 64-bit variable storage size not supported.\n", __FUNCTION__));
     return;
   }
+  NvStorageFvSize = mPlatformFvBaseAddress[0].FvSize;
 
   mPlatformFvBaseAddress[1].FvBase = PcdGet32(PcdFlashMicrocodeFvBase);
   mPlatformFvBaseAddress[1].FvSize = PcdGet32(PcdFlashMicrocodeFvSize);
@@ -186,8 +195,59 @@ FvbInitialize (
           }
           continue;
         }
-        BytesWritten = FvHeader->HeaderLength;
-        Status = SpiFlashWrite ((UINTN)BaseAddress, &BytesWritten, (UINT8*)FvHeader);
+
+        BytesWritten         = FvHeader->HeaderLength;
+        ExpectedBytesWritten = BytesWritten;
+        if (BaseAddress != NvStorageBaseAddress) {
+          Status = SpiFlashWrite ((UINTN)BaseAddress, &BytesWritten, (UINT8 *)FvHeader);
+        } else {
+          //
+          // This is Variable Store, rewrite both EFI_FIRMWARE_VOLUME_HEADER and VARIABLE_STORE_HEADER.
+          // The corrupted Variable content should be taken care by FaultTolerantWrite driver later.
+          //
+          NvStoreBuffer = NULL;
+          NvStoreBuffer = AllocateZeroPool (sizeof (VARIABLE_STORE_HEADER) + FvHeader->HeaderLength);
+          if (NvStoreBuffer != NULL) {
+            //
+            // Combine FV header and VariableStore header into the buffer.
+            //
+            CopyMem (NvStoreBuffer, FvHeader, FvHeader->HeaderLength);
+            VariableStoreHeader = (VARIABLE_STORE_HEADER *)(NvStoreBuffer + FvHeader->HeaderLength);
+            VariableStoreType   = PcdGet8 (PcdFlashVariableStoreType);
+            switch (VariableStoreType) {
+              case 0:
+                DEBUG ((DEBUG_ERROR, "Type: gEfiVariableGuid\n"));
+                CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid);
+                break;
+              case 1:
+                DEBUG ((DEBUG_ERROR, "Type: gEfiAuthenticatedVariableGuid\n"));
+                CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
+                break;
+              default:
+                break;
+            }
+
+            //
+            // Initialize common VariableStore header fields
+            //
+            VariableStoreHeader->Size      = (UINT32) (NvStorageFvSize - FvHeader->HeaderLength);
+            VariableStoreHeader->Format    = VARIABLE_STORE_FORMATTED;
+            VariableStoreHeader->State     = VARIABLE_STORE_HEALTHY;
+            VariableStoreHeader->Reserved  = 0;
+            VariableStoreHeader->Reserved1 = 0;
+
+            //
+            // Write buffer to flash
+            //
+            BytesWritten         = FvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER);
+            ExpectedBytesWritten = BytesWritten;
+            Status               = SpiFlashWrite ((UINTN)BaseAddress, &BytesWritten, NvStoreBuffer);
+            FreePool (NvStoreBuffer);
+          } else {
+            Status = EFI_OUT_OF_RESOURCES;
+          }
+        }
+
         if (EFI_ERROR (Status)) {
           DEBUG ((DEBUG_WARN, "ERROR - SpiFlashWrite Error  %r\n", Status));
           if (FvHeader != NULL) {
@@ -195,9 +255,9 @@ FvbInitialize (
           }
           continue;
         }
-        if (BytesWritten != FvHeader->HeaderLength) {
-          DEBUG ((DEBUG_WARN, "ERROR - BytesWritten != HeaderLength\n"));
-          DEBUG ((DEBUG_INFO, " BytesWritten = 0x%X\n HeaderLength = 0x%X\n", BytesWritten, FvHeader->HeaderLength));
+        if (BytesWritten != ExpectedBytesWritten) {
+          DEBUG ((DEBUG_WARN, "ERROR - BytesWritten != ExpectedBytesWritten\n"));
+          DEBUG ((DEBUG_INFO, " BytesWritten = 0x%X\n ExpectedBytesWritten = 0x%X\n", BytesWritten, ExpectedBytesWritten));
           if (FvHeader != NULL) {
             FreePool (FvHeader);
           }

+ 3 - 0
Silicon/Intel/IntelSiliconPkg/Feature/Flash/SpiFvbService/SpiFvbServiceSmm.inf

@@ -45,6 +45,7 @@
 [Pcd]
   gIntelSiliconPkgTokenSpaceGuid.PcdFlashMicrocodeFvBase         ## CONSUMES
   gIntelSiliconPkgTokenSpaceGuid.PcdFlashMicrocodeFvSize         ## CONSUMES
+  gIntelSiliconPkgTokenSpaceGuid.PcdFlashVariableStoreType       ## SOMETIMES_CONSUMES
 
 [Sources]
   FvbInfo.c
@@ -61,6 +62,8 @@
 [Guids]
   gEfiFirmwareFileSystem2Guid                   ## CONSUMES
   gEfiSystemNvDataFvGuid                        ## CONSUMES
+  gEfiVariableGuid                              ## SOMETIMES_CONSUMES
+  gEfiAuthenticatedVariableGuid                 ## SOMETIMES_CONSUMES
 
 [Depex]
   TRUE

+ 8 - 0
Silicon/Intel/IntelSiliconPkg/IntelSiliconPkg.dec

@@ -186,3 +186,11 @@
   # @Prompt VTd abort DMA mode support.
   gIntelSiliconPkgTokenSpaceGuid.PcdVTdSupportAbortDmaMode|FALSE|BOOLEAN|0x0000000C
 
+  ## Define Flash Variable Store type.<BR><BR>
+  #  When Flash Variable Store corruption happened, the SpiFvbService will recreate Variable Store
+  #  with valid header information provided by this PCD value.<BR>
+  #  0: Variable Store is gEfiVariableGuid type.<BR>
+  #  1: Variable Store is gEfiAuthenticatedVariableGuid type.<BR>
+  #  Other value: reserved for future use.<BR>
+  # @Prompt Flash Variable Store type.
+  gIntelSiliconPkgTokenSpaceGuid.PcdFlashVariableStoreType|0x00|UINT8|0x0000000E