]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Variable/Pei/Variable.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / Pei / Variable.c
... / ...
CommitLineData
1/** @file\r
2 Implement ReadOnly Variable Services required by PEIM and install\r
3 PEI ReadOnly Varaiable2 PPI. These services operates the non volatile storage space.\r
4\r
5Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
6Copyright (c) Microsoft Corporation.<BR>\r
7SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include "Variable.h"\r
12\r
13//\r
14// Module globals\r
15//\r
16EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {\r
17 PeiGetVariable,\r
18 PeiGetNextVariableName\r
19};\r
20\r
21EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {\r
22 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
23 &gEfiPeiReadOnlyVariable2PpiGuid,\r
24 &mVariablePpi\r
25};\r
26\r
27/**\r
28 Provide the functionality of the variable services.\r
29\r
30 @param FileHandle Handle of the file being invoked.\r
31 Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().\r
32 @param PeiServices General purpose services available to every PEIM.\r
33\r
34 @retval EFI_SUCCESS If the interface could be successfully installed\r
35 @retval Others Returned from PeiServicesInstallPpi()\r
36**/\r
37EFI_STATUS\r
38EFIAPI\r
39PeimInitializeVariableServices (\r
40 IN EFI_PEI_FILE_HANDLE FileHandle,\r
41 IN CONST EFI_PEI_SERVICES **PeiServices\r
42 )\r
43{\r
44 return PeiServicesInstallPpi (&mPpiListVariable);\r
45}\r
46\r
47/**\r
48\r
49 Gets the pointer to the first variable header in given variable store area.\r
50\r
51 @param VarStoreHeader Pointer to the Variable Store Header.\r
52\r
53 @return Pointer to the first variable header.\r
54\r
55**/\r
56VARIABLE_HEADER *\r
57GetStartPointer (\r
58 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
59 )\r
60{\r
61 //\r
62 // The start of variable store\r
63 //\r
64 return (VARIABLE_HEADER *)HEADER_ALIGN (VarStoreHeader + 1);\r
65}\r
66\r
67/**\r
68\r
69 Gets the pointer to the end of the variable storage area.\r
70\r
71 This function gets pointer to the end of the variable storage\r
72 area, according to the input variable store header.\r
73\r
74 @param VarStoreHeader Pointer to the Variable Store Header.\r
75\r
76 @return Pointer to the end of the variable storage area.\r
77\r
78**/\r
79VARIABLE_HEADER *\r
80GetEndPointer (\r
81 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
82 )\r
83{\r
84 //\r
85 // The end of variable store\r
86 //\r
87 return (VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)VarStoreHeader + VarStoreHeader->Size);\r
88}\r
89\r
90/**\r
91 This code checks if variable header is valid or not.\r
92\r
93 @param Variable Pointer to the Variable Header.\r
94\r
95 @retval TRUE Variable header is valid.\r
96 @retval FALSE Variable header is not valid.\r
97\r
98**/\r
99BOOLEAN\r
100IsValidVariableHeader (\r
101 IN VARIABLE_HEADER *Variable\r
102 )\r
103{\r
104 if ((Variable == NULL) || (Variable->StartId != VARIABLE_DATA)) {\r
105 return FALSE;\r
106 }\r
107\r
108 return TRUE;\r
109}\r
110\r
111/**\r
112 This code gets the size of variable header.\r
113\r
114 @param AuthFlag Authenticated variable flag.\r
115\r
116 @return Size of variable header in bytes in type UINTN.\r
117\r
118**/\r
119UINTN\r
120GetVariableHeaderSize (\r
121 IN BOOLEAN AuthFlag\r
122 )\r
123{\r
124 UINTN Value;\r
125\r
126 if (AuthFlag) {\r
127 Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);\r
128 } else {\r
129 Value = sizeof (VARIABLE_HEADER);\r
130 }\r
131\r
132 return Value;\r
133}\r
134\r
135/**\r
136 This code gets the size of name of variable.\r
137\r
138 @param Variable Pointer to the Variable Header.\r
139 @param AuthFlag Authenticated variable flag.\r
140\r
141 @return Size of variable in bytes in type UINTN.\r
142\r
143**/\r
144UINTN\r
145NameSizeOfVariable (\r
146 IN VARIABLE_HEADER *Variable,\r
147 IN BOOLEAN AuthFlag\r
148 )\r
149{\r
150 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;\r
151\r
152 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;\r
153 if (AuthFlag) {\r
154 if ((AuthVariable->State == (UINT8)(-1)) ||\r
155 (AuthVariable->DataSize == (UINT32)(-1)) ||\r
156 (AuthVariable->NameSize == (UINT32)(-1)) ||\r
157 (AuthVariable->Attributes == (UINT32)(-1)))\r
158 {\r
159 return 0;\r
160 }\r
161\r
162 return (UINTN)AuthVariable->NameSize;\r
163 } else {\r
164 if ((Variable->State == (UINT8)(-1)) ||\r
165 (Variable->DataSize == (UINT32)(-1)) ||\r
166 (Variable->NameSize == (UINT32)(-1)) ||\r
167 (Variable->Attributes == (UINT32)(-1)))\r
168 {\r
169 return 0;\r
170 }\r
171\r
172 return (UINTN)Variable->NameSize;\r
173 }\r
174}\r
175\r
176/**\r
177 This code gets the size of data of variable.\r
178\r
179 @param Variable Pointer to the Variable Header.\r
180 @param AuthFlag Authenticated variable flag.\r
181\r
182 @return Size of variable in bytes in type UINTN.\r
183\r
184**/\r
185UINTN\r
186DataSizeOfVariable (\r
187 IN VARIABLE_HEADER *Variable,\r
188 IN BOOLEAN AuthFlag\r
189 )\r
190{\r
191 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;\r
192\r
193 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;\r
194 if (AuthFlag) {\r
195 if ((AuthVariable->State == (UINT8)(-1)) ||\r
196 (AuthVariable->DataSize == (UINT32)(-1)) ||\r
197 (AuthVariable->NameSize == (UINT32)(-1)) ||\r
198 (AuthVariable->Attributes == (UINT32)(-1)))\r
199 {\r
200 return 0;\r
201 }\r
202\r
203 return (UINTN)AuthVariable->DataSize;\r
204 } else {\r
205 if ((Variable->State == (UINT8)(-1)) ||\r
206 (Variable->DataSize == (UINT32)(-1)) ||\r
207 (Variable->NameSize == (UINT32)(-1)) ||\r
208 (Variable->Attributes == (UINT32)(-1)))\r
209 {\r
210 return 0;\r
211 }\r
212\r
213 return (UINTN)Variable->DataSize;\r
214 }\r
215}\r
216\r
217/**\r
218 This code gets the pointer to the variable name.\r
219\r
220 @param Variable Pointer to the Variable Header.\r
221 @param AuthFlag Authenticated variable flag.\r
222\r
223 @return A CHAR16* pointer to Variable Name.\r
224\r
225**/\r
226CHAR16 *\r
227GetVariableNamePtr (\r
228 IN VARIABLE_HEADER *Variable,\r
229 IN BOOLEAN AuthFlag\r
230 )\r
231{\r
232 return (CHAR16 *)((UINTN)Variable + GetVariableHeaderSize (AuthFlag));\r
233}\r
234\r
235/**\r
236 This code gets the pointer to the variable guid.\r
237\r
238 @param Variable Pointer to the Variable Header.\r
239 @param AuthFlag Authenticated variable flag.\r
240\r
241 @return A EFI_GUID* pointer to Vendor Guid.\r
242\r
243**/\r
244EFI_GUID *\r
245GetVendorGuidPtr (\r
246 IN VARIABLE_HEADER *Variable,\r
247 IN BOOLEAN AuthFlag\r
248 )\r
249{\r
250 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;\r
251\r
252 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *)Variable;\r
253 if (AuthFlag) {\r
254 return &AuthVariable->VendorGuid;\r
255 } else {\r
256 return &Variable->VendorGuid;\r
257 }\r
258}\r
259\r
260/**\r
261 This code gets the pointer to the variable data.\r
262\r
263 @param Variable Pointer to the Variable Header.\r
264 @param VariableHeader Pointer to the Variable Header that has consecutive content.\r
265 @param AuthFlag Authenticated variable flag.\r
266\r
267 @return A UINT8* pointer to Variable Data.\r
268\r
269**/\r
270UINT8 *\r
271GetVariableDataPtr (\r
272 IN VARIABLE_HEADER *Variable,\r
273 IN VARIABLE_HEADER *VariableHeader,\r
274 IN BOOLEAN AuthFlag\r
275 )\r
276{\r
277 UINTN Value;\r
278\r
279 //\r
280 // Be careful about pad size for alignment\r
281 //\r
282 Value = (UINTN)GetVariableNamePtr (Variable, AuthFlag);\r
283 Value += NameSizeOfVariable (VariableHeader, AuthFlag);\r
284 Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader, AuthFlag));\r
285\r
286 return (UINT8 *)Value;\r
287}\r
288\r
289/**\r
290 This code gets the pointer to the next variable header.\r
291\r
292 @param StoreInfo Pointer to variable store info structure.\r
293 @param Variable Pointer to the Variable Header.\r
294 @param VariableHeader Pointer to the Variable Header that has consecutive content.\r
295\r
296 @return A VARIABLE_HEADER* pointer to next variable header.\r
297\r
298**/\r
299VARIABLE_HEADER *\r
300GetNextVariablePtr (\r
301 IN VARIABLE_STORE_INFO *StoreInfo,\r
302 IN VARIABLE_HEADER *Variable,\r
303 IN VARIABLE_HEADER *VariableHeader\r
304 )\r
305{\r
306 EFI_PHYSICAL_ADDRESS TargetAddress;\r
307 EFI_PHYSICAL_ADDRESS SpareAddress;\r
308 UINTN Value;\r
309\r
310 Value = (UINTN)GetVariableDataPtr (Variable, VariableHeader, StoreInfo->AuthFlag);\r
311 Value += DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag);\r
312 Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader, StoreInfo->AuthFlag));\r
313 //\r
314 // Be careful about pad size for alignment\r
315 //\r
316 Value = HEADER_ALIGN (Value);\r
317\r
318 if (StoreInfo->FtwLastWriteData != NULL) {\r
319 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
320 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
321 if (((UINTN)Variable < (UINTN)TargetAddress) && (Value >= (UINTN)TargetAddress)) {\r
322 //\r
323 // Next variable is in spare block.\r
324 //\r
325 Value = (UINTN)SpareAddress + (Value - (UINTN)TargetAddress);\r
326 }\r
327 }\r
328\r
329 return (VARIABLE_HEADER *)Value;\r
330}\r
331\r
332/**\r
333 Get variable store status.\r
334\r
335 @param VarStoreHeader Pointer to the Variable Store Header.\r
336\r
337 @retval EfiRaw Variable store is raw\r
338 @retval EfiValid Variable store is valid\r
339 @retval EfiInvalid Variable store is invalid\r
340\r
341**/\r
342VARIABLE_STORE_STATUS\r
343GetVariableStoreStatus (\r
344 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
345 )\r
346{\r
347 if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||\r
348 CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&\r
349 (VarStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&\r
350 (VarStoreHeader->State == VARIABLE_STORE_HEALTHY)\r
351 )\r
352 {\r
353 return EfiValid;\r
354 }\r
355\r
356 if ((((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff) &&\r
357 (((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff) &&\r
358 (((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff) &&\r
359 (((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff) &&\r
360 (VarStoreHeader->Size == 0xffffffff) &&\r
361 (VarStoreHeader->Format == 0xff) &&\r
362 (VarStoreHeader->State == 0xff)\r
363 )\r
364 {\r
365 return EfiRaw;\r
366 } else {\r
367 return EfiInvalid;\r
368 }\r
369}\r
370\r
371/**\r
372 Compare two variable names, one of them may be inconsecutive.\r
373\r
374 @param StoreInfo Pointer to variable store info structure.\r
375 @param Name1 Pointer to one variable name.\r
376 @param Name2 Pointer to another variable name.\r
377 @param NameSize Variable name size.\r
378\r
379 @retval TRUE Name1 and Name2 are identical.\r
380 @retval FALSE Name1 and Name2 are not identical.\r
381\r
382**/\r
383BOOLEAN\r
384CompareVariableName (\r
385 IN VARIABLE_STORE_INFO *StoreInfo,\r
386 IN CONST CHAR16 *Name1,\r
387 IN CONST CHAR16 *Name2,\r
388 IN UINTN NameSize\r
389 )\r
390{\r
391 EFI_PHYSICAL_ADDRESS TargetAddress;\r
392 EFI_PHYSICAL_ADDRESS SpareAddress;\r
393 UINTN PartialNameSize;\r
394\r
395 if (StoreInfo->FtwLastWriteData != NULL) {\r
396 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
397 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
398 if (((UINTN)Name1 < (UINTN)TargetAddress) && (((UINTN)Name1 + NameSize) > (UINTN)TargetAddress)) {\r
399 //\r
400 // Name1 is inconsecutive.\r
401 //\r
402 PartialNameSize = (UINTN)TargetAddress - (UINTN)Name1;\r
403 //\r
404 // Partial content is in NV storage.\r
405 //\r
406 if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, PartialNameSize) == 0) {\r
407 //\r
408 // Another partial content is in spare block.\r
409 //\r
410 if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {\r
411 return TRUE;\r
412 }\r
413 }\r
414\r
415 return FALSE;\r
416 } else if (((UINTN)Name2 < (UINTN)TargetAddress) && (((UINTN)Name2 + NameSize) > (UINTN)TargetAddress)) {\r
417 //\r
418 // Name2 is inconsecutive.\r
419 //\r
420 PartialNameSize = (UINTN)TargetAddress - (UINTN)Name2;\r
421 //\r
422 // Partial content is in NV storage.\r
423 //\r
424 if (CompareMem ((UINT8 *)Name2, (UINT8 *)Name1, PartialNameSize) == 0) {\r
425 //\r
426 // Another partial content is in spare block.\r
427 //\r
428 if (CompareMem ((UINT8 *)(UINTN)SpareAddress, (UINT8 *)Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {\r
429 return TRUE;\r
430 }\r
431 }\r
432\r
433 return FALSE;\r
434 }\r
435 }\r
436\r
437 //\r
438 // Both Name1 and Name2 are consecutive.\r
439 //\r
440 if (CompareMem ((UINT8 *)Name1, (UINT8 *)Name2, NameSize) == 0) {\r
441 return TRUE;\r
442 }\r
443\r
444 return FALSE;\r
445}\r
446\r
447/**\r
448 This function compares a variable with variable entries in database.\r
449\r
450 @param StoreInfo Pointer to variable store info structure.\r
451 @param Variable Pointer to the variable in our database\r
452 @param VariableHeader Pointer to the Variable Header that has consecutive content.\r
453 @param VariableName Name of the variable to compare to 'Variable'\r
454 @param VendorGuid GUID of the variable to compare to 'Variable'\r
455 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
456\r
457 @retval EFI_SUCCESS Found match variable\r
458 @retval EFI_NOT_FOUND Variable not found\r
459\r
460**/\r
461EFI_STATUS\r
462CompareWithValidVariable (\r
463 IN VARIABLE_STORE_INFO *StoreInfo,\r
464 IN VARIABLE_HEADER *Variable,\r
465 IN VARIABLE_HEADER *VariableHeader,\r
466 IN CONST CHAR16 *VariableName,\r
467 IN CONST EFI_GUID *VendorGuid,\r
468 OUT VARIABLE_POINTER_TRACK *PtrTrack\r
469 )\r
470{\r
471 VOID *Point;\r
472 EFI_GUID *TempVendorGuid;\r
473\r
474 TempVendorGuid = GetVendorGuidPtr (VariableHeader, StoreInfo->AuthFlag);\r
475\r
476 if (VariableName[0] == 0) {\r
477 PtrTrack->CurrPtr = Variable;\r
478 return EFI_SUCCESS;\r
479 } else {\r
480 //\r
481 // Don't use CompareGuid function here for performance reasons.\r
482 // Instead we compare the GUID a UINT32 at a time and branch\r
483 // on the first failed comparison.\r
484 //\r
485 if ((((INT32 *)VendorGuid)[0] == ((INT32 *)TempVendorGuid)[0]) &&\r
486 (((INT32 *)VendorGuid)[1] == ((INT32 *)TempVendorGuid)[1]) &&\r
487 (((INT32 *)VendorGuid)[2] == ((INT32 *)TempVendorGuid)[2]) &&\r
488 (((INT32 *)VendorGuid)[3] == ((INT32 *)TempVendorGuid)[3])\r
489 )\r
490 {\r
491 ASSERT (NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag) != 0);\r
492 Point = (VOID *)GetVariableNamePtr (Variable, StoreInfo->AuthFlag);\r
493 if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader, StoreInfo->AuthFlag))) {\r
494 PtrTrack->CurrPtr = Variable;\r
495 return EFI_SUCCESS;\r
496 }\r
497 }\r
498 }\r
499\r
500 return EFI_NOT_FOUND;\r
501}\r
502\r
503/**\r
504 Get HOB variable store.\r
505\r
506 @param[out] StoreInfo Return the store info.\r
507 @param[out] VariableStoreHeader Return variable store header.\r
508\r
509**/\r
510VOID\r
511GetHobVariableStore (\r
512 OUT VARIABLE_STORE_INFO *StoreInfo,\r
513 OUT VARIABLE_STORE_HEADER **VariableStoreHeader\r
514 )\r
515{\r
516 EFI_HOB_GUID_TYPE *GuidHob;\r
517\r
518 //\r
519 // Make sure there is no more than one Variable HOB.\r
520 //\r
521 DEBUG_CODE_BEGIN ();\r
522 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
523 if (GuidHob != NULL) {\r
524 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
525 DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));\r
526 ASSERT (FALSE);\r
527 } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {\r
528 DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));\r
529 ASSERT (FALSE);\r
530 }\r
531 } else {\r
532 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
533 if (GuidHob != NULL) {\r
534 if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
535 DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));\r
536 ASSERT (FALSE);\r
537 }\r
538 }\r
539 }\r
540\r
541 DEBUG_CODE_END ();\r
542\r
543 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
544 if (GuidHob != NULL) {\r
545 *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);\r
546 StoreInfo->AuthFlag = TRUE;\r
547 } else {\r
548 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
549 if (GuidHob != NULL) {\r
550 *VariableStoreHeader = (VARIABLE_STORE_HEADER *)GET_GUID_HOB_DATA (GuidHob);\r
551 StoreInfo->AuthFlag = FALSE;\r
552 }\r
553 }\r
554}\r
555\r
556/**\r
557 Return the variable store header and the store info based on the Index.\r
558\r
559 @param Type The type of the variable store.\r
560 @param StoreInfo Return the store info.\r
561\r
562 @return Pointer to the variable store header.\r
563**/\r
564VARIABLE_STORE_HEADER *\r
565GetVariableStore (\r
566 IN VARIABLE_STORE_TYPE Type,\r
567 OUT VARIABLE_STORE_INFO *StoreInfo\r
568 )\r
569{\r
570 EFI_STATUS Status;\r
571 EFI_HOB_GUID_TYPE *GuidHob;\r
572 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
573 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
574 EFI_PHYSICAL_ADDRESS NvStorageBase;\r
575 UINT32 NvStorageSize;\r
576 UINT64 NvStorageSize64;\r
577 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
578 UINT32 BackUpOffset;\r
579\r
580 StoreInfo->IndexTable = NULL;\r
581 StoreInfo->FtwLastWriteData = NULL;\r
582 StoreInfo->AuthFlag = FALSE;\r
583 VariableStoreHeader = NULL;\r
584 switch (Type) {\r
585 case VariableStoreTypeHob:\r
586 GetHobVariableStore (StoreInfo, &VariableStoreHeader);\r
587\r
588 break;\r
589\r
590 case VariableStoreTypeNv:\r
591 if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
592 //\r
593 // Emulated non-volatile variable mode is not enabled.\r
594 //\r
595\r
596 Status = GetVariableFlashNvStorageInfo (&NvStorageBase, &NvStorageSize64);\r
597 ASSERT_EFI_ERROR (Status);\r
598\r
599 Status = SafeUint64ToUint32 (NvStorageSize64, &NvStorageSize);\r
600 // This driver currently assumes the size will be UINT32 so assert the value is safe for now.\r
601 ASSERT_EFI_ERROR (Status);\r
602\r
603 ASSERT (NvStorageBase != 0);\r
604\r
605 //\r
606 // First let FvHeader point to NV storage base.\r
607 //\r
608 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)NvStorageBase;\r
609\r
610 //\r
611 // Check the FTW last write data hob.\r
612 //\r
613 BackUpOffset = 0;\r
614 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
615 if (GuidHob != NULL) {\r
616 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);\r
617 if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
618 //\r
619 // Let FvHeader point to spare block.\r
620 //\r
621 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FtwLastWriteData->SpareAddress;\r
622 DEBUG ((DEBUG_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));\r
623 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
624 StoreInfo->FtwLastWriteData = FtwLastWriteData;\r
625 //\r
626 // Flash NV storage from the offset is backed up in spare block.\r
627 //\r
628 BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);\r
629 DEBUG ((DEBUG_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN)FtwLastWriteData->SpareAddress));\r
630 //\r
631 // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.\r
632 //\r
633 }\r
634 }\r
635\r
636 //\r
637 // Check if the Firmware Volume is not corrupted\r
638 //\r
639 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
640 DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
641 break;\r
642 }\r
643\r
644 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINT8 *)FvHeader + FvHeader->HeaderLength);\r
645\r
646 StoreInfo->AuthFlag = (BOOLEAN)(CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));\r
647\r
648 GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);\r
649 if (GuidHob != NULL) {\r
650 StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);\r
651 } else {\r
652 //\r
653 // If it's the first time to access variable region in flash, create a guid hob to record\r
654 // VAR_ADDED type variable info.\r
655 // Note that as the resource of PEI phase is limited, only store the limited number of\r
656 // VAR_ADDED type variables to reduce access time.\r
657 //\r
658 StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *)BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));\r
659 StoreInfo->IndexTable->Length = 0;\r
660 StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);\r
661 StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);\r
662 StoreInfo->IndexTable->GoneThrough = 0;\r
663 }\r
664 }\r
665\r
666 break;\r
667\r
668 default:\r
669 ASSERT (FALSE);\r
670 break;\r
671 }\r
672\r
673 StoreInfo->VariableStoreHeader = VariableStoreHeader;\r
674 return VariableStoreHeader;\r
675}\r
676\r
677/**\r
678 Get variable header that has consecutive content.\r
679\r
680 @param StoreInfo Pointer to variable store info structure.\r
681 @param Variable Pointer to the Variable Header.\r
682 @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.\r
683\r
684 @retval TRUE Variable header is valid.\r
685 @retval FALSE Variable header is not valid.\r
686\r
687**/\r
688BOOLEAN\r
689GetVariableHeader (\r
690 IN VARIABLE_STORE_INFO *StoreInfo,\r
691 IN VARIABLE_HEADER *Variable,\r
692 OUT VARIABLE_HEADER **VariableHeader\r
693 )\r
694{\r
695 EFI_PHYSICAL_ADDRESS TargetAddress;\r
696 EFI_PHYSICAL_ADDRESS SpareAddress;\r
697 EFI_HOB_GUID_TYPE *GuidHob;\r
698 UINTN PartialHeaderSize;\r
699\r
700 if (Variable == NULL) {\r
701 return FALSE;\r
702 }\r
703\r
704 //\r
705 // First assume variable header pointed by Variable is consecutive.\r
706 //\r
707 *VariableHeader = Variable;\r
708\r
709 if (StoreInfo->FtwLastWriteData != NULL) {\r
710 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
711 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
712 if (((UINTN)Variable > (UINTN)SpareAddress) &&\r
713 (((UINTN)Variable - (UINTN)SpareAddress + (UINTN)TargetAddress) >= (UINTN)GetEndPointer (StoreInfo->VariableStoreHeader)))\r
714 {\r
715 //\r
716 // Reach the end of variable store.\r
717 //\r
718 return FALSE;\r
719 }\r
720\r
721 if (((UINTN)Variable < (UINTN)TargetAddress) && (((UINTN)Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN)TargetAddress)) {\r
722 //\r
723 // Variable header pointed by Variable is inconsecutive,\r
724 // create a guid hob to combine the two partial variable header content together.\r
725 //\r
726 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
727 if (GuidHob != NULL) {\r
728 *VariableHeader = (VARIABLE_HEADER *)GET_GUID_HOB_DATA (GuidHob);\r
729 } else {\r
730 *VariableHeader = (VARIABLE_HEADER *)BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));\r
731 PartialHeaderSize = (UINTN)TargetAddress - (UINTN)Variable;\r
732 //\r
733 // Partial content is in NV storage.\r
734 //\r
735 CopyMem ((UINT8 *)*VariableHeader, (UINT8 *)Variable, PartialHeaderSize);\r
736 //\r
737 // Another partial content is in spare block.\r
738 //\r
739 CopyMem ((UINT8 *)*VariableHeader + PartialHeaderSize, (UINT8 *)(UINTN)SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);\r
740 }\r
741 }\r
742 } else {\r
743 if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {\r
744 //\r
745 // Reach the end of variable store.\r
746 //\r
747 return FALSE;\r
748 }\r
749 }\r
750\r
751 return IsValidVariableHeader (*VariableHeader);\r
752}\r
753\r
754/**\r
755 Get variable name or data to output buffer.\r
756\r
757 @param StoreInfo Pointer to variable store info structure.\r
758 @param NameOrData Pointer to the variable name/data that may be inconsecutive.\r
759 @param Size Variable name/data size.\r
760 @param Buffer Pointer to output buffer to hold the variable name/data.\r
761\r
762**/\r
763VOID\r
764GetVariableNameOrData (\r
765 IN VARIABLE_STORE_INFO *StoreInfo,\r
766 IN UINT8 *NameOrData,\r
767 IN UINTN Size,\r
768 OUT UINT8 *Buffer\r
769 )\r
770{\r
771 EFI_PHYSICAL_ADDRESS TargetAddress;\r
772 EFI_PHYSICAL_ADDRESS SpareAddress;\r
773 UINTN PartialSize;\r
774\r
775 if (StoreInfo->FtwLastWriteData != NULL) {\r
776 TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
777 SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
778 if (((UINTN)NameOrData < (UINTN)TargetAddress) && (((UINTN)NameOrData + Size) > (UINTN)TargetAddress)) {\r
779 //\r
780 // Variable name/data is inconsecutive.\r
781 //\r
782 PartialSize = (UINTN)TargetAddress - (UINTN)NameOrData;\r
783 //\r
784 // Partial content is in NV storage.\r
785 //\r
786 CopyMem (Buffer, NameOrData, PartialSize);\r
787 //\r
788 // Another partial content is in spare block.\r
789 //\r
790 CopyMem (Buffer + PartialSize, (UINT8 *)(UINTN)SpareAddress, Size - PartialSize);\r
791 return;\r
792 }\r
793 }\r
794\r
795 //\r
796 // Variable name/data is consecutive.\r
797 //\r
798 CopyMem (Buffer, NameOrData, Size);\r
799}\r
800\r
801/**\r
802 Find the variable in the specified variable store.\r
803\r
804 @param StoreInfo Pointer to the store info structure.\r
805 @param VariableName Name of the variable to be found\r
806 @param VendorGuid Vendor GUID to be found.\r
807 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
808\r
809 @retval EFI_SUCCESS Variable found successfully\r
810 @retval EFI_NOT_FOUND Variable not found\r
811 @retval EFI_INVALID_PARAMETER Invalid variable name\r
812\r
813**/\r
814EFI_STATUS\r
815FindVariableEx (\r
816 IN VARIABLE_STORE_INFO *StoreInfo,\r
817 IN CONST CHAR16 *VariableName,\r
818 IN CONST EFI_GUID *VendorGuid,\r
819 OUT VARIABLE_POINTER_TRACK *PtrTrack\r
820 )\r
821{\r
822 VARIABLE_HEADER *Variable;\r
823 VARIABLE_HEADER *LastVariable;\r
824 VARIABLE_HEADER *MaxIndex;\r
825 UINTN Index;\r
826 UINTN Offset;\r
827 BOOLEAN StopRecord;\r
828 VARIABLE_HEADER *InDeletedVariable;\r
829 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
830 VARIABLE_INDEX_TABLE *IndexTable;\r
831 VARIABLE_HEADER *VariableHeader;\r
832\r
833 VariableStoreHeader = StoreInfo->VariableStoreHeader;\r
834\r
835 if (VariableStoreHeader == NULL) {\r
836 return EFI_INVALID_PARAMETER;\r
837 }\r
838\r
839 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
840 return EFI_UNSUPPORTED;\r
841 }\r
842\r
843 if (~VariableStoreHeader->Size == 0) {\r
844 return EFI_NOT_FOUND;\r
845 }\r
846\r
847 IndexTable = StoreInfo->IndexTable;\r
848 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);\r
849 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);\r
850\r
851 InDeletedVariable = NULL;\r
852\r
853 //\r
854 // No Variable Address equals zero, so 0 as initial value is safe.\r
855 //\r
856 MaxIndex = NULL;\r
857 VariableHeader = NULL;\r
858\r
859 if (IndexTable != NULL) {\r
860 //\r
861 // traverse the variable index table to look for varible.\r
862 // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.\r
863 //\r
864 for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {\r
865 ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));\r
866 Offset += IndexTable->Index[Index];\r
867 MaxIndex = (VARIABLE_HEADER *)((UINT8 *)IndexTable->StartPtr + Offset);\r
868 GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);\r
869 if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
870 if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
871 InDeletedVariable = PtrTrack->CurrPtr;\r
872 } else {\r
873 return EFI_SUCCESS;\r
874 }\r
875 }\r
876 }\r
877\r
878 if (IndexTable->GoneThrough != 0) {\r
879 //\r
880 // If the table has all the existing variables indexed, return.\r
881 //\r
882 PtrTrack->CurrPtr = InDeletedVariable;\r
883 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
884 }\r
885 }\r
886\r
887 if (MaxIndex != NULL) {\r
888 //\r
889 // HOB exists but the variable cannot be found in HOB\r
890 // If not found in HOB, then let's start from the MaxIndex we've found.\r
891 //\r
892 Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);\r
893 LastVariable = MaxIndex;\r
894 } else {\r
895 //\r
896 // Start Pointers for the variable.\r
897 // Actual Data Pointer where data can be written.\r
898 //\r
899 Variable = PtrTrack->StartPtr;\r
900 LastVariable = PtrTrack->StartPtr;\r
901 }\r
902\r
903 //\r
904 // Find the variable by walk through variable store\r
905 //\r
906 StopRecord = FALSE;\r
907 while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {\r
908 if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {\r
909 //\r
910 // Record Variable in VariableIndex HOB\r
911 //\r
912 if ((IndexTable != NULL) && !StopRecord) {\r
913 Offset = (UINTN)Variable - (UINTN)LastVariable;\r
914 if ((Offset > 0x0FFFF) || (IndexTable->Length >= sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {\r
915 //\r
916 // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),\r
917 // or the record buffer is full.\r
918 //\r
919 StopRecord = TRUE;\r
920 } else {\r
921 IndexTable->Index[IndexTable->Length++] = (UINT16)Offset;\r
922 LastVariable = Variable;\r
923 }\r
924 }\r
925\r
926 if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
927 if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
928 InDeletedVariable = PtrTrack->CurrPtr;\r
929 } else {\r
930 return EFI_SUCCESS;\r
931 }\r
932 }\r
933 }\r
934\r
935 Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);\r
936 }\r
937\r
938 //\r
939 // If gone through the VariableStore, that means we never find in Firmware any more.\r
940 //\r
941 if ((IndexTable != NULL) && !StopRecord) {\r
942 IndexTable->GoneThrough = 1;\r
943 }\r
944\r
945 PtrTrack->CurrPtr = InDeletedVariable;\r
946\r
947 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
948}\r
949\r
950/**\r
951 Find the variable in HOB and Non-Volatile variable storages.\r
952\r
953 @param VariableName Name of the variable to be found\r
954 @param VendorGuid Vendor GUID to be found.\r
955 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
956 @param StoreInfo Return the store info.\r
957\r
958 @retval EFI_SUCCESS Variable found successfully\r
959 @retval EFI_NOT_FOUND Variable not found\r
960 @retval EFI_INVALID_PARAMETER Invalid variable name\r
961**/\r
962EFI_STATUS\r
963FindVariable (\r
964 IN CONST CHAR16 *VariableName,\r
965 IN CONST EFI_GUID *VendorGuid,\r
966 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
967 OUT VARIABLE_STORE_INFO *StoreInfo\r
968 )\r
969{\r
970 EFI_STATUS Status;\r
971 VARIABLE_STORE_TYPE Type;\r
972\r
973 if ((VariableName[0] != 0) && (VendorGuid == NULL)) {\r
974 return EFI_INVALID_PARAMETER;\r
975 }\r
976\r
977 for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {\r
978 GetVariableStore (Type, StoreInfo);\r
979 Status = FindVariableEx (\r
980 StoreInfo,\r
981 VariableName,\r
982 VendorGuid,\r
983 PtrTrack\r
984 );\r
985 if (!EFI_ERROR (Status)) {\r
986 return Status;\r
987 }\r
988 }\r
989\r
990 return EFI_NOT_FOUND;\r
991}\r
992\r
993/**\r
994 This service retrieves a variable's value using its name and GUID.\r
995\r
996 Read the specified variable from the UEFI variable store. If the Data\r
997 buffer is too small to hold the contents of the variable, the error\r
998 EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer\r
999 size to obtain the data.\r
1000\r
1001 @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
1002 @param VariableName A pointer to a null-terminated string that is the variable's name.\r
1003 @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of\r
1004 VariableGuid and VariableName must be unique.\r
1005 @param Attributes If non-NULL, on return, points to the variable's attributes.\r
1006 @param DataSize On entry, points to the size in bytes of the Data buffer.\r
1007 On return, points to the size of the data returned in Data.\r
1008 @param Data Points to the buffer which will hold the returned variable value.\r
1009 May be NULL with a zero DataSize in order to determine the size of the buffer needed.\r
1010\r
1011 @retval EFI_SUCCESS The variable was read successfully.\r
1012 @retval EFI_NOT_FOUND The variable was be found.\r
1013 @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data.\r
1014 DataSize is updated with the size required for\r
1015 the specified variable.\r
1016 @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.\r
1017 @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.\r
1018\r
1019**/\r
1020EFI_STATUS\r
1021EFIAPI\r
1022PeiGetVariable (\r
1023 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
1024 IN CONST CHAR16 *VariableName,\r
1025 IN CONST EFI_GUID *VariableGuid,\r
1026 OUT UINT32 *Attributes,\r
1027 IN OUT UINTN *DataSize,\r
1028 OUT VOID *Data OPTIONAL\r
1029 )\r
1030{\r
1031 VARIABLE_POINTER_TRACK Variable;\r
1032 UINTN VarDataSize;\r
1033 EFI_STATUS Status;\r
1034 VARIABLE_STORE_INFO StoreInfo;\r
1035 VARIABLE_HEADER *VariableHeader;\r
1036\r
1037 if ((VariableName == NULL) || (VariableGuid == NULL) || (DataSize == NULL)) {\r
1038 return EFI_INVALID_PARAMETER;\r
1039 }\r
1040\r
1041 if (VariableName[0] == 0) {\r
1042 return EFI_NOT_FOUND;\r
1043 }\r
1044\r
1045 VariableHeader = NULL;\r
1046\r
1047 //\r
1048 // Find existing variable\r
1049 //\r
1050 Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);\r
1051 if (EFI_ERROR (Status)) {\r
1052 return Status;\r
1053 }\r
1054\r
1055 GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);\r
1056\r
1057 //\r
1058 // Get data size\r
1059 //\r
1060 VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);\r
1061 if (*DataSize >= VarDataSize) {\r
1062 if (Data == NULL) {\r
1063 return EFI_INVALID_PARAMETER;\r
1064 }\r
1065\r
1066 GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);\r
1067 Status = EFI_SUCCESS;\r
1068 } else {\r
1069 Status = EFI_BUFFER_TOO_SMALL;\r
1070 }\r
1071\r
1072 if (Attributes != NULL) {\r
1073 *Attributes = VariableHeader->Attributes;\r
1074 }\r
1075\r
1076 *DataSize = VarDataSize;\r
1077\r
1078 return Status;\r
1079}\r
1080\r
1081/**\r
1082 Return the next variable name and GUID.\r
1083\r
1084 This function is called multiple times to retrieve the VariableName\r
1085 and VariableGuid of all variables currently available in the system.\r
1086 On each call, the previous results are passed into the interface,\r
1087 and, on return, the interface returns the data for the next\r
1088 interface. When the entire variable list has been returned,\r
1089 EFI_NOT_FOUND is returned.\r
1090\r
1091 @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
1092\r
1093 @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.\r
1094 On return, the size of the variable name buffer.\r
1095 @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.\r
1096 On return, points to the next variable's null-terminated name string.\r
1097 @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID.\r
1098 On return, a pointer to the next variable's GUID.\r
1099\r
1100 @retval EFI_SUCCESS The variable was read successfully.\r
1101 @retval EFI_NOT_FOUND The variable could not be found.\r
1102 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting\r
1103 data. VariableNameSize is updated with the size\r
1104 required for the specified variable.\r
1105 @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or\r
1106 VariableNameSize is NULL.\r
1107 @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.\r
1108\r
1109**/\r
1110EFI_STATUS\r
1111EFIAPI\r
1112PeiGetNextVariableName (\r
1113 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
1114 IN OUT UINTN *VariableNameSize,\r
1115 IN OUT CHAR16 *VariableName,\r
1116 IN OUT EFI_GUID *VariableGuid\r
1117 )\r
1118{\r
1119 VARIABLE_STORE_TYPE Type;\r
1120 VARIABLE_POINTER_TRACK Variable;\r
1121 VARIABLE_POINTER_TRACK VariableInHob;\r
1122 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
1123 UINTN VarNameSize;\r
1124 EFI_STATUS Status;\r
1125 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
1126 VARIABLE_HEADER *VariableHeader;\r
1127 VARIABLE_STORE_INFO StoreInfo;\r
1128 VARIABLE_STORE_INFO StoreInfoForNv;\r
1129 VARIABLE_STORE_INFO StoreInfoForHob;\r
1130\r
1131 if ((VariableName == NULL) || (VariableGuid == NULL) || (VariableNameSize == NULL)) {\r
1132 return EFI_INVALID_PARAMETER;\r
1133 }\r
1134\r
1135 VariableHeader = NULL;\r
1136\r
1137 Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);\r
1138 if ((Variable.CurrPtr == NULL) || (Status != EFI_SUCCESS)) {\r
1139 return Status;\r
1140 }\r
1141\r
1142 if (VariableName[0] != 0) {\r
1143 //\r
1144 // If variable name is not NULL, get next variable\r
1145 //\r
1146 GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);\r
1147 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
1148 }\r
1149\r
1150 VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);\r
1151 VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);\r
1152\r
1153 while (TRUE) {\r
1154 //\r
1155 // Switch from HOB to Non-Volatile.\r
1156 //\r
1157 while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {\r
1158 //\r
1159 // Find current storage index\r
1160 //\r
1161 for (Type = (VARIABLE_STORE_TYPE)0; Type < VariableStoreTypeMax; Type++) {\r
1162 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {\r
1163 break;\r
1164 }\r
1165 }\r
1166\r
1167 ASSERT (Type < VariableStoreTypeMax);\r
1168 //\r
1169 // Switch to next storage\r
1170 //\r
1171 for (Type++; Type < VariableStoreTypeMax; Type++) {\r
1172 if (VariableStoreHeader[Type] != NULL) {\r
1173 break;\r
1174 }\r
1175 }\r
1176\r
1177 //\r
1178 // Capture the case that\r
1179 // 1. current storage is the last one, or\r
1180 // 2. no further storage\r
1181 //\r
1182 if (Type == VariableStoreTypeMax) {\r
1183 return EFI_NOT_FOUND;\r
1184 }\r
1185\r
1186 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
1187 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
1188 Variable.CurrPtr = Variable.StartPtr;\r
1189 GetVariableStore (Type, &StoreInfo);\r
1190 }\r
1191\r
1192 if ((VariableHeader->State == VAR_ADDED) || (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED))) {\r
1193 if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1194 //\r
1195 // If it is a IN_DELETED_TRANSITION variable,\r
1196 // and there is also a same ADDED one at the same time,\r
1197 // don't return it.\r
1198 //\r
1199 Status = FindVariableEx (\r
1200 &StoreInfo,\r
1201 GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),\r
1202 GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),\r
1203 &VariablePtrTrack\r
1204 );\r
1205 if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr != Variable.CurrPtr)) {\r
1206 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
1207 continue;\r
1208 }\r
1209 }\r
1210\r
1211 //\r
1212 // Don't return NV variable when HOB overrides it\r
1213 //\r
1214 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&\r
1215 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))\r
1216 )\r
1217 {\r
1218 Status = FindVariableEx (\r
1219 &StoreInfoForHob,\r
1220 GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),\r
1221 GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),\r
1222 &VariableInHob\r
1223 );\r
1224 if (!EFI_ERROR (Status)) {\r
1225 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
1226 continue;\r
1227 }\r
1228 }\r
1229\r
1230 VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);\r
1231 ASSERT (VarNameSize != 0);\r
1232\r
1233 if (VarNameSize <= *VariableNameSize) {\r
1234 GetVariableNameOrData (&StoreInfo, (UINT8 *)GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *)VariableName);\r
1235\r
1236 CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));\r
1237\r
1238 Status = EFI_SUCCESS;\r
1239 } else {\r
1240 Status = EFI_BUFFER_TOO_SMALL;\r
1241 }\r
1242\r
1243 *VariableNameSize = VarNameSize;\r
1244 //\r
1245 // Variable is found\r
1246 //\r
1247 return Status;\r
1248 } else {\r
1249 Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);\r
1250 }\r
1251 }\r
1252}\r