Home | History | Annotate | Download | only in EmuVariableFvbRuntimeDxe
      1 /** @file
      2   Firmware Block Services to support emulating non-volatile variables
      3   by pretending that a memory buffer is storage for the NV variables.
      4 
      5   Copyright (c) 2006 - 2013, 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 #include "PiDxe.h"
     17 #include <Guid/EventGroup.h>
     18 #include <Guid/SystemNvDataGuid.h>
     19 #include <Guid/VariableFormat.h>
     20 
     21 #include <Protocol/FirmwareVolumeBlock.h>
     22 #include <Protocol/DevicePath.h>
     23 
     24 #include <Library/UefiLib.h>
     25 #include <Library/UefiDriverEntryPoint.h>
     26 #include <Library/BaseLib.h>
     27 #include <Library/UefiRuntimeLib.h>
     28 #include <Library/DebugLib.h>
     29 #include <Library/BaseMemoryLib.h>
     30 #include <Library/MemoryAllocationLib.h>
     31 #include <Library/UefiBootServicesTableLib.h>
     32 #include <Library/DevicePathLib.h>
     33 #include <Library/PcdLib.h>
     34 #include <Library/PlatformFvbLib.h>
     35 #include "Fvb.h"
     36 
     37 #define EFI_AUTHENTICATED_VARIABLE_GUID \
     38 { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
     39 
     40 //
     41 // Virtual Address Change Event
     42 //
     43 // This is needed for runtime variable access.
     44 //
     45 EFI_EVENT   mEmuVarsFvbAddrChangeEvent = NULL;
     46 
     47 //
     48 // This is the single instance supported by this driver.  It
     49 // supports the FVB and Device Path protocols.
     50 //
     51 EFI_FW_VOL_BLOCK_DEVICE mEmuVarsFvb = {
     52   FVB_DEVICE_SIGNATURE,
     53   {     // DevicePath
     54     {
     55       {
     56         HARDWARE_DEVICE_PATH,
     57         HW_MEMMAP_DP,
     58         {
     59           sizeof (MEMMAP_DEVICE_PATH),
     60           0
     61         }
     62       },
     63       EfiMemoryMappedIO,
     64       0,
     65       0,
     66     },
     67     {
     68       END_DEVICE_PATH_TYPE,
     69       END_ENTIRE_DEVICE_PATH_SUBTYPE,
     70       {
     71         sizeof (EFI_DEVICE_PATH_PROTOCOL),
     72         0
     73       }
     74     }
     75   },
     76   NULL, // BufferPtr
     77   FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize), // BlockSize
     78   2 * FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize), // Size
     79   {     // FwVolBlockInstance
     80     FvbProtocolGetAttributes,
     81     FvbProtocolSetAttributes,
     82     FvbProtocolGetPhysicalAddress,
     83     FvbProtocolGetBlockSize,
     84     FvbProtocolRead,
     85     FvbProtocolWrite,
     86     FvbProtocolEraseBlocks,
     87     NULL
     88   },
     89 };
     90 
     91 
     92 /**
     93   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
     94 
     95   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
     96   It converts pointer to new virtual address.
     97 
     98   @param  Event        Event whose notification function is being invoked.
     99   @param  Context      Pointer to the notification function's context.
    100 
    101 **/
    102 VOID
    103 EFIAPI
    104 FvbVirtualAddressChangeEvent (
    105   IN EFI_EVENT        Event,
    106   IN VOID             *Context
    107   )
    108 {
    109   EfiConvertPointer (0x0, &mEmuVarsFvb.BufferPtr);
    110 }
    111 
    112 
    113 //
    114 // FVB protocol APIs
    115 //
    116 
    117 /**
    118   The GetPhysicalAddress() function retrieves the base address of
    119   a memory-mapped firmware volume. This function should be called
    120   only for memory-mapped firmware volumes.
    121 
    122   @param This     Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
    123 
    124   @param Address  Pointer to a caller-allocated
    125                   EFI_PHYSICAL_ADDRESS that, on successful
    126                   return from GetPhysicalAddress(), contains the
    127                   base address of the firmware volume.
    128 
    129   @retval EFI_SUCCESS       The firmware volume base address is returned.
    130 
    131   @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
    132 
    133 **/
    134 EFI_STATUS
    135 EFIAPI
    136 FvbProtocolGetPhysicalAddress (
    137   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    138   OUT       EFI_PHYSICAL_ADDRESS                *Address
    139   )
    140 {
    141   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    142 
    143   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    144 
    145   *Address = (EFI_PHYSICAL_ADDRESS)(UINTN) FvbDevice->BufferPtr;
    146 
    147   return EFI_SUCCESS;
    148 }
    149 
    150 
    151 /**
    152   The GetBlockSize() function retrieves the size of the requested
    153   block. It also returns the number of additional blocks with
    154   the identical size. The GetBlockSize() function is used to
    155   retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
    156 
    157 
    158   @param This           Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
    159 
    160   @param Lba            Indicates the block for which to return the size.
    161 
    162   @param BlockSize      Pointer to a caller-allocated UINTN in which
    163                         the size of the block is returned.
    164 
    165   @param NumberOfBlocks Pointer to a caller-allocated UINTN in
    166                         which the number of consecutive blocks,
    167                         starting with Lba, is returned. All
    168                         blocks in this range have a size of
    169                         BlockSize.
    170 
    171 
    172   @retval EFI_SUCCESS             The firmware volume base address is returned.
    173 
    174   @retval EFI_INVALID_PARAMETER   The requested LBA is out of range.
    175 
    176 **/
    177 EFI_STATUS
    178 EFIAPI
    179 FvbProtocolGetBlockSize (
    180   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    181   IN        EFI_LBA                             Lba,
    182   OUT       UINTN                               *BlockSize,
    183   OUT       UINTN                               *NumberOfBlocks
    184   )
    185 {
    186   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    187 
    188   if (Lba > 1) {
    189     return EFI_INVALID_PARAMETER;
    190   }
    191 
    192   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    193 
    194   *BlockSize = FvbDevice->BlockSize;
    195   *NumberOfBlocks = (UINTN) (2 - (UINTN) Lba);
    196 
    197   return EFI_SUCCESS;
    198 }
    199 
    200 
    201 /**
    202   The GetAttributes() function retrieves the attributes and
    203   current settings of the block. Status Codes Returned
    204 
    205   @param This       Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
    206 
    207   @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
    208                     attributes and current settings are
    209                     returned. Type EFI_FVB_ATTRIBUTES_2 is defined
    210                     in EFI_FIRMWARE_VOLUME_HEADER.
    211 
    212   @retval EFI_SUCCESS The firmware volume attributes were
    213                       returned.
    214 
    215 **/
    216 EFI_STATUS
    217 EFIAPI
    218 FvbProtocolGetAttributes (
    219   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    220   OUT       EFI_FVB_ATTRIBUTES_2                *Attributes
    221   )
    222 {
    223   *Attributes =
    224     (EFI_FVB_ATTRIBUTES_2) (
    225       EFI_FVB2_READ_ENABLED_CAP |
    226       EFI_FVB2_READ_STATUS |
    227       EFI_FVB2_WRITE_ENABLED_CAP |
    228       EFI_FVB2_WRITE_STATUS |
    229       EFI_FVB2_ERASE_POLARITY
    230       );
    231 
    232   return EFI_SUCCESS;
    233 }
    234 
    235 
    236 /**
    237   The SetAttributes() function sets configurable firmware volume
    238   attributes and returns the new settings of the firmware volume.
    239 
    240   @param This         Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
    241 
    242   @param Attributes   On input, Attributes is a pointer to
    243                       EFI_FVB_ATTRIBUTES_2 that contains the
    244                       desired firmware volume settings. On
    245                       successful return, it contains the new
    246                       settings of the firmware volume. Type
    247                       EFI_FVB_ATTRIBUTES_2 is defined in
    248                       EFI_FIRMWARE_VOLUME_HEADER.
    249 
    250   @retval EFI_SUCCESS           The firmware volume attributes were returned.
    251 
    252   @retval EFI_INVALID_PARAMETER The attributes requested are in
    253                                 conflict with the capabilities
    254                                 as declared in the firmware
    255                                 volume header.
    256 
    257 **/
    258 EFI_STATUS
    259 EFIAPI
    260 FvbProtocolSetAttributes (
    261   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    262   IN OUT    EFI_FVB_ATTRIBUTES_2                *Attributes
    263   )
    264 {
    265   return EFI_ACCESS_DENIED;
    266 }
    267 
    268 
    269 /**
    270   Erases and initializes a firmware volume block.
    271 
    272   The EraseBlocks() function erases one or more blocks as denoted
    273   by the variable argument list. The entire parameter list of
    274   blocks must be verified before erasing any blocks. If a block is
    275   requested that does not exist within the associated firmware
    276   volume (it has a larger index than the last block of the
    277   firmware volume), the EraseBlocks() function must return the
    278   status code EFI_INVALID_PARAMETER without modifying the contents
    279   of the firmware volume. Implementations should be mindful that
    280   the firmware volume might be in the WriteDisabled state. If it
    281   is in this state, the EraseBlocks() function must return the
    282   status code EFI_ACCESS_DENIED without modifying the contents of
    283   the firmware volume. All calls to EraseBlocks() must be fully
    284   flushed to the hardware before the EraseBlocks() service
    285   returns.
    286 
    287   @param This   Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
    288                 instance.
    289 
    290   @param ...    The variable argument list is a list of tuples.
    291                 Each tuple describes a range of LBAs to erase
    292                 and consists of the following:
    293                 - An EFI_LBA that indicates the starting LBA
    294                 - A UINTN that indicates the number of blocks to
    295                   erase
    296 
    297                 The list is terminated with an
    298                 EFI_LBA_LIST_TERMINATOR. For example, the
    299                 following indicates that two ranges of blocks
    300                 (5-7 and 10-11) are to be erased: EraseBlocks
    301                 (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
    302 
    303   @retval EFI_SUCCESS The erase request was successfully
    304                       completed.
    305 
    306   @retval EFI_ACCESS_DENIED   The firmware volume is in the
    307                               WriteDisabled state.
    308   @retval EFI_DEVICE_ERROR  The block device is not functioning
    309                             correctly and could not be written.
    310                             The firmware device may have been
    311                             partially erased.
    312   @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
    313                                 in the variable argument list do
    314                                 not exist in the firmware volume.
    315 
    316 **/
    317 EFI_STATUS
    318 EFIAPI
    319 FvbProtocolEraseBlocks (
    320   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    321   ...
    322   )
    323 {
    324   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    325   VA_LIST                 args;
    326   EFI_LBA                 StartingLba;
    327   UINTN                   NumOfLba;
    328   UINT8                   Erase;
    329   VOID                    *ErasePtr;
    330   UINTN                   EraseSize;
    331 
    332   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    333   Erase = 0;
    334 
    335   VA_START (args, This);
    336 
    337   do {
    338     StartingLba = VA_ARG (args, EFI_LBA);
    339     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
    340       break;
    341     }
    342 
    343     NumOfLba = VA_ARG (args, UINT32);
    344 
    345     //
    346     // Check input parameters
    347     //
    348     if ((NumOfLba == 0) || (StartingLba > 1) || ((StartingLba + NumOfLba) > 2)) {
    349       VA_END (args);
    350       return EFI_INVALID_PARAMETER;
    351     }
    352 
    353     if (StartingLba == 0) {
    354       Erase = (UINT8) (Erase | BIT0);
    355     }
    356     if ((StartingLba + NumOfLba) == 2) {
    357       Erase = (UINT8) (Erase | BIT1);
    358     }
    359 
    360   } while (1);
    361 
    362   VA_END (args);
    363 
    364   ErasePtr = (UINT8*) FvbDevice->BufferPtr;
    365   EraseSize = 0;
    366 
    367   if ((Erase & BIT0) != 0) {
    368     EraseSize = EraseSize + FvbDevice->BlockSize;
    369   } else {
    370     ErasePtr = (VOID*) ((UINT8*)ErasePtr + FvbDevice->BlockSize);
    371   }
    372 
    373   if ((Erase & BIT1) != 0) {
    374     EraseSize = EraseSize + FvbDevice->BlockSize;
    375   }
    376 
    377   if (EraseSize != 0) {
    378     SetMem (
    379       (VOID*) ErasePtr,
    380       EraseSize,
    381       ERASED_UINT8
    382       );
    383     VA_START (args, This);
    384     PlatformFvbBlocksErased (This, args);
    385     VA_END (args);
    386   }
    387 
    388   return EFI_SUCCESS;
    389 }
    390 
    391 
    392 /**
    393   Writes the specified number of bytes from the input buffer to the block.
    394 
    395   The Write() function writes the specified number of bytes from
    396   the provided buffer to the specified block and offset. If the
    397   firmware volume is sticky write, the caller must ensure that
    398   all the bits of the specified range to write are in the
    399   EFI_FVB_ERASE_POLARITY state before calling the Write()
    400   function, or else the result will be unpredictable. This
    401   unpredictability arises because, for a sticky-write firmware
    402   volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
    403   state but cannot flip it back again. In general, before
    404   calling the Write() function, the caller should call the
    405   EraseBlocks() function first to erase the specified block to
    406   write. A block erase cycle will transition bits from the
    407   (NOT)EFI_FVB_ERASE_POLARITY state back to the
    408   EFI_FVB_ERASE_POLARITY state. Implementations should be
    409   mindful that the firmware volume might be in the WriteDisabled
    410   state. If it is in this state, the Write() function must
    411   return the status code EFI_ACCESS_DENIED without modifying the
    412   contents of the firmware volume. The Write() function must
    413   also prevent spanning block boundaries. If a write is
    414   requested that spans a block boundary, the write must store up
    415   to the boundary but not beyond. The output parameter NumBytes
    416   must be set to correctly indicate the number of bytes actually
    417   written. The caller must be aware that a write may be
    418   partially completed. All writes, partial or otherwise, must be
    419   fully flushed to the hardware before the Write() service
    420   returns.
    421 
    422   @param This     Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
    423 
    424   @param Lba      The starting logical block index to write to.
    425 
    426   @param Offset   Offset into the block at which to begin writing.
    427 
    428   @param NumBytes Pointer to a UINTN. At entry, *NumBytes
    429                   contains the total size of the buffer. At
    430                   exit, *NumBytes contains the total number of
    431                   bytes actually written.
    432 
    433   @param Buffer   Pointer to a caller-allocated buffer that
    434                   contains the source for the write.
    435 
    436   @retval EFI_SUCCESS         The firmware volume was written successfully.
    437 
    438   @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
    439                               LBA boundary. On output, NumBytes
    440                               contains the total number of bytes
    441                               actually written.
    442 
    443   @retval EFI_ACCESS_DENIED   The firmware volume is in the
    444                               WriteDisabled state.
    445 
    446   @retval EFI_DEVICE_ERROR    The block device is malfunctioning
    447                               and could not be written.
    448 
    449 
    450 **/
    451 EFI_STATUS
    452 EFIAPI
    453 FvbProtocolWrite (
    454   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    455   IN        EFI_LBA                             Lba,
    456   IN        UINTN                               Offset,
    457   IN OUT    UINTN                               *NumBytes,
    458   IN        UINT8                               *Buffer
    459   )
    460 {
    461 
    462   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    463   UINT8                   *FvbDataPtr;
    464 
    465   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    466 
    467   if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) {
    468     return EFI_INVALID_PARAMETER;
    469   }
    470 
    471   if ((Offset + *NumBytes) > FvbDevice->BlockSize) {
    472     *NumBytes = FvbDevice->BlockSize - Offset;
    473   }
    474 
    475   FvbDataPtr =
    476     (UINT8*) FvbDevice->BufferPtr +
    477     MultU64x32 (Lba, (UINT32) FvbDevice->BlockSize) +
    478     Offset;
    479 
    480   if (*NumBytes > 0) {
    481     CopyMem (FvbDataPtr, Buffer, *NumBytes);
    482     PlatformFvbDataWritten (This, Lba, Offset, *NumBytes, Buffer);
    483   }
    484 
    485   return EFI_SUCCESS;
    486 }
    487 
    488 
    489 /**
    490   Reads the specified number of bytes into a buffer from the specified block.
    491 
    492   The Read() function reads the requested number of bytes from the
    493   requested block and stores them in the provided buffer.
    494   Implementations should be mindful that the firmware volume
    495   might be in the ReadDisabled state. If it is in this state,
    496   the Read() function must return the status code
    497   EFI_ACCESS_DENIED without modifying the contents of the
    498   buffer. The Read() function must also prevent spanning block
    499   boundaries. If a read is requested that would span a block
    500   boundary, the read must read up to the boundary but not
    501   beyond. The output parameter NumBytes must be set to correctly
    502   indicate the number of bytes actually read. The caller must be
    503   aware that a read may be partially completed.
    504 
    505   @param This     Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
    506 
    507   @param Lba      The starting logical block index
    508                   from which to read.
    509 
    510   @param Offset   Offset into the block at which to begin reading.
    511 
    512   @param NumBytes Pointer to a UINTN. At entry, *NumBytes
    513                   contains the total size of the buffer. At
    514                   exit, *NumBytes contains the total number of
    515                   bytes read.
    516 
    517   @param Buffer   Pointer to a caller-allocated buffer that will
    518                   be used to hold the data that is read.
    519 
    520   @retval EFI_SUCCESS         The firmware volume was read successfully
    521                               and contents are in Buffer.
    522 
    523   @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
    524                               boundary. On output, NumBytes
    525                               contains the total number of bytes
    526                               returned in Buffer.
    527 
    528   @retval EFI_ACCESS_DENIED   The firmware volume is in the
    529                               ReadDisabled state.
    530 
    531   @retval EFI_DEVICE_ERROR    The block device is not
    532                               functioning correctly and could
    533                               not be read.
    534 
    535 **/
    536 EFI_STATUS
    537 EFIAPI
    538 FvbProtocolRead (
    539   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
    540   IN        EFI_LBA                             Lba,
    541   IN        UINTN                               Offset,
    542   IN OUT    UINTN                               *NumBytes,
    543   IN OUT    UINT8                               *Buffer
    544   )
    545 {
    546   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    547   UINT8                   *FvbDataPtr;
    548 
    549   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    550 
    551   if ((Lba > 1) || (Offset > FvbDevice->BlockSize)) {
    552     return EFI_INVALID_PARAMETER;
    553   }
    554 
    555   if ((Offset + *NumBytes) > FvbDevice->BlockSize) {
    556     *NumBytes = FvbDevice->BlockSize - Offset;
    557   }
    558 
    559   FvbDataPtr =
    560     (UINT8*) FvbDevice->BufferPtr +
    561     MultU64x32 (Lba, (UINT32) FvbDevice->BlockSize) +
    562     Offset;
    563 
    564   if (*NumBytes > 0) {
    565     CopyMem (Buffer, FvbDataPtr, *NumBytes);
    566     PlatformFvbDataRead (This, Lba, Offset, *NumBytes, Buffer);
    567   }
    568 
    569   return EFI_SUCCESS;
    570 }
    571 
    572 
    573 /**
    574   Check the integrity of firmware volume header.
    575 
    576   @param[in] FwVolHeader - A pointer to a firmware volume header
    577 
    578   @retval  EFI_SUCCESS   - The firmware volume is consistent
    579   @retval  EFI_NOT_FOUND - The firmware volume has been corrupted.
    580 
    581 **/
    582 EFI_STATUS
    583 ValidateFvHeader (
    584   IN EFI_FIRMWARE_VOLUME_HEADER   *FwVolHeader
    585   )
    586 {
    587   UINT16  Checksum;
    588 
    589   //
    590   // Verify the header revision, header signature, length
    591   // Length of FvBlock cannot be 2**64-1
    592   // HeaderLength cannot be an odd number
    593   //
    594   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
    595       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
    596       (FwVolHeader->FvLength != EMU_FVB_SIZE) ||
    597       (FwVolHeader->HeaderLength != EMU_FV_HEADER_LENGTH)
    598       ) {
    599     DEBUG ((EFI_D_INFO, "EMU Variable FVB: Basic FV headers were invalid\n"));
    600     return EFI_NOT_FOUND;
    601   }
    602   //
    603   // Verify the header checksum
    604   //
    605   Checksum = CalculateSum16((VOID*) FwVolHeader, FwVolHeader->HeaderLength);
    606 
    607   if (Checksum != 0) {
    608     DEBUG ((EFI_D_INFO, "EMU Variable FVB: FV checksum was invalid\n"));
    609     return EFI_NOT_FOUND;
    610   }
    611 
    612   return EFI_SUCCESS;
    613 }
    614 
    615 
    616 /**
    617   Initializes the FV Header and Variable Store Header
    618   to support variable operations.
    619 
    620   @param[in]  Ptr - Location to initialize the headers
    621 
    622 **/
    623 VOID
    624 InitializeFvAndVariableStoreHeaders (
    625   IN  VOID   *Ptr
    626   )
    627 {
    628   //
    629   // Templates for standard (non-authenticated) variable FV header
    630   //
    631   STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndVarTemplate = {
    632     { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;
    633       // UINT8                     ZeroVector[16];
    634       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    635 
    636       // EFI_GUID                  FileSystemGuid;
    637       EFI_SYSTEM_NV_DATA_FV_GUID,
    638 
    639       // UINT64                    FvLength;
    640       EMU_FVB_SIZE,
    641 
    642       // UINT32                    Signature;
    643       EFI_FVH_SIGNATURE,
    644 
    645       // EFI_FVB_ATTRIBUTES_2      Attributes;
    646       0x4feff,
    647 
    648       // UINT16                    HeaderLength;
    649       EMU_FV_HEADER_LENGTH,
    650 
    651       // UINT16                    Checksum;
    652       0,
    653 
    654       // UINT16                    ExtHeaderOffset;
    655       0,
    656 
    657       // UINT8                     Reserved[1];
    658       {0},
    659 
    660       // UINT8                     Revision;
    661       EFI_FVH_REVISION,
    662 
    663       // EFI_FV_BLOCK_MAP_ENTRY    BlockMap[1];
    664       {
    665         {
    666           2, // UINT32 NumBlocks;
    667           EMU_FVB_BLOCK_SIZE  // UINT32 Length;
    668         }
    669       }
    670     },
    671     // EFI_FV_BLOCK_MAP_ENTRY     EndBlockMap;
    672     { 0, 0 }, // End of block map
    673     { // VARIABLE_STORE_HEADER      VarHdr;
    674       // EFI_GUID  Signature;
    675       EFI_VARIABLE_GUID,
    676 
    677       // UINT32  Size;
    678       (
    679         FixedPcdGet32 (PcdVariableStoreSize) -
    680         OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)
    681       ),
    682 
    683       // UINT8   Format;
    684       VARIABLE_STORE_FORMATTED,
    685 
    686       // UINT8   State;
    687       VARIABLE_STORE_HEALTHY,
    688 
    689       // UINT16  Reserved;
    690       0,
    691 
    692       // UINT32  Reserved1;
    693       0
    694     }
    695   };
    696 
    697   //
    698   // Templates for authenticated variable FV header
    699   //
    700   STATIC FVB_FV_HDR_AND_VARS_TEMPLATE FvAndAuthenticatedVarTemplate = {
    701     { // EFI_FIRMWARE_VOLUME_HEADER FvHdr;
    702       // UINT8                     ZeroVector[16];
    703       { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    704 
    705       // EFI_GUID                  FileSystemGuid;
    706       EFI_SYSTEM_NV_DATA_FV_GUID,
    707 
    708       // UINT64                    FvLength;
    709       EMU_FVB_SIZE,
    710 
    711       // UINT32                    Signature;
    712       EFI_FVH_SIGNATURE,
    713 
    714       // EFI_FVB_ATTRIBUTES_2      Attributes;
    715       0x4feff,
    716 
    717       // UINT16                    HeaderLength;
    718       EMU_FV_HEADER_LENGTH,
    719 
    720       // UINT16                    Checksum;
    721       0,
    722 
    723       // UINT16                    ExtHeaderOffset;
    724       0,
    725 
    726       // UINT8                     Reserved[1];
    727       {0},
    728 
    729       // UINT8                     Revision;
    730       EFI_FVH_REVISION,
    731 
    732       // EFI_FV_BLOCK_MAP_ENTRY    BlockMap[1];
    733       {
    734         {
    735           2, // UINT32 NumBlocks;
    736           EMU_FVB_BLOCK_SIZE  // UINT32 Length;
    737         }
    738       }
    739     },
    740     // EFI_FV_BLOCK_MAP_ENTRY     EndBlockMap;
    741     { 0, 0 }, // End of block map
    742     { // VARIABLE_STORE_HEADER      VarHdr;
    743         // EFI_GUID  Signature;     // need authenticated variables for secure boot
    744         EFI_AUTHENTICATED_VARIABLE_GUID,
    745 
    746       // UINT32  Size;
    747       (
    748         FixedPcdGet32 (PcdVariableStoreSize) -
    749         OFFSET_OF (FVB_FV_HDR_AND_VARS_TEMPLATE, VarHdr)
    750       ),
    751 
    752       // UINT8   Format;
    753       VARIABLE_STORE_FORMATTED,
    754 
    755       // UINT8   State;
    756       VARIABLE_STORE_HEALTHY,
    757 
    758       // UINT16  Reserved;
    759       0,
    760 
    761       // UINT32  Reserved1;
    762       0
    763     }
    764   };
    765 
    766   EFI_FIRMWARE_VOLUME_HEADER  *Fv;
    767 
    768   //
    769   // Copy the template structure into the location
    770   //
    771   if (FeaturePcdGet (PcdSecureBootEnable) == FALSE) {
    772     CopyMem (Ptr, (VOID*)&FvAndVarTemplate, sizeof (FvAndVarTemplate));
    773   } else {
    774     CopyMem (Ptr, (VOID*)&FvAndAuthenticatedVarTemplate, sizeof (FvAndAuthenticatedVarTemplate));
    775   }
    776 
    777   //
    778   // Update the checksum for the FV header
    779   //
    780   Fv = (EFI_FIRMWARE_VOLUME_HEADER*) Ptr;
    781   Fv->Checksum = CalculateCheckSum16 (Ptr, Fv->HeaderLength);
    782 }
    783 
    784 /**
    785   Main entry point.
    786 
    787   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
    788   @param[in] SystemTable    A pointer to the EFI System Table.
    789 
    790   @retval EFI_SUCCESS       Successfully initialized.
    791 
    792 **/
    793 EFI_STATUS
    794 EFIAPI
    795 FvbInitialize (
    796   IN EFI_HANDLE         ImageHandle,
    797   IN EFI_SYSTEM_TABLE   *SystemTable
    798   )
    799 {
    800   EFI_STATUS                          Status;
    801   VOID                                *Ptr;
    802   VOID                                *SubPtr;
    803   BOOLEAN                             Initialize;
    804   EFI_HANDLE                          Handle;
    805   EFI_PHYSICAL_ADDRESS                Address;
    806 
    807   DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n"));
    808 
    809   //
    810   // Verify that the PCD's are set correctly.
    811   //
    812   if (
    813        (PcdGet32 (PcdVariableStoreSize) +
    814         PcdGet32 (PcdFlashNvStorageFtwWorkingSize)
    815        ) >
    816        EMU_FVB_BLOCK_SIZE
    817      ) {
    818     DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n"));
    819     return EFI_INVALID_PARAMETER;
    820   }
    821 
    822   if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {
    823     DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since "
    824                         "flash variables appear to be supported.\n"));
    825     return EFI_ABORTED;
    826   }
    827 
    828   //
    829   // By default we will initialize the FV contents.  But, if
    830   // PcdEmuVariableNvStoreReserved is non-zero, then we will
    831   // use this location for our buffer.
    832   //
    833   // If this location does not have a proper FV header, then
    834   // we will initialize it.
    835   //
    836   Initialize = TRUE;
    837   if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) {
    838     Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved);
    839     DEBUG ((
    840       EFI_D_INFO,
    841       "EMU Variable FVB: Using pre-reserved block at %p\n",
    842       Ptr
    843       ));
    844     Status = ValidateFvHeader (Ptr);
    845     if (!EFI_ERROR (Status)) {
    846       DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n"));
    847       Initialize = FALSE;
    848     }
    849   } else {
    850     Ptr = AllocateAlignedRuntimePages (
    851             EFI_SIZE_TO_PAGES (EMU_FVB_SIZE),
    852             SIZE_64KB
    853             );
    854   }
    855 
    856   mEmuVarsFvb.BufferPtr = Ptr;
    857 
    858   //
    859   // Initialize the main FV header and variable store header
    860   //
    861   if (Initialize) {
    862     SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8);
    863     InitializeFvAndVariableStoreHeaders (Ptr);
    864   }
    865   PcdSet64 (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr);
    866 
    867   //
    868   // Initialize the Fault Tolerant Write data area
    869   //
    870   SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdVariableStoreSize));
    871   PcdSet32 (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr);
    872 
    873   //
    874   // Initialize the Fault Tolerant Write spare block
    875   //
    876   SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE);
    877   PcdSet32 (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr);
    878 
    879   //
    880   // Setup FVB device path
    881   //
    882   Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr;
    883   mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address;
    884   mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1;
    885 
    886   //
    887   // Install the protocols
    888   //
    889   DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n"));
    890   Handle = 0;
    891   Status = gBS->InstallMultipleProtocolInterfaces (
    892                   &Handle,
    893                   &gEfiFirmwareVolumeBlock2ProtocolGuid,
    894                   &mEmuVarsFvb.FwVolBlockInstance,
    895                   &gEfiDevicePathProtocolGuid,
    896                   &mEmuVarsFvb.DevicePath,
    897                   NULL
    898                   );
    899   ASSERT_EFI_ERROR (Status);
    900 
    901   //
    902   // Register for the virtual address change event
    903   //
    904   Status = gBS->CreateEventEx (
    905                   EVT_NOTIFY_SIGNAL,
    906                   TPL_NOTIFY,
    907                   FvbVirtualAddressChangeEvent,
    908                   NULL,
    909                   &gEfiEventVirtualAddressChangeGuid,
    910                   &mEmuVarsFvbAddrChangeEvent
    911                   );
    912   ASSERT_EFI_ERROR (Status);
    913 
    914   return EFI_SUCCESS;
    915 }
    916 
    917 
    918