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