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) {
27 MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
)),
28 PcdGet32 (PcdMaxHardwareErrorVariableSize
)
31 return MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxAuthVariableSize
));
36 Init emulated non-volatile variable store.
38 @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
40 @retval EFI_SUCCESS Function successfully executed.
41 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
45 InitEmuNonVolatileVariableStore (
46 OUT EFI_PHYSICAL_ADDRESS
*VariableStoreBase
49 VARIABLE_STORE_HEADER
*VariableStore
;
50 UINT32 VariableStoreLength
;
51 BOOLEAN FullyInitializeStore
;
52 UINT32 HwErrStorageSize
;
54 FullyInitializeStore
= TRUE
;
56 VariableStoreLength
= PcdGet32 (PcdVariableStoreSize
);
57 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
60 // Allocate memory for variable store.
62 if (PcdGet64 (PcdEmuVariableNvStoreReserved
) == 0) {
63 VariableStore
= (VARIABLE_STORE_HEADER
*)AllocateRuntimePool (VariableStoreLength
);
64 if (VariableStore
== NULL
) {
65 return EFI_OUT_OF_RESOURCES
;
69 // A memory location has been reserved for the NV variable store. Certain
70 // platforms may be able to preserve a memory range across system resets,
71 // thereby providing better NV variable emulation.
74 (VARIABLE_STORE_HEADER
*)(VOID
*)(UINTN
)
75 PcdGet64 (PcdEmuVariableNvStoreReserved
);
76 if ((VariableStore
->Size
== VariableStoreLength
) &&
77 (CompareGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
) ||
78 CompareGuid (&VariableStore
->Signature
, &gEfiVariableGuid
)) &&
79 (VariableStore
->Format
== VARIABLE_STORE_FORMATTED
) &&
80 (VariableStore
->State
== VARIABLE_STORE_HEALTHY
))
84 "Variable Store reserved at %p appears to be valid\n",
87 FullyInitializeStore
= FALSE
;
91 if (FullyInitializeStore
) {
92 SetMem (VariableStore
, VariableStoreLength
, 0xff);
94 // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
96 CopyGuid (&VariableStore
->Signature
, &gEfiAuthenticatedVariableGuid
);
97 VariableStore
->Size
= VariableStoreLength
;
98 VariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
99 VariableStore
->State
= VARIABLE_STORE_HEALTHY
;
100 VariableStore
->Reserved
= 0;
101 VariableStore
->Reserved1
= 0;
104 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)VariableStore
;
106 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
109 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
110 // is stored with common variable in the same NV region. So the platform integrator should
111 // ensure that the value of PcdHwErrStorageSize is less than the value of
112 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
114 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
116 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
)VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
117 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
118 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
;
124 Init real non-volatile variable store.
126 @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
128 @retval EFI_SUCCESS Function successfully executed.
129 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
130 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
134 InitRealNonVolatileVariableStore (
135 OUT EFI_PHYSICAL_ADDRESS
*VariableStoreBase
138 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
139 VARIABLE_STORE_HEADER
*VariableStore
;
140 UINT32 VariableStoreLength
;
141 EFI_HOB_GUID_TYPE
*GuidHob
;
142 EFI_PHYSICAL_ADDRESS NvStorageBase
;
143 UINT8
*NvStorageData
;
144 UINT32 NvStorageSize
;
145 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
148 UINT32 HwErrStorageSize
;
149 UINT32 MaxUserNvVariableSpaceSize
;
150 UINT32 BoottimeReservedNvVariableSpaceSize
;
154 mVariableModuleGlobal
->FvbInstance
= NULL
;
157 // Allocate runtime memory used for a memory copy of the FLASH region.
158 // Keep the memory and the FLASH in sync as updates occur.
160 NvStorageSize
= PcdGet32 (PcdFlashNvStorageVariableSize
);
161 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
162 if (NvStorageData
== NULL
) {
163 return EFI_OUT_OF_RESOURCES
;
166 NvStorageBase
= NV_STORAGE_VARIABLE_BASE
;
167 ASSERT (NvStorageBase
!= 0);
170 // Copy NV storage data to the memory buffer.
172 CopyMem (NvStorageData
, (UINT8
*)(UINTN
)NvStorageBase
, NvStorageSize
);
174 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
176 // If FTW protocol has been installed, no need to check FTW last write data hob.
178 if (EFI_ERROR (Status
)) {
180 // Check the FTW last write data hob.
182 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
183 if (GuidHob
!= NULL
) {
184 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*)GET_GUID_HOB_DATA (GuidHob
);
185 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
186 DEBUG ((DEBUG_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
)FtwLastWriteData
->SpareAddress
));
188 // Copy the backed up NV storage data to the memory buffer from spare block.
190 CopyMem (NvStorageData
, (UINT8
*)(UINTN
)(FtwLastWriteData
->SpareAddress
), NvStorageSize
);
191 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
192 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
)))
195 // Flash NV storage from the Offset is backed up in spare block.
197 BackUpOffset
= (UINT32
)(FtwLastWriteData
->TargetAddress
- NvStorageBase
);
198 BackUpSize
= NvStorageSize
- BackUpOffset
;
199 DEBUG ((DEBUG_INFO
, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset
, (UINTN
)FtwLastWriteData
->SpareAddress
));
201 // Copy the partial backed up NV storage data to the memory buffer from spare block.
203 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*)(UINTN
)FtwLastWriteData
->SpareAddress
, BackUpSize
);
208 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)NvStorageData
;
211 // Check if the Firmware Volume is not corrupted
213 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
214 FreePool (NvStorageData
);
215 DEBUG ((DEBUG_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
216 return EFI_VOLUME_CORRUPTED
;
219 VariableStore
= (VARIABLE_STORE_HEADER
*)((UINTN
)FvHeader
+ FvHeader
->HeaderLength
);
220 VariableStoreLength
= NvStorageSize
- FvHeader
->HeaderLength
;
221 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
222 ASSERT (VariableStore
->Size
== VariableStoreLength
);
225 // Check if the Variable Store header is not corrupted
227 if (GetVariableStoreStatus (VariableStore
) != EfiValid
) {
228 FreePool (NvStorageData
);
229 DEBUG ((DEBUG_ERROR
, "Variable Store header is corrupted\n"));
230 return EFI_VOLUME_CORRUPTED
;
233 mNvFvHeaderCache
= FvHeader
;
235 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)VariableStore
;
237 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
238 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
239 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
242 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
243 // is stored with common variable in the same NV region. So the platform integrator should
244 // ensure that the value of PcdHwErrStorageSize is less than the value of
245 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
247 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
249 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
250 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
252 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
254 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
255 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
257 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
259 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
)VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
260 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
261 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
265 "Variable driver common space: 0x%x 0x%x 0x%x\n",
266 mVariableModuleGlobal
->CommonVariableSpace
,
267 mVariableModuleGlobal
->CommonMaxUserVariableSpace
,
268 mVariableModuleGlobal
->CommonRuntimeVariableSpace
272 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
274 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
280 Init non-volatile variable store.
282 @retval EFI_SUCCESS Function successfully executed.
283 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
284 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
288 InitNonVolatileVariableStore (
292 VARIABLE_HEADER
*Variable
;
293 VARIABLE_HEADER
*NextVariable
;
294 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
298 if (PcdGetBool (PcdEmuVariableNvModeEnable
)) {
299 Status
= InitEmuNonVolatileVariableStore (&VariableStoreBase
);
300 if (EFI_ERROR (Status
)) {
304 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= TRUE
;
305 DEBUG ((DEBUG_INFO
, "Variable driver will work at emulated non-volatile variable mode!\n"));
307 Status
= InitRealNonVolatileVariableStore (&VariableStoreBase
);
308 if (EFI_ERROR (Status
)) {
312 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= FALSE
;
315 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
316 mNvVariableCache
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
317 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
319 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
320 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
323 // Parse non-volatile variable data and get last variable offset.
325 Variable
= GetStartPointer (mNvVariableCache
);
326 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
327 NextVariable
= GetNextVariablePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
328 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
329 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
330 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
332 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
335 Variable
= NextVariable
;
338 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
)Variable
- (UINTN
)mNvVariableCache
;