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