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