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