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