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