]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableNonVolatile.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
4dbebc2d 145 UINT64 NvStorageSize64;\r
6b0d7b01
MK
146 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
147 UINT32 BackUpOffset;\r
148 UINT32 BackUpSize;\r
149 UINT32 HwErrStorageSize;\r
150 UINT32 MaxUserNvVariableSpaceSize;\r
151 UINT32 BoottimeReservedNvVariableSpaceSize;\r
152 EFI_STATUS Status;\r
153 VOID *FtwProtocol;\r
154\r
155 mVariableModuleGlobal->FvbInstance = NULL;\r
156\r
4dbebc2d
MK
157 Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64);\r
158 ASSERT_EFI_ERROR (Status);\r
159\r
160 Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);\r
161 // This driver currently assumes the size will be UINT32 so assert the value is safe for now.\r
162 ASSERT_EFI_ERROR (Status);\r
163\r
164 ASSERT (NvStorageBase != 0);\r
165\r
6b0d7b01
MK
166 //\r
167 // Allocate runtime memory used for a memory copy of the FLASH region.\r
168 // Keep the memory and the FLASH in sync as updates occur.\r
169 //\r
6b0d7b01
MK
170 NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
171 if (NvStorageData == NULL) {\r
172 return EFI_OUT_OF_RESOURCES;\r
173 }\r
174\r
6b0d7b01
MK
175 //\r
176 // Copy NV storage data to the memory buffer.\r
177 //\r
1436aea4 178 CopyMem (NvStorageData, (UINT8 *)(UINTN)NvStorageBase, NvStorageSize);\r
6b0d7b01
MK
179\r
180 Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
181 //\r
182 // If FTW protocol has been installed, no need to check FTW last write data hob.\r
183 //\r
184 if (EFI_ERROR (Status)) {\r
185 //\r
186 // Check the FTW last write data hob.\r
187 //\r
188 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
189 if (GuidHob != NULL) {\r
1436aea4 190 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);\r
6b0d7b01 191 if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
1436aea4 192 DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));\r
6b0d7b01
MK
193 //\r
194 // Copy the backed up NV storage data to the memory buffer from spare block.\r
195 //\r
1436aea4 196 CopyMem (NvStorageData, (UINT8 *)(UINTN)(FtwLastWriteData->SpareAddress), NvStorageSize);\r
6b0d7b01 197 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
1436aea4
MK
198 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize)))\r
199 {\r
6b0d7b01
MK
200 //\r
201 // Flash NV storage from the Offset is backed up in spare block.\r
202 //\r
1436aea4
MK
203 BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);\r
204 BackUpSize = NvStorageSize - BackUpOffset;\r
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));\r
6b0d7b01
MK
206 //\r
207 // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
208 //\r
1436aea4 209 CopyMem (NvStorageData + BackUpOffset, (UINT8 *)(UINTN)FtwLastWriteData->SpareAddress, BackUpSize);\r
6b0d7b01
MK
210 }\r
211 }\r
212 }\r
213\r
1436aea4 214 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvStorageData;\r
6b0d7b01
MK
215\r
216 //\r
217 // Check if the Firmware Volume is not corrupted\r
218 //\r
219 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
220 FreePool (NvStorageData);\r
221 DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
222 return EFI_VOLUME_CORRUPTED;\r
223 }\r
224\r
1436aea4 225 VariableStore = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);\r
6b0d7b01
MK
226 VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;\r
227 ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
228 ASSERT (VariableStore->Size == VariableStoreLength);\r
229\r
230 //\r
231 // Check if the Variable Store header is not corrupted\r
232 //\r
233 if (GetVariableStoreStatus (VariableStore) != EfiValid) {\r
234 FreePool (NvStorageData);\r
1436aea4 235 DEBUG ((DEBUG_ERROR, "Variable Store header is corrupted\n"));\r
6b0d7b01
MK
236 return EFI_VOLUME_CORRUPTED;\r
237 }\r
238\r
239 mNvFvHeaderCache = FvHeader;\r
240\r
1436aea4 241 *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;\r
6b0d7b01 242\r
1436aea4
MK
243 HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
244 MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r
6b0d7b01
MK
245 BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);\r
246\r
247 //\r
248 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
249 // is stored with common variable in the same NV region. So the platform integrator should\r
250 // ensure that the value of PcdHwErrStorageSize is less than the value of\r
251 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
252 //\r
253 ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
254 //\r
255 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of\r
256 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
257 //\r
258 ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
259 //\r
260 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of\r
261 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
262 //\r
263 ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
264\r
1436aea4 265 mVariableModuleGlobal->CommonVariableSpace = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
6b0d7b01
MK
266 mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);\r
267 mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;\r
268\r
269 DEBUG ((\r
270 DEBUG_INFO,\r
271 "Variable driver common space: 0x%x 0x%x 0x%x\n",\r
272 mVariableModuleGlobal->CommonVariableSpace,\r
273 mVariableModuleGlobal->CommonMaxUserVariableSpace,\r
274 mVariableModuleGlobal->CommonRuntimeVariableSpace\r
275 ));\r
276\r
277 //\r
278 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
279 //\r
280 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
281\r
282 return EFI_SUCCESS;\r
283}\r
284\r
285/**\r
286 Init non-volatile variable store.\r
287\r
288 @retval EFI_SUCCESS Function successfully executed.\r
289 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
290 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r
291\r
292**/\r
293EFI_STATUS\r
294InitNonVolatileVariableStore (\r
295 VOID\r
296 )\r
297{\r
1436aea4
MK
298 VARIABLE_HEADER *Variable;\r
299 VARIABLE_HEADER *NextVariable;\r
300 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
301 UINTN VariableSize;\r
302 EFI_STATUS Status;\r
6b0d7b01
MK
303\r
304 if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
305 Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r
306 if (EFI_ERROR (Status)) {\r
307 return Status;\r
308 }\r
1436aea4 309\r
6b0d7b01
MK
310 mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r
311 DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r
312 } else {\r
313 Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r
314 if (EFI_ERROR (Status)) {\r
315 return Status;\r
316 }\r
1436aea4 317\r
6b0d7b01
MK
318 mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r
319 }\r
320\r
321 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
1436aea4
MK
322 mNvVariableCache = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
323 mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r
6b0d7b01 324\r
1436aea4 325 mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r
6b0d7b01
MK
326 mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r
327\r
328 //\r
329 // Parse non-volatile variable data and get last variable offset.\r
330 //\r
1436aea4 331 Variable = GetStartPointer (mNvVariableCache);\r
6b0d7b01
MK
332 while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
333 NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1436aea4 334 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
6b0d7b01
MK
335 if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
336 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
337 } else {\r
338 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
339 }\r
340\r
341 Variable = NextVariable;\r
342 }\r
1436aea4
MK
343\r
344 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)Variable - (UINTN)mNvVariableCache;\r
6b0d7b01
MK
345\r
346 return EFI_SUCCESS;\r
347}\r