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