]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
CommitLineData
052ad7e1 1/** @file\r
fa0737a8 2 The common variable operation routines shared by DXE_RUNTIME variable\r
8a2d4996 3 module and DXE_SMM variable module.\r
fa0737a8 4\r
18a7dbbc
SZ
5 Caution: This module requires additional review when modified.\r
6 This driver will have external input - variable data. They may be input in SMM mode.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.\r
11 They need check input parameter.\r
12\r
13 VariableServiceGetVariable() and VariableServiceSetVariable() are external API\r
14 to receive datasize and data buffer. The size should be checked carefully.\r
15\r
fa0737a8
SZ
16 VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
17 integer overflow. It should also check attribute to avoid authentication bypass.\r
18\r
302eb57b 19Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>\r
d741d141 20(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>\r
edf88807 21Copyright (c) Microsoft Corporation.<BR>\r
21320ef6 22Copyright (c) 2022, ARM Limited. All rights reserved.<BR>\r
edf88807 23\r
9d510e61 24SPDX-License-Identifier: BSD-2-Clause-Patent\r
8d3a5c82 25\r
052ad7e1 26**/\r
8d3a5c82 27\r
8d3a5c82 28#include "Variable.h"\r
6b0d7b01 29#include "VariableNonVolatile.h"\r
20a27a64 30#include "VariableParsing.h"\r
aab3b9b9 31#include "VariableRuntimeCache.h"\r
33a5a666 32\r
7800593d 33VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
8d3a5c82 34\r
7c80e839 35///\r
8a2d4996 36/// Define a memory cache that improves the search performance for a variable.\r
7cd69959 37/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.\r
7c80e839 38///\r
1436aea4 39VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
aa79b0b3 40\r
9b18845a
DL
41///\r
42/// Memory cache of Fv Header.\r
43///\r
1436aea4 44EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache = NULL;\r
9b18845a 45\r
8a2d4996 46///\r
47/// The memory entry used for variable statistics data.\r
48///\r
1436aea4 49VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
ff843847 50\r
ff843847
RN
51///\r
52/// The flag to indicate whether the platform has left the DXE phase of execution.\r
53///\r
1436aea4 54BOOLEAN mEndOfDxe = FALSE;\r
ff843847
RN
55\r
56///\r
8021f4c7
SZ
57/// It indicates the var check request source.\r
58/// In the implementation, DXE is regarded as untrusted, and SMM is trusted.\r
ff843847 59///\r
1436aea4 60VAR_CHECK_REQUEST_SOURCE mRequestSource = VarCheckFromUntrusted;\r
8d3a5c82 61\r
00ab76e0
SZ
62//\r
63// It will record the current boot error flag before EndOfDxe.\r
64//\r
1436aea4 65VAR_ERROR_FLAG mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;\r
33a5a666 66\r
1436aea4 67VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {\r
fa0737a8
SZ
68 {\r
69 &gEdkiiVarErrorFlagGuid,\r
70 VAR_ERROR_FLAG_NAME,\r
71 {\r
72 VAR_CHECK_VARIABLE_PROPERTY_REVISION,\r
73 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,\r
74 VARIABLE_ATTRIBUTE_NV_BS_RT,\r
75 sizeof (VAR_ERROR_FLAG),\r
76 sizeof (VAR_ERROR_FLAG)\r
77 }\r
78 },\r
79};\r
80\r
1436aea4 81AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {\r
fa0737a8 82 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,\r
dbd030bb
SZ
83 //\r
84 // StructSize, TO BE FILLED\r
85 //\r
86 0,\r
fa0737a8
SZ
87 //\r
88 // MaxAuthVariableSize, TO BE FILLED\r
89 //\r
90 0,\r
91 VariableExLibFindVariable,\r
92 VariableExLibFindNextVariable,\r
93 VariableExLibUpdateVariable,\r
94 VariableExLibGetScratchBuffer,\r
95 VariableExLibCheckRemainingSpaceForConsistency,\r
96 VariableExLibAtRuntime,\r
97};\r
98\r
1436aea4 99AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;\r
fa0737a8 100\r
7c80e839 101/**\r
102\r
103 This function writes data to the FWH at the correct LBA even if the LBAs\r
104 are fragmented.\r
105\r
8a2d4996 106 @param Global Pointer to VARAIBLE_GLOBAL structure.\r
107 @param Volatile Point out the Variable is Volatile or Non-Volatile.\r
108 @param SetByIndex TRUE if target pointer is given as index.\r
109 FALSE if target pointer is absolute.\r
110 @param Fvb Pointer to the writable FVB protocol.\r
7c80e839 111 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
8a2d4996 112 structure.\r
113 @param DataSize Size of data to be written.\r
114 @param Buffer Pointer to the buffer from which data is written.\r
7c80e839 115\r
8a2d4996 116 @retval EFI_INVALID_PARAMETER Parameters not valid.\r
989f7a2c 117 @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.\r
118 @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.\r
8a2d4996 119 @retval EFI_SUCCESS Variable store successfully updated.\r
7c80e839 120\r
121**/\r
8d3a5c82 122EFI_STATUS\r
8d3a5c82 123UpdateVariableStore (\r
8a9e0b72 124 IN VARIABLE_GLOBAL *Global,\r
125 IN BOOLEAN Volatile,\r
126 IN BOOLEAN SetByIndex,\r
127 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
128 IN UINTN DataPtrIndex,\r
129 IN UINT32 DataSize,\r
130 IN UINT8 *Buffer\r
8d3a5c82 131 )\r
8d3a5c82 132{\r
1436aea4
MK
133 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
134 UINTN BlockIndex2;\r
135 UINTN LinearOffset;\r
136 UINTN CurrWriteSize;\r
137 UINTN CurrWritePtr;\r
138 UINT8 *CurrBuffer;\r
139 EFI_LBA LbaNumber;\r
140 UINTN Size;\r
141 VARIABLE_STORE_HEADER *VolatileBase;\r
142 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
143 EFI_PHYSICAL_ADDRESS DataPtr;\r
144 EFI_STATUS Status;\r
8d3a5c82 145\r
1436aea4
MK
146 FvVolHdr = 0;\r
147 DataPtr = DataPtrIndex;\r
8d3a5c82 148\r
149 //\r
8a2d4996 150 // Check if the Data is Volatile.\r
8d3a5c82 151 //\r
7cd69959 152 if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
fa0737a8 153 if (Fvb == NULL) {\r
989f7a2c 154 return EFI_UNSUPPORTED;\r
fa0737a8 155 }\r
1436aea4
MK
156\r
157 Status = Fvb->GetPhysicalAddress (Fvb, &FvVolHdr);\r
8a9e0b72 158 ASSERT_EFI_ERROR (Status);\r
159\r
8d3a5c82 160 //\r
161 // Data Pointer should point to the actual Address where data is to be\r
8a2d4996 162 // written.\r
8d3a5c82 163 //\r
164 if (SetByIndex) {\r
052ad7e1 165 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
8d3a5c82 166 }\r
167\r
874c8434 168 if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {\r
989f7a2c 169 return EFI_OUT_OF_RESOURCES;\r
8d3a5c82 170 }\r
171 } else {\r
172 //\r
173 // Data Pointer should point to the actual Address where data is to be\r
8a2d4996 174 // written.\r
8d3a5c82 175 //\r
7cd69959 176 if (Volatile) {\r
1436aea4 177 VolatileBase = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
7cd69959
SZ
178 if (SetByIndex) {\r
179 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
180 }\r
8d3a5c82 181\r
1436aea4 182 if ((DataPtr + DataSize) > ((UINTN)VolatileBase + VolatileBase->Size)) {\r
7cd69959
SZ
183 return EFI_OUT_OF_RESOURCES;\r
184 }\r
185 } else {\r
186 //\r
187 // Emulated non-volatile variable mode.\r
188 //\r
189 if (SetByIndex) {\r
1436aea4 190 DataPtr += (UINTN)mNvVariableCache;\r
7cd69959
SZ
191 }\r
192\r
1436aea4 193 if ((DataPtr + DataSize) > ((UINTN)mNvVariableCache + mNvVariableCache->Size)) {\r
7cd69959
SZ
194 return EFI_OUT_OF_RESOURCES;\r
195 }\r
8d3a5c82 196 }\r
fa0737a8 197\r
c6492839 198 //\r
7cd69959 199 // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.\r
fa0737a8 200 //\r
c6492839 201 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
8d3a5c82 202 return EFI_SUCCESS;\r
203 }\r
fa0737a8 204\r
8d3a5c82 205 //\r
8a2d4996 206 // If we are here we are dealing with Non-Volatile Variables.\r
8d3a5c82 207 //\r
1436aea4
MK
208 LinearOffset = (UINTN)FvVolHdr;\r
209 CurrWritePtr = (UINTN)DataPtr;\r
8d3a5c82 210 CurrWriteSize = DataSize;\r
211 CurrBuffer = Buffer;\r
212 LbaNumber = 0;\r
213\r
214 if (CurrWritePtr < LinearOffset) {\r
215 return EFI_INVALID_PARAMETER;\r
216 }\r
217\r
9b18845a 218 for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
8d3a5c82 219 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
220 //\r
221 // Check to see if the Variable Writes are spanning through multiple\r
222 // blocks.\r
223 //\r
224 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
225 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
8a9e0b72 226 Status = Fvb->Write (\r
1436aea4
MK
227 Fvb,\r
228 LbaNumber,\r
229 (UINTN)(CurrWritePtr - LinearOffset),\r
230 &CurrWriteSize,\r
231 CurrBuffer\r
232 );\r
8a9e0b72 233 return Status;\r
8d3a5c82 234 } else {\r
1436aea4 235 Size = (UINT32)(LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
8a9e0b72 236 Status = Fvb->Write (\r
1436aea4
MK
237 Fvb,\r
238 LbaNumber,\r
239 (UINTN)(CurrWritePtr - LinearOffset),\r
240 &Size,\r
241 CurrBuffer\r
242 );\r
8d3a5c82 243 if (EFI_ERROR (Status)) {\r
244 return Status;\r
245 }\r
246\r
247 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
248 CurrBuffer = CurrBuffer + Size;\r
249 CurrWriteSize = CurrWriteSize - Size;\r
250 }\r
251 }\r
252\r
253 LinearOffset += PtrBlockMapEntry->Length;\r
254 LbaNumber++;\r
255 }\r
256 }\r
257\r
258 return EFI_SUCCESS;\r
259}\r
260\r
4edb1866
SZ
261/**\r
262 Record variable error flag.\r
263\r
264 @param[in] Flag Variable error flag to record.\r
265 @param[in] VariableName Name of variable.\r
266 @param[in] VendorGuid Guid of variable.\r
267 @param[in] Attributes Attributes of the variable.\r
268 @param[in] VariableSize Size of the variable.\r
269\r
270**/\r
271VOID\r
272RecordVarErrorFlag (\r
1436aea4
MK
273 IN VAR_ERROR_FLAG Flag,\r
274 IN CHAR16 *VariableName,\r
275 IN EFI_GUID *VendorGuid,\r
276 IN UINT32 Attributes,\r
277 IN UINTN VariableSize\r
4edb1866
SZ
278 )\r
279{\r
1436aea4
MK
280 EFI_STATUS Status;\r
281 VARIABLE_POINTER_TRACK Variable;\r
282 VAR_ERROR_FLAG *VarErrFlag;\r
283 VAR_ERROR_FLAG TempFlag;\r
4edb1866 284\r
db52c7f7 285 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
286 DEBUG ((DEBUG_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));\r
287 if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {\r
288 if (AtRuntime ()) {\r
289 DEBUG ((DEBUG_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));\r
4edb1866 290 } else {\r
1436aea4 291 DEBUG ((DEBUG_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));\r
4edb1866 292 }\r
1436aea4
MK
293 } else {\r
294 DEBUG ((DEBUG_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));\r
295 }\r
296\r
db52c7f7 297 DEBUG_CODE_END ();\r
4edb1866 298\r
00ab76e0
SZ
299 if (!mEndOfDxe) {\r
300 //\r
301 // Before EndOfDxe, just record the current boot variable error flag to local variable,\r
302 // and leave the variable error flag in NV flash as the last boot variable error flag.\r
303 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash\r
304 // will be initialized to this local current boot variable error flag.\r
305 //\r
306 mCurrentBootVarErrFlag &= Flag;\r
307 return;\r
308 }\r
309\r
4edb1866
SZ
310 //\r
311 // Record error flag (it should have be initialized).\r
312 //\r
313 Status = FindVariable (\r
314 VAR_ERROR_FLAG_NAME,\r
315 &gEdkiiVarErrorFlagGuid,\r
316 &Variable,\r
317 &mVariableModuleGlobal->VariableGlobal,\r
318 FALSE\r
319 );\r
320 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
321 VarErrFlag = (VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
322 TempFlag = *VarErrFlag;\r
323 TempFlag &= Flag;\r
4edb1866
SZ
324 if (TempFlag == *VarErrFlag) {\r
325 return;\r
326 }\r
1436aea4 327\r
4edb1866
SZ
328 Status = UpdateVariableStore (\r
329 &mVariableModuleGlobal->VariableGlobal,\r
330 FALSE,\r
331 FALSE,\r
332 mVariableModuleGlobal->FvbInstance,\r
1436aea4 333 (UINTN)VarErrFlag - (UINTN)mNvVariableCache + (UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
4edb1866
SZ
334 sizeof (TempFlag),\r
335 &TempFlag\r
336 );\r
337 if (!EFI_ERROR (Status)) {\r
338 //\r
339 // Update the data in NV cache.\r
340 //\r
4a23636a 341 *VarErrFlag = TempFlag;\r
1436aea4
MK
342 Status = SynchronizeRuntimeVariableCache (\r
343 &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,\r
344 0,\r
345 mNvVariableCache->Size\r
346 );\r
aab3b9b9 347 ASSERT_EFI_ERROR (Status);\r
4edb1866
SZ
348 }\r
349 }\r
350}\r
351\r
352/**\r
353 Initialize variable error flag.\r
354\r
355 Before EndOfDxe, the variable indicates the last boot variable error flag,\r
356 then it means the last boot variable error flag must be got before EndOfDxe.\r
357 After EndOfDxe, the variable indicates the current boot variable error flag,\r
358 then it means the current boot variable error flag must be got after EndOfDxe.\r
359\r
360**/\r
361VOID\r
362InitializeVarErrorFlag (\r
363 VOID\r
364 )\r
365{\r
1436aea4
MK
366 EFI_STATUS Status;\r
367 VARIABLE_POINTER_TRACK Variable;\r
368 VAR_ERROR_FLAG Flag;\r
369 VAR_ERROR_FLAG VarErrFlag;\r
4edb1866
SZ
370\r
371 if (!mEndOfDxe) {\r
372 return;\r
373 }\r
374\r
00ab76e0 375 Flag = mCurrentBootVarErrFlag;\r
87000d77 376 DEBUG ((DEBUG_INFO, "Initialize variable error flag (%02x)\n", Flag));\r
4edb1866
SZ
377\r
378 Status = FindVariable (\r
379 VAR_ERROR_FLAG_NAME,\r
380 &gEdkiiVarErrorFlagGuid,\r
381 &Variable,\r
382 &mVariableModuleGlobal->VariableGlobal,\r
383 FALSE\r
384 );\r
385 if (!EFI_ERROR (Status)) {\r
1436aea4 386 VarErrFlag = *((VAR_ERROR_FLAG *)GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat));\r
4edb1866
SZ
387 if (VarErrFlag == Flag) {\r
388 return;\r
389 }\r
390 }\r
391\r
392 UpdateVariable (\r
393 VAR_ERROR_FLAG_NAME,\r
394 &gEdkiiVarErrorFlagGuid,\r
395 &Flag,\r
396 sizeof (Flag),\r
397 VARIABLE_ATTRIBUTE_NV_BS_RT,\r
fa0737a8
SZ
398 0,\r
399 0,\r
400 &Variable,\r
401 NULL\r
4edb1866
SZ
402 );\r
403}\r
404\r
405/**\r
406 Is user variable?\r
407\r
408 @param[in] Variable Pointer to variable header.\r
409\r
410 @retval TRUE User variable.\r
411 @retval FALSE System variable.\r
412\r
413**/\r
414BOOLEAN\r
415IsUserVariable (\r
1436aea4 416 IN VARIABLE_HEADER *Variable\r
4edb1866
SZ
417 )\r
418{\r
1436aea4 419 VAR_CHECK_VARIABLE_PROPERTY Property;\r
4edb1866
SZ
420\r
421 //\r
422 // Only after End Of Dxe, the variables belong to system variable are fixed.\r
423 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
424 // then no need to check if the variable is user variable or not specially.\r
425 //\r
426 if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
04401023
MK
427 if (VarCheckLibVariablePropertyGet (\r
428 GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
429 GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
430 &Property\r
1436aea4
MK
431 ) == EFI_NOT_FOUND)\r
432 {\r
4edb1866
SZ
433 return TRUE;\r
434 }\r
435 }\r
1436aea4 436\r
4edb1866
SZ
437 return FALSE;\r
438}\r
439\r
440/**\r
441 Calculate common user variable total size.\r
442\r
443**/\r
444VOID\r
445CalculateCommonUserVariableTotalSize (\r
446 VOID\r
447 )\r
448{\r
1436aea4
MK
449 VARIABLE_HEADER *Variable;\r
450 VARIABLE_HEADER *NextVariable;\r
451 UINTN VariableSize;\r
452 VAR_CHECK_VARIABLE_PROPERTY Property;\r
4edb1866
SZ
453\r
454 //\r
455 // Only after End Of Dxe, the variables belong to system variable are fixed.\r
456 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
457 // then no need to calculate the common user variable total size specially.\r
458 //\r
459 if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
460 Variable = GetStartPointer (mNvVariableCache);\r
461 while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
04401023 462 NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1436aea4 463 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
4edb1866 464 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
04401023
MK
465 if (VarCheckLibVariablePropertyGet (\r
466 GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
467 GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
468 &Property\r
1436aea4
MK
469 ) == EFI_NOT_FOUND)\r
470 {\r
4edb1866
SZ
471 //\r
472 // No property, it is user variable.\r
473 //\r
474 mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
475 }\r
476 }\r
477\r
478 Variable = NextVariable;\r
479 }\r
480 }\r
481}\r
482\r
483/**\r
484 Initialize variable quota.\r
485\r
486**/\r
487VOID\r
488InitializeVariableQuota (\r
489 VOID\r
490 )\r
491{\r
8021f4c7 492 if (!mEndOfDxe) {\r
4edb1866
SZ
493 return;\r
494 }\r
4edb1866
SZ
495\r
496 InitializeVarErrorFlag ();\r
497 CalculateCommonUserVariableTotalSize ();\r
498}\r
052ad7e1 499\r
7c80e839 500/**\r
501\r
502 Variable store garbage collection and reclaim operation.\r
503\r
fa0737a8
SZ
504 @param[in] VariableBase Base address of variable store.\r
505 @param[out] LastVariableOffset Offset of last variable.\r
506 @param[in] IsVolatile The variable store is volatile or not;\r
507 if it is non-volatile, need FTW.\r
508 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.\r
509 @param[in] NewVariable Pointer to new variable.\r
510 @param[in] NewVariableSize New variable size.\r
7c80e839 511\r
fa0737a8
SZ
512 @return EFI_SUCCESS Reclaim operation has finished successfully.\r
513 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.\r
514 @return Others Unexpect error happened during reclaim operation.\r
7c80e839 515\r
516**/\r
8d3a5c82 517EFI_STATUS\r
8d3a5c82 518Reclaim (\r
1436aea4
MK
519 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
520 OUT UINTN *LastVariableOffset,\r
521 IN BOOLEAN IsVolatile,\r
522 IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,\r
523 IN VARIABLE_HEADER *NewVariable,\r
524 IN UINTN NewVariableSize\r
8d3a5c82 525 )\r
8d3a5c82 526{\r
1436aea4
MK
527 VARIABLE_HEADER *Variable;\r
528 VARIABLE_HEADER *AddedVariable;\r
529 VARIABLE_HEADER *NextVariable;\r
530 VARIABLE_HEADER *NextAddedVariable;\r
531 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
532 UINT8 *ValidBuffer;\r
533 UINTN MaximumBufferSize;\r
534 UINTN VariableSize;\r
535 UINTN NameSize;\r
536 UINT8 *CurrPtr;\r
537 VOID *Point0;\r
538 VOID *Point1;\r
539 BOOLEAN FoundAdded;\r
540 EFI_STATUS Status;\r
541 EFI_STATUS DoneStatus;\r
542 UINTN CommonVariableTotalSize;\r
543 UINTN CommonUserVariableTotalSize;\r
544 UINTN HwErrVariableTotalSize;\r
545 VARIABLE_HEADER *UpdatingVariable;\r
546 VARIABLE_HEADER *UpdatingInDeletedTransition;\r
547 BOOLEAN AuthFormat;\r
548\r
549 AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
550 UpdatingVariable = NULL;\r
7baf3c69 551 UpdatingInDeletedTransition = NULL;\r
23b06935 552 if (UpdatingPtrTrack != NULL) {\r
1436aea4 553 UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
7baf3c69 554 UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;\r
23b06935 555 }\r
8d3a5c82 556\r
1436aea4 557 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)VariableBase);\r
8f3a9e58 558\r
1436aea4 559 CommonVariableTotalSize = 0;\r
4edb1866 560 CommonUserVariableTotalSize = 0;\r
1436aea4 561 HwErrVariableTotalSize = 0;\r
8d3a5c82 562\r
7cd69959 563 if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
128ef095
SZ
564 //\r
565 // Start Pointers for the variable.\r
566 //\r
567 Variable = GetStartPointer (VariableStoreHeader);\r
568 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
569\r
6ebffb67 570 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
04401023 571 NextVariable = GetNextVariablePtr (Variable, AuthFormat);\r
1436aea4
MK
572 if (((Variable->State == VAR_ADDED) || (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) &&\r
573 (Variable != UpdatingVariable) &&\r
574 (Variable != UpdatingInDeletedTransition)\r
575 )\r
576 {\r
577 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
128ef095
SZ
578 MaximumBufferSize += VariableSize;\r
579 }\r
8d3a5c82 580\r
128ef095 581 Variable = NextVariable;\r
8d3a5c82 582 }\r
583\r
128ef095
SZ
584 if (NewVariable != NULL) {\r
585 //\r
586 // Add the new variable size.\r
587 //\r
588 MaximumBufferSize += NewVariableSize;\r
589 }\r
8d3a5c82 590\r
7baf3c69 591 //\r
128ef095
SZ
592 // Reserve the 1 Bytes with Oxff to identify the\r
593 // end of the variable buffer.\r
7baf3c69 594 //\r
128ef095 595 MaximumBufferSize += 1;\r
1436aea4 596 ValidBuffer = AllocatePool (MaximumBufferSize);\r
128ef095
SZ
597 if (ValidBuffer == NULL) {\r
598 return EFI_OUT_OF_RESOURCES;\r
599 }\r
600 } else {\r
601 //\r
602 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache\r
603 // as the buffer to reduce SMRAM consumption for SMM variable driver.\r
604 //\r
605 MaximumBufferSize = mNvVariableCache->Size;\r
1436aea4 606 ValidBuffer = (UINT8 *)mNvVariableCache;\r
8d3a5c82 607 }\r
608\r
814bae52 609 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
8d3a5c82 610\r
611 //\r
8a2d4996 612 // Copy variable store header.\r
8d3a5c82 613 //\r
814bae52 614 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
1436aea4 615 CurrPtr = (UINT8 *)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);\r
8d3a5c82 616\r
814bae52 617 //\r
8a2d4996 618 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
fa0737a8 619 //\r
814bae52 620 Variable = GetStartPointer (VariableStoreHeader);\r
6ebffb67 621 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
04401023 622 NextVariable = GetNextVariablePtr (Variable, AuthFormat);\r
1436aea4
MK
623 if ((Variable != UpdatingVariable) && (Variable->State == VAR_ADDED)) {\r
624 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
625 CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);\r
8d3a5c82 626 CurrPtr += VariableSize;\r
2fcdca1d 627 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 628 HwErrVariableTotalSize += VariableSize;\r
2fcdca1d 629 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 630 CommonVariableTotalSize += VariableSize;\r
4edb1866
SZ
631 if (IsUserVariable (Variable)) {\r
632 CommonUserVariableTotalSize += VariableSize;\r
633 }\r
2fcdca1d 634 }\r
8d3a5c82 635 }\r
1436aea4 636\r
8d3a5c82 637 Variable = NextVariable;\r
638 }\r
5ead4a07 639\r
814bae52 640 //\r
8a2d4996 641 // Reinstall all in delete transition variables.\r
fa0737a8 642 //\r
7baf3c69 643 Variable = GetStartPointer (VariableStoreHeader);\r
6ebffb67 644 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
04401023 645 NextVariable = GetNextVariablePtr (Variable, AuthFormat);\r
1436aea4 646 if ((Variable != UpdatingVariable) && (Variable != UpdatingInDeletedTransition) && (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {\r
814bae52 647 //\r
fa0737a8 648 // Buffer has cached all ADDED variable.\r
814bae52 649 // Per IN_DELETED variable, we have to guarantee that\r
fa0737a8
SZ
650 // no ADDED one in previous buffer.\r
651 //\r
652\r
1436aea4
MK
653 FoundAdded = FALSE;\r
654 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer);\r
655 while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)ValidBuffer))) {\r
04401023 656 NextAddedVariable = GetNextVariablePtr (AddedVariable, AuthFormat);\r
1436aea4 657 NameSize = NameSizeOfVariable (AddedVariable, AuthFormat);\r
04401023
MK
658 if (CompareGuid (\r
659 GetVendorGuidPtr (AddedVariable, AuthFormat),\r
660 GetVendorGuidPtr (Variable, AuthFormat)\r
1436aea4
MK
661 ) && (NameSize == NameSizeOfVariable (Variable, AuthFormat)))\r
662 {\r
663 Point0 = (VOID *)GetVariableNamePtr (AddedVariable, AuthFormat);\r
664 Point1 = (VOID *)GetVariableNamePtr (Variable, AuthFormat);\r
23b06935 665 if (CompareMem (Point0, Point1, NameSize) == 0) {\r
814bae52 666 FoundAdded = TRUE;\r
667 break;\r
668 }\r
669 }\r
1436aea4 670\r
814bae52 671 AddedVariable = NextAddedVariable;\r
672 }\r
1436aea4 673\r
814bae52 674 if (!FoundAdded) {\r
5ead4a07 675 //\r
8a2d4996 676 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
5ead4a07 677 //\r
1436aea4
MK
678 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
679 CopyMem (CurrPtr, (UINT8 *)Variable, VariableSize);\r
680 ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;\r
681 CurrPtr += VariableSize;\r
2fcdca1d 682 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 683 HwErrVariableTotalSize += VariableSize;\r
2fcdca1d 684 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 685 CommonVariableTotalSize += VariableSize;\r
4edb1866
SZ
686 if (IsUserVariable (Variable)) {\r
687 CommonUserVariableTotalSize += VariableSize;\r
688 }\r
2fcdca1d 689 }\r
814bae52 690 }\r
691 }\r
692\r
693 Variable = NextVariable;\r
694 }\r
8d3a5c82 695\r
7baf3c69
SZ
696 //\r
697 // Install the new variable if it is not NULL.\r
698 //\r
699 if (NewVariable != NULL) {\r
1436aea4 700 if (((UINTN)CurrPtr - (UINTN)ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
7baf3c69
SZ
701 //\r
702 // No enough space to store the new variable.\r
703 //\r
704 Status = EFI_OUT_OF_RESOURCES;\r
705 goto Done;\r
706 }\r
1436aea4 707\r
7baf3c69
SZ
708 if (!IsVolatile) {\r
709 if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
710 HwErrVariableTotalSize += NewVariableSize;\r
711 } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
712 CommonVariableTotalSize += NewVariableSize;\r
4edb1866
SZ
713 if (IsUserVariable (NewVariable)) {\r
714 CommonUserVariableTotalSize += NewVariableSize;\r
715 }\r
7baf3c69 716 }\r
1436aea4 717\r
7baf3c69 718 if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||\r
4edb1866 719 (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||\r
1436aea4
MK
720 (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace))\r
721 {\r
7baf3c69
SZ
722 //\r
723 // No enough space to store the new variable by NV or NV+HR attribute.\r
724 //\r
725 Status = EFI_OUT_OF_RESOURCES;\r
726 goto Done;\r
727 }\r
728 }\r
729\r
1436aea4
MK
730 CopyMem (CurrPtr, (UINT8 *)NewVariable, NewVariableSize);\r
731 ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED;\r
7baf3c69 732 if (UpdatingVariable != NULL) {\r
1436aea4 733 UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *)ValidBuffer)));\r
7baf3c69
SZ
734 UpdatingPtrTrack->InDeletedTransitionPtr = NULL;\r
735 }\r
1436aea4 736\r
7baf3c69
SZ
737 CurrPtr += NewVariableSize;\r
738 }\r
739\r
7cd69959 740 if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
8d3a5c82 741 //\r
7cd69959 742 // If volatile/emulated non-volatile variable store, just copy valid buffer.\r
8d3a5c82 743 //\r
1436aea4
MK
744 SetMem ((UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size, 0xff);\r
745 CopyMem ((UINT8 *)(UINTN)VariableBase, ValidBuffer, (UINTN)CurrPtr - (UINTN)ValidBuffer);\r
746 *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;\r
7cd69959
SZ
747 if (!IsVolatile) {\r
748 //\r
749 // Emulated non-volatile variable mode.\r
750 //\r
1436aea4
MK
751 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
752 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
7cd69959
SZ
753 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
754 }\r
1436aea4
MK
755\r
756 Status = EFI_SUCCESS;\r
8d3a5c82 757 } else {\r
758 //\r
759 // If non-volatile variable store, perform FTW here.\r
760 //\r
761 Status = FtwVariableSpace (\r
1436aea4
MK
762 VariableBase,\r
763 (VARIABLE_STORE_HEADER *)ValidBuffer\r
764 );\r
128ef095 765 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
766 *LastVariableOffset = (UINTN)CurrPtr - (UINTN)ValidBuffer;\r
767 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
768 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
4edb1866 769 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
128ef095 770 } else {\r
1436aea4
MK
771 mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
772 mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
b2c59ce8 773 mVariableModuleGlobal->CommonUserVariableTotalSize = 0;\r
1436aea4 774 Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
4edb1866 775 while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {\r
04401023 776 NextVariable = GetNextVariablePtr (Variable, AuthFormat);\r
1436aea4 777 VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r
128ef095 778 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
4edb1866 779 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
128ef095 780 } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
4edb1866
SZ
781 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
782 if (IsUserVariable (Variable)) {\r
783 mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
784 }\r
128ef095 785 }\r
8f3a9e58 786\r
4edb1866 787 Variable = NextVariable;\r
128ef095 788 }\r
1436aea4
MK
789\r
790 *LastVariableOffset = (UINTN)Variable - (UINTN)VariableBase;\r
8f3a9e58 791 }\r
8d3a5c82 792 }\r
793\r
7baf3c69 794Done:\r
256c4470 795 DoneStatus = EFI_SUCCESS;\r
7cd69959 796 if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
256c4470
MK
797 DoneStatus = SynchronizeRuntimeVariableCache (\r
798 &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache,\r
799 0,\r
800 VariableStoreHeader->Size\r
801 );\r
802 ASSERT_EFI_ERROR (DoneStatus);\r
128ef095
SZ
803 FreePool (ValidBuffer);\r
804 } else {\r
805 //\r
806 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.\r
807 //\r
1436aea4 808 CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
256c4470
MK
809 DoneStatus = SynchronizeRuntimeVariableCache (\r
810 &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache,\r
811 0,\r
812 VariableStoreHeader->Size\r
813 );\r
814 ASSERT_EFI_ERROR (DoneStatus);\r
815 }\r
816\r
817 if (!EFI_ERROR (Status) && EFI_ERROR (DoneStatus)) {\r
818 Status = DoneStatus;\r
128ef095 819 }\r
814bae52 820\r
8d3a5c82 821 return Status;\r
822}\r
823\r
7c80e839 824/**\r
825 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
826\r
827 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
828 If VariableName is an empty string, then we just return the first\r
829 qualified variable without comparing VariableName and VendorGuid.\r
9622df63
SZ
830 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check\r
831 at runtime when searching existing variable, only VariableName and VendorGuid are compared.\r
832 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.\r
7c80e839 833\r
fa0737a8
SZ
834 @param[in] VariableName Name of the variable to be found.\r
835 @param[in] VendorGuid Vendor GUID to be found.\r
836 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
7c80e839 837 including the range searched and the target position.\r
fa0737a8 838 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including\r
7c80e839 839 base of volatile variable storage area, base of\r
840 NV variable storage area, and a lock.\r
fa0737a8 841 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
9622df63 842 check at runtime when searching variable.\r
7c80e839 843\r
844 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
8a2d4996 845 VendorGuid is NULL.\r
846 @retval EFI_SUCCESS Variable successfully found.\r
255a3f33 847 @retval EFI_NOT_FOUND Variable not found\r
33a5a666 848\r
7c80e839 849**/\r
8d3a5c82 850EFI_STATUS\r
8d3a5c82 851FindVariable (\r
852 IN CHAR16 *VariableName,\r
853 IN EFI_GUID *VendorGuid,\r
854 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
9622df63
SZ
855 IN VARIABLE_GLOBAL *Global,\r
856 IN BOOLEAN IgnoreRtCheck\r
8d3a5c82 857 )\r
8d3a5c82 858{\r
1436aea4
MK
859 EFI_STATUS Status;\r
860 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
861 VARIABLE_STORE_TYPE Type;\r
0f7aff72 862\r
1436aea4 863 if ((VariableName[0] != 0) && (VendorGuid == NULL)) {\r
0f7aff72
RN
864 return EFI_INVALID_PARAMETER;\r
865 }\r
8d3a5c82 866\r
8d3a5c82 867 //\r
0f7aff72 868 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
36873a61 869 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
8a2d4996 870 // make use of this mapping to implement search algorithm.\r
8d3a5c82 871 //\r
1436aea4
MK
872 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)Global->VolatileVariableBase;\r
873 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *)(UINTN)Global->HobVariableBase;\r
0f7aff72 874 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
8d3a5c82 875\r
876 //\r
0f7aff72 877 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
8d3a5c82 878 //\r
1436aea4 879 for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {\r
0f7aff72
RN
880 if (VariableStoreHeader[Type] == NULL) {\r
881 continue;\r
882 }\r
814bae52 883\r
0f7aff72 884 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
1436aea4
MK
885 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
886 PtrTrack->Volatile = (BOOLEAN)(Type == VariableStoreTypeVolatile);\r
8d3a5c82 887\r
04401023
MK
888 Status = FindVariableEx (\r
889 VariableName,\r
890 VendorGuid,\r
891 IgnoreRtCheck,\r
892 PtrTrack,\r
893 mVariableModuleGlobal->VariableGlobal.AuthFormat\r
894 );\r
0f7aff72
RN
895 if (!EFI_ERROR (Status)) {\r
896 return Status;\r
814bae52 897 }\r
8d3a5c82 898 }\r
1436aea4 899\r
8d3a5c82 900 return EFI_NOT_FOUND;\r
901}\r
902\r
7c80e839 903/**\r
72399dae 904 Get index from supported language codes according to language string.\r
905\r
906 This code is used to get corresponding index in supported language codes. It can handle\r
0254efc0 907 RFC4646 and ISO639 language tags.\r
72399dae 908 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
0254efc0 909 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
72399dae 910\r
911 For example:\r
912 SupportedLang = "engfraengfra"\r
913 Lang = "eng"\r
914 Iso639Language = TRUE\r
915 The return value is "0".\r
916 Another example:\r
917 SupportedLang = "en;fr;en-US;fr-FR"\r
918 Lang = "fr-FR"\r
919 Iso639Language = FALSE\r
920 The return value is "3".\r
921\r
922 @param SupportedLang Platform supported language codes.\r
923 @param Lang Configured language.\r
0254efc0 924 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
72399dae 925\r
8a2d4996 926 @retval The index of language in the language codes.\r
8d3a5c82 927\r
7c80e839 928**/\r
72399dae 929UINTN\r
1436aea4
MK
930GetIndexFromSupportedLangCodes (\r
931 IN CHAR8 *SupportedLang,\r
932 IN CHAR8 *Lang,\r
933 IN BOOLEAN Iso639Language\r
fa0737a8 934 )\r
8d3a5c82 935{\r
1436aea4
MK
936 UINTN Index;\r
937 UINTN CompareLength;\r
938 UINTN LanguageLength;\r
72399dae 939\r
72399dae 940 if (Iso639Language) {\r
255a3f33 941 CompareLength = ISO_639_2_ENTRY_SIZE;\r
72399dae 942 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
943 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
944 //\r
945 // Successfully find the index of Lang string in SupportedLang string.\r
946 //\r
947 Index = Index / CompareLength;\r
948 return Index;\r
949 }\r
950 }\r
1436aea4 951\r
72399dae 952 ASSERT (FALSE);\r
953 return 0;\r
954 } else {\r
955 //\r
0254efc0 956 // Compare RFC4646 language code\r
72399dae 957 //\r
255a3f33 958 Index = 0;\r
1436aea4
MK
959 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++) {\r
960 }\r
255a3f33
RN
961\r
962 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {\r
72399dae 963 //\r
255a3f33 964 // Skip ';' characters in SupportedLang\r
72399dae 965 //\r
1436aea4
MK
966 for ( ; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++) {\r
967 }\r
968\r
255a3f33
RN
969 //\r
970 // Determine the length of the next language code in SupportedLang\r
971 //\r
1436aea4
MK
972 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++) {\r
973 }\r
fa0737a8
SZ
974\r
975 if ((CompareLength == LanguageLength) &&\r
1436aea4
MK
976 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0))\r
977 {\r
72399dae 978 //\r
979 // Successfully find the index of Lang string in SupportedLang string.\r
980 //\r
981 return Index;\r
982 }\r
72399dae 983 }\r
1436aea4 984\r
72399dae 985 ASSERT (FALSE);\r
986 return 0;\r
8d3a5c82 987 }\r
72399dae 988}\r
33a5a666 989\r
72399dae 990/**\r
991 Get language string from supported language codes according to index.\r
992\r
8a2d4996 993 This code is used to get corresponding language strings in supported language codes. It can handle\r
0254efc0 994 RFC4646 and ISO639 language tags.\r
72399dae 995 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
0254efc0 996 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
72399dae 997\r
998 For example:\r
999 SupportedLang = "engfraengfra"\r
1000 Index = "1"\r
1001 Iso639Language = TRUE\r
1002 The return value is "fra".\r
1003 Another example:\r
1004 SupportedLang = "en;fr;en-US;fr-FR"\r
1005 Index = "1"\r
1006 Iso639Language = FALSE\r
1007 The return value is "fr".\r
1008\r
1009 @param SupportedLang Platform supported language codes.\r
8a2d4996 1010 @param Index The index in supported language codes.\r
0254efc0 1011 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
72399dae 1012\r
8a2d4996 1013 @retval The language string in the language codes.\r
8d3a5c82 1014\r
72399dae 1015**/\r
1016CHAR8 *\r
72399dae 1017GetLangFromSupportedLangCodes (\r
1436aea4
MK
1018 IN CHAR8 *SupportedLang,\r
1019 IN UINTN Index,\r
1020 IN BOOLEAN Iso639Language\r
1021 )\r
72399dae 1022{\r
1436aea4
MK
1023 UINTN SubIndex;\r
1024 UINTN CompareLength;\r
1025 CHAR8 *Supported;\r
8d3a5c82 1026\r
72399dae 1027 SubIndex = 0;\r
1028 Supported = SupportedLang;\r
1029 if (Iso639Language) {\r
1030 //\r
8a2d4996 1031 // According to the index of Lang string in SupportedLang string to get the language.\r
1032 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.\r
72399dae 1033 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1034 //\r
1436aea4 1035 CompareLength = ISO_639_2_ENTRY_SIZE;\r
255a3f33 1036 mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
72399dae 1037 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
8d3a5c82 1038 } else {\r
72399dae 1039 while (TRUE) {\r
1040 //\r
8a2d4996 1041 // Take semicolon as delimitation, sequentially traverse supported language codes.\r
72399dae 1042 //\r
1043 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1044 Supported++;\r
1045 }\r
1436aea4 1046\r
72399dae 1047 if ((*Supported == '\0') && (SubIndex != Index)) {\r
1048 //\r
1049 // Have completed the traverse, but not find corrsponding string.\r
1050 // This case is not allowed to happen.\r
1051 //\r
1436aea4 1052 ASSERT (FALSE);\r
72399dae 1053 return NULL;\r
1054 }\r
1436aea4 1055\r
72399dae 1056 if (SubIndex == Index) {\r
1057 //\r
8a2d4996 1058 // According to the index of Lang string in SupportedLang string to get the language.\r
72399dae 1059 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1060 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1061 //\r
255a3f33 1062 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';\r
72399dae 1063 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
1064 }\r
1436aea4 1065\r
72399dae 1066 SubIndex++;\r
8a2d4996 1067\r
5c033766
RN
1068 //\r
1069 // Skip ';' characters in Supported\r
1070 //\r
1436aea4
MK
1071 for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {\r
1072 }\r
72399dae 1073 }\r
8d3a5c82 1074 }\r
8d3a5c82 1075}\r
1076\r
255a3f33 1077/**\r
fa0737a8
SZ
1078 Returns a pointer to an allocated buffer that contains the best matching language\r
1079 from a set of supported languages.\r
1080\r
1081 This function supports both ISO 639-2 and RFC 4646 language codes, but language\r
255a3f33
RN
1082 code types may not be mixed in a single call to this function. This function\r
1083 supports a variable argument list that allows the caller to pass in a prioritized\r
1084 list of language codes to test against all the language codes in SupportedLanguages.\r
1085\r
1086 If SupportedLanguages is NULL, then ASSERT().\r
1087\r
1088 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
fa0737a8 1089 contains a set of language codes in the format\r
255a3f33 1090 specified by Iso639Language.\r
051bf6e0
LG
1091 @param[in] Iso639Language If not zero, then all language codes are assumed to be\r
1092 in ISO 639-2 format. If zero, then all language\r
255a3f33 1093 codes are assumed to be in RFC 4646 language format\r
fa0737a8 1094 @param[in] ... A variable argument list that contains pointers to\r
255a3f33
RN
1095 Null-terminated ASCII strings that contain one or more\r
1096 language codes in the format specified by Iso639Language.\r
1097 The first language code from each of these language\r
1098 code lists is used to determine if it is an exact or\r
fa0737a8 1099 close match to any of the language codes in\r
255a3f33
RN
1100 SupportedLanguages. Close matches only apply to RFC 4646\r
1101 language codes, and the matching algorithm from RFC 4647\r
fa0737a8 1102 is used to determine if a close match is present. If\r
255a3f33
RN
1103 an exact or close match is found, then the matching\r
1104 language code from SupportedLanguages is returned. If\r
1105 no matches are found, then the next variable argument\r
fa0737a8 1106 parameter is evaluated. The variable argument list\r
255a3f33
RN
1107 is terminated by a NULL.\r
1108\r
1109 @retval NULL The best matching language could not be found in SupportedLanguages.\r
fa0737a8 1110 @retval NULL There are not enough resources available to return the best matching\r
255a3f33 1111 language.\r
fa0737a8 1112 @retval Other A pointer to a Null-terminated ASCII string that is the best matching\r
255a3f33
RN
1113 language in SupportedLanguages.\r
1114\r
1115**/\r
1116CHAR8 *\r
e1adae60 1117EFIAPI\r
255a3f33 1118VariableGetBestLanguage (\r
fa0737a8 1119 IN CONST CHAR8 *SupportedLanguages,\r
180ac200 1120 IN UINTN Iso639Language,\r
255a3f33
RN
1121 ...\r
1122 )\r
1123{\r
1124 VA_LIST Args;\r
1125 CHAR8 *Language;\r
1126 UINTN CompareLength;\r
1127 UINTN LanguageLength;\r
1128 CONST CHAR8 *Supported;\r
1129 CHAR8 *Buffer;\r
1130\r
fa0737a8
SZ
1131 if (SupportedLanguages == NULL) {\r
1132 return NULL;\r
1133 }\r
255a3f33
RN
1134\r
1135 VA_START (Args, Iso639Language);\r
1136 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
1137 //\r
1138 // Default to ISO 639-2 mode\r
1139 //\r
1140 CompareLength = 3;\r
1141 LanguageLength = MIN (3, AsciiStrLen (Language));\r
1142\r
1143 //\r
1144 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
1145 //\r
051bf6e0 1146 if (Iso639Language == 0) {\r
1436aea4
MK
1147 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++) {\r
1148 }\r
255a3f33
RN
1149 }\r
1150\r
1151 //\r
1152 // Trim back the length of Language used until it is empty\r
1153 //\r
1154 while (LanguageLength > 0) {\r
1155 //\r
1156 // Loop through all language codes in SupportedLanguages\r
1157 //\r
1158 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
1159 //\r
1160 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
1161 //\r
051bf6e0 1162 if (Iso639Language == 0) {\r
255a3f33
RN
1163 //\r
1164 // Skip ';' characters in Supported\r
1165 //\r
1436aea4
MK
1166 for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {\r
1167 }\r
1168\r
255a3f33
RN
1169 //\r
1170 // Determine the length of the next language code in Supported\r
1171 //\r
1436aea4
MK
1172 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++) {\r
1173 }\r
1174\r
255a3f33
RN
1175 //\r
1176 // If Language is longer than the Supported, then skip to the next language\r
1177 //\r
1178 if (LanguageLength > CompareLength) {\r
1179 continue;\r
1180 }\r
1181 }\r
1436aea4 1182\r
255a3f33
RN
1183 //\r
1184 // See if the first LanguageLength characters in Supported match Language\r
1185 //\r
1186 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
1187 VA_END (Args);\r
1188\r
1436aea4 1189 Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
255a3f33
RN
1190 Buffer[CompareLength] = '\0';\r
1191 return CopyMem (Buffer, Supported, CompareLength);\r
1192 }\r
1193 }\r
1194\r
051bf6e0 1195 if (Iso639Language != 0) {\r
255a3f33
RN
1196 //\r
1197 // If ISO 639 mode, then each language can only be tested once\r
1198 //\r
1199 LanguageLength = 0;\r
1200 } else {\r
1201 //\r
fa0737a8 1202 // If RFC 4646 mode, then trim Language from the right to the next '-' character\r
255a3f33 1203 //\r
1436aea4
MK
1204 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--) {\r
1205 }\r
255a3f33
RN
1206 }\r
1207 }\r
1208 }\r
1436aea4 1209\r
255a3f33
RN
1210 VA_END (Args);\r
1211\r
1212 //\r
fa0737a8 1213 // No matches were found\r
255a3f33
RN
1214 //\r
1215 return NULL;\r
1216}\r
1217\r
b2bd493e
SZ
1218/**\r
1219 This function is to check if the remaining variable space is enough to set\r
1220 all Variables from argument list successfully. The purpose of the check\r
1221 is to keep the consistency of the Variables to be in variable storage.\r
1222\r
1223 Note: Variables are assumed to be in same storage.\r
1224 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,\r
1225 so follow the argument sequence to check the Variables.\r
1226\r
1227 @param[in] Attributes Variable attributes for Variable entries.\r
fa0737a8
SZ
1228 @param[in] Marker VA_LIST style variable argument list.\r
1229 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.\r
1230 A NULL terminates the list. The VariableSize of\r
9a12e582
DG
1231 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.\r
1232 It will be changed to variable total size as output.\r
b2bd493e
SZ
1233\r
1234 @retval TRUE Have enough variable space to set the Variables successfully.\r
1235 @retval FALSE No enough variable space to set the Variables successfully.\r
1236\r
1237**/\r
1238BOOLEAN\r
1239EFIAPI\r
fa0737a8 1240CheckRemainingSpaceForConsistencyInternal (\r
1436aea4
MK
1241 IN UINT32 Attributes,\r
1242 IN VA_LIST Marker\r
b2bd493e
SZ
1243 )\r
1244{\r
1436aea4
MK
1245 EFI_STATUS Status;\r
1246 VA_LIST Args;\r
1247 VARIABLE_ENTRY_CONSISTENCY *VariableEntry;\r
1248 UINT64 MaximumVariableStorageSize;\r
1249 UINT64 RemainingVariableStorageSize;\r
1250 UINT64 MaximumVariableSize;\r
1251 UINTN TotalNeededSize;\r
1252 UINTN OriginalVarSize;\r
1253 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1254 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
1255 VARIABLE_HEADER *NextVariable;\r
1256 UINTN VarNameSize;\r
1257 UINTN VarDataSize;\r
b2bd493e
SZ
1258\r
1259 //\r
1260 // Non-Volatile related.\r
1261 //\r
1262 VariableStoreHeader = mNvVariableCache;\r
1263\r
1264 Status = VariableServiceQueryVariableInfoInternal (\r
1265 Attributes,\r
1266 &MaximumVariableStorageSize,\r
1267 &RemainingVariableStorageSize,\r
1268 &MaximumVariableSize\r
1269 );\r
1270 ASSERT_EFI_ERROR (Status);\r
1271\r
1272 TotalNeededSize = 0;\r
b7789dc6 1273 VA_COPY (Args, Marker);\r
b2bd493e
SZ
1274 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
1275 while (VariableEntry != NULL) {\r
9a12e582
DG
1276 //\r
1277 // Calculate variable total size.\r
1278 //\r
1436aea4
MK
1279 VarNameSize = StrSize (VariableEntry->Name);\r
1280 VarNameSize += GET_PAD_SIZE (VarNameSize);\r
1281 VarDataSize = VariableEntry->VariableSize;\r
1282 VarDataSize += GET_PAD_SIZE (VarDataSize);\r
04401023
MK
1283 VariableEntry->VariableSize = HEADER_ALIGN (\r
1284 GetVariableHeaderSize (\r
1285 mVariableModuleGlobal->VariableGlobal.AuthFormat\r
1286 ) + VarNameSize + VarDataSize\r
1287 );\r
9a12e582 1288\r
b2bd493e 1289 TotalNeededSize += VariableEntry->VariableSize;\r
1436aea4 1290 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
b2bd493e 1291 }\r
1436aea4
MK
1292\r
1293 VA_END (Args);\r
b2bd493e
SZ
1294\r
1295 if (RemainingVariableStorageSize >= TotalNeededSize) {\r
1296 //\r
1297 // Already have enough space.\r
1298 //\r
1299 return TRUE;\r
1300 } else if (AtRuntime ()) {\r
1301 //\r
1302 // At runtime, no reclaim.\r
1303 // The original variable space of Variables can't be reused.\r
1304 //\r
1305 return FALSE;\r
1306 }\r
1307\r
b7789dc6 1308 VA_COPY (Args, Marker);\r
b2bd493e
SZ
1309 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
1310 while (VariableEntry != NULL) {\r
1311 //\r
1312 // Check if Variable[Index] has been present and get its size.\r
1313 //\r
1436aea4 1314 OriginalVarSize = 0;\r
b2bd493e 1315 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
1436aea4
MK
1316 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);\r
1317 Status = FindVariableEx (\r
1318 VariableEntry->Name,\r
1319 VariableEntry->Guid,\r
1320 FALSE,\r
1321 &VariablePtrTrack,\r
1322 mVariableModuleGlobal->VariableGlobal.AuthFormat\r
1323 );\r
b2bd493e
SZ
1324 if (!EFI_ERROR (Status)) {\r
1325 //\r
1326 // Get size of Variable[Index].\r
1327 //\r
1436aea4
MK
1328 NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1329 OriginalVarSize = (UINTN)NextVariable - (UINTN)VariablePtrTrack.CurrPtr;\r
b2bd493e
SZ
1330 //\r
1331 // Add the original size of Variable[Index] to remaining variable storage size.\r
1332 //\r
1333 RemainingVariableStorageSize += OriginalVarSize;\r
1334 }\r
1436aea4 1335\r
b2bd493e
SZ
1336 if (VariableEntry->VariableSize > RemainingVariableStorageSize) {\r
1337 //\r
1338 // No enough space for Variable[Index].\r
1339 //\r
a0460be7 1340 VA_END (Args);\r
b2bd493e
SZ
1341 return FALSE;\r
1342 }\r
1436aea4 1343\r
b2bd493e
SZ
1344 //\r
1345 // Sub the (new) size of Variable[Index] from remaining variable storage size.\r
1346 //\r
1347 RemainingVariableStorageSize -= VariableEntry->VariableSize;\r
1436aea4 1348 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
b2bd493e 1349 }\r
1436aea4
MK
1350\r
1351 VA_END (Args);\r
b2bd493e
SZ
1352\r
1353 return TRUE;\r
1354}\r
1355\r
fa0737a8
SZ
1356/**\r
1357 This function is to check if the remaining variable space is enough to set\r
1358 all Variables from argument list successfully. The purpose of the check\r
1359 is to keep the consistency of the Variables to be in variable storage.\r
1360\r
1361 Note: Variables are assumed to be in same storage.\r
1362 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,\r
1363 so follow the argument sequence to check the Variables.\r
1364\r
1365 @param[in] Attributes Variable attributes for Variable entries.\r
1366 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.\r
1367 A NULL terminates the list. The VariableSize of\r
1368 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.\r
1369 It will be changed to variable total size as output.\r
1370\r
1371 @retval TRUE Have enough variable space to set the Variables successfully.\r
1372 @retval FALSE No enough variable space to set the Variables successfully.\r
1373\r
1374**/\r
1375BOOLEAN\r
1376EFIAPI\r
1377CheckRemainingSpaceForConsistency (\r
1436aea4 1378 IN UINT32 Attributes,\r
fa0737a8
SZ
1379 ...\r
1380 )\r
1381{\r
1436aea4
MK
1382 VA_LIST Marker;\r
1383 BOOLEAN Return;\r
fa0737a8
SZ
1384\r
1385 VA_START (Marker, Attributes);\r
1386\r
1387 Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);\r
1388\r
1389 VA_END (Marker);\r
1390\r
1391 return Return;\r
1392}\r
1393\r
72399dae 1394/**\r
1395 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
052ad7e1 1396\r
72399dae 1397 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
052ad7e1 1398\r
72399dae 1399 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
1400 and are read-only. Therefore, in variable driver, only store the original value for other use.\r
8d3a5c82 1401\r
8a2d4996 1402 @param[in] VariableName Name of variable.\r
8d3a5c82 1403\r
8a2d4996 1404 @param[in] Data Variable data.\r
8d3a5c82 1405\r
8a2d4996 1406 @param[in] DataSize Size of data. 0 means delete.\r
72399dae 1407\r
9bc5dabb
SZ
1408 @retval EFI_SUCCESS The update operation is successful or ignored.\r
1409 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.\r
1410 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.\r
1411 @retval Others Other errors happened during the update operation.\r
1412\r
7c80e839 1413**/\r
9bc5dabb 1414EFI_STATUS\r
d6550260 1415AutoUpdateLangVariable (\r
1436aea4
MK
1416 IN CHAR16 *VariableName,\r
1417 IN VOID *Data,\r
1418 IN UINTN DataSize\r
052ad7e1 1419 )\r
8d3a5c82 1420{\r
1436aea4
MK
1421 EFI_STATUS Status;\r
1422 CHAR8 *BestPlatformLang;\r
1423 CHAR8 *BestLang;\r
1424 UINTN Index;\r
1425 UINT32 Attributes;\r
1426 VARIABLE_POINTER_TRACK Variable;\r
1427 BOOLEAN SetLanguageCodes;\r
1428 VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];\r
8d3a5c82 1429\r
72399dae 1430 //\r
255a3f33 1431 // Don't do updates for delete operation\r
72399dae 1432 //\r
255a3f33 1433 if (DataSize == 0) {\r
9bc5dabb 1434 return EFI_SUCCESS;\r
255a3f33
RN
1435 }\r
1436\r
1437 SetLanguageCodes = FALSE;\r
8d3a5c82 1438\r
6675a21f 1439 if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {\r
255a3f33
RN
1440 //\r
1441 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
1442 //\r
8a2d4996 1443 if (AtRuntime ()) {\r
9bc5dabb 1444 return EFI_WRITE_PROTECTED;\r
255a3f33
RN
1445 }\r
1446\r
1447 SetLanguageCodes = TRUE;\r
1448\r
72399dae 1449 //\r
1450 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
1451 // Therefore, in variable driver, only store the original value for other use.\r
1452 //\r
255a3f33
RN
1453 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {\r
1454 FreePool (mVariableModuleGlobal->PlatformLangCodes);\r
1455 }\r
1436aea4 1456\r
255a3f33
RN
1457 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1458 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);\r
1459\r
72399dae 1460 //\r
fa0737a8 1461 // PlatformLang holds a single language from PlatformLangCodes,\r
255a3f33 1462 // so the size of PlatformLangCodes is enough for the PlatformLang.\r
72399dae 1463 //\r
255a3f33
RN
1464 if (mVariableModuleGlobal->PlatformLang != NULL) {\r
1465 FreePool (mVariableModuleGlobal->PlatformLang);\r
1466 }\r
1436aea4 1467\r
255a3f33
RN
1468 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
1469 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
6675a21f 1470 } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {\r
72399dae 1471 //\r
255a3f33 1472 // LangCodes is a volatile variable, so it can not be updated at runtime.\r
72399dae 1473 //\r
8a2d4996 1474 if (AtRuntime ()) {\r
9bc5dabb 1475 return EFI_WRITE_PROTECTED;\r
255a3f33
RN
1476 }\r
1477\r
1478 SetLanguageCodes = TRUE;\r
8d3a5c82 1479\r
8d3a5c82 1480 //\r
255a3f33
RN
1481 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
1482 // Therefore, in variable driver, only store the original value for other use.\r
8d3a5c82 1483 //\r
255a3f33
RN
1484 if (mVariableModuleGlobal->LangCodes != NULL) {\r
1485 FreePool (mVariableModuleGlobal->LangCodes);\r
1486 }\r
1436aea4 1487\r
255a3f33
RN
1488 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1489 ASSERT (mVariableModuleGlobal->LangCodes != NULL);\r
1490 }\r
8d3a5c82 1491\r
1436aea4
MK
1492 if ( SetLanguageCodes\r
1493 && (mVariableModuleGlobal->PlatformLangCodes != NULL)\r
1494 && (mVariableModuleGlobal->LangCodes != NULL))\r
1495 {\r
8d3a5c82 1496 //\r
255a3f33
RN
1497 // Update Lang if PlatformLang is already set\r
1498 // Update PlatformLang if Lang is already set\r
8d3a5c82 1499 //\r
6675a21f 1500 Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
255a3f33
RN
1501 if (!EFI_ERROR (Status)) {\r
1502 //\r
1503 // Update Lang\r
1504 //\r
6675a21f 1505 VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
04401023
MK
1506 Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1507 DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
255a3f33 1508 } else {\r
6675a21f 1509 Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
255a3f33
RN
1510 if (!EFI_ERROR (Status)) {\r
1511 //\r
1512 // Update PlatformLang\r
1513 //\r
6675a21f 1514 VariableName = EFI_LANG_VARIABLE_NAME;\r
04401023
MK
1515 Data = GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1516 DataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
255a3f33
RN
1517 } else {\r
1518 //\r
1519 // Neither PlatformLang nor Lang is set, directly return\r
1520 //\r
9bc5dabb 1521 return EFI_SUCCESS;\r
255a3f33
RN
1522 }\r
1523 }\r
1524 }\r
9bc5dabb
SZ
1525\r
1526 Status = EFI_SUCCESS;\r
1527\r
255a3f33
RN
1528 //\r
1529 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
1530 //\r
1531 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
8d3a5c82 1532\r
6675a21f 1533 if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {\r
8d3a5c82 1534 //\r
255a3f33 1535 // Update Lang when PlatformLangCodes/LangCodes were set.\r
8d3a5c82 1536 //\r
255a3f33
RN
1537 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1538 //\r
1539 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1540 //\r
1541 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
1542 if (BestPlatformLang != NULL) {\r
1543 //\r
1544 // Get the corresponding index in language codes.\r
1545 //\r
1546 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
fdb7765f 1547\r
255a3f33
RN
1548 //\r
1549 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
1550 //\r
1551 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
8d3a5c82 1552\r
255a3f33 1553 //\r
9a12e582 1554 // Check the variable space for both Lang and PlatformLang variable.\r
b2bd493e 1555 //\r
9a12e582 1556 VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
1436aea4
MK
1557 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
1558 VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;\r
fa0737a8 1559\r
9a12e582 1560 VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);\r
1436aea4
MK
1561 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
1562 VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
b2bd493e
SZ
1563 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
1564 //\r
1565 // No enough variable space to set both Lang and PlatformLang successfully.\r
1566 //\r
1567 Status = EFI_OUT_OF_RESOURCES;\r
1568 } else {\r
1569 //\r
1570 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
1571 //\r
1572 FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
8d3a5c82 1573\r
1436aea4
MK
1574 Status = UpdateVariable (\r
1575 EFI_LANG_VARIABLE_NAME,\r
1576 &gEfiGlobalVariableGuid,\r
1577 BestLang,\r
1578 ISO_639_2_ENTRY_SIZE + 1,\r
1579 Attributes,\r
1580 0,\r
1581 0,\r
1582 &Variable,\r
1583 NULL\r
1584 );\r
b2bd493e 1585 }\r
8d3a5c82 1586\r
87000d77 1587 DEBUG ((DEBUG_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));\r
255a3f33
RN
1588 }\r
1589 }\r
6675a21f 1590 } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {\r
72399dae 1591 //\r
255a3f33 1592 // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
72399dae 1593 //\r
255a3f33
RN
1594 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1595 //\r
1596 // When setting Lang, firstly get most matched language string from supported language codes.\r
1597 //\r
1598 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
1599 if (BestLang != NULL) {\r
1600 //\r
1601 // Get the corresponding index in language codes.\r
1602 //\r
1603 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
72399dae 1604\r
255a3f33
RN
1605 //\r
1606 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
1607 //\r
1608 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
1609\r
1610 //\r
9a12e582 1611 // Check the variable space for both PlatformLang and Lang variable.\r
b2bd493e 1612 //\r
9a12e582 1613 VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);\r
1436aea4
MK
1614 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
1615 VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
9a12e582
DG
1616\r
1617 VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
1436aea4
MK
1618 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
1619 VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;\r
b2bd493e
SZ
1620 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
1621 //\r
1622 // No enough variable space to set both PlatformLang and Lang successfully.\r
1623 //\r
1624 Status = EFI_OUT_OF_RESOURCES;\r
1625 } else {\r
1626 //\r
1627 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
1628 //\r
1629 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
72399dae 1630\r
1436aea4
MK
1631 Status = UpdateVariable (\r
1632 EFI_PLATFORM_LANG_VARIABLE_NAME,\r
1633 &gEfiGlobalVariableGuid,\r
1634 BestPlatformLang,\r
1635 AsciiStrSize (BestPlatformLang),\r
1636 Attributes,\r
1637 0,\r
1638 0,\r
1639 &Variable,\r
1640 NULL\r
1641 );\r
b2bd493e 1642 }\r
72399dae 1643\r
87000d77 1644 DEBUG ((DEBUG_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));\r
255a3f33
RN
1645 }\r
1646 }\r
72399dae 1647 }\r
9bc5dabb 1648\r
b2bd493e
SZ
1649 if (SetLanguageCodes) {\r
1650 //\r
1651 // Continue to set PlatformLangCodes or LangCodes.\r
1652 //\r
1653 return EFI_SUCCESS;\r
1654 } else {\r
1655 return Status;\r
1656 }\r
8d3a5c82 1657}\r
1658\r
fa0737a8
SZ
1659/**\r
1660 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,\r
1661 index of associated public key is needed.\r
052ad7e1 1662\r
8a2d4996 1663 @param[in] VariableName Name of variable.\r
1664 @param[in] VendorGuid Guid of variable.\r
1665 @param[in] Data Variable data.\r
1666 @param[in] DataSize Size of data. 0 means delete.\r
fa0737a8
SZ
1667 @param[in] Attributes Attributes of the variable.\r
1668 @param[in] KeyIndex Index of associated public key.\r
1669 @param[in] MonotonicCount Value of associated monotonic count.\r
23b06935 1670 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.\r
fa0737a8
SZ
1671 @param[in] TimeStamp Value of associated TimeStamp.\r
1672\r
72399dae 1673 @retval EFI_SUCCESS The update operation is success.\r
72399dae 1674 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
8d3a5c82 1675\r
7c80e839 1676**/\r
052ad7e1 1677EFI_STATUS\r
72399dae 1678UpdateVariable (\r
1436aea4
MK
1679 IN CHAR16 *VariableName,\r
1680 IN EFI_GUID *VendorGuid,\r
1681 IN VOID *Data,\r
1682 IN UINTN DataSize,\r
1683 IN UINT32 Attributes OPTIONAL,\r
1684 IN UINT32 KeyIndex OPTIONAL,\r
1685 IN UINT64 MonotonicCount OPTIONAL,\r
1686 IN OUT VARIABLE_POINTER_TRACK *CacheVariable,\r
1687 IN EFI_TIME *TimeStamp OPTIONAL\r
052ad7e1 1688 )\r
8d3a5c82 1689{\r
8a9e0b72 1690 EFI_STATUS Status;\r
1691 VARIABLE_HEADER *NextVariable;\r
72399dae 1692 UINTN ScratchSize;\r
fa0737a8 1693 UINTN MaxDataSize;\r
8a9e0b72 1694 UINTN VarNameOffset;\r
1695 UINTN VarDataOffset;\r
72399dae 1696 UINTN VarNameSize;\r
8a9e0b72 1697 UINTN VarSize;\r
72399dae 1698 BOOLEAN Volatile;\r
1699 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
8a9e0b72 1700 UINT8 State;\r
8a2d4996 1701 VARIABLE_POINTER_TRACK *Variable;\r
1702 VARIABLE_POINTER_TRACK NvVariable;\r
1703 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
aab3b9b9 1704 VARIABLE_RUNTIME_CACHE *VolatileCacheInstance;\r
fa0737a8
SZ
1705 UINT8 *BufferForMerge;\r
1706 UINTN MergedBufSize;\r
1707 BOOLEAN DataReady;\r
1708 UINTN DataOffset;\r
4edb1866
SZ
1709 BOOLEAN IsCommonVariable;\r
1710 BOOLEAN IsCommonUserVariable;\r
fa0737a8 1711 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;\r
04401023 1712 BOOLEAN AuthFormat;\r
fdb7765f 1713\r
1436aea4 1714 if ((mVariableModuleGlobal->FvbInstance == NULL) && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
5456306f 1715 //\r
fa0737a8 1716 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.\r
5456306f 1717 //\r
fa0737a8
SZ
1718 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
1719 //\r
1720 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
1721 //\r
87000d77 1722 DEBUG ((DEBUG_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));\r
fa0737a8
SZ
1723 return EFI_NOT_AVAILABLE_YET;\r
1724 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
1725 //\r
1726 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
1727 // The authenticated variable perhaps is not initialized, just return here.\r
1728 //\r
87000d77 1729 DEBUG ((DEBUG_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));\r
fa0737a8
SZ
1730 return EFI_NOT_AVAILABLE_YET;\r
1731 }\r
5456306f 1732 }\r
1733\r
04401023
MK
1734 AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
1735\r
31349131
SZ
1736 //\r
1737 // Check if CacheVariable points to the variable in variable HOB.\r
1738 // If yes, let CacheVariable points to the variable in NV variable cache.\r
1739 //\r
1740 if ((CacheVariable->CurrPtr != NULL) &&\r
1741 (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&\r
1436aea4
MK
1742 (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase))\r
1743 )\r
1744 {\r
31349131 1745 CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);\r
1436aea4 1746 CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);\r
31349131 1747 CacheVariable->Volatile = FALSE;\r
1436aea4
MK
1748 Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable, AuthFormat);\r
1749 if ((CacheVariable->CurrPtr == NULL) || EFI_ERROR (Status)) {\r
31349131
SZ
1750 //\r
1751 // There is no matched variable in NV variable cache.\r
1752 //\r
1753 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {\r
1754 //\r
1755 // It is to delete variable,\r
1756 // go to delete this variable in variable HOB and\r
1757 // try to flush other variables from HOB to flash.\r
1758 //\r
8d53adbe 1759 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);\r
31349131
SZ
1760 FlushHobVariableToFlash (VariableName, VendorGuid);\r
1761 return EFI_SUCCESS;\r
1762 }\r
1763 }\r
1764 }\r
1765\r
5456306f 1766 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
8a2d4996 1767 Variable = CacheVariable;\r
1768 } else {\r
8a2d4996 1769 //\r
5456306f 1770 // Update/Delete existing NV variable.\r
8a2d4996 1771 // CacheVariable points to the variable in the memory copy of Flash area\r
1772 // Now let Variable points to the same variable in Flash area.\r
1773 //\r
1436aea4
MK
1774 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1775 Variable = &NvVariable;\r
1776 Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
1777 Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));\r
9b18845a 1778\r
1436aea4 1779 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
23b06935
SZ
1780 if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
1781 Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
1782 } else {\r
1783 Variable->InDeletedTransitionPtr = NULL;\r
1784 }\r
1436aea4 1785\r
5456306f 1786 Variable->Volatile = FALSE;\r
fa0737a8 1787 }\r
5456306f 1788\r
1436aea4 1789 Fvb = mVariableModuleGlobal->FvbInstance;\r
fdb7765f 1790\r
fa0737a8
SZ
1791 //\r
1792 // Tricky part: Use scratch data area at the end of volatile variable store\r
1793 // as a temporary storage.\r
1794 //\r
1436aea4
MK
1795 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
1796 ScratchSize = mVariableModuleGlobal->ScratchBufferSize;\r
fa0737a8
SZ
1797 SetMem (NextVariable, ScratchSize, 0xff);\r
1798 DataReady = FALSE;\r
1799\r
72399dae 1800 if (Variable->CurrPtr != NULL) {\r
8d3a5c82 1801 //\r
8a2d4996 1802 // Update/Delete existing variable.\r
8d3a5c82 1803 //\r
fa0737a8 1804 if (AtRuntime ()) {\r
c6492839 1805 //\r
fa0737a8
SZ
1806 // If AtRuntime and the variable is Volatile and Runtime Access,\r
1807 // the volatile is ReadOnly, and SetVariable should be aborted and\r
c6492839 1808 // return EFI_WRITE_PROTECTED.\r
1809 //\r
72399dae 1810 if (Variable->Volatile) {\r
c6492839 1811 Status = EFI_WRITE_PROTECTED;\r
1812 goto Done;\r
1813 }\r
1436aea4 1814\r
c6492839 1815 //\r
fa0737a8
SZ
1816 // Only variable that have NV attributes can be updated/deleted in Runtime.\r
1817 //\r
9b18845a 1818 if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
fa0737a8
SZ
1819 Status = EFI_INVALID_PARAMETER;\r
1820 goto Done;\r
1821 }\r
1822\r
1823 //\r
1824 // Only variable that have RT attributes can be updated/deleted in Runtime.\r
c6492839 1825 //\r
9b18845a 1826 if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
c6492839 1827 Status = EFI_INVALID_PARAMETER;\r
fa0737a8 1828 goto Done;\r
c6492839 1829 }\r
1830 }\r
8a2d4996 1831\r
8d3a5c82 1832 //\r
c6492839 1833 // Setting a data variable with no access, or zero DataSize attributes\r
8a2d4996 1834 // causes it to be deleted.\r
fa0737a8
SZ
1835 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will\r
1836 // not delete the variable.\r
8d3a5c82 1837 //\r
1436aea4 1838 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {\r
23b06935
SZ
1839 if (Variable->InDeletedTransitionPtr != NULL) {\r
1840 //\r
1841 // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
1842 // set IN_DELETED_TRANSITION one to DELETED state first.\r
1843 //\r
ae658d91 1844 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
1436aea4 1845 State = CacheVariable->InDeletedTransitionPtr->State;\r
23b06935
SZ
1846 State &= VAR_DELETED;\r
1847 Status = UpdateVariableStore (\r
1848 &mVariableModuleGlobal->VariableGlobal,\r
1849 Variable->Volatile,\r
1850 FALSE,\r
1851 Fvb,\r
1436aea4 1852 (UINTN)&Variable->InDeletedTransitionPtr->State,\r
23b06935
SZ
1853 sizeof (UINT8),\r
1854 &State\r
1855 );\r
1856 if (!EFI_ERROR (Status)) {\r
1857 if (!Variable->Volatile) {\r
1858 CacheVariable->InDeletedTransitionPtr->State = State;\r
1859 }\r
1860 } else {\r
1861 goto Done;\r
1862 }\r
1863 }\r
1864\r
1436aea4 1865 State = CacheVariable->CurrPtr->State;\r
c6492839 1866 State &= VAR_DELETED;\r
1867\r
1868 Status = UpdateVariableStore (\r
052ad7e1 1869 &mVariableModuleGlobal->VariableGlobal,\r
72399dae 1870 Variable->Volatile,\r
c6492839 1871 FALSE,\r
8a9e0b72 1872 Fvb,\r
1436aea4 1873 (UINTN)&Variable->CurrPtr->State,\r
c6492839 1874 sizeof (UINT8),\r
1875 &State\r
fa0737a8 1876 );\r
33a5a666 1877 if (!EFI_ERROR (Status)) {\r
8d53adbe 1878 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE, &gVariableInfo);\r
8a2d4996 1879 if (!Variable->Volatile) {\r
1880 CacheVariable->CurrPtr->State = State;\r
335e2681 1881 FlushHobVariableToFlash (VariableName, VendorGuid);\r
8a2d4996 1882 }\r
33a5a666 1883 }\r
1436aea4 1884\r
fa0737a8 1885 goto Done;\r
c6492839 1886 }\r
1436aea4 1887\r
8d3a5c82 1888 //\r
8a2d4996 1889 // If the variable is marked valid, and the same data has been passed in,\r
c6492839 1890 // then return to the caller immediately.\r
8d3a5c82 1891 //\r
1436aea4 1892 if ((DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) == DataSize) &&\r
04401023 1893 (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr, AuthFormat), DataSize) == 0) &&\r
fa0737a8 1894 ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&\r
1436aea4
MK
1895 (TimeStamp == NULL))\r
1896 {\r
fa0737a8
SZ
1897 //\r
1898 // Variable content unchanged and no need to update timestamp, just return.\r
1899 //\r
8d53adbe 1900 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);\r
c6492839 1901 Status = EFI_SUCCESS;\r
1902 goto Done;\r
9b18845a 1903 } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||\r
1436aea4
MK
1904 (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))\r
1905 {\r
fa0737a8
SZ
1906 //\r
1907 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.\r
1908 //\r
1909 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {\r
1910 //\r
1911 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.\r
1912 // From DataOffset of NextVariable is to save the existing variable data.\r
1913 //\r
1436aea4
MK
1914 DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr, AuthFormat);\r
1915 BufferForMerge = (UINT8 *)((UINTN)NextVariable + DataOffset);\r
04401023
MK
1916 CopyMem (\r
1917 BufferForMerge,\r
1436aea4 1918 (UINT8 *)((UINTN)CacheVariable->CurrPtr + DataOffset),\r
04401023
MK
1919 DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)\r
1920 );\r
fa0737a8
SZ
1921\r
1922 //\r
9b4a2032 1923 // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.\r
fa0737a8
SZ
1924 //\r
1925 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
1926 MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;\r
9b4a2032 1927 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
fa0737a8 1928 MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;\r
9b4a2032
LE
1929 } else {\r
1930 MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;\r
fa0737a8
SZ
1931 }\r
1932\r
1933 //\r
1934 // Append the new data to the end of existing data.\r
1935 // Max Harware error record variable data size is different from common/auth variable.\r
1936 //\r
1937 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1938 MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;\r
1939 }\r
1940\r
04401023 1941 if (DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) + DataSize > MaxDataSize) {\r
fa0737a8
SZ
1942 //\r
1943 // Existing data size + new data size exceed maximum variable size limitation.\r
1944 //\r
1945 Status = EFI_INVALID_PARAMETER;\r
1946 goto Done;\r
1947 }\r
1436aea4 1948\r
04401023 1949 CopyMem (\r
1436aea4
MK
1950 (UINT8 *)(\r
1951 (UINTN)BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat)\r
1952 ),\r
04401023
MK
1953 Data,\r
1954 DataSize\r
1955 );\r
1956 MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr, AuthFormat) +\r
1436aea4 1957 DataSize;\r
fa0737a8
SZ
1958\r
1959 //\r
1960 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.\r
1961 //\r
1962 Data = BufferForMerge;\r
1963 DataSize = MergedBufSize;\r
1964 DataReady = TRUE;\r
1965 }\r
1966\r
c6492839 1967 //\r
8a2d4996 1968 // Mark the old variable as in delete transition.\r
c6492839 1969 //\r
1436aea4 1970 State = CacheVariable->CurrPtr->State;\r
c6492839 1971 State &= VAR_IN_DELETED_TRANSITION;\r
1972\r
1973 Status = UpdateVariableStore (\r
052ad7e1 1974 &mVariableModuleGlobal->VariableGlobal,\r
72399dae 1975 Variable->Volatile,\r
c6492839 1976 FALSE,\r
8a9e0b72 1977 Fvb,\r
1436aea4 1978 (UINTN)&Variable->CurrPtr->State,\r
c6492839 1979 sizeof (UINT8),\r
1980 &State\r
fa0737a8 1981 );\r
c6492839 1982 if (EFI_ERROR (Status)) {\r
fa0737a8
SZ
1983 goto Done;\r
1984 }\r
1436aea4 1985\r
8a2d4996 1986 if (!Variable->Volatile) {\r
1987 CacheVariable->CurrPtr->State = State;\r
1988 }\r
fa0737a8 1989 }\r
72399dae 1990 } else {\r
8d3a5c82 1991 //\r
8a2d4996 1992 // Not found existing variable. Create a new variable.\r
fa0737a8
SZ
1993 //\r
1994\r
1995 if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {\r
1996 Status = EFI_SUCCESS;\r
1997 goto Done;\r
1998 }\r
1999\r
8d3a5c82 2000 //\r
c6492839 2001 // Make sure we are trying to create a new variable.\r
fa0737a8 2002 // Setting a data variable with zero DataSize or no access attributes means to delete it.\r
8d3a5c82 2003 //\r
1436aea4 2004 if ((DataSize == 0) || ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {\r
c6492839 2005 Status = EFI_NOT_FOUND;\r
2006 goto Done;\r
2007 }\r
fa0737a8 2008\r
8d3a5c82 2009 //\r
8a2d4996 2010 // Only variable have NV|RT attribute can be created in Runtime.\r
c6492839 2011 //\r
8a2d4996 2012 if (AtRuntime () &&\r
1436aea4
MK
2013 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)))\r
2014 {\r
c6492839 2015 Status = EFI_INVALID_PARAMETER;\r
2016 goto Done;\r
fa0737a8 2017 }\r
c6492839 2018 }\r
2019\r
2020 //\r
2021 // Function part - create a new variable and copy the data.\r
2022 // Both update a variable and create a variable will come here.\r
c6492839 2023 //\r
1436aea4 2024 NextVariable->StartId = VARIABLE_DATA;\r
c6492839 2025 //\r
2026 // NextVariable->State = VAR_ADDED;\r
2027 //\r
1436aea4 2028 NextVariable->Reserved = 0;\r
fa0737a8 2029 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {\r
1436aea4 2030 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)NextVariable;\r
fa0737a8
SZ
2031 AuthVariable->PubKeyIndex = KeyIndex;\r
2032 AuthVariable->MonotonicCount = MonotonicCount;\r
2033 ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));\r
2034\r
2035 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r
1436aea4
MK
2036 (TimeStamp != NULL))\r
2037 {\r
fa0737a8
SZ
2038 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {\r
2039 CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
2040 } else {\r
2041 //\r
2042 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only\r
2043 // when the new TimeStamp value is later than the current timestamp associated\r
2044 // with the variable, we need associate the new timestamp with the updated value.\r
2045 //\r
2046 if (Variable->CurrPtr != NULL) {\r
1436aea4 2047 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {\r
fa0737a8 2048 CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
b7dc8888 2049 } else {\r
1436aea4 2050 CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *)CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));\r
fa0737a8
SZ
2051 }\r
2052 }\r
2053 }\r
2054 }\r
2055 }\r
2056\r
2057 //\r
2058 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned\r
2059 // Attributes bitmask parameter of a GetVariable() call.\r
2060 //\r
1436aea4 2061 NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);\r
fa0737a8 2062\r
1436aea4
MK
2063 VarNameOffset = GetVariableHeaderSize (AuthFormat);\r
2064 VarNameSize = StrSize (VariableName);\r
c6492839 2065 CopyMem (\r
1436aea4 2066 (UINT8 *)((UINTN)NextVariable + VarNameOffset),\r
c6492839 2067 VariableName,\r
2068 VarNameSize\r
2069 );\r
2070 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
fa0737a8
SZ
2071\r
2072 //\r
2073 // If DataReady is TRUE, it means the variable data has been saved into\r
2074 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.\r
2075 //\r
2076 if (!DataReady) {\r
2077 CopyMem (\r
1436aea4 2078 (UINT8 *)((UINTN)NextVariable + VarDataOffset),\r
fa0737a8
SZ
2079 Data,\r
2080 DataSize\r
2081 );\r
2082 }\r
2083\r
04401023
MK
2084 CopyMem (\r
2085 GetVendorGuidPtr (NextVariable, AuthFormat),\r
2086 VendorGuid,\r
2087 sizeof (EFI_GUID)\r
2088 );\r
c6492839 2089 //\r
2090 // There will be pad bytes after Data, the NextVariable->NameSize and\r
2091 // NextVariable->DataSize should not include pad size so that variable\r
8a2d4996 2092 // service can get actual size in GetVariable.\r
c6492839 2093 //\r
04401023
MK
2094 SetNameSizeOfVariable (NextVariable, VarNameSize, AuthFormat);\r
2095 SetDataSizeOfVariable (NextVariable, DataSize, AuthFormat);\r
c6492839 2096\r
2097 //\r
2098 // The actual size of the variable that stores in storage should\r
2099 // include pad size.\r
2100 //\r
2101 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
45f6c85b 2102 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
8d3a5c82 2103 //\r
8a2d4996 2104 // Create a nonvolatile variable.\r
8d3a5c82 2105 //\r
fd51bf70 2106 Volatile = FALSE;\r
4edb1866 2107\r
1436aea4 2108 IsCommonVariable = FALSE;\r
4edb1866
SZ
2109 IsCommonUserVariable = FALSE;\r
2110 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {\r
1436aea4 2111 IsCommonVariable = TRUE;\r
4edb1866
SZ
2112 IsCommonUserVariable = IsUserVariable (NextVariable);\r
2113 }\r
1436aea4
MK
2114\r
2115 if ( ( ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)\r
2116 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
2117 || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))\r
2118 || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))\r
2119 || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)))\r
2120 {\r
8a2d4996 2121 if (AtRuntime ()) {\r
4edb1866
SZ
2122 if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
2123 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2124 }\r
1436aea4 2125\r
4edb1866
SZ
2126 if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {\r
2127 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2128 }\r
1436aea4 2129\r
c6492839 2130 Status = EFI_OUT_OF_RESOURCES;\r
2131 goto Done;\r
2132 }\r
1436aea4 2133\r
c6492839 2134 //\r
7baf3c69 2135 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
c6492839 2136 //\r
fa0737a8
SZ
2137 Status = Reclaim (\r
2138 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2139 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2140 FALSE,\r
2141 Variable,\r
2142 NextVariable,\r
2143 HEADER_ALIGN (VarSize)\r
2144 );\r
7baf3c69
SZ
2145 if (!EFI_ERROR (Status)) {\r
2146 //\r
2147 // The new variable has been integrated successfully during reclaiming.\r
2148 //\r
2149 if (Variable->CurrPtr != NULL) {\r
1436aea4 2150 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));\r
7baf3c69
SZ
2151 CacheVariable->InDeletedTransitionPtr = NULL;\r
2152 }\r
1436aea4 2153\r
8d53adbe 2154 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);\r
7baf3c69 2155 FlushHobVariableToFlash (VariableName, VendorGuid);\r
4edb1866
SZ
2156 } else {\r
2157 if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
2158 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2159 }\r
1436aea4 2160\r
4edb1866
SZ
2161 if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {\r
2162 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2163 }\r
23b06935 2164 }\r
1436aea4 2165\r
7baf3c69 2166 goto Done;\r
8d3a5c82 2167 }\r
c6492839 2168\r
7cd69959
SZ
2169 if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
2170 //\r
2171 // Four steps\r
2172 // 1. Write variable header\r
2173 // 2. Set variable state to header valid\r
2174 // 3. Write variable data\r
2175 // 4. Set variable state to valid\r
2176 //\r
2177 //\r
2178 // Step 1:\r
2179 //\r
2180 Status = UpdateVariableStore (\r
2181 &mVariableModuleGlobal->VariableGlobal,\r
2182 FALSE,\r
2183 TRUE,\r
2184 Fvb,\r
2185 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1436aea4
MK
2186 (UINT32)GetVariableHeaderSize (AuthFormat),\r
2187 (UINT8 *)NextVariable\r
7cd69959 2188 );\r
130e2569 2189\r
7cd69959
SZ
2190 if (EFI_ERROR (Status)) {\r
2191 goto Done;\r
2192 }\r
130e2569 2193\r
7cd69959
SZ
2194 //\r
2195 // Step 2:\r
2196 //\r
2197 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1436aea4
MK
2198 Status = UpdateVariableStore (\r
2199 &mVariableModuleGlobal->VariableGlobal,\r
2200 FALSE,\r
2201 TRUE,\r
2202 Fvb,\r
2203 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
2204 sizeof (UINT8),\r
2205 &NextVariable->State\r
2206 );\r
c6492839 2207\r
7cd69959
SZ
2208 if (EFI_ERROR (Status)) {\r
2209 goto Done;\r
2210 }\r
1436aea4 2211\r
7cd69959
SZ
2212 //\r
2213 // Step 3:\r
2214 //\r
2215 Status = UpdateVariableStore (\r
2216 &mVariableModuleGlobal->VariableGlobal,\r
2217 FALSE,\r
2218 TRUE,\r
2219 Fvb,\r
04401023 2220 mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (AuthFormat),\r
1436aea4
MK
2221 (UINT32)(VarSize - GetVariableHeaderSize (AuthFormat)),\r
2222 (UINT8 *)NextVariable + GetVariableHeaderSize (AuthFormat)\r
7cd69959 2223 );\r
c6492839 2224\r
7cd69959
SZ
2225 if (EFI_ERROR (Status)) {\r
2226 goto Done;\r
2227 }\r
1436aea4 2228\r
7cd69959
SZ
2229 //\r
2230 // Step 4:\r
2231 //\r
2232 NextVariable->State = VAR_ADDED;\r
1436aea4
MK
2233 Status = UpdateVariableStore (\r
2234 &mVariableModuleGlobal->VariableGlobal,\r
2235 FALSE,\r
2236 TRUE,\r
2237 Fvb,\r
2238 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
2239 sizeof (UINT8),\r
2240 &NextVariable->State\r
2241 );\r
8d3a5c82 2242\r
7cd69959
SZ
2243 if (EFI_ERROR (Status)) {\r
2244 goto Done;\r
2245 }\r
2246\r
2247 //\r
2248 // Update the memory copy of Flash region.\r
2249 //\r
2250 CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);\r
2251 } else {\r
2252 //\r
2253 // Emulated non-volatile variable mode.\r
2254 //\r
2255 NextVariable->State = VAR_ADDED;\r
1436aea4
MK
2256 Status = UpdateVariableStore (\r
2257 &mVariableModuleGlobal->VariableGlobal,\r
2258 FALSE,\r
2259 TRUE,\r
2260 Fvb,\r
2261 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2262 (UINT32)VarSize,\r
2263 (UINT8 *)NextVariable\r
2264 );\r
7cd69959
SZ
2265\r
2266 if (EFI_ERROR (Status)) {\r
2267 goto Done;\r
2268 }\r
2269 }\r
ebe34c96 2270\r
72399dae 2271 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
8d3a5c82 2272\r
2fcdca1d 2273 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
2274 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
2275 } else {\r
2276 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
4edb1866
SZ
2277 if (IsCommonUserVariable) {\r
2278 mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);\r
2279 }\r
2fcdca1d 2280 }\r
c6492839 2281 } else {\r
2282 //\r
8a2d4996 2283 // Create a volatile variable.\r
fa0737a8 2284 //\r
fd51bf70 2285 Volatile = TRUE;\r
c6492839 2286\r
1436aea4
MK
2287 if ((UINT32)(VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
2288 ((VARIABLE_STORE_HEADER *)((UINTN)(mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size)\r
2289 {\r
8d3a5c82 2290 //\r
7baf3c69 2291 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
8d3a5c82 2292 //\r
fa0737a8
SZ
2293 Status = Reclaim (\r
2294 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
2295 &mVariableModuleGlobal->VolatileLastVariableOffset,\r
2296 TRUE,\r
2297 Variable,\r
2298 NextVariable,\r
2299 HEADER_ALIGN (VarSize)\r
2300 );\r
7baf3c69
SZ
2301 if (!EFI_ERROR (Status)) {\r
2302 //\r
2303 // The new variable has been integrated successfully during reclaiming.\r
2304 //\r
2305 if (Variable->CurrPtr != NULL) {\r
1436aea4 2306 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN)CacheVariable->StartPtr + ((UINTN)Variable->CurrPtr - (UINTN)Variable->StartPtr));\r
7baf3c69
SZ
2307 CacheVariable->InDeletedTransitionPtr = NULL;\r
2308 }\r
1436aea4 2309\r
8d53adbe 2310 UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);\r
23b06935 2311 }\r
1436aea4 2312\r
7baf3c69 2313 goto Done;\r
8d3a5c82 2314 }\r
8d3a5c82 2315\r
c6492839 2316 NextVariable->State = VAR_ADDED;\r
1436aea4
MK
2317 Status = UpdateVariableStore (\r
2318 &mVariableModuleGlobal->VariableGlobal,\r
2319 TRUE,\r
2320 TRUE,\r
2321 Fvb,\r
2322 mVariableModuleGlobal->VolatileLastVariableOffset,\r
2323 (UINT32)VarSize,\r
2324 (UINT8 *)NextVariable\r
2325 );\r
c6492839 2326\r
2327 if (EFI_ERROR (Status)) {\r
2328 goto Done;\r
8d3a5c82 2329 }\r
c6492839 2330\r
72399dae 2331 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
c6492839 2332 }\r
72399dae 2333\r
c6492839 2334 //\r
8a2d4996 2335 // Mark the old variable as deleted.\r
c6492839 2336 //\r
1436aea4 2337 if (!EFI_ERROR (Status) && (Variable->CurrPtr != NULL)) {\r
23b06935
SZ
2338 if (Variable->InDeletedTransitionPtr != NULL) {\r
2339 //\r
2340 // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
2341 // set IN_DELETED_TRANSITION one to DELETED state first.\r
2342 //\r
ae658d91 2343 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
1436aea4 2344 State = CacheVariable->InDeletedTransitionPtr->State;\r
23b06935
SZ
2345 State &= VAR_DELETED;\r
2346 Status = UpdateVariableStore (\r
2347 &mVariableModuleGlobal->VariableGlobal,\r
2348 Variable->Volatile,\r
2349 FALSE,\r
2350 Fvb,\r
1436aea4 2351 (UINTN)&Variable->InDeletedTransitionPtr->State,\r
23b06935
SZ
2352 sizeof (UINT8),\r
2353 &State\r
2354 );\r
2355 if (!EFI_ERROR (Status)) {\r
2356 if (!Variable->Volatile) {\r
2357 CacheVariable->InDeletedTransitionPtr->State = State;\r
2358 }\r
2359 } else {\r
2360 goto Done;\r
2361 }\r
2362 }\r
2363\r
1436aea4 2364 State = CacheVariable->CurrPtr->State;\r
c6492839 2365 State &= VAR_DELETED;\r
2366\r
2367 Status = UpdateVariableStore (\r
1436aea4
MK
2368 &mVariableModuleGlobal->VariableGlobal,\r
2369 Variable->Volatile,\r
2370 FALSE,\r
2371 Fvb,\r
2372 (UINTN)&Variable->CurrPtr->State,\r
2373 sizeof (UINT8),\r
2374 &State\r
2375 );\r
fa0737a8 2376 if (!EFI_ERROR (Status) && !Variable->Volatile) {\r
8a2d4996 2377 CacheVariable->CurrPtr->State = State;\r
2378 }\r
72399dae 2379 }\r
2380\r
2381 if (!EFI_ERROR (Status)) {\r
8d53adbe 2382 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE, &gVariableInfo);\r
335e2681
SZ
2383 if (!Volatile) {\r
2384 FlushHobVariableToFlash (VariableName, VendorGuid);\r
2385 }\r
72399dae 2386 }\r
2387\r
2388Done:\r
aab3b9b9 2389 if (!EFI_ERROR (Status)) {\r
1436aea4 2390 if (((Variable->CurrPtr != NULL) && !Variable->Volatile) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {\r
aab3b9b9 2391 VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeNvCache);\r
6fe77f34
MK
2392 } else {\r
2393 VolatileCacheInstance = &(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeVolatileCache);\r
aab3b9b9
MK
2394 }\r
2395\r
2396 if (VolatileCacheInstance->Store != NULL) {\r
2397 Status = SynchronizeRuntimeVariableCache (\r
2398 VolatileCacheInstance,\r
2399 0,\r
2400 VolatileCacheInstance->Store->Size\r
2401 );\r
2402 ASSERT_EFI_ERROR (Status);\r
2403 }\r
2404 }\r
2405\r
72399dae 2406 return Status;\r
2407}\r
2408\r
2409/**\r
2410\r
2411 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
2412\r
18a7dbbc
SZ
2413 Caution: This function may receive untrusted input.\r
2414 This function may be invoked in SMM mode, and datasize is external input.\r
2415 This function will do basic validation, before parse the data.\r
2416\r
72399dae 2417 @param VariableName Name of Variable to be found.\r
2418 @param VendorGuid Variable vendor GUID.\r
2419 @param Attributes Attribute value of the variable found.\r
2420 @param DataSize Size of Data found. If size is less than the\r
2421 data, this value contains the required size.\r
dd59d95e
SZ
2422 @param Data The buffer to return the contents of the variable. May be NULL\r
2423 with a zero DataSize in order to determine the size buffer needed.\r
fa0737a8 2424\r
8a2d4996 2425 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2426 @return EFI_SUCCESS Find the specified variable.\r
2427 @return EFI_NOT_FOUND Not found.\r
2428 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
72399dae 2429\r
2430**/\r
2431EFI_STATUS\r
2432EFIAPI\r
8a2d4996 2433VariableServiceGetVariable (\r
1436aea4
MK
2434 IN CHAR16 *VariableName,\r
2435 IN EFI_GUID *VendorGuid,\r
2436 OUT UINT32 *Attributes OPTIONAL,\r
2437 IN OUT UINTN *DataSize,\r
2438 OUT VOID *Data OPTIONAL\r
72399dae 2439 )\r
2440{\r
2441 EFI_STATUS Status;\r
2442 VARIABLE_POINTER_TRACK Variable;\r
2443 UINTN VarDataSize;\r
2444\r
1436aea4 2445 if ((VariableName == NULL) || (VendorGuid == NULL) || (DataSize == NULL)) {\r
72399dae 2446 return EFI_INVALID_PARAMETER;\r
2447 }\r
2448\r
e19eab61
SZ
2449 if (VariableName[0] == 0) {\r
2450 return EFI_NOT_FOUND;\r
2451 }\r
2452\r
1436aea4 2453 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fa0737a8 2454\r
9622df63 2455 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
1436aea4 2456 if ((Variable.CurrPtr == NULL) || EFI_ERROR (Status)) {\r
72399dae 2457 goto Done;\r
2458 }\r
2459\r
2460 //\r
2461 // Get data size\r
2462 //\r
04401023 2463 VarDataSize = DataSizeOfVariable (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
72399dae 2464 ASSERT (VarDataSize != 0);\r
2465\r
2466 if (*DataSize >= VarDataSize) {\r
2467 if (Data == NULL) {\r
2468 Status = EFI_INVALID_PARAMETER;\r
2469 goto Done;\r
33a5a666 2470 }\r
72399dae 2471\r
04401023 2472 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), VarDataSize);\r
72399dae 2473\r
2474 *DataSize = VarDataSize;\r
8d53adbe 2475 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE, &gVariableInfo);\r
fa0737a8 2476\r
72399dae 2477 Status = EFI_SUCCESS;\r
2478 goto Done;\r
2479 } else {\r
2480 *DataSize = VarDataSize;\r
1436aea4 2481 Status = EFI_BUFFER_TOO_SMALL;\r
72399dae 2482 goto Done;\r
8d3a5c82 2483 }\r
2484\r
72399dae 2485Done:\r
1436aea4
MK
2486 if ((Status == EFI_SUCCESS) || (Status == EFI_BUFFER_TOO_SMALL)) {\r
2487 if ((Attributes != NULL) && (Variable.CurrPtr != NULL)) {\r
edf88807
MK
2488 *Attributes = Variable.CurrPtr->Attributes;\r
2489 }\r
2490 }\r
1436aea4 2491\r
72399dae 2492 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2493 return Status;\r
2494}\r
2495\r
fa0737a8
SZ
2496/**\r
2497\r
2498 This code Finds the Next available variable.\r
2499\r
2500 Caution: This function may receive untrusted input.\r
2501 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
2502\r
6f817f9b
SZ
2503 @param VariableNameSize The size of the VariableName buffer. The size must be large\r
2504 enough to fit input string supplied in VariableName buffer.\r
fa0737a8
SZ
2505 @param VariableName Pointer to variable name.\r
2506 @param VendorGuid Variable Vendor Guid.\r
2507\r
6f817f9b
SZ
2508 @retval EFI_SUCCESS The function completed successfully.\r
2509 @retval EFI_NOT_FOUND The next variable was not found.\r
2510 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.\r
2511 VariableNameSize has been updated with the size needed to complete the request.\r
2512 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.\r
2513 @retval EFI_INVALID_PARAMETER VariableName is NULL.\r
2514 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.\r
2515 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and\r
2516 GUID of an existing variable.\r
2517 @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of\r
2518 the input VariableName buffer.\r
fa0737a8
SZ
2519\r
2520**/\r
2521EFI_STATUS\r
2522EFIAPI\r
2523VariableServiceGetNextVariableName (\r
1436aea4
MK
2524 IN OUT UINTN *VariableNameSize,\r
2525 IN OUT CHAR16 *VariableName,\r
2526 IN OUT EFI_GUID *VendorGuid\r
fa0737a8
SZ
2527 )\r
2528{\r
1436aea4
MK
2529 EFI_STATUS Status;\r
2530 UINTN MaxLen;\r
2531 UINTN VarNameSize;\r
2532 BOOLEAN AuthFormat;\r
2533 VARIABLE_HEADER *VariablePtr;\r
2534 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
fa0737a8 2535\r
1436aea4 2536 if ((VariableNameSize == NULL) || (VariableName == NULL) || (VendorGuid == NULL)) {\r
fa0737a8
SZ
2537 return EFI_INVALID_PARAMETER;\r
2538 }\r
2539\r
04401023
MK
2540 AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
2541\r
6f817f9b
SZ
2542 //\r
2543 // Calculate the possible maximum length of name string, including the Null terminator.\r
2544 //\r
2545 MaxLen = *VariableNameSize / sizeof (CHAR16);\r
2546 if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {\r
2547 //\r
2548 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,\r
2549 // follow spec to return EFI_INVALID_PARAMETER.\r
2550 //\r
2551 return EFI_INVALID_PARAMETER;\r
2552 }\r
2553\r
1436aea4 2554 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fa0737a8 2555\r
f8ff4cca
MK
2556 //\r
2557 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
2558 // The index and attributes mapping must be kept in this order as FindVariable\r
2559 // makes use of this mapping to implement search algorithm.\r
2560 //\r
1436aea4
MK
2561 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
2562 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
f8ff4cca
MK
2563 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
2564\r
04401023
MK
2565 Status = VariableServiceGetNextVariableInternal (\r
2566 VariableName,\r
2567 VendorGuid,\r
2568 VariableStoreHeader,\r
2569 &VariablePtr,\r
2570 AuthFormat\r
2571 );\r
fa0737a8 2572 if (!EFI_ERROR (Status)) {\r
04401023 2573 VarNameSize = NameSizeOfVariable (VariablePtr, AuthFormat);\r
fa0737a8
SZ
2574 ASSERT (VarNameSize != 0);\r
2575 if (VarNameSize <= *VariableNameSize) {\r
04401023
MK
2576 CopyMem (\r
2577 VariableName,\r
2578 GetVariableNamePtr (VariablePtr, AuthFormat),\r
2579 VarNameSize\r
2580 );\r
2581 CopyMem (\r
2582 VendorGuid,\r
2583 GetVendorGuidPtr (VariablePtr, AuthFormat),\r
2584 sizeof (EFI_GUID)\r
2585 );\r
fa0737a8
SZ
2586 Status = EFI_SUCCESS;\r
2587 } else {\r
2588 Status = EFI_BUFFER_TOO_SMALL;\r
2589 }\r
2590\r
2591 *VariableNameSize = VarNameSize;\r
2592 }\r
2593\r
72399dae 2594 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2595 return Status;\r
2596}\r
2597\r
2598/**\r
2599\r
2600 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
2601\r
18a7dbbc
SZ
2602 Caution: This function may receive untrusted input.\r
2603 This function may be invoked in SMM mode, and datasize and data are external input.\r
2604 This function will do basic validation, before parse the data.\r
fa0737a8
SZ
2605 This function will parse the authentication carefully to avoid security issues, like\r
2606 buffer overflow, integer overflow.\r
2607 This function will check attribute carefully to avoid authentication bypass.\r
18a7dbbc 2608\r
8a2d4996 2609 @param VariableName Name of Variable to be found.\r
2610 @param VendorGuid Variable vendor GUID.\r
72399dae 2611 @param Attributes Attribute value of the variable found\r
2612 @param DataSize Size of Data found. If size is less than the\r
2613 data, this value contains the required size.\r
8a2d4996 2614 @param Data Data pointer.\r
72399dae 2615\r
8a2d4996 2616 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2617 @return EFI_SUCCESS Set successfully.\r
2618 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
2619 @return EFI_NOT_FOUND Not found.\r
2620 @return EFI_WRITE_PROTECTED Variable is read-only.\r
72399dae 2621\r
2622**/\r
2623EFI_STATUS\r
2624EFIAPI\r
8a2d4996 2625VariableServiceSetVariable (\r
1436aea4
MK
2626 IN CHAR16 *VariableName,\r
2627 IN EFI_GUID *VendorGuid,\r
2628 IN UINT32 Attributes,\r
2629 IN UINTN DataSize,\r
2630 IN VOID *Data\r
72399dae 2631 )\r
2632{\r
1436aea4
MK
2633 VARIABLE_POINTER_TRACK Variable;\r
2634 EFI_STATUS Status;\r
2635 VARIABLE_HEADER *NextVariable;\r
2636 EFI_PHYSICAL_ADDRESS Point;\r
2637 UINTN PayloadSize;\r
2638 BOOLEAN AuthFormat;\r
04401023
MK
2639\r
2640 AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
72399dae 2641\r
2642 //\r
8a2d4996 2643 // Check input parameters.\r
72399dae 2644 //\r
1436aea4 2645 if ((VariableName == NULL) || (VariableName[0] == 0) || (VendorGuid == NULL)) {\r
72399dae 2646 return EFI_INVALID_PARAMETER;\r
fa0737a8 2647 }\r
48a0e6bf 2648\r
1436aea4 2649 if ((DataSize != 0) && (Data == NULL)) {\r
48a0e6bf 2650 return EFI_INVALID_PARAMETER;\r
2651 }\r
2652\r
8e38f18e 2653 //\r
fa0737a8 2654 // Check for reserverd bit in variable attribute.\r
4073f85d
ZC
2655 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow\r
2656 // the delete operation of common authenticated variable at user physical presence.\r
2657 // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib\r
8e38f18e 2658 //\r
4073f85d 2659 if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {\r
8e38f18e 2660 return EFI_INVALID_PARAMETER;\r
2661 }\r
2662\r
72399dae 2663 //\r
21320ef6 2664 // Check if the combination of attribute bits is valid.\r
72399dae 2665 //\r
2666 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
21320ef6
SW
2667 //\r
2668 // Make sure if runtime bit is set, boot service bit is set also.\r
2669 //\r
67943427 2670 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2671 return EFI_UNSUPPORTED;\r
2672 } else {\r
2673 return EFI_INVALID_PARAMETER;\r
2674 }\r
21320ef6
SW
2675 } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {\r
2676 //\r
2677 // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid\r
2678 //\r
68c1bedb
SY
2679 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2680 return EFI_UNSUPPORTED;\r
2681 } else {\r
2682 return EFI_INVALID_PARAMETER;\r
2683 }\r
fa0737a8
SZ
2684 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
2685 if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {\r
2686 //\r
2687 // Not support authenticated variable write.\r
2688 //\r
2689 return EFI_INVALID_PARAMETER;\r
2690 }\r
2691 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
2692 if (PcdGet32 (PcdHwErrStorageSize) == 0) {\r
2693 //\r
2694 // Not support harware error record variable variable.\r
2695 //\r
2696 return EFI_INVALID_PARAMETER;\r
2697 }\r
2698 }\r
2699\r
2700 //\r
2701 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute\r
2702 // cannot be set both.\r
2703 //\r
1436aea4
MK
2704 if ( ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
2705 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS))\r
2706 {\r
67943427 2707 return EFI_UNSUPPORTED;\r
72399dae 2708 }\r
2709\r
fa0737a8 2710 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
67943427 2711 //\r
2712 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.\r
2713 // Maybe it's the delete operation of common authenticated variable at user physical presence.\r
2714 //\r
2715 if (DataSize != AUTHINFO_SIZE) {\r
2716 return EFI_UNSUPPORTED;\r
fa0737a8 2717 }\r
1436aea4 2718\r
fa0737a8
SZ
2719 PayloadSize = DataSize - AUTHINFO_SIZE;\r
2720 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {\r
2721 //\r
2722 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
2723 //\r
1436aea4
MK
2724 if ((DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA) ||\r
2725 (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo))) ||\r
2726 (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))\r
2727 {\r
fa0737a8
SZ
2728 return EFI_SECURITY_VIOLATION;\r
2729 }\r
1436aea4 2730\r
e83d841f 2731 //\r
49395ea0
HW
2732 // The VariableSpeculationBarrier() call here is to ensure the above sanity\r
2733 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed\r
e83d841f
HW
2734 // before the execution of subsequent codes.\r
2735 //\r
49395ea0 2736 VariableSpeculationBarrier ();\r
fa0737a8
SZ
2737 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
2738 } else {\r
2739 PayloadSize = DataSize;\r
2740 }\r
2741\r
1436aea4 2742 if ((UINTN)(~0) - PayloadSize < StrSize (VariableName)) {\r
fa0737a8
SZ
2743 //\r
2744 // Prevent whole variable size overflow\r
56251c66 2745 //\r
56251c66 2746 return EFI_INVALID_PARAMETER;\r
2747 }\r
2748\r
72399dae 2749 //\r
2750 // The size of the VariableName, including the Unicode Null in bytes plus\r
188e4e84 2751 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
fa0737a8 2752 // bytes for HwErrRec#### variable.\r
72399dae 2753 //\r
2754 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
04401023 2755 if (StrSize (VariableName) + PayloadSize >\r
1436aea4
MK
2756 PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (AuthFormat))\r
2757 {\r
72399dae 2758 return EFI_INVALID_PARAMETER;\r
2759 }\r
72399dae 2760 } else {\r
2761 //\r
2762 // The size of the VariableName, including the Unicode Null in bytes plus\r
9b4a2032 2763 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.\r
72399dae 2764 //\r
fa0737a8 2765 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
04401023
MK
2766 if (StrSize (VariableName) + PayloadSize >\r
2767 mVariableModuleGlobal->MaxAuthVariableSize -\r
1436aea4
MK
2768 GetVariableHeaderSize (AuthFormat))\r
2769 {\r
2770 DEBUG ((\r
2771 DEBUG_ERROR,\r
a90c7df7 2772 "%a: Failed to set variable '%s' with Guid %g\n",\r
1436aea4
MK
2773 __FUNCTION__,\r
2774 VariableName,\r
2775 VendorGuid\r
2776 ));\r
2777 DEBUG ((\r
2778 DEBUG_ERROR,\r
a90c7df7
VS
2779 "NameSize(0x%x) + PayloadSize(0x%x) > "\r
2780 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
1436aea4
MK
2781 StrSize (VariableName),\r
2782 PayloadSize,\r
a90c7df7 2783 mVariableModuleGlobal->MaxAuthVariableSize,\r
04401023 2784 GetVariableHeaderSize (AuthFormat)\r
a90c7df7 2785 ));\r
fa0737a8
SZ
2786 return EFI_INVALID_PARAMETER;\r
2787 }\r
9b4a2032 2788 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
04401023 2789 if (StrSize (VariableName) + PayloadSize >\r
1436aea4
MK
2790 mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (AuthFormat))\r
2791 {\r
2792 DEBUG ((\r
2793 DEBUG_ERROR,\r
a90c7df7 2794 "%a: Failed to set variable '%s' with Guid %g\n",\r
1436aea4
MK
2795 __FUNCTION__,\r
2796 VariableName,\r
2797 VendorGuid\r
2798 ));\r
2799 DEBUG ((\r
2800 DEBUG_ERROR,\r
a90c7df7
VS
2801 "NameSize(0x%x) + PayloadSize(0x%x) > "\r
2802 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
1436aea4
MK
2803 StrSize (VariableName),\r
2804 PayloadSize,\r
a90c7df7 2805 mVariableModuleGlobal->MaxVariableSize,\r
04401023 2806 GetVariableHeaderSize (AuthFormat)\r
a90c7df7 2807 ));\r
fa0737a8
SZ
2808 return EFI_INVALID_PARAMETER;\r
2809 }\r
9b4a2032 2810 } else {\r
04401023 2811 if (StrSize (VariableName) + PayloadSize >\r
1436aea4
MK
2812 mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (AuthFormat))\r
2813 {\r
2814 DEBUG ((\r
2815 DEBUG_ERROR,\r
a90c7df7 2816 "%a: Failed to set variable '%s' with Guid %g\n",\r
1436aea4
MK
2817 __FUNCTION__,\r
2818 VariableName,\r
2819 VendorGuid\r
2820 ));\r
2821 DEBUG ((\r
2822 DEBUG_ERROR,\r
a90c7df7
VS
2823 "NameSize(0x%x) + PayloadSize(0x%x) > "\r
2824 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
1436aea4
MK
2825 StrSize (VariableName),\r
2826 PayloadSize,\r
a90c7df7 2827 mVariableModuleGlobal->MaxVolatileVariableSize,\r
04401023 2828 GetVariableHeaderSize (AuthFormat)\r
a90c7df7 2829 ));\r
9b4a2032
LE
2830 return EFI_INVALID_PARAMETER;\r
2831 }\r
efb01a10 2832 }\r
6675a21f
SZ
2833 }\r
2834\r
2f6aa774
JY
2835 //\r
2836 // Special Handling for MOR Lock variable.\r
2837 //\r
1436aea4 2838 Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize));\r
2f6aa774
JY
2839 if (Status == EFI_ALREADY_STARTED) {\r
2840 //\r
2841 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().\r
2842 // Variable driver can just return SUCCESS.\r
2843 //\r
2844 return EFI_SUCCESS;\r
2845 }\r
1436aea4 2846\r
2f6aa774
JY
2847 if (EFI_ERROR (Status)) {\r
2848 return Status;\r
2849 }\r
2850\r
1436aea4 2851 Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize), mRequestSource);\r
fa0737a8
SZ
2852 if (EFI_ERROR (Status)) {\r
2853 return Status;\r
2854 }\r
2855\r
1436aea4 2856 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
72399dae 2857\r
2858 //\r
8a2d4996 2859 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
72399dae 2860 //\r
2861 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
8a2d4996 2862 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
72399dae 2863 //\r
8a2d4996 2864 // Parse non-volatile variable data and get last variable offset.\r
72399dae 2865 //\r
1436aea4
MK
2866 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);\r
2867 while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point))) {\r
04401023 2868 NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);\r
72399dae 2869 }\r
1436aea4
MK
2870\r
2871 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)NextVariable - (UINTN)Point;\r
72399dae 2872 }\r
2873\r
2874 //\r
8a2d4996 2875 // Check whether the input variable is already existed.\r
72399dae 2876 //\r
9622df63
SZ
2877 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
2878 if (!EFI_ERROR (Status)) {\r
2879 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
ff843847
RN
2880 Status = EFI_WRITE_PROTECTED;\r
2881 goto Done;\r
9622df63 2882 }\r
1436aea4
MK
2883\r
2884 if ((Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes)) {\r
6e67fec0
SZ
2885 //\r
2886 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not\r
2887 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:\r
2888 // 1. No access attributes specified\r
2889 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE\r
2890 //\r
2891 Status = EFI_INVALID_PARAMETER;\r
87000d77 2892 DEBUG ((DEBUG_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));\r
6e67fec0
SZ
2893 goto Done;\r
2894 }\r
9622df63 2895 }\r
72399dae 2896\r
b2bd493e 2897 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {\r
9bc5dabb 2898 //\r
b2bd493e 2899 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
9bc5dabb 2900 //\r
b2bd493e
SZ
2901 Status = AutoUpdateLangVariable (VariableName, Data, DataSize);\r
2902 if (EFI_ERROR (Status)) {\r
2903 //\r
2904 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.\r
2905 //\r
2906 goto Done;\r
2907 }\r
9bc5dabb 2908 }\r
72399dae 2909\r
fa0737a8
SZ
2910 if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {\r
2911 Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);\r
2912 } else {\r
2913 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);\r
2914 }\r
72399dae 2915\r
ff843847 2916Done:\r
fdb7765f 2917 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
052ad7e1 2918 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fdb7765f 2919\r
fa0737a8
SZ
2920 if (!AtRuntime ()) {\r
2921 if (!EFI_ERROR (Status)) {\r
2922 SecureBootHook (\r
2923 VariableName,\r
2924 VendorGuid\r
2925 );\r
2926 }\r
2927 }\r
2928\r
8d3a5c82 2929 return Status;\r
2930}\r
2931\r
7c80e839 2932/**\r
8d3a5c82 2933\r
2934 This code returns information about the EFI variables.\r
2935\r
18a7dbbc
SZ
2936 Caution: This function may receive untrusted input.\r
2937 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
2938\r
7c80e839 2939 @param Attributes Attributes bitmask to specify the type of variables\r
2940 on which to return information.\r
2941 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
2942 for the EFI variables associated with the attributes specified.\r
2943 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
2944 for EFI variables associated with the attributes specified.\r
2945 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
2946 associated with the attributes specified.\r
8d3a5c82 2947\r
7c80e839 2948 @return EFI_SUCCESS Query successfully.\r
8d3a5c82 2949\r
7c80e839 2950**/\r
052ad7e1
A
2951EFI_STATUS\r
2952EFIAPI\r
b2bd493e 2953VariableServiceQueryVariableInfoInternal (\r
1436aea4
MK
2954 IN UINT32 Attributes,\r
2955 OUT UINT64 *MaximumVariableStorageSize,\r
2956 OUT UINT64 *RemainingVariableStorageSize,\r
2957 OUT UINT64 *MaximumVariableSize\r
052ad7e1 2958 )\r
8d3a5c82 2959{\r
1436aea4
MK
2960 VARIABLE_HEADER *Variable;\r
2961 VARIABLE_HEADER *NextVariable;\r
2962 UINT64 VariableSize;\r
2963 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2964 UINT64 CommonVariableTotalSize;\r
2965 UINT64 HwErrVariableTotalSize;\r
2966 EFI_STATUS Status;\r
2967 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
2fcdca1d 2968\r
2969 CommonVariableTotalSize = 0;\r
1436aea4 2970 HwErrVariableTotalSize = 0;\r
8d3a5c82 2971\r
1436aea4 2972 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
8d3a5c82 2973 //\r
2974 // Query is Volatile related.\r
2975 //\r
1436aea4 2976 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 2977 } else {\r
2978 //\r
2979 // Query is Non-Volatile related.\r
2980 //\r
8a2d4996 2981 VariableStoreHeader = mNvVariableCache;\r
8d3a5c82 2982 }\r
2983\r
2984 //\r
2985 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2986 // with the storage size (excluding the storage header size).\r
2987 //\r
1436aea4 2988 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
c6492839 2989\r
2990 //\r
2991 // Harware error record variable needs larger size.\r
2992 //\r
2fcdca1d 2993 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
188e4e84 2994 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
1436aea4
MK
2995 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) -\r
2996 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
2fcdca1d 2997 } else {\r
2998 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
4edb1866
SZ
2999 if (AtRuntime ()) {\r
3000 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;\r
3001 } else {\r
3002 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;\r
3003 }\r
2fcdca1d 3004 }\r
3005\r
3006 //\r
9b4a2032 3007 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.\r
2fcdca1d 3008 //\r
fa0737a8 3009 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
04401023 3010 *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -\r
1436aea4 3011 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
9b4a2032 3012 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
04401023 3013 *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize -\r
1436aea4 3014 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
9b4a2032 3015 } else {\r
04401023 3016 *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize -\r
1436aea4 3017 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
fa0737a8 3018 }\r
c6492839 3019 }\r
8d3a5c82 3020\r
3021 //\r
3022 // Point to the starting address of the variables.\r
3023 //\r
9cad030b 3024 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 3025\r
3026 //\r
3027 // Now walk through the related variable store.\r
3028 //\r
6ebffb67 3029 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
04401023 3030 NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
1436aea4 3031 VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;\r
8d3a5c82 3032\r
8a2d4996 3033 if (AtRuntime ()) {\r
8d3a5c82 3034 //\r
8a2d4996 3035 // We don't take the state of the variables in mind\r
8d3a5c82 3036 // when calculating RemainingVariableStorageSize,\r
3037 // since the space occupied by variables not marked with\r
3038 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
3039 //\r
3b425367 3040 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2fcdca1d 3041 HwErrVariableTotalSize += VariableSize;\r
3042 } else {\r
3043 CommonVariableTotalSize += VariableSize;\r
3044 }\r
8d3a5c82 3045 } else {\r
3046 //\r
8a2d4996 3047 // Only care about Variables with State VAR_ADDED, because\r
8d3a5c82 3048 // the space not marked as VAR_ADDED is reclaimable now.\r
3049 //\r
3050 if (Variable->State == VAR_ADDED) {\r
3b425367 3051 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2fcdca1d 3052 HwErrVariableTotalSize += VariableSize;\r
3053 } else {\r
3054 CommonVariableTotalSize += VariableSize;\r
3055 }\r
b2bd493e
SZ
3056 } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
3057 //\r
3058 // If it is a IN_DELETED_TRANSITION variable,\r
3059 // and there is not also a same ADDED one at the same time,\r
3060 // this IN_DELETED_TRANSITION variable is valid.\r
3061 //\r
3062 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
1436aea4
MK
3063 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);\r
3064 Status = FindVariableEx (\r
3065 GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
3066 GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
3067 FALSE,\r
3068 &VariablePtrTrack,\r
3069 mVariableModuleGlobal->VariableGlobal.AuthFormat\r
3070 );\r
3071 if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State != VAR_ADDED)) {\r
b2bd493e
SZ
3072 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
3073 HwErrVariableTotalSize += VariableSize;\r
3074 } else {\r
3075 CommonVariableTotalSize += VariableSize;\r
3076 }\r
3077 }\r
8d3a5c82 3078 }\r
3079 }\r
3080\r
3081 //\r
8a2d4996 3082 // Go to the next one.\r
8d3a5c82 3083 //\r
3084 Variable = NextVariable;\r
3085 }\r
3086\r
1436aea4 3087 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2fcdca1d 3088 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
4edb1866
SZ
3089 } else {\r
3090 if (*MaximumVariableStorageSize < CommonVariableTotalSize) {\r
3091 *RemainingVariableStorageSize = 0;\r
3092 } else {\r
3093 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
3094 }\r
2fcdca1d 3095 }\r
3096\r
04401023 3097 if (*RemainingVariableStorageSize < GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) {\r
c6492839 3098 *MaximumVariableSize = 0;\r
04401023 3099 } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) <\r
1436aea4
MK
3100 *MaximumVariableSize\r
3101 )\r
3102 {\r
04401023 3103 *MaximumVariableSize = *RemainingVariableStorageSize -\r
1436aea4 3104 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
c6492839 3105 }\r
3106\r
8d3a5c82 3107 return EFI_SUCCESS;\r
3108}\r
3109\r
b2bd493e
SZ
3110/**\r
3111\r
3112 This code returns information about the EFI variables.\r
3113\r
18a7dbbc
SZ
3114 Caution: This function may receive untrusted input.\r
3115 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
3116\r
b2bd493e
SZ
3117 @param Attributes Attributes bitmask to specify the type of variables\r
3118 on which to return information.\r
3119 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
3120 for the EFI variables associated with the attributes specified.\r
3121 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
3122 for EFI variables associated with the attributes specified.\r
3123 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
3124 associated with the attributes specified.\r
3125\r
3126 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
3127 @return EFI_SUCCESS Query successfully.\r
3128 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
3129\r
3130**/\r
3131EFI_STATUS\r
3132EFIAPI\r
3133VariableServiceQueryVariableInfo (\r
1436aea4
MK
3134 IN UINT32 Attributes,\r
3135 OUT UINT64 *MaximumVariableStorageSize,\r
3136 OUT UINT64 *RemainingVariableStorageSize,\r
3137 OUT UINT64 *MaximumVariableSize\r
b2bd493e
SZ
3138 )\r
3139{\r
1436aea4 3140 EFI_STATUS Status;\r
b2bd493e 3141\r
1436aea4 3142 if ((MaximumVariableStorageSize == NULL) || (RemainingVariableStorageSize == NULL) || (MaximumVariableSize == NULL) || (Attributes == 0)) {\r
b2bd493e
SZ
3143 return EFI_INVALID_PARAMETER;\r
3144 }\r
3145\r
67943427 3146 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
3147 //\r
3148 // Deprecated attribute, make this check as highest priority.\r
3149 //\r
3150 return EFI_UNSUPPORTED;\r
3151 }\r
3152\r
fa0737a8 3153 if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {\r
b2bd493e
SZ
3154 //\r
3155 // Make sure the Attributes combination is supported by the platform.\r
3156 //\r
3157 return EFI_UNSUPPORTED;\r
21320ef6
SW
3158 } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {\r
3159 //\r
3160 // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid\r
3161 //\r
3162 return EFI_INVALID_PARAMETER;\r
b2bd493e
SZ
3163 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
3164 //\r
3165 // Make sure if runtime bit is set, boot service bit is set also.\r
3166 //\r
3167 return EFI_INVALID_PARAMETER;\r
3168 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
3169 //\r
3170 // Make sure RT Attribute is set if we are in Runtime phase.\r
3171 //\r
3172 return EFI_INVALID_PARAMETER;\r
3173 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
3174 //\r
3175 // Make sure Hw Attribute is set with NV.\r
3176 //\r
3177 return EFI_INVALID_PARAMETER;\r
fa0737a8
SZ
3178 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
3179 if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {\r
3180 //\r
3181 // Not support authenticated variable write.\r
3182 //\r
3183 return EFI_UNSUPPORTED;\r
3184 }\r
3185 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
3186 if (PcdGet32 (PcdHwErrStorageSize) == 0) {\r
3187 //\r
3188 // Not support harware error record variable variable.\r
3189 //\r
3190 return EFI_UNSUPPORTED;\r
3191 }\r
b2bd493e
SZ
3192 }\r
3193\r
1436aea4 3194 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
b2bd493e
SZ
3195\r
3196 Status = VariableServiceQueryVariableInfoInternal (\r
3197 Attributes,\r
3198 MaximumVariableStorageSize,\r
3199 RemainingVariableStorageSize,\r
3200 MaximumVariableSize\r
3201 );\r
3202\r
3203 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
3204 return Status;\r
3205}\r
7c80e839 3206\r
3207/**\r
8a2d4996 3208 This function reclaims variable storage if free size is below the threshold.\r
18a7dbbc
SZ
3209\r
3210 Caution: This function may be invoked at SMM mode.\r
3211 Care must be taken to make sure not security issue.\r
3212\r
7c80e839 3213**/\r
7800593d 3214VOID\r
1436aea4 3215ReclaimForOS (\r
8a2d4996 3216 VOID\r
7800593d
LG
3217 )\r
3218{\r
1436aea4
MK
3219 EFI_STATUS Status;\r
3220 UINTN RemainingCommonRuntimeVariableSpace;\r
3221 UINTN RemainingHwErrVariableSpace;\r
3222 STATIC BOOLEAN Reclaimed;\r
0fb5e515
SZ
3223\r
3224 //\r
3225 // This function will be called only once at EndOfDxe or ReadyToBoot event.\r
3226 //\r
3227 if (Reclaimed) {\r
3228 return;\r
3229 }\r
1436aea4 3230\r
0fb5e515 3231 Reclaimed = TRUE;\r
7800593d 3232\r
1436aea4 3233 Status = EFI_SUCCESS;\r
7800593d 3234\r
4edb1866
SZ
3235 if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {\r
3236 RemainingCommonRuntimeVariableSpace = 0;\r
3237 } else {\r
3238 RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
3239 }\r
2fcdca1d 3240\r
3241 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
fa0737a8 3242\r
7800593d 3243 //\r
4edb1866 3244 // Check if the free area is below a threshold.\r
7800593d 3245 //\r
fa0737a8
SZ
3246 if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||\r
3247 (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||\r
3248 ((PcdGet32 (PcdHwErrStorageSize) != 0) &&\r
1436aea4
MK
3249 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))))\r
3250 {\r
7800593d 3251 Status = Reclaim (\r
1436aea4
MK
3252 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
3253 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
3254 FALSE,\r
3255 NULL,\r
3256 NULL,\r
3257 0\r
3258 );\r
7800593d
LG
3259 ASSERT_EFI_ERROR (Status);\r
3260 }\r
3261}\r
3262\r
9b4a2032
LE
3263/**\r
3264 Get maximum variable size, covering both non-volatile and volatile variables.\r
3265\r
3266 @return Maximum variable size.\r
3267\r
3268**/\r
3269UINTN\r
3270GetMaxVariableSize (\r
3271 VOID\r
3272 )\r
3273{\r
1436aea4 3274 UINTN MaxVariableSize;\r
9b4a2032 3275\r
1436aea4 3276 MaxVariableSize = GetNonVolatileMaxVariableSize ();\r
9b4a2032
LE
3277 //\r
3278 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals\r
3279 // the default zero value.\r
3280 //\r
3281 if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {\r
3282 MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);\r
3283 }\r
1436aea4 3284\r
9b4a2032
LE
3285 return MaxVariableSize;\r
3286}\r
3287\r
335e2681
SZ
3288/**\r
3289 Flush the HOB variable to flash.\r
3290\r
3291 @param[in] VariableName Name of variable has been updated or deleted.\r
3292 @param[in] VendorGuid Guid of variable has been updated or deleted.\r
3293\r
3294**/\r
3295VOID\r
3296FlushHobVariableToFlash (\r
1436aea4
MK
3297 IN CHAR16 *VariableName,\r
3298 IN EFI_GUID *VendorGuid\r
335e2681
SZ
3299 )\r
3300{\r
1436aea4
MK
3301 EFI_STATUS Status;\r
3302 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
3303 VARIABLE_HEADER *Variable;\r
3304 VOID *VariableData;\r
3305 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
3306 BOOLEAN ErrorFlag;\r
3307 BOOLEAN AuthFormat;\r
3308\r
3309 ErrorFlag = FALSE;\r
04401023 3310 AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
335e2681
SZ
3311\r
3312 //\r
3313 // Flush the HOB variable to flash.\r
3314 //\r
3315 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
1436aea4 3316 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
335e2681
SZ
3317 //\r
3318 // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
3319 //\r
3320 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
3321 for ( Variable = GetStartPointer (VariableStoreHeader)\r
1436aea4
MK
3322 ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))\r
3323 ; Variable = GetNextVariablePtr (Variable, AuthFormat)\r
3324 )\r
3325 {\r
335e2681
SZ
3326 if (Variable->State != VAR_ADDED) {\r
3327 //\r
3328 // The HOB variable has been set to DELETED state in local.\r
3329 //\r
3330 continue;\r
3331 }\r
1436aea4 3332\r
335e2681 3333 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
1436aea4 3334 if ((VendorGuid == NULL) || (VariableName == NULL) ||\r
04401023 3335 !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthFormat)) ||\r
1436aea4
MK
3336 (StrCmp (VariableName, GetVariableNamePtr (Variable, AuthFormat)) != 0))\r
3337 {\r
04401023
MK
3338 VariableData = GetVariableDataPtr (Variable, AuthFormat);\r
3339 FindVariable (\r
3340 GetVariableNamePtr (Variable, AuthFormat),\r
3341 GetVendorGuidPtr (Variable, AuthFormat),\r
3342 &VariablePtrTrack,\r
1436aea4
MK
3343 &mVariableModuleGlobal->VariableGlobal,\r
3344 FALSE\r
04401023 3345 );\r
31349131 3346 Status = UpdateVariable (\r
04401023
MK
3347 GetVariableNamePtr (Variable, AuthFormat),\r
3348 GetVendorGuidPtr (Variable, AuthFormat),\r
31349131 3349 VariableData,\r
04401023 3350 DataSizeOfVariable (Variable, AuthFormat),\r
31349131
SZ
3351 Variable->Attributes,\r
3352 0,\r
3353 0,\r
3354 &VariablePtrTrack,\r
3355 NULL\r
1436aea4 3356 );\r
04401023
MK
3357 DEBUG ((\r
3358 DEBUG_INFO,\r
3359 "Variable driver flush the HOB variable to flash: %g %s %r\n",\r
3360 GetVendorGuidPtr (Variable, AuthFormat),\r
3361 GetVariableNamePtr (Variable, AuthFormat),\r
3362 Status\r
3363 ));\r
335e2681
SZ
3364 } else {\r
3365 //\r
31349131 3366 // The updated or deleted variable is matched with this HOB variable.\r
335e2681
SZ
3367 // Don't break here because we will try to set other HOB variables\r
3368 // since this variable could be set successfully.\r
3369 //\r
3370 Status = EFI_SUCCESS;\r
3371 }\r
1436aea4 3372\r
335e2681
SZ
3373 if (!EFI_ERROR (Status)) {\r
3374 //\r
3375 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
3376 // set the HOB variable to DELETED state in local.\r
3377 //\r
04401023
MK
3378 DEBUG ((\r
3379 DEBUG_INFO,\r
3380 "Variable driver set the HOB variable to DELETED state in local: %g %s\n",\r
3381 GetVendorGuidPtr (Variable, AuthFormat),\r
3382 GetVariableNamePtr (Variable, AuthFormat)\r
3383 ));\r
335e2681
SZ
3384 Variable->State &= VAR_DELETED;\r
3385 } else {\r
3386 ErrorFlag = TRUE;\r
3387 }\r
3388 }\r
1436aea4 3389\r
aab3b9b9
MK
3390 if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store != NULL) {\r
3391 Status = SynchronizeRuntimeVariableCache (\r
3392 &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,\r
3393 0,\r
3394 mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store->Size\r
3395 );\r
3396 ASSERT_EFI_ERROR (Status);\r
3397 }\r
1436aea4 3398\r
335e2681
SZ
3399 if (ErrorFlag) {\r
3400 //\r
3401 // We still have HOB variable(s) not flushed in flash.\r
3402 //\r
1436aea4 3403 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStoreHeader;\r
335e2681
SZ
3404 } else {\r
3405 //\r
3406 // All HOB variables have been flushed in flash.\r
3407 //\r
87000d77 3408 DEBUG ((DEBUG_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
aab3b9b9
MK
3409 if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete != NULL) {\r
3410 *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = TRUE;\r
3411 }\r
1436aea4 3412\r
335e2681 3413 if (!AtRuntime ()) {\r
1436aea4 3414 FreePool ((VOID *)VariableStoreHeader);\r
335e2681
SZ
3415 }\r
3416 }\r
3417 }\r
335e2681 3418}\r
8a2d4996 3419\r
7c80e839 3420/**\r
904e0ca9 3421 Initializes variable write service.\r
7c80e839 3422\r
8a2d4996 3423 @retval EFI_SUCCESS Function successfully executed.\r
3424 @retval Others Fail to initialize the variable service.\r
3425\r
3426**/\r
3427EFI_STATUS\r
3428VariableWriteServiceInitialize (\r
3429 VOID\r
3430 )\r
3431{\r
1436aea4
MK
3432 EFI_STATUS Status;\r
3433 UINTN Index;\r
3434 UINT8 Data;\r
3435 VARIABLE_ENTRY_PROPERTY *VariableEntry;\r
8a2d4996 3436\r
1436aea4 3437 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
31349131 3438\r
8a2d4996 3439 //\r
3440 // Check if the free area is really free.\r
3441 //\r
9b18845a 3442 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {\r
1436aea4 3443 Data = ((UINT8 *)mNvVariableCache)[Index];\r
8a2d4996 3444 if (Data != 0xff) {\r
3445 //\r
3446 // There must be something wrong in variable store, do reclaim operation.\r
3447 //\r
3448 Status = Reclaim (\r
3449 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
3450 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
3451 FALSE,\r
335e2681 3452 NULL,\r
7baf3c69
SZ
3453 NULL,\r
3454 0\r
8a2d4996 3455 );\r
3456 if (EFI_ERROR (Status)) {\r
31349131 3457 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8a2d4996 3458 return Status;\r
3459 }\r
1436aea4 3460\r
8a2d4996 3461 break;\r
3462 }\r
3463 }\r
3464\r
335e2681 3465 FlushHobVariableToFlash (NULL, NULL);\r
0f7aff72 3466\r
fa0737a8 3467 Status = EFI_SUCCESS;\r
8021f4c7 3468 ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));\r
fa0737a8
SZ
3469 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {\r
3470 //\r
3471 // Authenticated variable initialize.\r
3472 //\r
1436aea4 3473 mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);\r
04401023 3474 mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -\r
1436aea4 3475 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
8021f4c7 3476 Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);\r
fa0737a8 3477 if (!EFI_ERROR (Status)) {\r
87000d77 3478 DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable support!\n"));\r
fa0737a8 3479 mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;\r
8021f4c7
SZ
3480 if (mAuthContextOut.AuthVarEntry != NULL) {\r
3481 for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {\r
3482 VariableEntry = &mAuthContextOut.AuthVarEntry[Index];\r
1436aea4
MK
3483 Status = VarCheckLibVariablePropertySet (\r
3484 VariableEntry->Name,\r
3485 VariableEntry->Guid,\r
3486 &VariableEntry->VariableProperty\r
3487 );\r
fa0737a8
SZ
3488 ASSERT_EFI_ERROR (Status);\r
3489 }\r
3490 }\r
3491 } else if (Status == EFI_UNSUPPORTED) {\r
87000d77
MK
3492 DEBUG ((DEBUG_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));\r
3493 DEBUG ((DEBUG_INFO, "Variable driver will continue to work without auth variable support!\n"));\r
fa0737a8 3494 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;\r
1436aea4 3495 Status = EFI_SUCCESS;\r
fa0737a8
SZ
3496 }\r
3497 }\r
3498\r
3499 if (!EFI_ERROR (Status)) {\r
33f615e2 3500 for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {\r
fa0737a8 3501 VariableEntry = &mVariableEntryProperty[Index];\r
1436aea4 3502 Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);\r
fa0737a8
SZ
3503 ASSERT_EFI_ERROR (Status);\r
3504 }\r
3505 }\r
3506\r
31349131 3507 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2f6aa774
JY
3508\r
3509 //\r
3510 // Initialize MOR Lock variable.\r
3511 //\r
3512 MorLockInit ();\r
3513\r
fa0737a8 3514 return Status;\r
8a2d4996 3515}\r
3516\r
a37044ef
LG
3517/**\r
3518 Convert normal variable storage to the allocated auth variable storage.\r
3519\r
3520 @param[in] NormalVarStorage Pointer to the normal variable storage header\r
3521\r
3522 @retval the allocated auth variable storage\r
3523**/\r
3524VOID *\r
3525ConvertNormalVarStorageToAuthVarStorage (\r
1436aea4 3526 VARIABLE_STORE_HEADER *NormalVarStorage\r
a37044ef
LG
3527 )\r
3528{\r
1436aea4
MK
3529 VARIABLE_HEADER *StartPtr;\r
3530 UINT8 *NextPtr;\r
3531 VARIABLE_HEADER *EndPtr;\r
3532 UINTN AuthVarStroageSize;\r
3533 AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;\r
3534 VARIABLE_STORE_HEADER *AuthVarStorage;\r
a37044ef 3535\r
1436aea4 3536 AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);\r
a37044ef
LG
3537 //\r
3538 // Set AuthFormat as FALSE for normal variable storage\r
3539 //\r
3540 mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;\r
3541\r
3542 //\r
3543 // Calculate Auth Variable Storage Size\r
3544 //\r
3545 StartPtr = GetStartPointer (NormalVarStorage);\r
3546 EndPtr = GetEndPointer (NormalVarStorage);\r
3547 while (StartPtr < EndPtr) {\r
3548 if (StartPtr->State == VAR_ADDED) {\r
1436aea4 3549 AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);\r
a37044ef
LG
3550 AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);\r
3551 AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);\r
3552 AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);\r
3553 }\r
1436aea4
MK
3554\r
3555 StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
a37044ef
LG
3556 }\r
3557\r
3558 //\r
3559 // Allocate Runtime memory for Auth Variable Storage\r
3560 //\r
3561 AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);\r
3562 ASSERT (AuthVarStorage != NULL);\r
3563 if (AuthVarStorage == NULL) {\r
3564 return NULL;\r
3565 }\r
3566\r
3567 //\r
3568 // Copy Variable from Normal storage to Auth storage\r
3569 //\r
1436aea4
MK
3570 StartPtr = GetStartPointer (NormalVarStorage);\r
3571 EndPtr = GetEndPointer (NormalVarStorage);\r
3572 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)GetStartPointer (AuthVarStorage);\r
a37044ef
LG
3573 while (StartPtr < EndPtr) {\r
3574 if (StartPtr->State == VAR_ADDED) {\r
1436aea4 3575 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (AuthStartPtr);\r
a37044ef
LG
3576 //\r
3577 // Copy Variable Header\r
3578 //\r
1436aea4
MK
3579 AuthStartPtr->StartId = StartPtr->StartId;\r
3580 AuthStartPtr->State = StartPtr->State;\r
3581 AuthStartPtr->Attributes = StartPtr->Attributes;\r
3582 AuthStartPtr->NameSize = StartPtr->NameSize;\r
3583 AuthStartPtr->DataSize = StartPtr->DataSize;\r
a37044ef
LG
3584 CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);\r
3585 //\r
3586 // Copy Variable Name\r
3587 //\r
1436aea4 3588 NextPtr = (UINT8 *)(AuthStartPtr + 1);\r
04401023
MK
3589 CopyMem (\r
3590 NextPtr,\r
3591 GetVariableNamePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat),\r
3592 AuthStartPtr->NameSize\r
3593 );\r
a37044ef
LG
3594 //\r
3595 // Copy Variable Data\r
3596 //\r
3597 NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);\r
04401023 3598 CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), AuthStartPtr->DataSize);\r
a37044ef
LG
3599 //\r
3600 // Go to next variable\r
3601 //\r
1436aea4 3602 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)(NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));\r
a37044ef 3603 }\r
1436aea4 3604\r
04401023 3605 StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
a37044ef 3606 }\r
1436aea4 3607\r
a37044ef
LG
3608 //\r
3609 // Update Auth Storage Header\r
3610 //\r
3611 AuthVarStorage->Format = NormalVarStorage->Format;\r
3612 AuthVarStorage->State = NormalVarStorage->State;\r
1436aea4 3613 AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);\r
a37044ef
LG
3614 CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);\r
3615 ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);\r
8a2d4996 3616\r
a37044ef
LG
3617 //\r
3618 // Restore AuthFormat\r
3619 //\r
3620 mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;\r
3621 return AuthVarStorage;\r
3622}\r
09808bd3
SZ
3623\r
3624/**\r
3625 Get HOB variable store.\r
3626\r
5f463523 3627 @param[in] VariableGuid NV variable store signature.\r
09808bd3
SZ
3628\r
3629 @retval EFI_SUCCESS Function successfully executed.\r
3630 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
3631\r
3632**/\r
3633EFI_STATUS\r
3634GetHobVariableStore (\r
1436aea4 3635 IN EFI_GUID *VariableGuid\r
09808bd3
SZ
3636 )\r
3637{\r
1436aea4
MK
3638 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
3639 UINT64 VariableStoreLength;\r
3640 EFI_HOB_GUID_TYPE *GuidHob;\r
3641 BOOLEAN NeedConvertNormalToAuth;\r
09808bd3 3642\r
fdd3e77a
SZ
3643 //\r
3644 // Make sure there is no more than one Variable HOB.\r
3645 //\r
db52c7f7 3646 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
3647 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
3648 if (GuidHob != NULL) {\r
3649 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
3650 DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));\r
3651 ASSERT (FALSE);\r
3652 } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {\r
3653 DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));\r
3654 ASSERT (FALSE);\r
3655 }\r
3656 } else {\r
3657 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
fdd3e77a 3658 if (GuidHob != NULL) {\r
1436aea4
MK
3659 if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
3660 DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));\r
fdd3e77a
SZ
3661 ASSERT (FALSE);\r
3662 }\r
fdd3e77a 3663 }\r
1436aea4
MK
3664 }\r
3665\r
db52c7f7 3666 DEBUG_CODE_END ();\r
fdd3e77a 3667\r
09808bd3
SZ
3668 //\r
3669 // Combinations supported:\r
3670 // 1. Normal NV variable store +\r
3671 // Normal HOB variable store\r
3672 // 2. Auth NV variable store +\r
3673 // Auth HOB variable store\r
3674 // 3. Auth NV variable store +\r
3675 // Normal HOB variable store (code will convert it to Auth Format)\r
3676 //\r
3677 NeedConvertNormalToAuth = FALSE;\r
1436aea4
MK
3678 GuidHob = GetFirstGuidHob (VariableGuid);\r
3679 if ((GuidHob == NULL) && (VariableGuid == &gEfiAuthenticatedVariableGuid)) {\r
09808bd3
SZ
3680 //\r
3681 // Try getting it from normal variable HOB\r
3682 //\r
1436aea4 3683 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
09808bd3
SZ
3684 NeedConvertNormalToAuth = TRUE;\r
3685 }\r
1436aea4 3686\r
09808bd3
SZ
3687 if (GuidHob != NULL) {\r
3688 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
3689 VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);\r
3690 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
3691 if (!NeedConvertNormalToAuth) {\r
1436aea4 3692 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimeCopyPool ((UINTN)VariableStoreLength, (VOID *)VariableStoreHeader);\r
09808bd3 3693 } else {\r
1436aea4 3694 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertNormalVarStorageToAuthVarStorage ((VOID *)VariableStoreHeader);\r
09808bd3 3695 }\r
1436aea4 3696\r
09808bd3
SZ
3697 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
3698 return EFI_OUT_OF_RESOURCES;\r
3699 }\r
3700 } else {\r
87000d77 3701 DEBUG ((DEBUG_ERROR, "HOB Variable Store header is corrupted!\n"));\r
09808bd3
SZ
3702 }\r
3703 }\r
3704\r
3705 return EFI_SUCCESS;\r
3706}\r
3707\r
8a2d4996 3708/**\r
3709 Initializes variable store area for non-volatile and volatile variable.\r
7c80e839 3710\r
3711 @retval EFI_SUCCESS Function successfully executed.\r
3712 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
3713\r
3714**/\r
8d3a5c82 3715EFI_STATUS\r
8d3a5c82 3716VariableCommonInitialize (\r
8a2d4996 3717 VOID\r
8d3a5c82 3718 )\r
8d3a5c82 3719{\r
1436aea4
MK
3720 EFI_STATUS Status;\r
3721 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
3722 UINTN ScratchSize;\r
3723 EFI_GUID *VariableGuid;\r
8d3a5c82 3724\r
7800593d
LG
3725 //\r
3726 // Allocate runtime memory for variable driver global structure.\r
3727 //\r
72399dae 3728 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
7800593d
LG
3729 if (mVariableModuleGlobal == NULL) {\r
3730 return EFI_OUT_OF_RESOURCES;\r
3731 }\r
8d3a5c82 3732\r
8a2d4996 3733 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
8d3a5c82 3734\r
fa0737a8
SZ
3735 //\r
3736 // Init non-volatile variable store.\r
3737 //\r
701d603f 3738 Status = InitNonVolatileVariableStore ();\r
fa0737a8
SZ
3739 if (EFI_ERROR (Status)) {\r
3740 FreePool (mVariableModuleGlobal);\r
3741 return Status;\r
3742 }\r
3743\r
3744 //\r
3745 // mVariableModuleGlobal->VariableGlobal.AuthFormat\r
3746 // has been initialized in InitNonVolatileVariableStore().\r
3747 //\r
3748 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {\r
87000d77 3749 DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable format!\n"));\r
fa0737a8
SZ
3750 //\r
3751 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.\r
3752 //\r
3753 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;\r
1436aea4 3754 VariableGuid = &gEfiAuthenticatedVariableGuid;\r
fa0737a8 3755 } else {\r
87000d77 3756 DEBUG ((DEBUG_INFO, "Variable driver will work without auth variable support!\n"));\r
fa0737a8 3757 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;\r
1436aea4 3758 VariableGuid = &gEfiVariableGuid;\r
fa0737a8
SZ
3759 }\r
3760\r
0f7aff72
RN
3761 //\r
3762 // Get HOB variable store.\r
3763 //\r
09808bd3
SZ
3764 Status = GetHobVariableStore (VariableGuid);\r
3765 if (EFI_ERROR (Status)) {\r
701d603f
SZ
3766 if (mNvFvHeaderCache != NULL) {\r
3767 FreePool (mNvFvHeaderCache);\r
3768 }\r
1436aea4 3769\r
09808bd3
SZ
3770 FreePool (mVariableModuleGlobal);\r
3771 return Status;\r
0f7aff72
RN
3772 }\r
3773\r
9b4a2032
LE
3774 mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?\r
3775 PcdGet32 (PcdMaxVolatileVariableSize) :\r
3776 mVariableModuleGlobal->MaxVariableSize\r
3777 );\r
8d3a5c82 3778 //\r
2fcdca1d 3779 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
8d3a5c82 3780 //\r
1436aea4 3781 ScratchSize = GetMaxVariableSize ();\r
fa0737a8 3782 mVariableModuleGlobal->ScratchBufferSize = ScratchSize;\r
1436aea4 3783 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
8d3a5c82 3784 if (VolatileVariableStore == NULL) {\r
3e02ebb2 3785 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
1436aea4 3786 FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
3e02ebb2 3787 }\r
1436aea4 3788\r
701d603f
SZ
3789 if (mNvFvHeaderCache != NULL) {\r
3790 FreePool (mNvFvHeaderCache);\r
3791 }\r
1436aea4 3792\r
8d3a5c82 3793 FreePool (mVariableModuleGlobal);\r
3794 return EFI_OUT_OF_RESOURCES;\r
3795 }\r
3796\r
188e4e84 3797 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
8d3a5c82 3798\r
3799 //\r
8a2d4996 3800 // Initialize Variable Specific Data.\r
8d3a5c82 3801 //\r
1436aea4
MK
3802 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VolatileVariableStore;\r
3803 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN)GetStartPointer (VolatileVariableStore) - (UINTN)VolatileVariableStore;\r
8d3a5c82 3804\r
fa0737a8 3805 CopyGuid (&VolatileVariableStore->Signature, VariableGuid);\r
1436aea4
MK
3806 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
3807 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
3808 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
3809 VolatileVariableStore->Reserved = 0;\r
3810 VolatileVariableStore->Reserved1 = 0;\r
8d3a5c82 3811\r
fa0737a8 3812 return EFI_SUCCESS;\r
8d3a5c82 3813}\r
052ad7e1 3814\r
aa75dfec 3815/**\r
8a2d4996 3816 Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
aa75dfec 3817\r
fa0737a8 3818 @param[in] Address The Flash address.\r
8a2d4996 3819 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.\r
3820 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.\r
aa75dfec 3821\r
aa75dfec 3822**/\r
8a2d4996 3823EFI_STATUS\r
3824GetFvbInfoByAddress (\r
3825 IN EFI_PHYSICAL_ADDRESS Address,\r
3826 OUT EFI_HANDLE *FvbHandle OPTIONAL,\r
3827 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL\r
8a9e0b72 3828 )\r
3829{\r
1436aea4
MK
3830 EFI_STATUS Status;\r
3831 EFI_HANDLE *HandleBuffer;\r
3832 UINTN HandleCount;\r
3833 UINTN Index;\r
3834 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
3835 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
3836 EFI_FVB_ATTRIBUTES_2 Attributes;\r
3837 UINTN BlockSize;\r
3838 UINTN NumberOfBlocks;\r
1fcbeaea 3839\r
4e1005ec 3840 HandleBuffer = NULL;\r
8a9e0b72 3841 //\r
8a2d4996 3842 // Get all FVB handles.\r
8a9e0b72 3843 //\r
8a2d4996 3844 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
8a9e0b72 3845 if (EFI_ERROR (Status)) {\r
8a2d4996 3846 return EFI_NOT_FOUND;\r
8a9e0b72 3847 }\r
8a2d4996 3848\r
8a9e0b72 3849 //\r
8a2d4996 3850 // Get the FVB to access variable store.\r
8a9e0b72 3851 //\r
8a2d4996 3852 Fvb = NULL;\r
f0480ecf 3853 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
8a2d4996 3854 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
8a9e0b72 3855 if (EFI_ERROR (Status)) {\r
3856 Status = EFI_NOT_FOUND;\r
3857 break;\r
3858 }\r
3859\r
3860 //\r
3861 // Ensure this FVB protocol supported Write operation.\r
3862 //\r
3863 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
3864 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
1fcbeaea 3865 continue;\r
8a9e0b72 3866 }\r
1fcbeaea 3867\r
8a9e0b72 3868 //\r
8a2d4996 3869 // Compare the address and select the right one.\r
8a9e0b72 3870 //\r
3871 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
3872 if (EFI_ERROR (Status)) {\r
3873 continue;\r
3874 }\r
3875\r
1fcbeaea
DG
3876 //\r
3877 // Assume one FVB has one type of BlockSize.\r
3878 //\r
3879 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);\r
3880 if (EFI_ERROR (Status)) {\r
3881 continue;\r
3882 }\r
3883\r
3884 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {\r
8a2d4996 3885 if (FvbHandle != NULL) {\r
1436aea4 3886 *FvbHandle = HandleBuffer[Index];\r
8a2d4996 3887 }\r
1436aea4 3888\r
8a2d4996 3889 if (FvbProtocol != NULL) {\r
3890 *FvbProtocol = Fvb;\r
3891 }\r
1436aea4 3892\r
8a2d4996 3893 Status = EFI_SUCCESS;\r
8a9e0b72 3894 break;\r
3895 }\r
3896 }\r
1436aea4 3897\r
8a9e0b72 3898 FreePool (HandleBuffer);\r
533020ef 3899\r
8a2d4996 3900 if (Fvb == NULL) {\r
3901 Status = EFI_NOT_FOUND;\r
8a9e0b72 3902 }\r
fa0737a8
SZ
3903\r
3904 return Status;\r
052ad7e1 3905}\r