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
5Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16
17#include "Variable.h"
18
19//
20// Module globals
21//
22EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {
23  PeiGetVariable,
24  PeiGetNextVariableName
25};
26
27EFI_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**/
44EFI_STATUS
45EFIAPI
46PeimInitializeVariableServices (
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**/
63VARIABLE_HEADER *
64GetStartPointer (
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**/
83VARIABLE_HEADER *
84GetEndPointer (
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**/
104BOOLEAN
105IsValidVariableHeader (
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**/
124UINTN
125GetVariableHeaderSize (
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**/
149UINTN
150NameSizeOfVariable (
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**/
187UINTN
188DataSizeOfVariable (
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**/
224CHAR16 *
225GetVariableNamePtr (
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**/
242EFI_GUID *
243GetVendorGuidPtr (
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**/
268UINT8 *
269GetVariableDataPtr (
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**/
298VARIABLE_HEADER *
299GetNextVariablePtr (
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**/
341VARIABLE_STORE_STATUS
342GetVariableStoreStatus (
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**/
382BOOLEAN
383CompareVariableName (
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**/
457EFI_STATUS
458CompareWithValidVariable (
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  Return the variable store header and the store info based on the Index.
500
501  @param Type       The type of the variable store.
502  @param StoreInfo  Return the store info.
503
504  @return  Pointer to the variable store header.
505**/
506VARIABLE_STORE_HEADER *
507GetVariableStore (
508  IN VARIABLE_STORE_TYPE         Type,
509  OUT VARIABLE_STORE_INFO        *StoreInfo
510  )
511{
512  EFI_HOB_GUID_TYPE                     *GuidHob;
513  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
514  VARIABLE_STORE_HEADER                 *VariableStoreHeader;
515  EFI_PHYSICAL_ADDRESS                  NvStorageBase;
516  UINT32                                NvStorageSize;
517  FAULT_TOLERANT_WRITE_LAST_WRITE_DATA  *FtwLastWriteData;
518  UINT32                                BackUpOffset;
519
520  StoreInfo->IndexTable = NULL;
521  StoreInfo->FtwLastWriteData = NULL;
522  StoreInfo->AuthFlag = FALSE;
523  VariableStoreHeader = NULL;
524  switch (Type) {
525    case VariableStoreTypeHob:
526      GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
527      if (GuidHob != NULL) {
528        VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
529        StoreInfo->AuthFlag = TRUE;
530      } else {
531        GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
532        if (GuidHob != NULL) {
533          VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
534          StoreInfo->AuthFlag = FALSE;
535        }
536      }
537      break;
538
539    case VariableStoreTypeNv:
540      if (GetBootModeHob () != BOOT_IN_RECOVERY_MODE) {
541        //
542        // The content of NV storage for variable is not reliable in recovery boot mode.
543        //
544
545        NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
546        NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
547                                                PcdGet64 (PcdFlashNvStorageVariableBase64) :
548                                                PcdGet32 (PcdFlashNvStorageVariableBase)
549                                               );
550        //
551        // First let FvHeader point to NV storage base.
552        //
553        FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase;
554
555        //
556        // Check the FTW last write data hob.
557        //
558        BackUpOffset = 0;
559        GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
560        if (GuidHob != NULL) {
561          FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
562          if (FtwLastWriteData->TargetAddress == NvStorageBase) {
563            //
564            // Let FvHeader point to spare block.
565            //
566            FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress;
567            DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
568          } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
569            StoreInfo->FtwLastWriteData = FtwLastWriteData;
570            //
571            // Flash NV storage from the offset is backed up in spare block.
572            //
573            BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
574            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));
575            //
576            // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.
577            //
578          }
579        }
580
581        //
582        // Check if the Firmware Volume is not corrupted
583        //
584        if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
585          DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
586          break;
587        }
588
589        VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength);
590
591        StoreInfo->AuthFlag = (BOOLEAN) (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));
592
593        GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
594        if (GuidHob != NULL) {
595          StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
596        } else {
597          //
598          // If it's the first time to access variable region in flash, create a guid hob to record
599          // VAR_ADDED type variable info.
600          // Note that as the resource of PEI phase is limited, only store the limited number of
601          // VAR_ADDED type variables to reduce access time.
602          //
603          StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
604          StoreInfo->IndexTable->Length      = 0;
605          StoreInfo->IndexTable->StartPtr    = GetStartPointer (VariableStoreHeader);
606          StoreInfo->IndexTable->EndPtr      = GetEndPointer   (VariableStoreHeader);
607          StoreInfo->IndexTable->GoneThrough = 0;
608        }
609      }
610      break;
611
612    default:
613      ASSERT (FALSE);
614      break;
615  }
616
617  StoreInfo->VariableStoreHeader = VariableStoreHeader;
618  return VariableStoreHeader;
619}
620
621/**
622  Get variable header that has consecutive content.
623
624  @param StoreInfo      Pointer to variable store info structure.
625  @param Variable       Pointer to the Variable Header.
626  @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
627
628  @retval TRUE          Variable header is valid.
629  @retval FALSE         Variable header is not valid.
630
631**/
632BOOLEAN
633GetVariableHeader (
634  IN VARIABLE_STORE_INFO    *StoreInfo,
635  IN VARIABLE_HEADER        *Variable,
636  OUT VARIABLE_HEADER       **VariableHeader
637  )
638{
639  EFI_PHYSICAL_ADDRESS  TargetAddress;
640  EFI_PHYSICAL_ADDRESS  SpareAddress;
641  EFI_HOB_GUID_TYPE     *GuidHob;
642  UINTN                 PartialHeaderSize;
643
644  if (Variable == NULL) {
645    return FALSE;
646  }
647
648  //
649  // First assume variable header pointed by Variable is consecutive.
650  //
651  *VariableHeader = Variable;
652
653  if (StoreInfo->FtwLastWriteData != NULL) {
654    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
655    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
656    if (((UINTN) Variable > (UINTN) SpareAddress) &&
657        (((UINTN) Variable - (UINTN) SpareAddress + (UINTN) TargetAddress) >= (UINTN) GetEndPointer (StoreInfo->VariableStoreHeader))) {
658      //
659      // Reach the end of variable store.
660      //
661      return FALSE;
662    }
663    if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN) TargetAddress)) {
664      //
665      // Variable header pointed by Variable is inconsecutive,
666      // create a guid hob to combine the two partial variable header content together.
667      //
668      GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
669      if (GuidHob != NULL) {
670        *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
671      } else {
672        *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));
673        PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;
674        //
675        // Partial content is in NV storage.
676        //
677        CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);
678        //
679        // Another partial content is in spare block.
680        //
681        CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);
682      }
683    }
684  } else {
685    if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {
686      //
687      // Reach the end of variable store.
688      //
689      return FALSE;
690    }
691  }
692
693  return IsValidVariableHeader (*VariableHeader);
694}
695
696/**
697  Get variable name or data to output buffer.
698
699  @param  StoreInfo     Pointer to variable store info structure.
700  @param  NameOrData    Pointer to the variable name/data that may be inconsecutive.
701  @param  Size          Variable name/data size.
702  @param  Buffer        Pointer to output buffer to hold the variable name/data.
703
704**/
705VOID
706GetVariableNameOrData (
707  IN VARIABLE_STORE_INFO    *StoreInfo,
708  IN UINT8                  *NameOrData,
709  IN UINTN                  Size,
710  OUT UINT8                 *Buffer
711  )
712{
713  EFI_PHYSICAL_ADDRESS  TargetAddress;
714  EFI_PHYSICAL_ADDRESS  SpareAddress;
715  UINTN                 PartialSize;
716
717  if (StoreInfo->FtwLastWriteData != NULL) {
718    TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
719    SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
720    if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) {
721      //
722      // Variable name/data is inconsecutive.
723      //
724      PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData;
725      //
726      // Partial content is in NV storage.
727      //
728      CopyMem (Buffer, NameOrData, PartialSize);
729      //
730      // Another partial content is in spare block.
731      //
732      CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize);
733      return;
734    }
735  }
736
737  //
738  // Variable name/data is consecutive.
739  //
740  CopyMem (Buffer, NameOrData, Size);
741}
742
743/**
744  Find the variable in the specified variable store.
745
746  @param  StoreInfo           Pointer to the store info structure.
747  @param  VariableName        Name of the variable to be found
748  @param  VendorGuid          Vendor GUID to be found.
749  @param  PtrTrack            Variable Track Pointer structure that contains Variable Information.
750
751  @retval  EFI_SUCCESS            Variable found successfully
752  @retval  EFI_NOT_FOUND          Variable not found
753  @retval  EFI_INVALID_PARAMETER  Invalid variable name
754
755**/
756EFI_STATUS
757FindVariableEx (
758  IN VARIABLE_STORE_INFO         *StoreInfo,
759  IN CONST CHAR16                *VariableName,
760  IN CONST EFI_GUID              *VendorGuid,
761  OUT VARIABLE_POINTER_TRACK     *PtrTrack
762  )
763{
764  VARIABLE_HEADER         *Variable;
765  VARIABLE_HEADER         *LastVariable;
766  VARIABLE_HEADER         *MaxIndex;
767  UINTN                   Index;
768  UINTN                   Offset;
769  BOOLEAN                 StopRecord;
770  VARIABLE_HEADER         *InDeletedVariable;
771  VARIABLE_STORE_HEADER   *VariableStoreHeader;
772  VARIABLE_INDEX_TABLE    *IndexTable;
773  VARIABLE_HEADER         *VariableHeader;
774
775  VariableStoreHeader = StoreInfo->VariableStoreHeader;
776
777  if (VariableStoreHeader == NULL) {
778    return EFI_INVALID_PARAMETER;
779  }
780
781  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
782    return EFI_UNSUPPORTED;
783  }
784
785  if (~VariableStoreHeader->Size == 0) {
786    return EFI_NOT_FOUND;
787  }
788
789  IndexTable = StoreInfo->IndexTable;
790  PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
791  PtrTrack->EndPtr   = GetEndPointer   (VariableStoreHeader);
792
793  InDeletedVariable = NULL;
794
795  //
796  // No Variable Address equals zero, so 0 as initial value is safe.
797  //
798  MaxIndex   = NULL;
799  VariableHeader = NULL;
800
801  if (IndexTable != NULL) {
802    //
803    // traverse the variable index table to look for varible.
804    // The IndexTable->Index[Index] records the distance of two neighbouring VAR_ADDED type variables.
805    //
806    for (Offset = 0, Index = 0; Index < IndexTable->Length; Index++) {
807      ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
808      Offset   += IndexTable->Index[Index];
809      MaxIndex  = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset);
810      GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
811      if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
812        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
813          InDeletedVariable = PtrTrack->CurrPtr;
814        } else {
815          return EFI_SUCCESS;
816        }
817      }
818    }
819
820    if (IndexTable->GoneThrough != 0) {
821      //
822      // If the table has all the existing variables indexed, return.
823      //
824      PtrTrack->CurrPtr = InDeletedVariable;
825      return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
826    }
827  }
828
829  if (MaxIndex != NULL) {
830    //
831    // HOB exists but the variable cannot be found in HOB
832    // If not found in HOB, then let's start from the MaxIndex we've found.
833    //
834    Variable     = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
835    LastVariable = MaxIndex;
836  } else {
837    //
838    // Start Pointers for the variable.
839    // Actual Data Pointer where data can be written.
840    //
841    Variable     = PtrTrack->StartPtr;
842    LastVariable = PtrTrack->StartPtr;
843  }
844
845  //
846  // Find the variable by walk through variable store
847  //
848  StopRecord = FALSE;
849  while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
850    if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
851      //
852      // Record Variable in VariableIndex HOB
853      //
854      if ((IndexTable != NULL) && !StopRecord) {
855        Offset = (UINTN) Variable - (UINTN) LastVariable;
856        if ((Offset > 0x0FFFF) || (IndexTable->Length == sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]))) {
857          //
858          // Stop to record if the distance of two neighbouring VAR_ADDED variable is larger than the allowable scope(UINT16),
859          // or the record buffer is full.
860          //
861          StopRecord = TRUE;
862        } else {
863          IndexTable->Index[IndexTable->Length++] = (UINT16) Offset;
864          LastVariable = Variable;
865        }
866      }
867
868      if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
869        if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
870          InDeletedVariable = PtrTrack->CurrPtr;
871        } else {
872          return EFI_SUCCESS;
873        }
874      }
875    }
876
877    Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
878  }
879  //
880  // If gone through the VariableStore, that means we never find in Firmware any more.
881  //
882  if ((IndexTable != NULL) && !StopRecord) {
883    IndexTable->GoneThrough = 1;
884  }
885
886  PtrTrack->CurrPtr = InDeletedVariable;
887
888  return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
889}
890
891/**
892  Find the variable in HOB and Non-Volatile variable storages.
893
894  @param  VariableName  Name of the variable to be found
895  @param  VendorGuid    Vendor GUID to be found.
896  @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.
897  @param  StoreInfo     Return the store info.
898
899  @retval  EFI_SUCCESS            Variable found successfully
900  @retval  EFI_NOT_FOUND          Variable not found
901  @retval  EFI_INVALID_PARAMETER  Invalid variable name
902**/
903EFI_STATUS
904FindVariable (
905  IN CONST  CHAR16            *VariableName,
906  IN CONST  EFI_GUID          *VendorGuid,
907  OUT VARIABLE_POINTER_TRACK  *PtrTrack,
908  OUT VARIABLE_STORE_INFO     *StoreInfo
909  )
910{
911  EFI_STATUS                  Status;
912  VARIABLE_STORE_TYPE         Type;
913
914  if (VariableName[0] != 0 && VendorGuid == NULL) {
915    return EFI_INVALID_PARAMETER;
916  }
917
918  for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
919    GetVariableStore (Type, StoreInfo);
920    Status = FindVariableEx (
921               StoreInfo,
922               VariableName,
923               VendorGuid,
924               PtrTrack
925               );
926    if (!EFI_ERROR (Status)) {
927      return Status;
928    }
929  }
930
931  return EFI_NOT_FOUND;
932}
933
934/**
935  This service retrieves a variable's value using its name and GUID.
936
937  Read the specified variable from the UEFI variable store. If the Data
938  buffer is too small to hold the contents of the variable, the error
939  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer
940  size to obtain the data.
941
942  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
943  @param  VariableName          A pointer to a null-terminated string that is the variable's name.
944  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of
945                                VariableGuid and VariableName must be unique.
946  @param  Attributes            If non-NULL, on return, points to the variable's attributes.
947  @param  DataSize              On entry, points to the size in bytes of the Data buffer.
948                                On return, points to the size of the data returned in Data.
949  @param  Data                  Points to the buffer which will hold the returned variable value.
950
951  @retval EFI_SUCCESS           The variable was read successfully.
952  @retval EFI_NOT_FOUND         The variable could not be found.
953  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data.
954                                DataSize is updated with the size required for
955                                the specified variable.
956  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.
957  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
958
959**/
960EFI_STATUS
961EFIAPI
962PeiGetVariable (
963  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
964  IN CONST  CHAR16                          *VariableName,
965  IN CONST  EFI_GUID                        *VariableGuid,
966  OUT       UINT32                          *Attributes,
967  IN OUT    UINTN                           *DataSize,
968  OUT       VOID                            *Data
969  )
970{
971  VARIABLE_POINTER_TRACK  Variable;
972  UINTN                   VarDataSize;
973  EFI_STATUS              Status;
974  VARIABLE_STORE_INFO     StoreInfo;
975  VARIABLE_HEADER         *VariableHeader;
976
977  if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {
978    return EFI_INVALID_PARAMETER;
979  }
980
981  if (VariableName[0] == 0) {
982    return EFI_NOT_FOUND;
983  }
984
985  VariableHeader = NULL;
986
987  //
988  // Find existing variable
989  //
990  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
991  if (EFI_ERROR (Status)) {
992    return Status;
993  }
994  GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
995
996  //
997  // Get data size
998  //
999  VarDataSize = DataSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
1000  if (*DataSize >= VarDataSize) {
1001    if (Data == NULL) {
1002      return EFI_INVALID_PARAMETER;
1003    }
1004
1005    GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader, StoreInfo.AuthFlag), VarDataSize, Data);
1006
1007    if (Attributes != NULL) {
1008      *Attributes = VariableHeader->Attributes;
1009    }
1010
1011    *DataSize = VarDataSize;
1012    return EFI_SUCCESS;
1013  } else {
1014    *DataSize = VarDataSize;
1015    return EFI_BUFFER_TOO_SMALL;
1016  }
1017}
1018
1019/**
1020  Return the next variable name and GUID.
1021
1022  This function is called multiple times to retrieve the VariableName
1023  and VariableGuid of all variables currently available in the system.
1024  On each call, the previous results are passed into the interface,
1025  and, on return, the interface returns the data for the next
1026  interface. When the entire variable list has been returned,
1027  EFI_NOT_FOUND is returned.
1028
1029  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.
1030
1031  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.
1032                            On return, the size of the variable name buffer.
1033  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.
1034                            On return, points to the next variable's null-terminated name string.
1035  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID.
1036                            On return, a pointer to the next variable's GUID.
1037
1038  @retval EFI_SUCCESS           The variable was read successfully.
1039  @retval EFI_NOT_FOUND         The variable could not be found.
1040  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting
1041                                data. VariableNameSize is updated with the size
1042                                required for the specified variable.
1043  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or
1044                                VariableNameSize is NULL.
1045  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.
1046
1047**/
1048EFI_STATUS
1049EFIAPI
1050PeiGetNextVariableName (
1051  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
1052  IN OUT UINTN                              *VariableNameSize,
1053  IN OUT CHAR16                             *VariableName,
1054  IN OUT EFI_GUID                           *VariableGuid
1055  )
1056{
1057  VARIABLE_STORE_TYPE     Type;
1058  VARIABLE_POINTER_TRACK  Variable;
1059  VARIABLE_POINTER_TRACK  VariableInHob;
1060  VARIABLE_POINTER_TRACK  VariablePtrTrack;
1061  UINTN                   VarNameSize;
1062  EFI_STATUS              Status;
1063  VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];
1064  VARIABLE_HEADER         *VariableHeader;
1065  VARIABLE_STORE_INFO     StoreInfo;
1066  VARIABLE_STORE_INFO     StoreInfoForNv;
1067  VARIABLE_STORE_INFO     StoreInfoForHob;
1068
1069  if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {
1070    return EFI_INVALID_PARAMETER;
1071  }
1072
1073  VariableHeader = NULL;
1074
1075  Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
1076  if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
1077    return Status;
1078  }
1079
1080  if (VariableName[0] != 0) {
1081    //
1082    // If variable name is not NULL, get next variable
1083    //
1084    GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
1085    Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
1086  }
1087
1088  VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
1089  VariableStoreHeader[VariableStoreTypeNv]  = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
1090
1091  while (TRUE) {
1092    //
1093    // Switch from HOB to Non-Volatile.
1094    //
1095    while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
1096      //
1097      // Find current storage index
1098      //
1099      for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
1100        if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
1101          break;
1102        }
1103      }
1104      ASSERT (Type < VariableStoreTypeMax);
1105      //
1106      // Switch to next storage
1107      //
1108      for (Type++; Type < VariableStoreTypeMax; Type++) {
1109        if (VariableStoreHeader[Type] != NULL) {
1110          break;
1111        }
1112      }
1113      //
1114      // Capture the case that
1115      // 1. current storage is the last one, or
1116      // 2. no further storage
1117      //
1118      if (Type == VariableStoreTypeMax) {
1119        return EFI_NOT_FOUND;
1120      }
1121      Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
1122      Variable.EndPtr   = GetEndPointer   (VariableStoreHeader[Type]);
1123      Variable.CurrPtr  = Variable.StartPtr;
1124      GetVariableStore (Type, &StoreInfo);
1125    }
1126
1127    if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1128      if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1129        //
1130        // If it is a IN_DELETED_TRANSITION variable,
1131        // and there is also a same ADDED one at the same time,
1132        // don't return it.
1133        //
1134        Status = FindVariableEx (
1135                   &StoreInfo,
1136                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
1137                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
1138                   &VariablePtrTrack
1139                   );
1140        if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) {
1141          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
1142          continue;
1143        }
1144      }
1145
1146      //
1147      // Don't return NV variable when HOB overrides it
1148      //
1149      if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
1150          (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
1151         ) {
1152        Status = FindVariableEx (
1153                   &StoreInfoForHob,
1154                   GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag),
1155                   GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag),
1156                   &VariableInHob
1157                   );
1158        if (!EFI_ERROR (Status)) {
1159          Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
1160          continue;
1161        }
1162      }
1163
1164      VarNameSize = NameSizeOfVariable (VariableHeader, StoreInfo.AuthFlag);
1165      ASSERT (VarNameSize != 0);
1166
1167      if (VarNameSize <= *VariableNameSize) {
1168        GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr, StoreInfo.AuthFlag), VarNameSize, (UINT8 *) VariableName);
1169
1170        CopyMem (VariableGuid, GetVendorGuidPtr (VariableHeader, StoreInfo.AuthFlag), sizeof (EFI_GUID));
1171
1172        Status = EFI_SUCCESS;
1173      } else {
1174        Status = EFI_BUFFER_TOO_SMALL;
1175      }
1176
1177      *VariableNameSize = VarNameSize;
1178      //
1179      // Variable is found
1180      //
1181      return Status;
1182    } else {
1183      Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
1184    }
1185  }
1186}
1187