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