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