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