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