2 Common variable non-volatile store routines.
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "VariableNonVolatile.h"
10 #include "VariableParsing.h"
12 extern VARIABLE_MODULE_GLOBAL
*mVariableModuleGlobal
;
15 Get non-volatile maximum variable size.
17 @return Non-volatile maximum variable size.
21 GetNonVolatileMaxVariableSize (
25 if (PcdGet32 (PcdHwErrStorageSize
) != 0) {
26 return MAX (MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
27 PcdGet32 (PcdMaxHardwareErrorVariableSize
));
29 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
34 Init emulated non-volatile variable store.
36 @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
38 @retval EFI_SUCCESS Function successfully executed.
39 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
43 InitEmuNonVolatileVariableStore (
44 OUT EFI_PHYSICAL_ADDRESS
*VariableStoreBase
47 VARIABLE_STORE_HEADER
*VariableStore
;
48 UINT32 VariableStoreLength
;
49 BOOLEAN FullyInitializeStore
;
50 UINT32 HwErrStorageSize
;
52 FullyInitializeStore
= TRUE
;
54 VariableStoreLength
= PcdGet32 (PcdVariableStoreSize
);
55 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
58 // Allocate memory for variable store.
60 if (PcdGet64 (PcdEmuVariableNvStoreReserved
) == 0) {
61 VariableStore
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePool (VariableStoreLength
);
62 if (VariableStore
== NULL
) {
63 return EFI_OUT_OF_RESOURCES
;
67 // A memory location has been reserved for the NV variable store. Certain
68 // platforms may be able to preserve a memory range across system resets,
69 // thereby providing better NV variable emulation.
72 (VARIABLE_STORE_HEADER
*)(VOID
*)(UINTN
)
73 PcdGet64 (PcdEmuVariableNvStoreReserved
);
74 if ((VariableStore
->Size
== VariableStoreLength
) &&
75 (CompareGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
76 CompareGuid (&VariableStore
->Signature
, &gEfiVariableGuid
)) &&
77 (VariableStore
->Format
== VARIABLE_STORE_FORMATTED
) &&
78 (VariableStore
->State
== VARIABLE_STORE_HEALTHY
)) {
81 "Variable Store reserved at %p appears to be valid\n",
84 FullyInitializeStore
= FALSE
;
88 if (FullyInitializeStore
) {
89 SetMem (VariableStore
, VariableStoreLength
, 0xff);
91 // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
93 CopyGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
94 VariableStore
->Size
= VariableStoreLength
;
95 VariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
96 VariableStore
->State
= VARIABLE_STORE_HEALTHY
;
97 VariableStore
->Reserved
= 0;
98 VariableStore
->Reserved1
= 0;
101 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
103 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
106 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
107 // is stored with common variable in the same NV region. So the platform integrator should
108 // ensure that the value of PcdHwErrStorageSize is less than the value of
109 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
111 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
113 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
114 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
115 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
121 Init real non-volatile variable store.
123 @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
125 @retval EFI_SUCCESS Function successfully executed.
126 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
127 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
131 InitRealNonVolatileVariableStore (
132 OUT EFI_PHYSICAL_ADDRESS
*VariableStoreBase
135 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
136 VARIABLE_STORE_HEADER
*VariableStore
;
137 UINT32 VariableStoreLength
;
138 EFI_HOB_GUID_TYPE
*GuidHob
;
139 EFI_PHYSICAL_ADDRESS NvStorageBase
;
140 UINT8
*NvStorageData
;
141 UINT32 NvStorageSize
;
142 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
145 UINT32 HwErrStorageSize
;
146 UINT32 MaxUserNvVariableSpaceSize
;
147 UINT32 BoottimeReservedNvVariableSpaceSize
;
151 mVariableModuleGlobal
->FvbInstance
= NULL
;
154 // Allocate runtime memory used for a memory copy of the FLASH region.
155 // Keep the memory and the FLASH in sync as updates occur.
157 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
158 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
159 if (NvStorageData
== NULL
) {
160 return EFI_OUT_OF_RESOURCES
;
163 NvStorageBase
= NV_STORAGE_VARIABLE_BASE
;
164 ASSERT (NvStorageBase
!= 0);
167 // Copy NV storage data to the memory buffer.
169 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) NvStorageBase
, NvStorageSize
);
171 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
173 // If FTW protocol has been installed, no need to check FTW last write data hob.
175 if (EFI_ERROR (Status
)) {
177 // Check the FTW last write data hob.
179 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
180 if (GuidHob
!= NULL
) {
181 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
182 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
183 DEBUG ((DEBUG_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
) FtwLastWriteData
->SpareAddress
));
185 // Copy the backed up NV storage data to the memory buffer from spare block.
187 CopyMem (NvStorageData
, (UINT8
*) (UINTN
) (FtwLastWriteData
->SpareAddress
), NvStorageSize
);
188 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
189 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
))) {
191 // Flash NV storage from the Offset is backed up in spare block.
193 BackUpOffset
= (UINT32
) (FtwLastWriteData
->TargetAddress
- NvStorageBase
);
194 BackUpSize
= NvStorageSize
- BackUpOffset
;
195 DEBUG ((DEBUG_INFO
, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset
, (UINTN
) FtwLastWriteData
->SpareAddress
));
197 // Copy the partial backed up NV storage data to the memory buffer from spare block.
199 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*) (UINTN
) FtwLastWriteData
->SpareAddress
, BackUpSize
);
204 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) NvStorageData
;
207 // Check if the Firmware Volume is not corrupted
209 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
210 FreePool (NvStorageData
);
211 DEBUG ((DEBUG_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
212 return EFI_VOLUME_CORRUPTED
;
215 VariableStore
= (VARIABLE_STORE_HEADER
*) ((UINTN
) FvHeader
+ FvHeader
->HeaderLength
);
216 VariableStoreLength
= NvStorageSize
- FvHeader
->HeaderLength
;
217 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
218 ASSERT (VariableStore
->Size
== VariableStoreLength
);
221 // Check if the Variable Store header is not corrupted
223 if (GetVariableStoreStatus (VariableStore
) != EfiValid
) {
224 FreePool (NvStorageData
);
225 DEBUG((DEBUG_ERROR
, "Variable Store header is corrupted\n"));
226 return EFI_VOLUME_CORRUPTED
;
229 mNvFvHeaderCache
= FvHeader
;
231 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
233 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
234 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
235 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
238 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
239 // is stored with common variable in the same NV region. So the platform integrator should
240 // ensure that the value of PcdHwErrStorageSize is less than the value of
241 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
243 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
245 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
246 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
248 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
250 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
251 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
253 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
255 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
) VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
256 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
257 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
261 "Variable driver common space: 0x%x 0x%x 0x%x\n",
262 mVariableModuleGlobal
->CommonVariableSpace
,
263 mVariableModuleGlobal
->CommonMaxUserVariableSpace
,
264 mVariableModuleGlobal
->CommonRuntimeVariableSpace
268 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
270 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
276 Init non-volatile variable store.
278 @retval EFI_SUCCESS Function successfully executed.
279 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
280 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
284 InitNonVolatileVariableStore (
288 VARIABLE_HEADER
*Variable
;
289 VARIABLE_HEADER
*NextVariable
;
290 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
294 if (PcdGetBool (PcdEmuVariableNvModeEnable
)) {
295 Status
= InitEmuNonVolatileVariableStore (&VariableStoreBase
);
296 if (EFI_ERROR (Status
)) {
299 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= TRUE
;
300 DEBUG ((DEBUG_INFO
, "Variable driver will work at emulated non-volatile variable mode!\n"));
302 Status
= InitRealNonVolatileVariableStore (&VariableStoreBase
);
303 if (EFI_ERROR (Status
)) {
306 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= FALSE
;
309 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
310 mNvVariableCache
= (VARIABLE_STORE_HEADER
*) (UINTN
) VariableStoreBase
;
311 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
313 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
314 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
317 // Parse non-volatile variable data and get last variable offset.
319 Variable
= GetStartPointer (mNvVariableCache
);
320 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
321 NextVariable
= GetNextVariablePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
322 VariableSize
= (UINTN
) NextVariable
- (UINTN
) Variable
;
323 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
324 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
326 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
329 Variable
= NextVariable
;
331 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
) Variable
- (UINTN
) mNvVariableCache
;