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