Home | History | Annotate | Download | only in FvbServicesRuntimeDxe
      1 /**@file
      2 
      3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   FWBlockService.c
     15 
     16 Abstract:
     17 
     18 Revision History
     19 
     20 **/
     21 
     22 //
     23 // The package level header files this module uses
     24 //
     25 #include <PiDxe.h>
     26 #include <WinNtDxe.h>
     27 //
     28 // The protocols, PPI and GUID defintions for this module
     29 //
     30 #include <Guid/EventGroup.h>
     31 #include <Protocol/FirmwareVolumeBlock.h>
     32 #include <Protocol/DevicePath.h>
     33 //
     34 // The Library classes this module consumes
     35 //
     36 #include <Library/UefiLib.h>
     37 #include <Library/UefiDriverEntryPoint.h>
     38 #include <Library/BaseLib.h>
     39 #include <Library/DxeServicesTableLib.h>
     40 #include <Library/UefiRuntimeLib.h>
     41 #include <Library/DebugLib.h>
     42 #include <Library/HobLib.h>
     43 #include <Library/BaseMemoryLib.h>
     44 #include <Library/MemoryAllocationLib.h>
     45 #include <Library/UefiBootServicesTableLib.h>
     46 #include <Library/DevicePathLib.h>
     47 
     48 #include "FWBlockService.h"
     49 
     50 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
     51 
     52 ESAL_FWB_GLOBAL         *mFvbModuleGlobal;
     53 
     54 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
     55   {
     56     {
     57       HARDWARE_DEVICE_PATH,
     58       HW_MEMMAP_DP,
     59       {
     60         (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
     61         (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
     62       }
     63     },
     64     EfiMemoryMappedIO,
     65     (EFI_PHYSICAL_ADDRESS) 0,
     66     (EFI_PHYSICAL_ADDRESS) 0,
     67   },
     68   {
     69     END_DEVICE_PATH_TYPE,
     70     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     71     {
     72       END_DEVICE_PATH_LENGTH,
     73       0
     74     }
     75   }
     76 };
     77 
     78 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
     79   {
     80     {
     81       MEDIA_DEVICE_PATH,
     82       MEDIA_PIWG_FW_VOL_DP,
     83       {
     84         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
     85         (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
     86       }
     87     },
     88     { 0 }
     89   },
     90   {
     91     END_DEVICE_PATH_TYPE,
     92     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     93     {
     94       END_DEVICE_PATH_LENGTH,
     95       0
     96     }
     97   }
     98 };
     99 
    100 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
    101   FVB_DEVICE_SIGNATURE,
    102   NULL,
    103   0,
    104   {
    105     FvbProtocolGetAttributes,
    106     FvbProtocolSetAttributes,
    107     FvbProtocolGetPhysicalAddress,
    108     FvbProtocolGetBlockSize,
    109     FvbProtocolRead,
    110     FvbProtocolWrite,
    111     FvbProtocolEraseBlocks,
    112     NULL
    113   }
    114 };
    115 
    116 
    117 
    118 VOID
    119 EFIAPI
    120 FvbVirtualddressChangeEvent (
    121   IN EFI_EVENT        Event,
    122   IN VOID             *Context
    123   )
    124 /*++
    125 
    126 Routine Description:
    127 
    128   Fixup internal data so that EFI and SAL can be call in virtual mode.
    129   Call the passed in Child Notify event and convert the mFvbModuleGlobal
    130   date items to there virtual address.
    131 
    132   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]  - Physical copy of instance data
    133   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]   - Virtual pointer to common
    134                                                 instance data.
    135 
    136 Arguments:
    137 
    138   (Standard EFI notify event - EFI_EVENT_NOTIFY)
    139 
    140 Returns:
    141 
    142   None
    143 
    144 --*/
    145 {
    146   EFI_FW_VOL_INSTANCE *FwhInstance;
    147   UINTN               Index;
    148 
    149   EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
    150 
    151   //
    152   // Convert the base address of all the instances
    153   //
    154   Index       = 0;
    155   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
    156   while (Index < mFvbModuleGlobal->NumFv) {
    157     EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
    158     FwhInstance = (EFI_FW_VOL_INSTANCE *)
    159       (
    160         (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
    161           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
    162       );
    163     Index++;
    164   }
    165 
    166   EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
    167   EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
    168 }
    169 
    170 EFI_STATUS
    171 GetFvbInstance (
    172   IN  UINTN                               Instance,
    173   IN  ESAL_FWB_GLOBAL                     *Global,
    174   OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
    175   IN BOOLEAN                              Virtual
    176   )
    177 /*++
    178 
    179 Routine Description:
    180   Retrieves the physical address of a memory mapped FV
    181 
    182 Arguments:
    183   Instance              - The FV instance whose base address is going to be
    184                           returned
    185   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    186                           instance data
    187   FwhInstance           - The EFI_FW_VOL_INSTANCE fimrware instance structure
    188   Virtual               - Whether CPU is in virtual or physical mode
    189 
    190 Returns:
    191   EFI_SUCCESS           - Successfully returns
    192   EFI_INVALID_PARAMETER - Instance not found
    193 
    194 --*/
    195 {
    196   EFI_FW_VOL_INSTANCE *FwhRecord;
    197 
    198   if (Instance >= Global->NumFv) {
    199     return EFI_INVALID_PARAMETER;
    200   }
    201   //
    202   // Find the right instance of the FVB private data
    203   //
    204   FwhRecord = Global->FvInstance[Virtual];
    205   while (Instance > 0) {
    206     FwhRecord = (EFI_FW_VOL_INSTANCE *)
    207       (
    208         (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
    209           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
    210       );
    211     Instance--;
    212   }
    213 
    214   *FwhInstance = FwhRecord;
    215 
    216   return EFI_SUCCESS;
    217 }
    218 
    219 EFI_STATUS
    220 FvbGetPhysicalAddress (
    221   IN UINTN                                Instance,
    222   OUT EFI_PHYSICAL_ADDRESS                *Address,
    223   IN ESAL_FWB_GLOBAL                      *Global,
    224   IN BOOLEAN                              Virtual
    225   )
    226 /*++
    227 
    228 Routine Description:
    229   Retrieves the physical address of a memory mapped FV
    230 
    231 Arguments:
    232   Instance              - The FV instance whose base address is going to be
    233                           returned
    234   Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
    235                           that on successful return, contains the base address
    236                           of the firmware volume.
    237   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    238                           instance data
    239   Virtual               - Whether CPU is in virtual or physical mode
    240 
    241 Returns:
    242   EFI_SUCCESS           - Successfully returns
    243   EFI_INVALID_PARAMETER - Instance not found
    244 
    245 --*/
    246 {
    247   EFI_FW_VOL_INSTANCE *FwhInstance;
    248   EFI_STATUS          Status;
    249 
    250   //
    251   // Find the right instance of the FVB private data
    252   //
    253   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    254   ASSERT_EFI_ERROR (Status);
    255   *Address = FwhInstance->FvBase[Virtual];
    256 
    257   return EFI_SUCCESS;
    258 }
    259 
    260 EFI_STATUS
    261 FvbGetVolumeAttributes (
    262   IN UINTN                                Instance,
    263   OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
    264   IN ESAL_FWB_GLOBAL                      *Global,
    265   IN BOOLEAN                              Virtual
    266   )
    267 /*++
    268 
    269 Routine Description:
    270   Retrieves attributes, insures positive polarity of attribute bits, returns
    271   resulting attributes in output parameter
    272 
    273 Arguments:
    274   Instance              - The FV instance whose attributes is going to be
    275                           returned
    276   Attributes            - Output buffer which contains attributes
    277   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    278                           instance data
    279   Virtual               - Whether CPU is in virtual or physical mode
    280 
    281 Returns:
    282   EFI_SUCCESS           - Successfully returns
    283   EFI_INVALID_PARAMETER - Instance not found
    284 
    285 --*/
    286 {
    287   EFI_FW_VOL_INSTANCE *FwhInstance;
    288   EFI_STATUS          Status;
    289 
    290   //
    291   // Find the right instance of the FVB private data
    292   //
    293   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    294   ASSERT_EFI_ERROR (Status);
    295   *Attributes = FwhInstance->VolumeHeader.Attributes;
    296 
    297   return EFI_SUCCESS;
    298 }
    299 
    300 EFI_STATUS
    301 FvbGetLbaAddress (
    302   IN  UINTN                               Instance,
    303   IN  EFI_LBA                             Lba,
    304   OUT UINTN                               *LbaAddress,
    305   OUT UINTN                               *LbaLength,
    306   OUT UINTN                               *NumOfBlocks,
    307   IN  ESAL_FWB_GLOBAL                     *Global,
    308   IN  BOOLEAN                             Virtual
    309   )
    310 /*++
    311 
    312 Routine Description:
    313   Retrieves the starting address of an LBA in an FV
    314 
    315 Arguments:
    316   Instance              - The FV instance which the Lba belongs to
    317   Lba                   - The logical block address
    318   LbaAddress            - On output, contains the physical starting address
    319                           of the Lba
    320   LbaLength             - On output, contains the length of the block
    321   NumOfBlocks           - A pointer to a caller allocated UINTN in which the
    322                           number of consecutive blocks starting with Lba is
    323                           returned. All blocks in this range have a size of
    324                           BlockSize
    325   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    326                           instance data
    327   Virtual               - Whether CPU is in virtual or physical mode
    328 
    329 Returns:
    330   EFI_SUCCESS           - Successfully returns
    331   EFI_INVALID_PARAMETER - Instance not found
    332 
    333 --*/
    334 {
    335   UINT32                  NumBlocks;
    336   UINT32                  BlockLength;
    337   UINTN                   Offset;
    338   EFI_LBA                 StartLba;
    339   EFI_LBA                 NextLba;
    340   EFI_FW_VOL_INSTANCE     *FwhInstance;
    341   EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
    342   EFI_STATUS              Status;
    343 
    344   //
    345   // Find the right instance of the FVB private data
    346   //
    347   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    348   ASSERT_EFI_ERROR (Status);
    349 
    350   StartLba  = 0;
    351   Offset    = 0;
    352   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
    353 
    354   //
    355   // Parse the blockmap of the FV to find which map entry the Lba belongs to
    356   //
    357   while (TRUE) {
    358     NumBlocks   = BlockMap->NumBlocks;
    359     BlockLength = BlockMap->Length;
    360 
    361     if (NumBlocks == 0 || BlockLength == 0) {
    362       return EFI_INVALID_PARAMETER;
    363     }
    364 
    365     NextLba = StartLba + NumBlocks;
    366 
    367     //
    368     // The map entry found
    369     //
    370     if (Lba >= StartLba && Lba < NextLba) {
    371       Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
    372       if (LbaAddress != NULL) {
    373         *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
    374       }
    375 
    376       if (LbaLength != NULL) {
    377         *LbaLength = BlockLength;
    378       }
    379 
    380       if (NumOfBlocks != NULL) {
    381         *NumOfBlocks = (UINTN) (NextLba - Lba);
    382       }
    383 
    384       return EFI_SUCCESS;
    385     }
    386 
    387     StartLba  = NextLba;
    388     Offset    = Offset + NumBlocks * BlockLength;
    389     BlockMap++;
    390   }
    391 }
    392 
    393 EFI_STATUS
    394 FvbReadBlock (
    395   IN UINTN                                Instance,
    396   IN EFI_LBA                              Lba,
    397   IN UINTN                                BlockOffset,
    398   IN OUT UINTN                            *NumBytes,
    399   IN UINT8                                *Buffer,
    400   IN ESAL_FWB_GLOBAL                      *Global,
    401   IN BOOLEAN                              Virtual
    402   )
    403 /*++
    404 
    405 Routine Description:
    406   Reads specified number of bytes into a buffer from the specified block
    407 
    408 Arguments:
    409   Instance              - The FV instance to be read from
    410   Lba                   - The logical block address to be read from
    411   BlockOffset           - Offset into the block at which to begin reading
    412   NumBytes              - Pointer that on input contains the total size of
    413                           the buffer. On output, it contains the total number
    414                           of bytes read
    415   Buffer                - Pointer to a caller allocated buffer that will be
    416                           used to hold the data read
    417   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    418                           instance data
    419   Virtual               - Whether CPU is in virtual or physical mode
    420 
    421 Returns:
    422   EFI_SUCCESS           - The firmware volume was read successfully and
    423                           contents are in Buffer
    424   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
    425                           NumBytes contains the total number of bytes returned
    426                           in Buffer
    427   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
    428   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    429                           could not be read
    430   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    431 
    432 --*/
    433 {
    434   EFI_FVB_ATTRIBUTES_2  Attributes;
    435   UINTN                 LbaAddress;
    436   UINTN                 LbaLength;
    437   EFI_STATUS            Status;
    438 
    439   //
    440   // Check for invalid conditions
    441   //
    442   if ((NumBytes == NULL) || (Buffer == NULL)) {
    443     return EFI_INVALID_PARAMETER;
    444   }
    445 
    446   if (*NumBytes == 0) {
    447     return EFI_INVALID_PARAMETER;
    448   }
    449 
    450   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
    451   if (EFI_ERROR (Status)) {
    452     return Status;
    453   }
    454   //
    455   // Check if the FV is read enabled
    456   //
    457   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    458 
    459   if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
    460     return EFI_ACCESS_DENIED;
    461   }
    462   //
    463   // Perform boundary checks and adjust NumBytes
    464   //
    465   if (BlockOffset > LbaLength) {
    466     return EFI_INVALID_PARAMETER;
    467   }
    468 
    469   if (LbaLength < (*NumBytes + BlockOffset)) {
    470     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    471     Status    = EFI_BAD_BUFFER_SIZE;
    472   }
    473 
    474   CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));
    475 
    476   return Status;
    477 }
    478 
    479 EFI_STATUS
    480 FvbWriteBlock (
    481   IN UINTN                                Instance,
    482   IN EFI_LBA                              Lba,
    483   IN UINTN                                BlockOffset,
    484   IN OUT UINTN                            *NumBytes,
    485   IN UINT8                                *Buffer,
    486   IN ESAL_FWB_GLOBAL                      *Global,
    487   IN BOOLEAN                              Virtual
    488   )
    489 /*++
    490 
    491 Routine Description:
    492   Writes specified number of bytes from the input buffer to the block
    493 
    494 Arguments:
    495   Instance              - The FV instance to be written to
    496   Lba                   - The starting logical block index to write to
    497   BlockOffset           - Offset into the block at which to begin writing
    498   NumBytes              - Pointer that on input contains the total size of
    499                           the buffer. On output, it contains the total number
    500                           of bytes actually written
    501   Buffer                - Pointer to a caller allocated buffer that contains
    502                           the source for the write
    503   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    504                           instance data
    505   Virtual               - Whether CPU is in virtual or physical mode
    506 
    507 Returns:
    508   EFI_SUCCESS           - The firmware volume was written successfully
    509   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
    510                           NumBytes contains the total number of bytes
    511                           actually written
    512   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    513   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    514                           could not be written
    515   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    516 
    517 --*/
    518 {
    519   EFI_FVB_ATTRIBUTES_2  Attributes;
    520   UINTN                 LbaAddress;
    521   UINTN                 LbaLength;
    522   EFI_STATUS            Status;
    523 
    524   //
    525   // Check for invalid conditions
    526   //
    527   if ((NumBytes == NULL) || (Buffer == NULL)) {
    528     return EFI_INVALID_PARAMETER;
    529   }
    530 
    531   if (*NumBytes == 0) {
    532     return EFI_INVALID_PARAMETER;
    533   }
    534 
    535   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
    536   if (EFI_ERROR (Status)) {
    537     return Status;
    538   }
    539   //
    540   // Check if the FV is write enabled
    541   //
    542   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    543 
    544   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    545     return EFI_ACCESS_DENIED;
    546   }
    547   //
    548   // Perform boundary checks and adjust NumBytes
    549   //
    550   if (BlockOffset > LbaLength) {
    551     return EFI_INVALID_PARAMETER;
    552   }
    553 
    554   if (LbaLength < (*NumBytes + BlockOffset)) {
    555     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    556     Status    = EFI_BAD_BUFFER_SIZE;
    557   }
    558   //
    559   // Write data
    560   //
    561   CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));
    562 
    563   return Status;
    564 }
    565 
    566 EFI_STATUS
    567 FvbEraseBlock (
    568   IN UINTN                                Instance,
    569   IN EFI_LBA                              Lba,
    570   IN ESAL_FWB_GLOBAL                      *Global,
    571   IN BOOLEAN                              Virtual
    572   )
    573 /*++
    574 
    575 Routine Description:
    576   Erases and initializes a firmware volume block
    577 
    578 Arguments:
    579   Instance              - The FV instance to be erased
    580   Lba                   - The logical block index to be erased
    581   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    582                           instance data
    583   Virtual               - Whether CPU is in virtual or physical mode
    584 
    585 Returns:
    586   EFI_SUCCESS           - The erase request was successfully completed
    587   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    588   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    589                           could not be written. Firmware device may have been
    590                           partially erased
    591   EFI_INVALID_PARAMETER - Instance not found
    592 
    593 --*/
    594 {
    595 
    596   EFI_FVB_ATTRIBUTES_2  Attributes;
    597   UINTN                 LbaAddress;
    598   UINTN                 LbaLength;
    599   EFI_STATUS            Status;
    600   UINT8                 Data;
    601 
    602   //
    603   // Check if the FV is write enabled
    604   //
    605   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    606 
    607   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    608     return EFI_ACCESS_DENIED;
    609   }
    610   //
    611   // Get the starting address of the block for erase.
    612   //
    613   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
    614 
    615   if (EFI_ERROR (Status)) {
    616     return Status;
    617   }
    618 
    619   if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
    620     Data = 0xFF;
    621   } else {
    622     Data = 0x0;
    623   }
    624 
    625   SetMem ((UINT8 *) LbaAddress, LbaLength, Data);
    626 
    627   return EFI_SUCCESS;
    628 }
    629 
    630 EFI_STATUS
    631 FvbSetVolumeAttributes (
    632   IN UINTN                                  Instance,
    633   IN OUT EFI_FVB_ATTRIBUTES_2               *Attributes,
    634   IN ESAL_FWB_GLOBAL                        *Global,
    635   IN BOOLEAN                                Virtual
    636   )
    637 /*++
    638 
    639 Routine Description:
    640   Modifies the current settings of the firmware volume according to the
    641   input parameter, and returns the new setting of the volume
    642 
    643 Arguments:
    644   Instance              - The FV instance whose attributes is going to be
    645                           modified
    646   Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
    647                           containing the desired firmware volume settings.
    648                           On successful return, it contains the new settings
    649                           of the firmware volume
    650   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    651                           instance data
    652   Virtual               - Whether CPU is in virtual or physical mode
    653 
    654 Returns:
    655   EFI_SUCCESS           - Successfully returns
    656   EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
    657   EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
    658                           in conflict with the capabilities as declared in the
    659                           firmware volume header
    660 
    661 --*/
    662 {
    663   EFI_FW_VOL_INSTANCE   *FwhInstance;
    664   EFI_FVB_ATTRIBUTES_2  OldAttributes;
    665   EFI_FVB_ATTRIBUTES_2  *AttribPtr;
    666   UINT32                Capabilities;
    667   UINT32                OldStatus;
    668   UINT32                NewStatus;
    669   EFI_STATUS            Status;
    670   EFI_FVB_ATTRIBUTES_2  UnchangedAttributes;
    671 
    672   //
    673   // Find the right instance of the FVB private data
    674   //
    675   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    676   ASSERT_EFI_ERROR (Status);
    677 
    678   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
    679   OldAttributes = *AttribPtr;
    680   Capabilities  = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
    681                                    EFI_FVB2_READ_ENABLED_CAP | \
    682                                    EFI_FVB2_WRITE_DISABLED_CAP | \
    683                                    EFI_FVB2_WRITE_ENABLED_CAP | \
    684                                    EFI_FVB2_LOCK_CAP \
    685                                    );
    686   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
    687   NewStatus     = *Attributes & EFI_FVB2_STATUS;
    688 
    689   UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
    690                         EFI_FVB2_READ_ENABLED_CAP   | \
    691                         EFI_FVB2_WRITE_DISABLED_CAP | \
    692                         EFI_FVB2_WRITE_ENABLED_CAP  | \
    693                         EFI_FVB2_LOCK_CAP           | \
    694                         EFI_FVB2_STICKY_WRITE       | \
    695                         EFI_FVB2_MEMORY_MAPPED      | \
    696                         EFI_FVB2_ERASE_POLARITY     | \
    697                         EFI_FVB2_READ_LOCK_CAP      | \
    698                         EFI_FVB2_WRITE_LOCK_CAP     | \
    699                         EFI_FVB2_ALIGNMENT;
    700 
    701   //
    702   // Some attributes of FV is read only can *not* be set
    703   //
    704   if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
    705     return EFI_INVALID_PARAMETER;
    706   }
    707   //
    708   // If firmware volume is locked, no status bit can be updated
    709   //
    710   if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
    711     if (OldStatus ^ NewStatus) {
    712       return EFI_ACCESS_DENIED;
    713     }
    714   }
    715   //
    716   // Test read disable
    717   //
    718   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    719     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
    720       return EFI_INVALID_PARAMETER;
    721     }
    722   }
    723   //
    724   // Test read enable
    725   //
    726   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    727     if (NewStatus & EFI_FVB2_READ_STATUS) {
    728       return EFI_INVALID_PARAMETER;
    729     }
    730   }
    731   //
    732   // Test write disable
    733   //
    734   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    735     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
    736       return EFI_INVALID_PARAMETER;
    737     }
    738   }
    739   //
    740   // Test write enable
    741   //
    742   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    743     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
    744       return EFI_INVALID_PARAMETER;
    745     }
    746   }
    747   //
    748   // Test lock
    749   //
    750   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    751     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
    752       return EFI_INVALID_PARAMETER;
    753     }
    754   }
    755 
    756   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
    757   *AttribPtr  = (*AttribPtr) | NewStatus;
    758   *Attributes = *AttribPtr;
    759 
    760   return EFI_SUCCESS;
    761 }
    762 //
    763 // FVB protocol APIs
    764 //
    765 EFI_STATUS
    766 EFIAPI
    767 FvbProtocolGetPhysicalAddress (
    768   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
    769   OUT EFI_PHYSICAL_ADDRESS                        *Address
    770   )
    771 /*++
    772 
    773 Routine Description:
    774 
    775   Retrieves the physical address of the device.
    776 
    777 Arguments:
    778 
    779   This                  - Calling context
    780   Address               - Output buffer containing the address.
    781 
    782 Returns:
    783 
    784 Returns:
    785   EFI_SUCCESS           - Successfully returns
    786 
    787 --*/
    788 {
    789   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    790 
    791   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    792 
    793   return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
    794 }
    795 
    796 EFI_STATUS
    797 EFIAPI
    798 FvbProtocolGetBlockSize (
    799   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
    800   IN CONST EFI_LBA                                     Lba,
    801   OUT UINTN                                       *BlockSize,
    802   OUT UINTN                                       *NumOfBlocks
    803   )
    804 /*++
    805 
    806 Routine Description:
    807   Retrieve the size of a logical block
    808 
    809 Arguments:
    810   This                  - Calling context
    811   Lba                   - Indicates which block to return the size for.
    812   BlockSize             - A pointer to a caller allocated UINTN in which
    813                           the size of the block is returned
    814   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
    815                           number of consecutive blocks starting with Lba is
    816                           returned. All blocks in this range have a size of
    817                           BlockSize
    818 
    819 Returns:
    820   EFI_SUCCESS           - The firmware volume was read successfully and
    821                           contents are in Buffer
    822 
    823 --*/
    824 {
    825   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    826 
    827   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    828 
    829   return FvbGetLbaAddress (
    830           FvbDevice->Instance,
    831           Lba,
    832           NULL,
    833           BlockSize,
    834           NumOfBlocks,
    835           mFvbModuleGlobal,
    836           EfiGoneVirtual ()
    837           );
    838 }
    839 
    840 EFI_STATUS
    841 EFIAPI
    842 FvbProtocolGetAttributes (
    843   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
    844   OUT EFI_FVB_ATTRIBUTES_2                              *Attributes
    845   )
    846 /*++
    847 
    848 Routine Description:
    849     Retrieves Volume attributes.  No polarity translations are done.
    850 
    851 Arguments:
    852     This                - Calling context
    853     Attributes          - output buffer which contains attributes
    854 
    855 Returns:
    856   EFI_SUCCESS           - Successfully returns
    857 
    858 --*/
    859 {
    860   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    861 
    862   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    863 
    864   return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
    865 }
    866 
    867 EFI_STATUS
    868 EFIAPI
    869 FvbProtocolSetAttributes (
    870   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
    871   IN OUT EFI_FVB_ATTRIBUTES_2                           *Attributes
    872   )
    873 /*++
    874 
    875 Routine Description:
    876   Sets Volume attributes. No polarity translations are done.
    877 
    878 Arguments:
    879   This                  - Calling context
    880   Attributes            - output buffer which contains attributes
    881 
    882 Returns:
    883   EFI_SUCCESS           - Successfully returns
    884 
    885 --*/
    886 {
    887   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    888 
    889   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    890 
    891   return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
    892 }
    893 
    894 EFI_STATUS
    895 EFIAPI
    896 FvbProtocolEraseBlocks (
    897   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
    898   ...
    899   )
    900 /*++
    901 
    902 Routine Description:
    903 
    904   The EraseBlock() function erases one or more blocks as denoted by the
    905   variable argument list. The entire parameter list of blocks must be verified
    906   prior to erasing any blocks.  If a block is requested that does not exist
    907   within the associated firmware volume (it has a larger index than the last
    908   block of the firmware volume), the EraseBlock() function must return
    909   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
    910 
    911 Arguments:
    912   This                  - Calling context
    913   ...                   - Starting LBA followed by Number of Lba to erase.
    914                           a -1 to terminate the list.
    915 
    916 Returns:
    917   EFI_SUCCESS           - The erase request was successfully completed
    918   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    919   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    920                           could not be written. Firmware device may have been
    921                           partially erased
    922 
    923 --*/
    924 {
    925   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    926   EFI_FW_VOL_INSTANCE     *FwhInstance;
    927   UINTN                   NumOfBlocks;
    928   VA_LIST                 args;
    929   EFI_LBA                 StartingLba;
    930   UINTN                   NumOfLba;
    931   EFI_STATUS              Status;
    932 
    933   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    934 
    935   Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
    936   ASSERT_EFI_ERROR (Status);
    937 
    938   NumOfBlocks = FwhInstance->NumOfBlocks;
    939 
    940   VA_START (args, This);
    941 
    942   do {
    943     StartingLba = VA_ARG (args, EFI_LBA);
    944     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
    945       break;
    946     }
    947 
    948     NumOfLba = VA_ARG (args, UINT32);
    949 
    950     //
    951     // Check input parameters
    952     //
    953     if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
    954       VA_END (args);
    955       return EFI_INVALID_PARAMETER;
    956     }
    957   } while (1);
    958 
    959   VA_END (args);
    960 
    961   VA_START (args, This);
    962   do {
    963     StartingLba = VA_ARG (args, EFI_LBA);
    964     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
    965       break;
    966     }
    967 
    968     NumOfLba = VA_ARG (args, UINT32);
    969 
    970     while (NumOfLba > 0) {
    971       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
    972       if (EFI_ERROR (Status)) {
    973         VA_END (args);
    974         return Status;
    975       }
    976 
    977       StartingLba++;
    978       NumOfLba--;
    979     }
    980 
    981   } while (1);
    982 
    983   VA_END (args);
    984 
    985   return EFI_SUCCESS;
    986 }
    987 
    988 EFI_STATUS
    989 EFIAPI
    990 FvbProtocolWrite (
    991   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
    992   IN       EFI_LBA                                      Lba,
    993   IN       UINTN                                        Offset,
    994   IN OUT   UINTN                                    *NumBytes,
    995   IN       UINT8                                        *Buffer
    996   )
    997 /*++
    998 
    999 Routine Description:
   1000 
   1001   Writes data beginning at Lba:Offset from FV. The write terminates either
   1002   when *NumBytes of data have been written, or when a block boundary is
   1003   reached.  *NumBytes is updated to reflect the actual number of bytes
   1004   written. The write opertion does not include erase. This routine will
   1005   attempt to write only the specified bytes. If the writes do not stick,
   1006   it will return an error.
   1007 
   1008 Arguments:
   1009   This                  - Calling context
   1010   Lba                   - Block in which to begin write
   1011   Offset                - Offset in the block at which to begin write
   1012   NumBytes              - On input, indicates the requested write size. On
   1013                           output, indicates the actual number of bytes written
   1014   Buffer                - Buffer containing source data for the write.
   1015 
   1016 Returns:
   1017   EFI_SUCCESS           - The firmware volume was written successfully
   1018   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
   1019                           NumBytes contains the total number of bytes
   1020                           actually written
   1021   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
   1022   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1023                           could not be written
   1024   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1025 
   1026 --*/
   1027 {
   1028 
   1029   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1030 
   1031   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1032 
   1033   return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1034 }
   1035 
   1036 EFI_STATUS
   1037 EFIAPI
   1038 FvbProtocolRead (
   1039   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
   1040   IN CONST EFI_LBA                                      Lba,
   1041   IN CONST UINTN                                        Offset,
   1042   IN OUT UINTN                                    *NumBytes,
   1043   IN UINT8                                        *Buffer
   1044   )
   1045 /*++
   1046 
   1047 Routine Description:
   1048 
   1049   Reads data beginning at Lba:Offset from FV. The Read terminates either
   1050   when *NumBytes of data have been read, or when a block boundary is
   1051   reached.  *NumBytes is updated to reflect the actual number of bytes
   1052   written. The write opertion does not include erase. This routine will
   1053   attempt to write only the specified bytes. If the writes do not stick,
   1054   it will return an error.
   1055 
   1056 Arguments:
   1057   This                  - Calling context
   1058   Lba                   - Block in which to begin Read
   1059   Offset                - Offset in the block at which to begin Read
   1060   NumBytes              - On input, indicates the requested write size. On
   1061                           output, indicates the actual number of bytes Read
   1062   Buffer                - Buffer containing source data for the Read.
   1063 
   1064 Returns:
   1065   EFI_SUCCESS           - The firmware volume was read successfully and
   1066                           contents are in Buffer
   1067   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
   1068                           NumBytes contains the total number of bytes returned
   1069                           in Buffer
   1070   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
   1071   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1072                           could not be read
   1073   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1074 
   1075 --*/
   1076 {
   1077 
   1078   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1079 
   1080   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1081 
   1082   return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1083 }
   1084 
   1085 EFI_STATUS
   1086 ValidateFvHeader (
   1087   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
   1088   )
   1089 /*++
   1090 
   1091 Routine Description:
   1092   Check the integrity of firmware volume header
   1093 
   1094 Arguments:
   1095   FwVolHeader           - A pointer to a firmware volume header
   1096 
   1097 Returns:
   1098   EFI_SUCCESS           - The firmware volume is consistent
   1099   EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
   1100 
   1101 --*/
   1102 {
   1103   //
   1104   // Verify the header revision, header signature, length
   1105   // Length of FvBlock cannot be 2**64-1
   1106   // HeaderLength cannot be an odd number
   1107   //
   1108   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
   1109       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
   1110       (FwVolHeader->FvLength == ((UINTN) -1)) ||
   1111       ((FwVolHeader->HeaderLength & 0x01) != 0)
   1112       ) {
   1113     return EFI_NOT_FOUND;
   1114   }
   1115 
   1116   //
   1117   // Verify the header checksum
   1118   //
   1119   if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
   1120     return EFI_NOT_FOUND;
   1121   }
   1122 
   1123   return EFI_SUCCESS;
   1124 }
   1125 
   1126 EFI_STATUS
   1127 EFIAPI
   1128 FvbInitialize (
   1129   IN EFI_HANDLE         ImageHandle,
   1130   IN EFI_SYSTEM_TABLE   *SystemTable
   1131   )
   1132 /*++
   1133 
   1134 Routine Description:
   1135   This function does common initialization for FVB services
   1136 
   1137 Arguments:
   1138 
   1139 Returns:
   1140 
   1141 --*/
   1142 {
   1143   EFI_STATUS                          Status;
   1144   EFI_FW_VOL_INSTANCE                 *FwhInstance;
   1145   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
   1146   EFI_DXE_SERVICES                    *DxeServices;
   1147   EFI_GCD_MEMORY_SPACE_DESCRIPTOR     Descriptor;
   1148   UINT32                              BufferSize;
   1149   EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
   1150   EFI_HANDLE                          FwbHandle;
   1151   EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
   1152   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
   1153   UINT32                              MaxLbaSize;
   1154   EFI_PHYSICAL_ADDRESS                BaseAddress;
   1155   UINT64                              Length;
   1156   UINTN                               NumOfBlocks;
   1157   EFI_PEI_HOB_POINTERS                FvHob;
   1158 
   1159   //
   1160   // Get the DXE services table
   1161   //
   1162   DxeServices = gDS;
   1163 
   1164   //
   1165   // Allocate runtime services data for global variable, which contains
   1166   // the private data of all firmware volume block instances
   1167   //
   1168   mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
   1169   ASSERT (mFvbModuleGlobal != NULL);
   1170 
   1171   //
   1172   // Calculate the total size for all firmware volume block instances
   1173   //
   1174   BufferSize            = 0;
   1175 
   1176   FvHob.Raw = GetHobList ();
   1177   while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
   1178     BaseAddress = FvHob.FirmwareVolume->BaseAddress;
   1179     Length      = FvHob.FirmwareVolume->Length;
   1180     //
   1181     // Check if it is a "real" flash
   1182     //
   1183     Status = DxeServices->GetMemorySpaceDescriptor (
   1184                             BaseAddress,
   1185                             &Descriptor
   1186                             );
   1187     if (EFI_ERROR (Status)) {
   1188       break;
   1189     }
   1190 
   1191     if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
   1192       FvHob.Raw = GET_NEXT_HOB (FvHob);
   1193       continue;
   1194     }
   1195 
   1196     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
   1197     Status      = ValidateFvHeader (FwVolHeader);
   1198     if (EFI_ERROR (Status)) {
   1199       //
   1200       // Get FvbInfo
   1201       //
   1202       Status = GetFvbInfo (Length, &FwVolHeader);
   1203       if (EFI_ERROR (Status)) {
   1204         FvHob.Raw = GET_NEXT_HOB (FvHob);
   1205         continue;
   1206       }
   1207     }
   1208 
   1209     BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
   1210     FvHob.Raw = GET_NEXT_HOB (FvHob);
   1211   }
   1212 
   1213   //
   1214   // Only need to allocate once. There is only one copy of physical memory for
   1215   // the private data of each FV instance. But in virtual mode or in physical
   1216   // mode, the address of the the physical memory may be different.
   1217   //
   1218   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);
   1219   ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);
   1220 
   1221   //
   1222   // Make a virtual copy of the FvInstance pointer.
   1223   //
   1224   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
   1225   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
   1226 
   1227   mFvbModuleGlobal->NumFv                   = 0;
   1228   MaxLbaSize = 0;
   1229 
   1230   FvHob.Raw = GetHobList ();
   1231   while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
   1232     BaseAddress = FvHob.FirmwareVolume->BaseAddress;
   1233     Length      = FvHob.FirmwareVolume->Length;
   1234     //
   1235     // Check if it is a "real" flash
   1236     //
   1237     Status = DxeServices->GetMemorySpaceDescriptor (
   1238                             BaseAddress,
   1239                             &Descriptor
   1240                             );
   1241     if (EFI_ERROR (Status)) {
   1242       break;
   1243     }
   1244 
   1245     if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
   1246       FvHob.Raw = GET_NEXT_HOB (FvHob);
   1247       continue;
   1248     }
   1249 
   1250     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
   1251     Status      = ValidateFvHeader (FwVolHeader);
   1252     if (EFI_ERROR (Status)) {
   1253       //
   1254       // Get FvbInfo to provide in FwhInstance.
   1255       //
   1256       Status = GetFvbInfo (Length, &FwVolHeader);
   1257       if (EFI_ERROR (Status)) {
   1258         FvHob.Raw = GET_NEXT_HOB (FvHob);
   1259         continue;
   1260       }
   1261       //
   1262       //  Write healthy FV header back.
   1263       //
   1264       CopyMem (
   1265         (VOID *) (UINTN) BaseAddress,
   1266         (VOID *) FwVolHeader,
   1267         FwVolHeader->HeaderLength
   1268         );
   1269     }
   1270 
   1271     FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
   1272     FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
   1273 
   1274     CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
   1275     FwVolHeader = &(FwhInstance->VolumeHeader);
   1276     EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
   1277 
   1278     NumOfBlocks = 0;
   1279 
   1280     for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
   1281       //
   1282       // Get the maximum size of a block.
   1283       //
   1284       if (MaxLbaSize < PtrBlockMapEntry->Length) {
   1285         MaxLbaSize = PtrBlockMapEntry->Length;
   1286       }
   1287 
   1288       NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
   1289     }
   1290     //
   1291     // The total number of blocks in the FV.
   1292     //
   1293     FwhInstance->NumOfBlocks = NumOfBlocks;
   1294 
   1295     //
   1296     // Add a FVB Protocol Instance
   1297     //
   1298     FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
   1299     ASSERT (FvbDevice != NULL);
   1300 
   1301     CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
   1302 
   1303     FvbDevice->Instance = mFvbModuleGlobal->NumFv;
   1304     mFvbModuleGlobal->NumFv++;
   1305 
   1306 
   1307     //
   1308     // Set up the devicepath
   1309     //
   1310     if (FwVolHeader->ExtHeaderOffset == 0) {
   1311         //
   1312         // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
   1313         //
   1314       FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
   1315       ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
   1316       ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress   = BaseAddress + FwVolHeader->FvLength - 1;
   1317     } else {
   1318       FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
   1319       CopyGuid (
   1320         &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
   1321         (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
   1322         );
   1323     }
   1324     //
   1325     // Find a handle with a matching device path that has supports FW Block protocol
   1326     //
   1327     Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->DevicePath, &FwbHandle);
   1328     if (EFI_ERROR (Status)) {
   1329       //
   1330       // LocateDevicePath fails so install a new interface and device path
   1331       //
   1332       FwbHandle = NULL;
   1333       Status = gBS->InstallMultipleProtocolInterfaces (
   1334                       &FwbHandle,
   1335                       &gEfiFirmwareVolumeBlockProtocolGuid,
   1336                       &FvbDevice->FwVolBlockInstance,
   1337                       &gEfiDevicePathProtocolGuid,
   1338                       FvbDevice->DevicePath,
   1339                       NULL
   1340                       );
   1341       ASSERT_EFI_ERROR (Status);
   1342     } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
   1343       //
   1344       // Device allready exists, so reinstall the FVB protocol
   1345       //
   1346       Status = gBS->HandleProtocol (
   1347                       FwbHandle,
   1348                       &gEfiFirmwareVolumeBlockProtocolGuid,
   1349                       (VOID**)&OldFwbInterface
   1350                       );
   1351       ASSERT_EFI_ERROR (Status);
   1352 
   1353       Status = gBS->ReinstallProtocolInterface (
   1354                       FwbHandle,
   1355                       &gEfiFirmwareVolumeBlockProtocolGuid,
   1356                       OldFwbInterface,
   1357                       &FvbDevice->FwVolBlockInstance
   1358                       );
   1359       ASSERT_EFI_ERROR (Status);
   1360 
   1361     } else {
   1362       //
   1363       // There was a FVB protocol on an End Device Path node
   1364       //
   1365       ASSERT (FALSE);
   1366     }
   1367 
   1368     FwhInstance = (EFI_FW_VOL_INSTANCE *)
   1369       (
   1370         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
   1371           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
   1372       );
   1373 
   1374     FvHob.Raw = GET_NEXT_HOB (FvHob);
   1375   }
   1376 
   1377   return EFI_SUCCESS;
   1378 }
   1379