From 3e02ebb2bbe0fd4da880511b1f35951e1c4b8404 Mon Sep 17 00:00:00 2001 From: Star Zeng Date: Wed, 3 Jul 2013 09:08:40 +0000 Subject: [PATCH] MdeModulePkg: Variable drivers robustly handle crashes during Reclaim(). PEI variable implementation checks only the variable header signature for validity. This does not seem robust if system crash occurred during previous Reclaim() operation. If the crash occurred while FTW was rewriting the variable FV, the signature could be valid even though the rest of the FV isn't valid. Solution: Add a FaultTolerantWritePei driver to check and provide the FTW last write status, then PEI variable and early phase(before FTW protocol ready) of DXE variable can check the status and determine if all or partial variable data has been backed up in spare block, and then use the backed up data. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14454 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Guid/FaultTolerantWrite.h | 54 +++ MdeModulePkg/Include/Guid/SystemNvDataGuid.h | 73 ++- MdeModulePkg/MdeModulePkg.dec | 8 + MdeModulePkg/MdeModulePkg.dsc | 1 + .../FaultTolerantWrite.c | 26 +- .../FaultTolerantWrite.h | 44 +- .../FaultTolerantWriteDxe.inf | 4 +- .../FaultTolerantWriteSmm.inf | 2 +- .../Universal/FaultTolerantWriteDxe/FtwMisc.c | 15 +- .../UpdateWorkingBlock.c | 12 +- .../FaultTolerantWritePei.c | 318 +++++++++++++ .../FaultTolerantWritePei.inf | 61 +++ .../Universal/Variable/Pei/Variable.c | 449 +++++++++++++----- .../Universal/Variable/Pei/Variable.h | 14 +- .../Universal/Variable/Pei/VariablePei.inf | 12 +- .../Universal/Variable/RuntimeDxe/Variable.c | 231 +++++---- .../Universal/Variable/RuntimeDxe/Variable.h | 1 + .../RuntimeDxe/VariableRuntimeDxe.inf | 1 + .../Variable/RuntimeDxe/VariableSmm.inf | 1 + 19 files changed, 1051 insertions(+), 276 deletions(-) create mode 100644 MdeModulePkg/Include/Guid/FaultTolerantWrite.h create mode 100644 MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c create mode 100644 MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf diff --git a/MdeModulePkg/Include/Guid/FaultTolerantWrite.h b/MdeModulePkg/Include/Guid/FaultTolerantWrite.h new file mode 100644 index 0000000000..cb7b454b2b --- /dev/null +++ b/MdeModulePkg/Include/Guid/FaultTolerantWrite.h @@ -0,0 +1,54 @@ +/** @file + Define the GUID gEdkiiFaultTolerantWriteGuid that will be used to build + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob and install PPI to inform the check + for FTW last write data has been done. The GUID hob will be only built if FTW last write was + still in progress with SpareComplete set and DestinationComplete not set. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _FAULT_TOLERANT_WRITE_H_ +#define _FAULT_TOLERANT_WRITE_H_ + +#define EDKII_FAULT_TOLERANT_WRITE_GUID \ + { \ + 0x1d3e9cb8, 0x43af, 0x490b, { 0x83, 0xa, 0x35, 0x16, 0xaa, 0x53, 0x20, 0x47 } \ + } + +// +// FTW Last write data. It will be used as gEdkiiFaultTolerantWriteGuid GUID hob data. +// +typedef struct { + /// + /// Target address to be updated in FTW last write. + /// + EFI_PHYSICAL_ADDRESS TargetAddress; + /// + /// Spare address to back up the updated buffer. + /// + EFI_PHYSICAL_ADDRESS SpareAddress; + /// + /// The length of data that have been backed up in spare block. + /// It is also the length of target block that has been erased. + /// + UINT64 Length; +} FAULT_TOLERANT_WRITE_LAST_WRITE_DATA; + +// +// This GUID will be used to install PPI to inform the check for FTW last write data has been done. +// The related FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob will be only built if +// FTW last write was still in progress with SpareComplete set and DestinationComplete not set. +// It means the target buffer has been backed up in spare block, then target block has been erased, +// but the target buffer has not been writen in target block from spare block. +// +extern EFI_GUID gEdkiiFaultTolerantWriteGuid; + +#endif diff --git a/MdeModulePkg/Include/Guid/SystemNvDataGuid.h b/MdeModulePkg/Include/Guid/SystemNvDataGuid.h index 4e21888356..40446bcc10 100644 --- a/MdeModulePkg/Include/Guid/SystemNvDataGuid.h +++ b/MdeModulePkg/Include/Guid/SystemNvDataGuid.h @@ -1,10 +1,10 @@ /** @file - This file defines NvDataFv GUID and FTW working block structure header. - This guid can be used as FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER if + This file defines NvDataFv GUID and FTW working block structures. + The NvDataFv GUID can be used as FileSystemGuid in EFI_FIRMWARE_VOLUME_HEADER if this FV image contains NV data, such as NV variable data. - This guid can also be used as the signature of FTW working block header. + This file also defines WorkingBlockSignature GUID for FTW working block signature. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -21,10 +21,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define EFI_SYSTEM_NV_DATA_FV_GUID \ {0xfff12b8d, 0x7696, 0x4c8b, {0xa9, 0x85, 0x27, 0x47, 0x7, 0x5b, 0x4f, 0x50} } -/// -/// An NvDataFv GUID used as the signature of FTW working block header. -/// +#define EDKII_WORKING_BLOCK_SIGNATURE_GUID \ + {0x9e58292b, 0x7c68, 0x497d, {0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95} } + extern EFI_GUID gEfiSystemNvDataFvGuid; +extern EFI_GUID gEdkiiWorkingBlockSignatureGuid; #define WORKING_BLOCK_VALID 0x1 #define WORKING_BLOCK_INVALID 0x2 @@ -35,7 +36,9 @@ extern EFI_GUID gEfiSystemNvDataFvGuid; /// typedef struct { /// - /// System Non Volatile FV Guid. + /// FTW working block signature. + /// Its value has be updated from gEfiSystemNvDataFvGuid to gEdkiiWorkingBlockSignatureGuid, + /// because its write queue data format has been updated to support the crossing archs. /// EFI_GUID Signature; /// @@ -55,8 +58,60 @@ typedef struct { UINT64 WriteQueueSize; /// /// Write Queue data. - /// UINT8 WriteQueue[WriteQueueSize]; + /// + /// EFI_FAULT_TOLERANT_WRITE_HEADER FtwHeader; + /// EFI_FAULT_TOLERANT_WRITE_RECORD FtwRecord[FtwHeader.NumberOfWrites] + /// EFI_FAULT_TOLERANT_WRITE_HEADER FtwHeader2; + /// EFI_FAULT_TOLERANT_WRITE_RECORD FtwRecord2[FtwHeader2.NumberOfWrites] + /// ... /// } EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER; +#define FTW_VALID_STATE 0 +#define FTW_INVALID_STATE 1 + +// +// EFI Fault tolerant block update write queue entry. +// +typedef struct { + UINT8 HeaderAllocated : 1; + UINT8 WritesAllocated : 1; + UINT8 Complete : 1; + UINT8 Reserved : 5; + EFI_GUID CallerId; + UINT64 NumberOfWrites; + UINT64 PrivateDataSize; +} EFI_FAULT_TOLERANT_WRITE_HEADER; + +// +// EFI Fault tolerant block update write queue record. +// +typedef struct { + UINT8 BootBlockUpdate : 1; + UINT8 SpareComplete : 1; + UINT8 DestinationComplete : 1; + UINT8 Reserved : 5; + EFI_LBA Lba; + UINT64 Offset; + UINT64 Length; + // + // Relative offset to spare block. + // + INT64 RelativeOffset; + // + // UINT8 PrivateData[PrivateDataSize] + // +} EFI_FAULT_TOLERANT_WRITE_RECORD; + +#define FTW_RECORD_SIZE(PrivateDataSize) (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize) + +#define FTW_RECORD_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \ + ((UINTN) (NumberOfWrites) * (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize)) + +#define FTW_WRITE_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \ + ( \ + sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + (UINTN) (NumberOfWrites) * \ + (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + (UINTN) PrivateDataSize) \ + ) + #endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 3c07c69a97..7db47ecfb8 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -119,6 +119,14 @@ # Include/Guid/SystemNvDataGuid.h gEfiSystemNvDataFvGuid = { 0xFFF12B8D, 0x7696, 0x4C8B, { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }} + ## GUID used as the signature of FTW working block header. + # Include/Guid/SystemNvDataGuid.h + gEdkiiWorkingBlockSignatureGuid = { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }} + + ## GUID used to build FTW last write data hob and install PPI to inform the check for FTW last write data has been done. + # Include/Guid/FaultTolerantWrite.h + gEdkiiFaultTolerantWriteGuid = { 0x1d3e9cb8, 0x43af, 0x490b, { 0x83, 0xa, 0x35, 0x16, 0xaa, 0x53, 0x20, 0x47 }} + ## Guid specify the device is the console out device. # Include/Guid/ConsoleOutDevice.h gEfiConsoleOutDeviceGuid = { 0xD3B36F2C, 0xD551, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 444cd8358c..6e1bbeb950 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -294,6 +294,7 @@ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf MdeModulePkg/Application/VariableInfo/VariableInfo.inf + MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf MdeModulePkg/Universal/Variable/Pei/VariablePei.inf MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c index 2f110167d7..3d1d29dfd9 100644 --- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c +++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c @@ -3,7 +3,7 @@ These are the common Fault Tolerant Write (FTW) functions that are shared by DXE FTW driver and SMM FTW driver. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -95,7 +95,7 @@ FtwAllocate ( // // Check if there is enough space for the coming allocation // - if (WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) { + if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) { DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId)); return EFI_BUFFER_TOO_SMALL; } @@ -115,7 +115,7 @@ FtwAllocate ( // If workspace is not enough, then reclaim workspace // Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace; - if (Offset + WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) { + if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) { Status = FtwReclaimWorkSpace (FtwDevice, TRUE); if (EFI_ERROR (Status)) { return EFI_ABORTED; @@ -365,7 +365,7 @@ FtwWrite ( // // If Record is out of the range of Header, return access denied. // - if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) { + if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) { return EFI_ACCESS_DENIED; } @@ -415,13 +415,13 @@ FtwWrite ( Record->Lba = Lba; Record->Offset = Offset; Record->Length = Length; - Record->FvBaseAddress = FvbPhysicalAddress; + Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * FtwDevice->BlockSize) - (INT64) FtwDevice->SpareAreaAddress; if (PrivateData != NULL) { - CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize); + CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize); } MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace; - MyLength = RECORD_SIZE (Header->PrivateDataSize); + MyLength = FTW_RECORD_SIZE (Header->PrivateDataSize); Status = FtwDevice->FtwFvBlock->Write ( FtwDevice->FtwFvBlock, @@ -693,6 +693,10 @@ FtwAbort ( return EFI_ABORTED; } + if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) { + return EFI_NOT_FOUND; + } + if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) { return EFI_NOT_FOUND; } @@ -809,16 +813,16 @@ FtwGetLastWrite ( // CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID)); *Lba = Record->Lba; - *Offset = Record->Offset; - *Length = Record->Length; + *Offset = (UINTN) Record->Offset; + *Length = (UINTN) Record->Length; *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE); if (*PrivateDataSize < Header->PrivateDataSize) { - *PrivateDataSize = Header->PrivateDataSize; + *PrivateDataSize = (UINTN) Header->PrivateDataSize; PrivateData = NULL; Status = EFI_BUFFER_TOO_SMALL; } else { - *PrivateDataSize = Header->PrivateDataSize; + *PrivateDataSize = (UINTN) Header->PrivateDataSize; CopyMem (PrivateData, Record + 1, *PrivateDataSize); Status = EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h index 8deae8851a..78c65f2af6 100644 --- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h +++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.h @@ -3,7 +3,7 @@ The internal header file includes the common header files, defines internal structure and functions used by FtwLite module. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -38,59 +38,17 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // #define FTW_ERASE_POLARITY 1 -#define FTW_VALID_STATE 0 -#define FTW_INVALID_STATE 1 - #define FTW_ERASED_BYTE ((UINT8) (255)) #define FTW_POLARITY_REVERT ((UINT8) (255)) -// -// EFI Fault tolerant block update write queue entry -// -typedef struct { - UINT8 HeaderAllocated : 1; - UINT8 WritesAllocated : 1; - UINT8 Complete : 1; #define HEADER_ALLOCATED 0x1 #define WRITES_ALLOCATED 0x2 #define WRITES_COMPLETED 0x4 - UINT8 Reserved : 5; - EFI_GUID CallerId; - UINTN NumberOfWrites; - UINTN PrivateDataSize; -} EFI_FAULT_TOLERANT_WRITE_HEADER; -// -// EFI Fault tolerant block update write queue record -// -typedef struct { - UINT8 BootBlockUpdate : 1; - UINT8 SpareComplete : 1; - UINT8 DestinationComplete : 1; #define BOOT_BLOCK_UPDATE 0x1 #define SPARE_COMPLETED 0x2 #define DEST_COMPLETED 0x4 - UINT8 Reserved : 5; - EFI_LBA Lba; - UINTN Offset; - UINTN Length; - EFI_PHYSICAL_ADDRESS FvBaseAddress; - // - // UINT8 PrivateData[PrivateDataSize] - // -} EFI_FAULT_TOLERANT_WRITE_RECORD; - - -#define RECORD_SIZE(PrivateDataSize) (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + PrivateDataSize) - -#define RECORD_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \ - ((NumberOfWrites) * (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + PrivateDataSize)) -#define WRITE_TOTAL_SIZE(NumberOfWrites, PrivateDataSize) \ - ( \ - sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + (NumberOfWrites) * \ - (sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD) + PrivateDataSize) \ - ) #define FTW_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'T', 'W', 'D') diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf index f60ab287e5..3d4b9123a1 100644 --- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf +++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf @@ -3,7 +3,7 @@ # which provides fault tolerant write capability for block devices. # Its implementation depends on the full functionality FVB protocol that support read, write/erase flash access. # -# Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -49,7 +49,7 @@ PcdLib [Guids] - gEfiSystemNvDataFvGuid ## CONSUMES ## FV Signature of Working Space Header + gEdkiiWorkingBlockSignatureGuid ## CONSUMES ## FV Signature of Working Space Header [Protocols] gEfiSwapAddressRangeProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## CONSUMES diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf index c39f84ca3c..a5c8a58f22 100644 --- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf +++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf @@ -52,7 +52,7 @@ PcdLib [Guids] - gEfiSystemNvDataFvGuid ## CONSUMES ## FV Signature of Working Space Header + gEdkiiWorkingBlockSignatureGuid ## CONSUMES ## FV Signature of Working Space Header [Protocols] gEfiSmmSwapAddressRangeProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdFullFtwServiceEnable ## CONSUMES diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c index 2e4052c1ea..fdd9dfa0c1 100644 --- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c +++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/FtwMisc.c @@ -689,6 +689,7 @@ FlushSpareBlockToWorkingBlock ( return EFI_ABORTED; } + FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_INVALID_STATE; FtwDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE; return EFI_SUCCESS; @@ -775,7 +776,7 @@ FtwGetLastWriteHeader ( Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER); while (FtwHeader->Complete == FTW_VALID_STATE) { - Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); + Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); // // If Offset exceed the FTW work space boudary, return error. // @@ -834,7 +835,7 @@ FtwGetLastWriteRecord ( FtwRecord++; if (FtwWriteHeader->PrivateDataSize != 0) { - FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + FtwWriteHeader->PrivateDataSize); + FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize); } } // @@ -844,7 +845,7 @@ FtwGetLastWriteRecord ( // also return the last record. // if (Index == FtwWriteHeader->NumberOfWrites) { - *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - RECORD_SIZE (FtwWriteHeader->PrivateDataSize)); + *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize)); return EFI_SUCCESS; } @@ -901,7 +902,7 @@ IsLastRecordOfWrites ( Head = (UINT8 *) FtwHeader; Ptr = (UINT8 *) FtwRecord; - Head += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize); + Head += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites - 1, FtwHeader->PrivateDataSize); return (BOOLEAN) (Head == Ptr); } @@ -929,7 +930,7 @@ GetPreviousRecordOfWrites ( } Ptr = (UINT8 *) (*FtwRecord); - Ptr -= RECORD_SIZE (FtwHeader->PrivateDataSize); + Ptr -= FTW_RECORD_SIZE (FtwHeader->PrivateDataSize); *FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) Ptr; return EFI_SUCCESS; } @@ -1259,7 +1260,7 @@ InitFtwProtocol ( FtwHeader = FtwDevice->FtwLastWriteHeader; Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace; if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) { - Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); + Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); } if (!IsErasedFlashBuffer (FtwDevice->FtwWorkSpace + Offset, FtwDevice->FtwWorkSpaceSize - Offset)) { @@ -1283,7 +1284,7 @@ InitFtwProtocol ( // if (SpareCompleted) THEN Restart to fault tolerant write. // FvbHandle = NULL; - FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb); + FvbHandle = GetFvbByAddress ((EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) FtwDevice->SpareAreaAddress + FtwDevice->FtwLastWriteRecord->RelativeOffset), &Fvb); if (FvbHandle != NULL) { Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle); DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status)); diff --git a/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c b/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c index bd8285d00e..4c658b2977 100644 --- a/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c +++ b/MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c @@ -2,7 +2,7 @@ Internal functions to operate Working Block Space. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -32,9 +32,9 @@ InitializeLocalWorkSpaceHeader ( EFI_STATUS Status; // - // Check signature with gEfiSystemNvDataFvGuid. + // Check signature with gEdkiiWorkingBlockSignatureGuid. // - if (CompareGuid (&gEfiSystemNvDataFvGuid, &mWorkingBlockHeader.Signature)) { + if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &mWorkingBlockHeader.Signature)) { // // The local work space header has been initialized. // @@ -48,11 +48,11 @@ InitializeLocalWorkSpaceHeader ( ); // - // Here using gEfiSystemNvDataFvGuid as the signature. + // Here using gEdkiiWorkingBlockSignatureGuid as the signature. // CopyMem ( &mWorkingBlockHeader.Signature, - &gEfiSystemNvDataFvGuid, + &gEdkiiWorkingBlockSignatureGuid, sizeof (EFI_GUID) ); mWorkingBlockHeader.WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)); @@ -322,7 +322,7 @@ FtwReclaimWorkSpace ( CopyMem ( Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER), FtwDevice->FtwLastWriteHeader, - WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize) + FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize) ); } } diff --git a/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c b/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c new file mode 100644 index 0000000000..ec03216c06 --- /dev/null +++ b/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.c @@ -0,0 +1,318 @@ +/** @file + This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform + the check for FTW last write data has been done. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEdkiiFaultTolerantWriteGuid, + NULL +}; + +/** + Get the last Write Header pointer. + The last write header is the header whose 'complete' state hasn't been set. + After all, this header may be a EMPTY header entry for next Allocate. + + + @param FtwWorkSpaceHeader Pointer of the working block header + @param FtwWorkSpaceSize Size of the work space + @param FtwWriteHeader Pointer to retrieve the last write header + + @retval EFI_SUCCESS Get the last write record successfully + @retval EFI_ABORTED The FTW work space is damaged + +**/ +EFI_STATUS +FtwGetLastWriteHeader ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader, + IN UINTN FtwWorkSpaceSize, + OUT EFI_FAULT_TOLERANT_WRITE_HEADER **FtwWriteHeader + ) +{ + UINTN Offset; + EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader; + + *FtwWriteHeader = NULL; + FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) (FtwWorkSpaceHeader + 1); + Offset = sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER); + + while (FtwHeader->Complete == FTW_VALID_STATE) { + Offset += FTW_WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize); + // + // If Offset exceed the FTW work space boudary, return error. + // + if (Offset >= FtwWorkSpaceSize) { + *FtwWriteHeader = FtwHeader; + return EFI_ABORTED; + } + + FtwHeader = (EFI_FAULT_TOLERANT_WRITE_HEADER *) ((UINT8 *) FtwWorkSpaceHeader + Offset); + } + // + // Last write header is found + // + *FtwWriteHeader = FtwHeader; + + return EFI_SUCCESS; +} + +/** + Get the last Write Record pointer. The last write Record is the Record + whose DestinationCompleted state hasn't been set. After all, this Record + may be a EMPTY record entry for next write. + + + @param FtwWriteHeader Pointer to the write record header + @param FtwWriteRecord Pointer to retrieve the last write record + + @retval EFI_SUCCESS Get the last write record successfully + @retval EFI_ABORTED The FTW work space is damaged + +**/ +EFI_STATUS +FtwGetLastWriteRecord ( + IN EFI_FAULT_TOLERANT_WRITE_HEADER *FtwWriteHeader, + OUT EFI_FAULT_TOLERANT_WRITE_RECORD **FtwWriteRecord + ) +{ + UINTN Index; + EFI_FAULT_TOLERANT_WRITE_RECORD *FtwRecord; + + *FtwWriteRecord = NULL; + FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) (FtwWriteHeader + 1); + + // + // Try to find the last write record "that has not completed" + // + for (Index = 0; Index < FtwWriteHeader->NumberOfWrites; Index += 1) { + if (FtwRecord->DestinationComplete != FTW_VALID_STATE) { + // + // The last write record is found + // + *FtwWriteRecord = FtwRecord; + return EFI_SUCCESS; + } + + FtwRecord++; + + if (FtwWriteHeader->PrivateDataSize != 0) { + FtwRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord + (UINTN) FtwWriteHeader->PrivateDataSize); + } + } + // + // if Index == NumberOfWrites, then + // the last record has been written successfully, + // but the Header->Complete Flag has not been set. + // also return the last record. + // + if (Index == FtwWriteHeader->NumberOfWrites) { + *FtwWriteRecord = (EFI_FAULT_TOLERANT_WRITE_RECORD *) ((UINTN) FtwRecord - FTW_RECORD_SIZE (FtwWriteHeader->PrivateDataSize)); + return EFI_SUCCESS; + } + + return EFI_ABORTED; +} + +/** + Check to see if it is a valid work space. + + + @param WorkingHeader Pointer of working block header + @param WorkingLength Working block length + + @retval TRUE The work space is valid. + @retval FALSE The work space is invalid. + +**/ +BOOLEAN +IsValidWorkSpace ( + IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader, + IN UINTN WorkingLength + ) +{ + UINT8 Data; + + if (WorkingHeader == NULL) { + return FALSE; + } + + if ((WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) || (WorkingHeader->WorkingBlockInvalid == FTW_VALID_STATE)) { + DEBUG ((EFI_D_ERROR, "FtwPei: Work block header valid bit check error\n")); + return FALSE; + } + + if (WorkingHeader->WriteQueueSize != (WorkingLength - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))) { + DEBUG ((EFI_D_ERROR, "FtwPei: Work block header WriteQueueSize check error\n")); + return FALSE; + } + + // + // Check signature with gEdkiiWorkingBlockSignatureGuid + // + if (!CompareGuid (&gEdkiiWorkingBlockSignatureGuid, &WorkingHeader->Signature)) { + DEBUG ((EFI_D_ERROR, "FtwPei: Work block header signature check error, it should be gEdkiiWorkingBlockSignatureGuid\n")); + // + // To be compatible with old signature gEfiSystemNvDataFvGuid. + // + if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) { + return FALSE; + } else { + Data = *(UINT8 *) (WorkingHeader + 1); + if (Data != 0xff) { + DEBUG ((EFI_D_ERROR, "FtwPei: Old format FTW structure can't be handled\n")); + ASSERT (FALSE); + return FALSE; + } + } + } + + return TRUE; + +} + +/** + Main entry for Fault Tolerant Write PEIM. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Pointer to PEI Services table. + + @retval EFI_SUCCESS If the interface could be successfully installed + @retval Others Returned from PeiServicesInstallPpi() + +**/ +EFI_STATUS +EFIAPI +PeimFaultTolerantWriteInitialize ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkingBlockHeader; + EFI_FAULT_TOLERANT_WRITE_HEADER *FtwLastWriteHeader; + EFI_FAULT_TOLERANT_WRITE_RECORD *FtwLastWriteRecord; + EFI_PHYSICAL_ADDRESS WorkSpaceAddress; + UINTN WorkSpaceLength; + EFI_PHYSICAL_ADDRESS SpareAreaAddress; + UINTN SpareAreaLength; + EFI_PHYSICAL_ADDRESS WorkSpaceInSpareArea; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA FtwLastWrite; + + FtwWorkingBlockHeader = NULL; + FtwLastWriteHeader = NULL; + FtwLastWriteRecord = NULL; + + WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwWorkingBase64); + if (WorkSpaceAddress == 0) { + WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase); + } + WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize); + + SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageFtwSpareBase64); + if (SpareAreaAddress == 0) { + SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase); + } + SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize); + + // + // The address of FTW working base and spare base must not be 0. + // + ASSERT ((WorkSpaceAddress != 0) && (SpareAreaAddress != 0)); + + FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (UINTN) WorkSpaceAddress; + if (IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) { + Status = FtwGetLastWriteHeader ( + FtwWorkingBlockHeader, + WorkSpaceLength, + &FtwLastWriteHeader + ); + if (!EFI_ERROR (Status)) { + Status = FtwGetLastWriteRecord ( + FtwLastWriteHeader, + &FtwLastWriteRecord + ); + } + + if (!EFI_ERROR (Status) && ((FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE) && (FtwLastWriteRecord->DestinationComplete != FTW_VALID_STATE))) { + // + // If FTW last write was still in progress with SpareComplete set and DestinationComplete not set. + // It means the target buffer has been backed up in spare block, then target block has been erased, + // but the target buffer has not been writen in target block from spare block, we need to build + // FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob to hold the FTW last write data. + // + FtwLastWrite.TargetAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) ((INT64) SpareAreaAddress + FtwLastWriteRecord->RelativeOffset); + FtwLastWrite.SpareAddress = SpareAreaAddress; + FtwLastWrite.Length = SpareAreaLength; + DEBUG (( + EFI_D_INFO, + "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n", + (UINTN) FtwLastWrite.TargetAddress, + (UINTN) FtwLastWrite.SpareAddress, + (UINTN) FtwLastWrite.Length)); + BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *) &FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA)); + } + } else { + FtwWorkingBlockHeader = NULL; + // + // If the working block workspace is not valid, try to find workspace in the spare block. + // + WorkSpaceInSpareArea = SpareAreaAddress + SpareAreaLength - WorkSpaceLength; + while (WorkSpaceInSpareArea >= SpareAreaAddress) { + if (CompareGuid (&gEdkiiWorkingBlockSignatureGuid, (EFI_GUID *) (UINTN) WorkSpaceInSpareArea)) { + // + // Found the workspace. + // + DEBUG ((EFI_D_INFO, "FtwPei: workspace in spare block is at 0x%x.\n", (UINTN) WorkSpaceInSpareArea)); + FtwWorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (UINTN) WorkSpaceInSpareArea; + break; + } + WorkSpaceInSpareArea = WorkSpaceInSpareArea - sizeof (EFI_GUID); + } + if ((FtwWorkingBlockHeader != NULL) && IsValidWorkSpace (FtwWorkingBlockHeader, WorkSpaceLength)) { + // + // It was workspace self reclaim, build FAULT_TOLERANT_WRITE_LAST_WRITE_DATA GUID hob for it. + // + FtwLastWrite.TargetAddress = WorkSpaceAddress - (WorkSpaceInSpareArea - SpareAreaAddress); + FtwLastWrite.SpareAddress = SpareAreaAddress; + FtwLastWrite.Length = SpareAreaLength; + DEBUG (( + EFI_D_INFO, + "FtwPei last write data: TargetAddress - 0x%x SpareAddress - 0x%x Length - 0x%x\n", + (UINTN) FtwLastWrite.TargetAddress, + (UINTN) FtwLastWrite.SpareAddress, + (UINTN) FtwLastWrite.Length)); + BuildGuidDataHob (&gEdkiiFaultTolerantWriteGuid, (VOID *) &FtwLastWrite, sizeof (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA)); + } else { + // + // Both are invalid. + // + DEBUG ((EFI_D_ERROR, "FtwPei: Both working and spare block are invalid.\n")); + } + } + + // + // Install gEdkiiFaultTolerantWriteGuid PPI to inform the check for FTW last write data has been done. + // + return PeiServicesInstallPpi (&mPpiListVariable); +} diff --git a/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf b/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf new file mode 100644 index 0000000000..bcc2313a64 --- /dev/null +++ b/MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf @@ -0,0 +1,61 @@ +## @file +# This driver installs gEdkiiFaultTolerantWriteGuid PPI to inform +# the check for FTW last write data has been done. +# +# Copyright (c) 2013, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FaultTolerantWritePei + FILE_GUID = AAC33064-9ED0-4b89-A5AD-3EA767960B22 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimFaultTolerantWriteInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + FaultTolerantWritePei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + PeimEntryPoint + PeiServicesLib + BaseLib + DebugLib + HobLib + BaseMemoryLib + PcdLib + +[Guids] + gEdkiiFaultTolerantWriteGuid ## CONSUMES + gEdkiiWorkingBlockSignatureGuid ## CONSUMES + gEfiSystemNvDataFvGuid ## CONSUMES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + +[Depex] + TRUE + diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c index 10ad3f51d0..df0304748c 100644 --- a/MdeModulePkg/Universal/Variable/Pei/Variable.c +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c @@ -11,7 +11,6 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: **/ @@ -174,7 +173,6 @@ GetVariableNamePtr ( IN VARIABLE_HEADER *Variable ) { - return (CHAR16 *) (Variable + 1); } @@ -182,14 +180,16 @@ GetVariableNamePtr ( /** This code gets the pointer to the variable data. - @param Variable Pointer to the Variable Header. + @param Variable Pointer to the Variable Header. + @param VariableHeader Pointer to the Variable Header that has consecutive content. @return A UINT8* pointer to Variable Data. **/ UINT8 * GetVariableDataPtr ( - IN VARIABLE_HEADER *Variable + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader ) { UINTN Value; @@ -198,8 +198,8 @@ GetVariableDataPtr ( // Be careful about pad size for alignment // Value = (UINTN) GetVariableNamePtr (Variable); - Value += NameSizeOfVariable (Variable); - Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); + Value += NameSizeOfVariable (VariableHeader); + Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader)); return (UINT8 *) Value; } @@ -208,34 +208,48 @@ GetVariableDataPtr ( /** This code gets the pointer to the next variable header. - @param Variable Pointer to the Variable Header. + @param StoreInfo Pointer to variable store info structure. + @param Variable Pointer to the Variable Header. + @param VariableHeader Pointer to the Variable Header that has consecutive content. @return A VARIABLE_HEADER* pointer to next variable header. **/ VARIABLE_HEADER * GetNextVariablePtr ( - IN VARIABLE_HEADER *Variable + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader ) { - UINTN Value; - - if (!IsValidVariableHeader (Variable)) { - return NULL; - } - - Value = (UINTN) GetVariableDataPtr (Variable); - Value += DataSizeOfVariable (Variable); - Value += GET_PAD_SIZE (DataSizeOfVariable (Variable)); + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN Value; + Value = (UINTN) GetVariableDataPtr (Variable, VariableHeader); + Value += DataSizeOfVariable (VariableHeader); + Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader)); // // Be careful about pad size for alignment // - return (VARIABLE_HEADER *) HEADER_ALIGN (Value); + Value = HEADER_ALIGN (Value); + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN) Variable < (UINTN) TargetAddress) && (Value >= (UINTN) TargetAddress)) { + // + // Next variable is in spare block. + // + Value = (UINTN) SpareAddress + (Value - (UINTN) TargetAddress); + } + } + + return (VARIABLE_HEADER *) Value; } /** - This code gets the pointer to the variable name. + Get variable store status. @param VarStoreHeader Pointer to the Variable Store Header. @@ -249,7 +263,6 @@ GetVariableStoreStatus ( IN VARIABLE_STORE_HEADER *VarStoreHeader ) { - if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) && VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && VarStoreHeader->State == VARIABLE_STORE_HEALTHY @@ -273,11 +286,85 @@ GetVariableStoreStatus ( } } +/** + Compare two variable names, one of them may be inconsecutive. + + @param StoreInfo Pointer to variable store info structure. + @param Name1 Pointer to one variable name. + @param Name2 Pointer to another variable name. + @param NameSize Variable name size. + + @retval TRUE Name1 and Name2 are identical. + @retval FALSE Name1 and Name2 are not identical. + +**/ +BOOLEAN +CompareVariableName ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN CONST CHAR16 *Name1, + IN CONST CHAR16 *Name2, + IN UINTN NameSize + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialNameSize; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN) Name1 < (UINTN) TargetAddress) && (((UINTN) Name1 + NameSize) > (UINTN) TargetAddress)) { + // + // Name1 is inconsecutive. + // + PartialNameSize = (UINTN) TargetAddress - (UINTN) Name1; + // + // Partial content is in NV storage. + // + if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, PartialNameSize) == 0) { + // + // Another partial content is in spare block. + // + if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) { + return TRUE; + } + } + return FALSE; + } else if (((UINTN) Name2 < (UINTN) TargetAddress) && (((UINTN) Name2 + NameSize) > (UINTN) TargetAddress)) { + // + // Name2 is inconsecutive. + // + PartialNameSize = (UINTN) TargetAddress - (UINTN) Name2; + // + // Partial content is in NV storage. + // + if (CompareMem ((UINT8 *) Name2, (UINT8 *) Name1, PartialNameSize) == 0) { + // + // Another partial content is in spare block. + // + if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) { + return TRUE; + } + } + return FALSE; + } + } + + // + // Both Name1 and Name2 are consecutive. + // + if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) { + return TRUE; + } + return FALSE; +} /** This function compares a variable with variable entries in database. + @param StoreInfo Pointer to variable store info structure. @param Variable Pointer to the variable in our database + @param VariableHeader Pointer to the Variable Header that has consecutive content. @param VariableName Name of the variable to compare to 'Variable' @param VendorGuid GUID of the variable to compare to 'Variable' @param PtrTrack Variable Track Pointer structure that contains Variable Information. @@ -288,7 +375,9 @@ GetVariableStoreStatus ( **/ EFI_STATUS CompareWithValidVariable ( + IN VARIABLE_STORE_INFO *StoreInfo, IN VARIABLE_HEADER *Variable, + IN VARIABLE_HEADER *VariableHeader, IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, OUT VARIABLE_POINTER_TRACK *PtrTrack @@ -305,14 +394,14 @@ CompareWithValidVariable ( // Instead we compare the GUID a UINT32 at a time and branch // on the first failed comparison. // - if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) && - (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) && - (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) && - (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3]) + if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &VariableHeader->VendorGuid)[0]) && + (((INT32 *) VendorGuid)[1] == ((INT32 *) &VariableHeader->VendorGuid)[1]) && + (((INT32 *) VendorGuid)[2] == ((INT32 *) &VariableHeader->VendorGuid)[2]) && + (((INT32 *) VendorGuid)[3] == ((INT32 *) &VariableHeader->VendorGuid)[3]) ) { - ASSERT (NameSizeOfVariable (Variable) != 0); + ASSERT (NameSizeOfVariable (VariableHeader) != 0); Point = (VOID *) GetVariableNamePtr (Variable); - if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable)) == 0) { + if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader))) { PtrTrack->CurrPtr = Variable; return EFI_SUCCESS; } @@ -323,26 +412,29 @@ CompareWithValidVariable ( } /** - Return the variable store header and the index table based on the Index. + Return the variable store header and the store info based on the Index. @param Type The type of the variable store. - @param IndexTable Return the index table. + @param StoreInfo Return the store info. @return Pointer to the variable store header. **/ VARIABLE_STORE_HEADER * GetVariableStore ( IN VARIABLE_STORE_TYPE Type, - OUT VARIABLE_INDEX_TABLE **IndexTable OPTIONAL + OUT VARIABLE_STORE_INFO *StoreInfo ) { - EFI_HOB_GUID_TYPE *GuidHob; - EFI_FIRMWARE_VOLUME_HEADER *FvHeader; - VARIABLE_STORE_HEADER *VariableStoreHeader; - - if (IndexTable != NULL) { - *IndexTable = NULL; - } + EFI_HOB_GUID_TYPE *GuidHob; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + EFI_PHYSICAL_ADDRESS NvStorageBase; + UINT32 NvStorageSize; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + UINT32 BackUpOffset; + + StoreInfo->IndexTable = NULL; + StoreInfo->FtwLastWriteData = NULL; VariableStoreHeader = NULL; switch (Type) { case VariableStoreTypeHob: @@ -357,10 +449,42 @@ GetVariableStore ( // // The content of NV storage for variable is not reliable in recovery boot mode. // - FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? - PcdGet64 (PcdFlashNvStorageVariableBase64) : - PcdGet32 (PcdFlashNvStorageVariableBase) - ); + + NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); + NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ? + PcdGet64 (PcdFlashNvStorageVariableBase64) : + PcdGet32 (PcdFlashNvStorageVariableBase) + ); + // + // First let FvHeader point to NV storage base. + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase; + + // + // Check the FTW last write data hob. + // + BackUpOffset = 0; + GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); + if (GuidHob != NULL) { + FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob); + if (FtwLastWriteData->TargetAddress == NvStorageBase) { + // + // Let FvHeader point to spare block. + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress; + DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress)); + } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { + StoreInfo->FtwLastWriteData = FtwLastWriteData; + // + // Flash NV storage from the offset is backed up in spare block. + // + BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); + DEBUG ((EFI_D_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress)); + // + // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base. + // + } + } // // Check if the Firmware Volume is not corrupted @@ -372,23 +496,21 @@ GetVariableStore ( VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength); - if (IndexTable != NULL) { - GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); - if (GuidHob != NULL) { - *IndexTable = GET_GUID_HOB_DATA (GuidHob); - } else { - // - // If it's the first time to access variable region in flash, create a guid hob to record - // VAR_ADDED type variable info. - // Note that as the resource of PEI phase is limited, only store the limited number of - // VAR_ADDED type variables to reduce access time. - // - *IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); - (*IndexTable)->Length = 0; - (*IndexTable)->StartPtr = GetStartPointer (VariableStoreHeader); - (*IndexTable)->EndPtr = GetEndPointer (VariableStoreHeader); - (*IndexTable)->GoneThrough = 0; - } + GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); + if (GuidHob != NULL) { + StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob); + } else { + // + // If it's the first time to access variable region in flash, create a guid hob to record + // VAR_ADDED type variable info. + // Note that as the resource of PEI phase is limited, only store the limited number of + // VAR_ADDED type variables to reduce access time. + // + StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); + StoreInfo->IndexTable->Length = 0; + StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader); + StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader); + StoreInfo->IndexTable->GoneThrough = 0; } } break; @@ -398,14 +520,118 @@ GetVariableStore ( break; } + StoreInfo->VariableStoreHeader = VariableStoreHeader; return VariableStoreHeader; } +/** + Get variable header that has consecutive content. + + @param StoreInfo Pointer to variable store info structure. + @param Variable Pointer to the Variable Header. + @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +GetVariableHeader ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN VARIABLE_HEADER *Variable, + OUT VARIABLE_HEADER **VariableHeader + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + EFI_HOB_GUID_TYPE *GuidHob; + UINTN PartialHeaderSize; + + // + // First assume variable header pointed by Variable is consecutive. + // + *VariableHeader = Variable; + + if ((Variable != NULL) && (StoreInfo->FtwLastWriteData != NULL)) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + sizeof (VARIABLE_HEADER)) > (UINTN) TargetAddress)) { + // + // Variable header pointed by Variable is inconsecutive, + // create a guid hob to combine the two partial variable header content together. + // + GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid); + if (GuidHob != NULL) { + *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob); + } else { + *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, sizeof (VARIABLE_HEADER)); + PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable; + // + // Partial content is in NV storage. + // + CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize); + // + // Another partial content is in spare block. + // + CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, sizeof (VARIABLE_HEADER) - PartialHeaderSize); + } + } + } + + return IsValidVariableHeader (*VariableHeader); +} + +/** + Get variable name or data to output buffer. + + @param StoreInfo Pointer to variable store info structure. + @param NameOrData Pointer to the variable name/data that may be inconsecutive. + @param Size Variable name/data size. + @param Buffer Pointer to output buffer to hold the variable name/data. + +**/ +VOID +GetVariableNameOrData ( + IN VARIABLE_STORE_INFO *StoreInfo, + IN UINT8 *NameOrData, + IN UINTN Size, + OUT UINT8 *Buffer + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + EFI_PHYSICAL_ADDRESS SpareAddress; + UINTN PartialSize; + + if (StoreInfo->FtwLastWriteData != NULL) { + TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress; + SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress; + if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) { + // + // Variable name/data is inconsecutive. + // + PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData; + // + // Partial content is in NV storage. + // + CopyMem (Buffer, NameOrData, PartialSize); + // + // Another partial content is in spare block. + // + CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize); + return; + } + } + + // + // Variable name/data is consecutive. + // + CopyMem (Buffer, NameOrData, Size); +} + /** Find the variable in the specified variable store. - @param VariableStoreHeader Pointer to the variable store header. - @param IndexTable Pointer to the index table. + @param StoreInfo Pointer to the store info structure. @param VariableName Name of the variable to be found @param VendorGuid Vendor GUID to be found. @param PtrTrack Variable Track Pointer structure that contains Variable Information. @@ -417,8 +643,7 @@ GetVariableStore ( **/ EFI_STATUS FindVariableEx ( - IN VARIABLE_STORE_HEADER *VariableStoreHeader, - IN VARIABLE_INDEX_TABLE *IndexTable, + IN VARIABLE_STORE_INFO *StoreInfo, IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, OUT VARIABLE_POINTER_TRACK *PtrTrack @@ -431,6 +656,11 @@ FindVariableEx ( UINTN Offset; BOOLEAN StopRecord; VARIABLE_HEADER *InDeletedVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_INDEX_TABLE *IndexTable; + VARIABLE_HEADER *VariableHeader; + + VariableStoreHeader = StoreInfo->VariableStoreHeader; if (VariableStoreHeader == NULL) { return EFI_INVALID_PARAMETER; @@ -444,6 +674,7 @@ FindVariableEx ( return EFI_NOT_FOUND; } + IndexTable = StoreInfo->IndexTable; PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader); PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader); @@ -453,6 +684,7 @@ FindVariableEx ( // No Variable Address equals zero, so 0 as initial value is safe. // MaxIndex = NULL; + VariableHeader = NULL; if (IndexTable != NULL) { // @@ -463,8 +695,9 @@ FindVariableEx ( ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0])); Offset += IndexTable->Index[Index]; MaxIndex = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset); - if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { - if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader); + if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { InDeletedVariable = PtrTrack->CurrPtr; } else { return EFI_SUCCESS; @@ -486,7 +719,7 @@ FindVariableEx ( // HOB exists but the variable cannot be found in HOB // If not found in HOB, then let's start from the MaxIndex we've found. // - Variable = GetNextVariablePtr (MaxIndex); + Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader); LastVariable = MaxIndex; } else { // @@ -501,8 +734,8 @@ FindVariableEx ( // Find the variable by walk through variable store // StopRecord = FALSE; - while ((Variable < PtrTrack->EndPtr) && IsValidVariableHeader (Variable)) { - if (Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) { + if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { // // Record Variable in VariableIndex HOB // @@ -520,8 +753,8 @@ FindVariableEx ( } } - if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { - if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { InDeletedVariable = PtrTrack->CurrPtr; } else { return EFI_SUCCESS; @@ -529,7 +762,7 @@ FindVariableEx ( } } - Variable = GetNextVariablePtr (Variable); + Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader); } // // If gone through the VariableStore, that means we never find in Firmware any more. @@ -549,6 +782,7 @@ FindVariableEx ( @param VariableName Name of the variable to be found @param VendorGuid Vendor GUID to be found. @param PtrTrack Variable Track Pointer structure that contains Variable Information. + @param StoreInfo Return the store info. @retval EFI_SUCCESS Variable found successfully @retval EFI_NOT_FOUND Variable not found @@ -558,12 +792,11 @@ EFI_STATUS FindVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid, - OUT VARIABLE_POINTER_TRACK *PtrTrack + OUT VARIABLE_POINTER_TRACK *PtrTrack, + OUT VARIABLE_STORE_INFO *StoreInfo ) { EFI_STATUS Status; - VARIABLE_STORE_HEADER *VariableStoreHeader; - VARIABLE_INDEX_TABLE *IndexTable; VARIABLE_STORE_TYPE Type; if (VariableName[0] != 0 && VendorGuid == NULL) { @@ -571,10 +804,9 @@ FindVariable ( } for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { - VariableStoreHeader = GetVariableStore (Type, &IndexTable); + GetVariableStore (Type, StoreInfo); Status = FindVariableEx ( - VariableStoreHeader, - IndexTable, + StoreInfo, VariableName, VendorGuid, PtrTrack @@ -627,6 +859,8 @@ PeiGetVariable ( VARIABLE_POINTER_TRACK Variable; UINTN VarDataSize; EFI_STATUS Status; + VARIABLE_STORE_INFO StoreInfo; + VARIABLE_HEADER *VariableHeader; if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) { return EFI_INVALID_PARAMETER; @@ -635,23 +869,25 @@ PeiGetVariable ( // // Find existing variable // - Status = FindVariable (VariableName, VariableGuid, &Variable); + Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo); if (EFI_ERROR (Status)) { return Status; } + GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader); + // // Get data size // - VarDataSize = DataSizeOfVariable (Variable.CurrPtr); + VarDataSize = DataSizeOfVariable (VariableHeader); if (*DataSize >= VarDataSize) { if (Data == NULL) { return EFI_INVALID_PARAMETER; } - CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader), VarDataSize, Data); if (Attributes != NULL) { - *Attributes = Variable.CurrPtr->Attributes; + *Attributes = VariableHeader->Attributes; } *DataSize = VarDataSize; @@ -704,16 +940,19 @@ PeiGetNextVariableName ( VARIABLE_POINTER_TRACK Variable; VARIABLE_POINTER_TRACK VariableInHob; VARIABLE_POINTER_TRACK VariablePtrTrack; - VARIABLE_INDEX_TABLE *IndexTable; UINTN VarNameSize; EFI_STATUS Status; VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax]; + VARIABLE_HEADER *VariableHeader; + VARIABLE_STORE_INFO StoreInfo; + VARIABLE_STORE_INFO StoreInfoForNv; + VARIABLE_STORE_INFO StoreInfoForHob; if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) { return EFI_INVALID_PARAMETER; } - Status = FindVariable (VariableName, VariableGuid, &Variable); + Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo); if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { return Status; } @@ -722,20 +961,18 @@ PeiGetNextVariableName ( // // If variable name is not NULL, get next variable // - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader); + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); } - VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, NULL); - VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, NULL); + VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob); + VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv); while (TRUE) { // // Switch from HOB to Non-Volatile. // - while ((Variable.CurrPtr >= Variable.EndPtr) || - (Variable.CurrPtr == NULL) || - !IsValidVariableHeader (Variable.CurrPtr) - ) { + while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) { // // Find current storage index // @@ -764,31 +1001,24 @@ PeiGetNextVariableName ( Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]); Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]); Variable.CurrPtr = Variable.StartPtr; + GetVariableStore (Type, &StoreInfo); } - if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { - if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { // // If it is a IN_DELETED_TRANSITION variable, // and there is also a same ADDED one at the same time, // don't return it. // - for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) { - if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) { - break; - } - } - ASSERT (Type < VariableStoreTypeMax); - GetVariableStore (Type, &IndexTable); Status = FindVariableEx ( - VariableStoreHeader[Type], - IndexTable, + &StoreInfo, GetVariableNamePtr (Variable.CurrPtr), - &Variable.CurrPtr->VendorGuid, + &VariableHeader->VendorGuid, &VariablePtrTrack ); - if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) { - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) { + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); continue; } } @@ -800,25 +1030,24 @@ PeiGetNextVariableName ( (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv])) ) { Status = FindVariableEx ( - VariableStoreHeader[VariableStoreTypeHob], - NULL, + &StoreInfoForHob, GetVariableNamePtr (Variable.CurrPtr), - &Variable.CurrPtr->VendorGuid, + &VariableHeader->VendorGuid, &VariableInHob ); if (!EFI_ERROR (Status)) { - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); continue; } } - VarNameSize = NameSizeOfVariable (Variable.CurrPtr); + VarNameSize = NameSizeOfVariable (VariableHeader); ASSERT (VarNameSize != 0); if (VarNameSize <= *VariableNameSize) { - CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize); + GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr), VarNameSize, (UINT8 *) VariableName); - CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); + CopyMem (VariableGuid, &VariableHeader->VendorGuid, sizeof (EFI_GUID)); Status = EFI_SUCCESS; } else { @@ -831,7 +1060,7 @@ PeiGetNextVariableName ( // return Status; } else { - Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader); } } } diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Pei/Variable.h index e0d8679d63..55277b04f1 100644 --- a/MdeModulePkg/Universal/Variable/Pei/Variable.h +++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h @@ -3,7 +3,7 @@ The internal header file includes the common header files, defines internal structure and functions used by PeiVariable module. -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -31,6 +31,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include typedef enum { VariableStoreTypeHob, @@ -38,6 +39,17 @@ typedef enum { VariableStoreTypeMax } VARIABLE_STORE_TYPE; +typedef struct { + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_INDEX_TABLE *IndexTable; + // + // If it is not NULL, it means there may be an inconsecutive variable whose + // partial content is still in NV storage, but another partial content is backed up + // in spare block. + // + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; +} VARIABLE_STORE_INFO; + // // Functions // diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf index da07cf7b7a..8bae162a37 100644 --- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf +++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf @@ -3,7 +3,7 @@ # Implement ReadOnly Variable Services required by PEIM and install # PEI ReadOnly Varaiable2 PPI. These services operates the non-volatile storage space. # -# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -49,16 +49,18 @@ gEfiVariableGuid gEfiVariableIndexTableGuid gEfiSystemNvDataFvGuid + gEdkiiFaultTolerantWriteGuid [Ppis] - gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_PRODUCES (Not for boot mode RECOVERY) + gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES [Pcd] - gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES - gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES [Depex] - TRUE + gEdkiiFaultTolerantWriteGuid # # [BootMode] diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index 9f983ffc9f..09b8b4bd21 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -2582,6 +2582,135 @@ ReclaimForOS( } } +/** + Init non-volatile variable store. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. + +**/ +EFI_STATUS +InitNonVolatileVariableStore ( + VOID + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_HEADER *NextVariable; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINT64 VariableStoreLength; + UINTN VariableSize; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_PHYSICAL_ADDRESS NvStorageBase; + UINT8 *NvStorageData; + UINT32 NvStorageSize; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + UINT32 BackUpOffset; + UINT32 BackUpSize; + + mVariableModuleGlobal->FvbInstance = NULL; + + // + // Note that in EdkII variable driver implementation, Hardware Error Record type variable + // is stored with common variable in the same NV region. So the platform integrator should + // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of + // PcdFlashNvStorageVariableSize. + // + ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); + + // + // Allocate runtime memory used for a memory copy of the FLASH region. + // Keep the memory and the FLASH in sync as updates occur. + // + NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); + NvStorageData = AllocateRuntimeZeroPool (NvStorageSize); + if (NvStorageData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (NvStorageBase == 0) { + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + // + // Copy NV storage data to the memory buffer. + // + CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize); + + // + // Check the FTW last write data hob. + // + GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); + if (GuidHob != NULL) { + FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob); + if (FtwLastWriteData->TargetAddress == NvStorageBase) { + DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress)); + // + // Copy the backed up NV storage data to the memory buffer from spare block. + // + CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize); + } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && + (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { + // + // Flash NV storage from the offset is backed up in spare block. + // + BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); + BackUpSize = NvStorageSize - BackUpOffset; + DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress)); + // + // Copy the partial backed up NV storage data to the memory buffer from spare block. + // + CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize); + } + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData; + + // + // Check if the Firmware Volume is not corrupted + // + if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { + FreePool (NvStorageData); + DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n")); + return EFI_VOLUME_CORRUPTED; + } + + VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength); + VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength); + + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; + mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase; + if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) { + FreePool (NvStorageData); + DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n")); + return EFI_VOLUME_CORRUPTED; + } + ASSERT(mNvVariableCache->Size == VariableStoreLength); + + // + // The max variable or hardware error variable size should be < variable store size. + // + ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength); + + // + // Parse non-volatile variable data and get last variable offset. + // + NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase); + while (IsValidVariableHeader (NextVariable)) { + VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER); + if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); + } else { + mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); + } + + NextVariable = GetNextVariablePtr (NextVariable); + } + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase; + + return EFI_SUCCESS; +} + /** Flush the HOB variable to flash. @@ -2673,7 +2802,7 @@ FlushHobVariableToFlash ( } /** - Initializes variable write service after FVB was ready. + Initializes variable write service after FTW was ready. @retval EFI_SUCCESS Function successfully executed. @retval Others Fail to initialize the variable service. @@ -2689,8 +2818,18 @@ VariableWriteServiceInitialize ( UINTN Index; UINT8 Data; EFI_PHYSICAL_ADDRESS VariableStoreBase; + EFI_PHYSICAL_ADDRESS NvStorageBase; - VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (NvStorageBase == 0) { + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength); + + // + // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready. + // + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; // @@ -2737,12 +2876,8 @@ VariableCommonInitialize ( EFI_STATUS Status; VARIABLE_STORE_HEADER *VolatileVariableStore; VARIABLE_STORE_HEADER *VariableStoreHeader; - VARIABLE_HEADER *NextVariable; - EFI_PHYSICAL_ADDRESS TempVariableStoreHeader; - EFI_PHYSICAL_ADDRESS VariableStoreBase; UINT64 VariableStoreLength; UINTN ScratchSize; - UINTN VariableSize; EFI_HOB_GUID_TYPE *GuidHob; // @@ -2755,14 +2890,6 @@ VariableCommonInitialize ( InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY); - // - // Note that in EdkII variable driver implementation, Hardware Error Record type variable - // is stored with common variable in the same NV region. So the platform integrator should - // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of - // PcdFlashNvStorageVariableSize. - // - ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); - // // Get HOB variable store. // @@ -2773,6 +2900,7 @@ VariableCommonInitialize ( if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader); if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) { + FreePool (mVariableModuleGlobal); return EFI_OUT_OF_RESOURCES; } } else { @@ -2786,6 +2914,9 @@ VariableCommonInitialize ( ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize); if (VolatileVariableStore == NULL) { + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { + FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase); + } FreePool (mVariableModuleGlobal); return EFI_OUT_OF_RESOURCES; } @@ -2797,7 +2928,6 @@ VariableCommonInitialize ( // mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore; mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore; - mVariableModuleGlobal->FvbInstance = NULL; CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid); VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize); @@ -2807,74 +2937,13 @@ VariableCommonInitialize ( VolatileVariableStore->Reserved1 = 0; // - // Get non-volatile variable store. - // - - TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); - if (TempVariableStoreHeader == 0) { - TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); - } - - // - // Check if the Firmware Volume is not corrupted - // - if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) || - (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) { - Status = EFI_VOLUME_CORRUPTED; - DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n")); - goto Done; - } - - VariableStoreBase = TempVariableStoreHeader + \ - (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength); - VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \ - (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength); - - mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; - VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; - if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { - Status = EFI_VOLUME_CORRUPTED; - DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n")); - goto Done; - } - ASSERT(VariableStoreHeader->Size == VariableStoreLength); - - // - // The max variable or hardware error variable size should be < variable store size. - // - ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength); - - // - // Parse non-volatile variable data and get last variable offset. - // - NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase); - while (IsValidVariableHeader (NextVariable)) { - VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER); - if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); - } else { - mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); - } - - NextVariable = GetNextVariablePtr (NextVariable); - } - - mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase; - - // - // Allocate runtime memory used for a memory copy of the FLASH region. - // Keep the memory and the FLASH in sync as updates occur + // Init non-volatile variable store. // - mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength); - if (mNvVariableCache == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } - CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength); - Status = EFI_SUCCESS; - -Done: + Status = InitNonVolatileVariableStore (); if (EFI_ERROR (Status)) { + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { + FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase); + } FreePool (mVariableModuleGlobal); FreePool (VolatileVariableStore); } diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h index b5e6edec93..264a2396c6 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -39,6 +39,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #define VARIABLE_RECLAIM_THRESHOLD (1024) diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 8cbefefa1b..c712ba0200 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -68,6 +68,7 @@ gEfiSystemNvDataFvGuid ## CONSUMES gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event + gEdkiiFaultTolerantWriteGuid ## CONSUMES [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf index c229805bc9..89ec686ca1 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf @@ -77,6 +77,7 @@ gSmmVariableWriteGuid ## PRODUCES ## SMM Variable Write Guid gEfiSystemNvDataFvGuid ## CONSUMES gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES + gEdkiiFaultTolerantWriteGuid ## CONSUMES [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize -- 2.39.2