]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableNonVolatile.c
CommitLineData
6b0d7b01
MK
1/** @file\r
2 Common variable non-volatile store routines.\r
3\r
4Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "VariableNonVolatile.h"\r
10#include "VariableParsing.h"\r
11\r
12extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
13\r
14/**\r
15 Get non-volatile maximum variable size.\r
16\r
17 @return Non-volatile maximum variable size.\r
18\r
19**/\r
20UINTN\r
21GetNonVolatileMaxVariableSize (\r
22 VOID\r
23 )\r
24{\r
25 if (PcdGet32 (PcdHwErrStorageSize) != 0) {\r
1436aea4
MK
26 return MAX (\r
27 MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),\r
28 PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
29 );\r
6b0d7b01
MK
30 } else {\r
31 return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));\r
32 }\r
33}\r
34\r
35/**\r
36 Init emulated non-volatile variable store.\r
37\r
38 @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.\r
39\r
40 @retval EFI_SUCCESS Function successfully executed.\r
41 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
42\r
43**/\r
44EFI_STATUS\r
45InitEmuNonVolatileVariableStore (\r
46 OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase\r
47 )\r
48{\r
1436aea4
MK
49 VARIABLE_STORE_HEADER *VariableStore;\r
50 UINT32 VariableStoreLength;\r
51 BOOLEAN FullyInitializeStore;\r
52 UINT32 HwErrStorageSize;\r
6b0d7b01
MK
53\r
54 FullyInitializeStore = TRUE;\r
55\r
56 VariableStoreLength = PcdGet32 (PcdVariableStoreSize);\r
57 ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
58\r
59 //\r
60 // Allocate memory for variable store.\r
61 //\r
62 if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {\r
1436aea4 63 VariableStore = (VARIABLE_STORE_HEADER *)AllocateRuntimePool (VariableStoreLength);\r
6b0d7b01
MK
64 if (VariableStore == NULL) {\r
65 return EFI_OUT_OF_RESOURCES;\r
66 }\r
67 } else {\r
68 //\r
69 // A memory location has been reserved for the NV variable store. Certain\r
70 // platforms may be able to preserve a memory range across system resets,\r
71 // thereby providing better NV variable emulation.\r
72 //\r
73 VariableStore =\r
1436aea4
MK
74 (VARIABLE_STORE_HEADER *)(VOID *)(UINTN)\r
75 PcdGet64 (PcdEmuVariableNvStoreReserved);\r
6b0d7b01
MK
76 if ((VariableStore->Size == VariableStoreLength) &&\r
77 (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||\r
78 CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&\r
79 (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&\r
1436aea4
MK
80 (VariableStore->State == VARIABLE_STORE_HEALTHY))\r
81 {\r
82 DEBUG ((\r
6b0d7b01
MK
83 DEBUG_INFO,\r
84 "Variable Store reserved at %p appears to be valid\n",\r
85 VariableStore\r
86 ));\r
87 FullyInitializeStore = FALSE;\r
88 }\r
89 }\r
90\r
91 if (FullyInitializeStore) {\r
92 SetMem (VariableStore, VariableStoreLength, 0xff);\r
93 //\r
94 // Use gEfiAuthenticatedVariableGuid for potential auth variable support.\r
95 //\r
96 CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
1436aea4
MK
97 VariableStore->Size = VariableStoreLength;\r
98 VariableStore->Format = VARIABLE_STORE_FORMATTED;\r
99 VariableStore->State = VARIABLE_STORE_HEALTHY;\r
100 VariableStore->Reserved = 0;\r
101 VariableStore->Reserved1 = 0;\r
6b0d7b01
MK
102 }\r
103\r
1436aea4 104 *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;\r
6b0d7b01
MK
105\r
106 HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
107\r
108 //\r
109 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
110 // is stored with common variable in the same NV region. So the platform integrator should\r
111 // ensure that the value of PcdHwErrStorageSize is less than the value of\r
112 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
113 //\r
114 ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
115\r
1436aea4 116 mVariableModuleGlobal->CommonVariableSpace = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
6b0d7b01
MK
117 mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
118 mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
119\r
120 return EFI_SUCCESS;\r
121}\r
122\r
123/**\r
124 Init real non-volatile variable store.\r
125\r
126 @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.\r
127\r
128 @retval EFI_SUCCESS Function successfully executed.\r
129 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
130 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r
131\r
132**/\r
133EFI_STATUS\r
134InitRealNonVolatileVariableStore (\r
1436aea4 135 OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase\r
6b0d7b01
MK
136 )\r
137{\r
138 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
139 VARIABLE_STORE_HEADER *VariableStore;\r
140 UINT32 VariableStoreLength;\r
141 EFI_HOB_GUID_TYPE *GuidHob;\r
142 EFI_PHYSICAL_ADDRESS NvStorageBase;\r
143 UINT8 *NvStorageData;\r
144 UINT32 NvStorageSize;\r
145 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
146 UINT32 BackUpOffset;\r
147 UINT32 BackUpSize;\r
148 UINT32 HwErrStorageSize;\r
149 UINT32 MaxUserNvVariableSpaceSize;\r
150 UINT32 BoottimeReservedNvVariableSpaceSize;\r
151 EFI_STATUS Status;\r
152 VOID *FtwProtocol;\r
153\r
154 mVariableModuleGlobal->FvbInstance = NULL;\r
155\r
156 //\r
157 // Allocate runtime memory used for a memory copy of the FLASH region.\r
158 // Keep the memory and the FLASH in sync as updates occur.\r
159 //\r
160 NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
161 NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
162 if (NvStorageData == NULL) {\r
163 return EFI_OUT_OF_RESOURCES;\r
164 }\r
165\r
166 NvStorageBase = NV_STORAGE_VARIABLE_BASE;\r
167 ASSERT (NvStorageBase != 0);\r
168\r
169 //\r
170 // Copy NV storage data to the memory buffer.\r
171 //\r
1436aea4 172 CopyMem (NvStorageData, (UINT8 *)(UINTN)NvStorageBase, NvStorageSize);\r
6b0d7b01
MK
173\r
174 Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
175 //\r
176 // If FTW protocol has been installed, no need to check FTW last write data hob.\r
177 //\r
178 if (EFI_ERROR (Status)) {\r
179 //\r
180 // Check the FTW last write data hob.\r
181 //\r
182 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
183 if (GuidHob != NULL) {\r
1436aea4 184 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);\r
6b0d7b01 185 if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
1436aea4 186 DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));\r
6b0d7b01
MK
187 //\r
188 // Copy the backed up NV storage data to the memory buffer from spare block.\r
189 //\r
1436aea4 190 CopyMem (NvStorageData, (UINT8 *)(UINTN)(FtwLastWriteData->SpareAddress), NvStorageSize);\r
6b0d7b01 191 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
1436aea4
MK
192 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize)))\r
193 {\r
6b0d7b01
MK
194 //\r
195 // Flash NV storage from the Offset is backed up in spare block.\r
196 //\r
1436aea4
MK
197 BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);\r
198 BackUpSize = NvStorageSize - BackUpOffset;\r
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));\r
6b0d7b01
MK
200 //\r
201 // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
202 //\r
1436aea4 203 CopyMem (NvStorageData + BackUpOffset, (UINT8 *)(UINTN)FtwLastWriteData->SpareAddress, BackUpSize);\r
6b0d7b01
MK
204 }\r
205 }\r
206 }\r
207\r
1436aea4 208 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvStorageData;\r
6b0d7b01
MK
209\r
210 //\r
211 // Check if the Firmware Volume is not corrupted\r
212 //\r
213 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
214 FreePool (NvStorageData);\r
215 DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
216 return EFI_VOLUME_CORRUPTED;\r
217 }\r
218\r
1436aea4 219 VariableStore = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);\r
6b0d7b01
MK
220 VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;\r
221 ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
222 ASSERT (VariableStore->Size == VariableStoreLength);\r
223\r
224 //\r
225 // Check if the Variable Store header is not corrupted\r
226 //\r
227 if (GetVariableStoreStatus (VariableStore) != EfiValid) {\r
228 FreePool (NvStorageData);\r
1436aea4 229 DEBUG ((DEBUG_ERROR, "Variable Store header is corrupted\n"));\r
6b0d7b01
MK
230 return EFI_VOLUME_CORRUPTED;\r
231 }\r
232\r
233 mNvFvHeaderCache = FvHeader;\r
234\r
1436aea4 235 *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;\r
6b0d7b01 236\r
1436aea4
MK
237 HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
238 MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r
6b0d7b01
MK
239 BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);\r
240\r
241 //\r
242 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
243 // is stored with common variable in the same NV region. So the platform integrator should\r
244 // ensure that the value of PcdHwErrStorageSize is less than the value of\r
245 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
246 //\r
247 ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
248 //\r
249 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of\r
250 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
251 //\r
252 ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
253 //\r
254 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of\r
255 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
256 //\r
257 ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
258\r
1436aea4 259 mVariableModuleGlobal->CommonVariableSpace = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
6b0d7b01
MK
260 mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);\r
261 mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;\r
262\r
263 DEBUG ((\r
264 DEBUG_INFO,\r
265 "Variable driver common space: 0x%x 0x%x 0x%x\n",\r
266 mVariableModuleGlobal->CommonVariableSpace,\r
267 mVariableModuleGlobal->CommonMaxUserVariableSpace,\r
268 mVariableModuleGlobal->CommonRuntimeVariableSpace\r
269 ));\r
270\r
271 //\r
272 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
273 //\r
274 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
275\r
276 return EFI_SUCCESS;\r
277}\r
278\r
279/**\r
280 Init non-volatile variable store.\r
281\r
282 @retval EFI_SUCCESS Function successfully executed.\r
283 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
284 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r
285\r
286**/\r
287EFI_STATUS\r
288InitNonVolatileVariableStore (\r
289 VOID\r
290 )\r
291{\r
1436aea4
MK
292 VARIABLE_HEADER *Variable;\r
293 VARIABLE_HEADER *NextVariable;\r
294 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
295 UINTN VariableSize;\r
296 EFI_STATUS Status;\r
6b0d7b01
MK
297\r
298 if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
299 Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r
300 if (EFI_ERROR (Status)) {\r
301 return Status;\r
302 }\r
1436aea4 303\r
6b0d7b01
MK
304 mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r
305 DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r
306 } else {\r
307 Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r
308 if (EFI_ERROR (Status)) {\r
309 return Status;\r
310 }\r
1436aea4 311\r
6b0d7b01
MK
312 mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r
313 }\r
314\r
315 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
1436aea4
MK
316 mNvVariableCache = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
317 mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r
6b0d7b01 318\r
1436aea4 319 mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r
6b0d7b01
MK
320 mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r
321\r
322 //\r
323 // Parse non-volatile variable data and get last variable offset.\r
324 //\r
1436aea4 325 Variable = GetStartPointer (mNvVariableCache);\r
6b0d7b01
MK
326 while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
327 NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1436aea4 328 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
6b0d7b01
MK
329 if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
330 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
331 } else {\r
332 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
333 }\r
334\r
335 Variable = NextVariable;\r
336 }\r
1436aea4
MK
337\r
338 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)Variable - (UINTN)mNvVariableCache;\r
6b0d7b01
MK
339\r
340 return EFI_SUCCESS;\r
341}\r