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