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