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