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