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 UINT64 NvStorageSize64
;
146 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*FtwLastWriteData
;
149 UINT32 HwErrStorageSize
;
150 UINT32 MaxUserNvVariableSpaceSize
;
151 UINT32 BoottimeReservedNvVariableSpaceSize
;
155 mVariableModuleGlobal
->FvbInstance
= NULL
;
157 Status
= GetVariableFlashNvStorageInfo (&NvStorageBase
, &NvStorageSize64
);
158 ASSERT_EFI_ERROR (Status
);
160 Status
= SafeUint64ToUint32 (NvStorageSize64
, &NvStorageSize
);
161 // This driver currently assumes the size will be UINT32 so assert the value is safe for now.
162 ASSERT_EFI_ERROR (Status
);
164 ASSERT (NvStorageBase
!= 0);
167 // Allocate runtime memory used for a memory copy of the FLASH region.
168 // Keep the memory and the FLASH in sync as updates occur.
170 NvStorageData
= AllocateRuntimeZeroPool (NvStorageSize
);
171 if (NvStorageData
== NULL
) {
172 return EFI_OUT_OF_RESOURCES
;
176 // Copy NV storage data to the memory buffer.
178 CopyMem (NvStorageData
, (UINT8
*)(UINTN
)NvStorageBase
, NvStorageSize
);
180 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
182 // If FTW protocol has been installed, no need to check FTW last write data hob.
184 if (EFI_ERROR (Status
)) {
186 // Check the FTW last write data hob.
188 GuidHob
= GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid
);
189 if (GuidHob
!= NULL
) {
190 FtwLastWriteData
= (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA
*)GET_GUID_HOB_DATA (GuidHob
);
191 if (FtwLastWriteData
->TargetAddress
== NvStorageBase
) {
192 DEBUG ((DEBUG_INFO
, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN
)FtwLastWriteData
->SpareAddress
));
194 // Copy the backed up NV storage data to the memory buffer from spare block.
196 CopyMem (NvStorageData
, (UINT8
*)(UINTN
)(FtwLastWriteData
->SpareAddress
), NvStorageSize
);
197 } else if ((FtwLastWriteData
->TargetAddress
> NvStorageBase
) &&
198 (FtwLastWriteData
->TargetAddress
< (NvStorageBase
+ NvStorageSize
)))
201 // Flash NV storage from the Offset is backed up in spare block.
203 BackUpOffset
= (UINT32
)(FtwLastWriteData
->TargetAddress
- NvStorageBase
);
204 BackUpSize
= NvStorageSize
- BackUpOffset
;
205 DEBUG ((DEBUG_INFO
, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset
, (UINTN
)FtwLastWriteData
->SpareAddress
));
207 // Copy the partial backed up NV storage data to the memory buffer from spare block.
209 CopyMem (NvStorageData
+ BackUpOffset
, (UINT8
*)(UINTN
)FtwLastWriteData
->SpareAddress
, BackUpSize
);
214 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)NvStorageData
;
217 // Check if the Firmware Volume is not corrupted
219 if ((FvHeader
->Signature
!= EFI_FVH_SIGNATURE
) || (!CompareGuid (&gEfiSystemNvDataFvGuid
, &FvHeader
->FileSystemGuid
))) {
220 FreePool (NvStorageData
);
221 DEBUG ((DEBUG_ERROR
, "Firmware Volume for Variable Store is corrupted\n"));
222 return EFI_VOLUME_CORRUPTED
;
225 VariableStore
= (VARIABLE_STORE_HEADER
*)((UINTN
)FvHeader
+ FvHeader
->HeaderLength
);
226 VariableStoreLength
= NvStorageSize
- FvHeader
->HeaderLength
;
227 ASSERT (sizeof (VARIABLE_STORE_HEADER
) <= VariableStoreLength
);
228 ASSERT (VariableStore
->Size
== VariableStoreLength
);
231 // Check if the Variable Store header is not corrupted
233 if (GetVariableStoreStatus (VariableStore
) != EfiValid
) {
234 FreePool (NvStorageData
);
235 DEBUG ((DEBUG_ERROR
, "Variable Store header is corrupted\n"));
236 return EFI_VOLUME_CORRUPTED
;
239 mNvFvHeaderCache
= FvHeader
;
241 *VariableStoreBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)VariableStore
;
243 HwErrStorageSize
= PcdGet32 (PcdHwErrStorageSize
);
244 MaxUserNvVariableSpaceSize
= PcdGet32 (PcdMaxUserNvVariableSpaceSize
);
245 BoottimeReservedNvVariableSpaceSize
= PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize
);
248 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
249 // is stored with common variable in the same NV region. So the platform integrator should
250 // ensure that the value of PcdHwErrStorageSize is less than the value of
251 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
253 ASSERT (HwErrStorageSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
255 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
256 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
258 ASSERT (MaxUserNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
260 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
261 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
263 ASSERT (BoottimeReservedNvVariableSpaceSize
< (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
));
265 mVariableModuleGlobal
->CommonVariableSpace
= ((UINTN
)VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
) - HwErrStorageSize
);
266 mVariableModuleGlobal
->CommonMaxUserVariableSpace
= ((MaxUserNvVariableSpaceSize
!= 0) ? MaxUserNvVariableSpaceSize
: mVariableModuleGlobal
->CommonVariableSpace
);
267 mVariableModuleGlobal
->CommonRuntimeVariableSpace
= mVariableModuleGlobal
->CommonVariableSpace
- BoottimeReservedNvVariableSpaceSize
;
271 "Variable driver common space: 0x%x 0x%x 0x%x\n",
272 mVariableModuleGlobal
->CommonVariableSpace
,
273 mVariableModuleGlobal
->CommonMaxUserVariableSpace
,
274 mVariableModuleGlobal
->CommonRuntimeVariableSpace
278 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
280 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength
- sizeof (VARIABLE_STORE_HEADER
)));
286 Init non-volatile variable store.
288 @retval EFI_SUCCESS Function successfully executed.
289 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
290 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
294 InitNonVolatileVariableStore (
298 VARIABLE_HEADER
*Variable
;
299 VARIABLE_HEADER
*NextVariable
;
300 EFI_PHYSICAL_ADDRESS VariableStoreBase
;
304 if (PcdGetBool (PcdEmuVariableNvModeEnable
)) {
305 Status
= InitEmuNonVolatileVariableStore (&VariableStoreBase
);
306 if (EFI_ERROR (Status
)) {
310 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= TRUE
;
311 DEBUG ((DEBUG_INFO
, "Variable driver will work at emulated non-volatile variable mode!\n"));
313 Status
= InitRealNonVolatileVariableStore (&VariableStoreBase
);
314 if (EFI_ERROR (Status
)) {
318 mVariableModuleGlobal
->VariableGlobal
.EmuNvMode
= FALSE
;
321 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
= VariableStoreBase
;
322 mNvVariableCache
= (VARIABLE_STORE_HEADER
*)(UINTN
)VariableStoreBase
;
323 mVariableModuleGlobal
->VariableGlobal
.AuthFormat
= (BOOLEAN
)(CompareGuid (&mNvVariableCache
->Signature
, &gEfiAuthenticatedVariableGuid
));
325 mVariableModuleGlobal
->MaxVariableSize
= PcdGet32 (PcdMaxVariableSize
);
326 mVariableModuleGlobal
->MaxAuthVariableSize
= ((PcdGet32 (PcdMaxAuthVariableSize
) != 0) ? PcdGet32 (PcdMaxAuthVariableSize
) : mVariableModuleGlobal
->MaxVariableSize
);
329 // Parse non-volatile variable data and get last variable offset.
331 Variable
= GetStartPointer (mNvVariableCache
);
332 while (IsValidVariableHeader (Variable
, GetEndPointer (mNvVariableCache
))) {
333 NextVariable
= GetNextVariablePtr (Variable
, mVariableModuleGlobal
->VariableGlobal
.AuthFormat
);
334 VariableSize
= (UINTN
)NextVariable
- (UINTN
)Variable
;
335 if ((Variable
->Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
336 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VariableSize
;
338 mVariableModuleGlobal
->CommonVariableTotalSize
+= VariableSize
;
341 Variable
= NextVariable
;
344 mVariableModuleGlobal
->NonVolatileLastVariableOffset
= (UINTN
)Variable
- (UINTN
)mNvVariableCache
;