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