Home | History | Annotate | Download | only in SpiFvbServices
      1 /** @file
      2 
      3 Copyright (c) 2013-2015 Intel Corporation.
      4 
      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 
     16 #include "FwBlockService.h"
     17 
     18 ESAL_FWB_GLOBAL         *mFvbModuleGlobal;
     19 
     20 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
     21   FVB_DEVICE_SIGNATURE,  // Signature
     22   //
     23   // FV_DEVICE_PATH                      FvDevicePath
     24   //
     25   {
     26     {
     27       {
     28         HARDWARE_DEVICE_PATH,
     29         HW_MEMMAP_DP,
     30         {
     31           (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
     32           (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
     33         }
     34       },
     35       EfiMemoryMappedIO,
     36       (EFI_PHYSICAL_ADDRESS) 0,
     37       (EFI_PHYSICAL_ADDRESS) 0
     38     },
     39     {
     40       END_DEVICE_PATH_TYPE,
     41       END_ENTIRE_DEVICE_PATH_SUBTYPE,
     42       {
     43         END_DEVICE_PATH_LENGTH,
     44         0
     45       }
     46     }
     47   },
     48   //
     49   //   UEFI_FV_DEVICE_PATH                 UefiFvDevicePath
     50   //
     51   {
     52     {
     53       {
     54         MEDIA_DEVICE_PATH,
     55         MEDIA_PIWG_FW_VOL_DP,
     56         {
     57           (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
     58           (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
     59         }
     60       },
     61       { 0 }
     62     },
     63     {
     64       END_DEVICE_PATH_TYPE,
     65       END_ENTIRE_DEVICE_PATH_SUBTYPE,
     66       {
     67         END_DEVICE_PATH_LENGTH,
     68         0
     69       }
     70     }
     71   },
     72   0,      // Instance
     73   //
     74   // EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  FwVolBlockInstance
     75   //
     76   {
     77     FvbProtocolGetAttributes,
     78     FvbProtocolSetAttributes,
     79     FvbProtocolGetPhysicalAddress,
     80     FvbProtocolGetBlockSize,
     81     FvbProtocolRead,
     82     FvbProtocolWrite,
     83     FvbProtocolEraseBlocks,
     84     NULL
     85   }
     86 };
     87 
     88 UINT32 mInSmmMode = 0;
     89 EFI_SMM_SYSTEM_TABLE2*   mSmst = NULL;
     90 
     91 VOID
     92 PublishFlashDeviceInfo (
     93   IN SPI_INIT_TABLE   *Found
     94   )
     95 /*++
     96 
     97 Routine Description:
     98 
     99   Publish info on found flash device to other drivers via PcdSpiFlashDeviceSize.
    100 
    101 Arguments:
    102   Found                 - Pointer to entry in mSpiInitTable for found flash part.
    103 
    104 Returns:
    105   None
    106 
    107 --*/
    108 {
    109   EFI_STATUS  Status;
    110 
    111   //
    112   // Publish Byte Size of found flash device.
    113   //
    114   Status = PcdSet32S (PcdSpiFlashDeviceSize, (UINT32)(Found->BiosStartOffset + Found->BiosSize));
    115   ASSERT_EFI_ERROR (Status);
    116 }
    117 
    118 VOID
    119 FvbVirtualddressChangeEvent (
    120   IN EFI_EVENT        Event,
    121   IN VOID             *Context
    122   )
    123 /*++
    124 
    125 Routine Description:
    126 
    127   Fixup internal data so that EFI and SAL can be call in virtual mode.
    128   Call the passed in Child Notify event and convert the mFvbModuleGlobal
    129   date items to there virtual address.
    130 
    131   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]  - Physical copy of instance data
    132   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]   - Virtual pointer to common
    133                                                 instance data.
    134 
    135 Arguments:
    136 
    137   (Standard EFI notify event - EFI_EVENT_NOTIFY)
    138 
    139 Returns:
    140 
    141   None
    142 
    143 --*/
    144 {
    145   EFI_FW_VOL_INSTANCE *FwhInstance;
    146   UINTN               Index;
    147 
    148   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
    149 
    150   //
    151   // Convert the base address of all the instances
    152   //
    153   Index       = 0;
    154   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
    155   while (Index < mFvbModuleGlobal->NumFv) {
    156 
    157   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
    158     //
    159     // SpiWrite and SpiErase always use Physical Address instead of
    160     // Virtual Address, even in Runtime. So we need not convert pointer
    161     // for FvWriteBase[FVB_VIRTUAL]
    162     //
    163     // EfiConvertPointer (0, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]);
    164     //
    165     FwhInstance = (EFI_FW_VOL_INSTANCE *)
    166       (
    167         (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
    168           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
    169       );
    170     Index++;
    171   }
    172 
    173   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
    174   //
    175   // Convert SPI_PROTOCOL instance for runtime
    176   //
    177   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->SpiProtocol);
    178   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal);
    179 }
    180 
    181 VOID
    182 FvbMemWrite8 (
    183   IN  UINT64                              Dest,
    184   IN  UINT8                               Byte
    185   )
    186 {
    187   MmioWrite8 ((UINTN)Dest, Byte);
    188 
    189   return ;
    190 }
    191 
    192 EFI_STATUS
    193 GetFvbInstance (
    194   IN  UINTN                               Instance,
    195   IN  ESAL_FWB_GLOBAL                     *Global,
    196   OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
    197   IN BOOLEAN                              Virtual
    198   )
    199 /*++
    200 
    201 Routine Description:
    202   Retrieves the physical address of a memory mapped FV
    203 
    204 Arguments:
    205   Instance              - The FV instance whose base address is going to be
    206                           returned
    207   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    208                           instance data
    209   FwhInstance           - The EFI_FW_VOL_INSTANCE fimrware instance structure
    210   Virtual               - Whether CPU is in virtual or physical mode
    211 
    212 Returns:
    213   EFI_SUCCESS           - Successfully returns
    214   EFI_INVALID_PARAMETER - Instance not found
    215 
    216 --*/
    217 {
    218   EFI_FW_VOL_INSTANCE *FwhRecord;
    219 
    220   if (Instance >= Global->NumFv) {
    221     return EFI_INVALID_PARAMETER;
    222   }
    223   //
    224   // Find the right instance of the FVB private data
    225   //
    226   FwhRecord = Global->FvInstance[Virtual];
    227   while (Instance > 0) {
    228     FwhRecord = (EFI_FW_VOL_INSTANCE *)
    229       (
    230         (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
    231           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
    232       );
    233     Instance--;
    234   }
    235 
    236   *FwhInstance = FwhRecord;
    237 
    238   return EFI_SUCCESS;
    239 }
    240 
    241 EFI_STATUS
    242 FvbGetPhysicalAddress (
    243   IN UINTN                                Instance,
    244   OUT EFI_PHYSICAL_ADDRESS                *Address,
    245   IN ESAL_FWB_GLOBAL                      *Global,
    246   IN BOOLEAN                              Virtual
    247   )
    248 /*++
    249 
    250 Routine Description:
    251   Retrieves the physical address of a memory mapped FV
    252 
    253 Arguments:
    254   Instance              - The FV instance whose base address is going to be
    255                           returned
    256   Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
    257                           that on successful return, contains the base address
    258                           of the firmware volume.
    259   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    260                           instance data
    261   Virtual               - Whether CPU is in virtual or physical mode
    262 
    263 Returns:
    264   EFI_SUCCESS           - Successfully returns
    265   EFI_INVALID_PARAMETER - Instance not found
    266 
    267 --*/
    268 {
    269   EFI_FW_VOL_INSTANCE *FwhInstance;
    270   EFI_STATUS          Status;
    271 
    272   FwhInstance = NULL;
    273 
    274   //
    275   // Find the right instance of the FVB private data
    276   //
    277   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    278   ASSERT_EFI_ERROR (Status);
    279   *Address = FwhInstance->FvBase[Virtual];
    280 
    281   return EFI_SUCCESS;
    282 }
    283 
    284 EFI_STATUS
    285 FvbGetVolumeAttributes (
    286   IN UINTN                                Instance,
    287   OUT EFI_FVB_ATTRIBUTES_2                  *Attributes,
    288   IN ESAL_FWB_GLOBAL                      *Global,
    289   IN BOOLEAN                              Virtual
    290   )
    291 /*++
    292 
    293 Routine Description:
    294   Retrieves attributes, insures positive polarity of attribute bits, returns
    295   resulting attributes in output parameter
    296 
    297 Arguments:
    298   Instance              - The FV instance whose attributes is going to be
    299                           returned
    300   Attributes            - Output buffer which contains attributes
    301   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    302                           instance data
    303   Virtual               - Whether CPU is in virtual or physical mode
    304 
    305 Returns:
    306   EFI_SUCCESS           - Successfully returns
    307   EFI_INVALID_PARAMETER - Instance not found
    308 
    309 --*/
    310 {
    311   EFI_FW_VOL_INSTANCE *FwhInstance;
    312   EFI_STATUS          Status;
    313 
    314   FwhInstance = NULL;
    315 
    316   //
    317   // Find the right instance of the FVB private data
    318   //
    319   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    320   ASSERT_EFI_ERROR (Status);
    321   *Attributes = FwhInstance->VolumeHeader.Attributes;
    322 
    323   return EFI_SUCCESS;
    324 }
    325 
    326 EFI_STATUS
    327 FvbGetLbaAddress (
    328   IN  UINTN                               Instance,
    329   IN  EFI_LBA                             Lba,
    330   OUT UINTN                               *LbaAddress,
    331   OUT UINTN                               *LbaWriteAddress,
    332   OUT UINTN                               *LbaLength,
    333   OUT UINTN                               *NumOfBlocks,
    334   IN  ESAL_FWB_GLOBAL                     *Global,
    335   IN  BOOLEAN                             Virtual
    336   )
    337 /*++
    338 
    339 Routine Description:
    340   Retrieves the starting address of an LBA in an FV
    341 
    342 Arguments:
    343   Instance              - The FV instance which the Lba belongs to
    344   Lba                   - The logical block address
    345   LbaAddress            - On output, contains the physical starting address
    346                           of the Lba
    347   LbaWriteAddress       - On output, contains the physical starting address
    348                           of the Lba for writing
    349   LbaLength             - On output, contains the length of the block
    350   NumOfBlocks           - A pointer to a caller allocated UINTN in which the
    351                           number of consecutive blocks starting with Lba is
    352                           returned. All blocks in this range have a size of
    353                           BlockSize
    354   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    355                           instance data
    356   Virtual               - Whether CPU is in virtual or physical mode
    357 
    358 Returns:
    359   EFI_SUCCESS           - Successfully returns
    360   EFI_INVALID_PARAMETER - Instance not found
    361 
    362 --*/
    363 {
    364   UINT32                  NumBlocks;
    365   UINT32                  BlockLength;
    366   UINTN                   Offset;
    367   EFI_LBA                 StartLba;
    368   EFI_LBA                 NextLba;
    369   EFI_FW_VOL_INSTANCE     *FwhInstance;
    370   EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
    371   EFI_STATUS              Status;
    372 
    373   FwhInstance = NULL;
    374 
    375   //
    376   // Find the right instance of the FVB private data
    377   //
    378   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    379   ASSERT_EFI_ERROR (Status);
    380 
    381   StartLba  = 0;
    382   Offset    = 0;
    383   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
    384 
    385   //
    386   // Parse the blockmap of the FV to find which map entry the Lba belongs to
    387   //
    388   while (TRUE) {
    389     NumBlocks   = BlockMap->NumBlocks;
    390     BlockLength = BlockMap->Length;
    391 
    392     if ((NumBlocks == 0) || (BlockLength == 0)) {
    393       return EFI_INVALID_PARAMETER;
    394     }
    395 
    396     NextLba = StartLba + NumBlocks;
    397 
    398     //
    399     // The map entry found
    400     //
    401     if (Lba >= StartLba && Lba < NextLba) {
    402       Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
    403       if (LbaAddress) {
    404         *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
    405       }
    406 
    407       if (LbaWriteAddress) {
    408         *LbaWriteAddress = FwhInstance->FvWriteBase[Virtual] + Offset;
    409       }
    410 
    411       if (LbaLength) {
    412         *LbaLength = BlockLength;
    413       }
    414 
    415       if (NumOfBlocks) {
    416         *NumOfBlocks = (UINTN) (NextLba - Lba);
    417       }
    418 
    419       return EFI_SUCCESS;
    420     }
    421 
    422     StartLba  = NextLba;
    423     Offset    = Offset + NumBlocks * BlockLength;
    424     BlockMap++;
    425   }
    426 }
    427 
    428 EFI_STATUS
    429 FvbReadBlock (
    430   IN UINTN                                Instance,
    431   IN EFI_LBA                              Lba,
    432   IN UINTN                                BlockOffset,
    433   IN OUT UINTN                            *NumBytes,
    434   IN UINT8                                *Buffer,
    435   IN ESAL_FWB_GLOBAL                      *Global,
    436   IN BOOLEAN                              Virtual
    437   )
    438 /*++
    439 
    440 Routine Description:
    441   Reads specified number of bytes into a buffer from the specified block
    442 
    443 Arguments:
    444   Instance              - The FV instance to be read from
    445   Lba                   - The logical block address to be read from
    446   BlockOffset           - Offset into the block at which to begin reading
    447   NumBytes              - Pointer that on input contains the total size of
    448                           the buffer. On output, it contains the total number
    449                           of bytes read
    450   Buffer                - Pointer to a caller allocated buffer that will be
    451                           used to hold the data read
    452   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    453                           instance data
    454   Virtual               - Whether CPU is in virtual or physical mode
    455 
    456 Returns:
    457   EFI_SUCCESS           - The firmware volume was read successfully and
    458                           contents are in Buffer
    459   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
    460                           NumBytes contains the total number of bytes returned
    461                           in Buffer
    462   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
    463   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    464                           could not be read
    465   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    466 
    467 --*/
    468 {
    469   EFI_FVB_ATTRIBUTES_2  Attributes;
    470   UINTN               LbaAddress;
    471   UINTN               LbaLength;
    472   EFI_STATUS          Status;
    473 
    474   //
    475   // Check for invalid conditions
    476   //
    477   if ((NumBytes == NULL) || (Buffer == NULL)) {
    478     return EFI_INVALID_PARAMETER;
    479   }
    480 
    481   if (*NumBytes == 0) {
    482     return EFI_INVALID_PARAMETER;
    483   }
    484 
    485   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, NULL, &LbaLength, NULL, Global, Virtual);
    486   if (EFI_ERROR (Status)) {
    487     return Status;
    488   }
    489   //
    490   // Check if the FV is read enabled
    491   //
    492   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    493 
    494   if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
    495     return EFI_ACCESS_DENIED;
    496   }
    497   //
    498   // Perform boundary checks and adjust NumBytes
    499   //
    500   if (BlockOffset > LbaLength) {
    501     return EFI_INVALID_PARAMETER;
    502   }
    503 
    504   if (LbaLength < (*NumBytes + BlockOffset)) {
    505     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    506     Status    = EFI_BAD_BUFFER_SIZE;
    507   }
    508 
    509   MmioReadBuffer8 (LbaAddress + BlockOffset, (UINTN) *NumBytes, Buffer);
    510 
    511   return Status;
    512 }
    513 
    514 EFI_STATUS
    515 FlashFdWrite (
    516   IN  UINTN                               WriteAddress,
    517   IN  UINTN                               Address,
    518   IN OUT UINTN                            *NumBytes,
    519   IN  UINT8                               *Buffer,
    520   IN  UINTN                               LbaLength
    521   )
    522 /*++
    523 
    524 Routine Description:
    525   Writes specified number of bytes from the input buffer to the address
    526 
    527 Arguments:
    528 
    529 Returns:
    530 
    531 --*/
    532 {
    533   EFI_STATUS  Status;
    534 
    535   Status = EFI_SUCCESS;
    536 
    537   //
    538   // TODO:  Suggested that this code be "critical section"
    539   //
    540   WriteAddress -= ( PcdGet32 (PcdFlashAreaBaseAddress) );
    541   if (mInSmmMode == 0) { // !(EfiInManagementInterrupt ())) {
    542     Status = mFvbModuleGlobal->SpiProtocol->Execute (
    543                                             mFvbModuleGlobal->SpiProtocol,
    544                                             SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
    545                                             0,                      // PrefixOpcodeIndex
    546                                             TRUE,                   // DataCycle
    547                                             TRUE,                   // Atomic
    548                                             TRUE,                   // ShiftOut
    549                                             WriteAddress,           // Address
    550                                             (UINT32) (*NumBytes),   // Data Number
    551                                             Buffer,
    552                                             EnumSpiRegionBios
    553                                             );
    554 
    555   } else {
    556     Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
    557                                             mFvbModuleGlobal->SmmSpiProtocol,
    558                                             SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
    559                                             0,                      // PrefixOpcodeIndex
    560                                             TRUE,                   // DataCycle
    561                                             TRUE,                   // Atomic
    562                                             TRUE,                   // ShiftOut
    563                                             WriteAddress,           // Address
    564                                             (UINT32) (*NumBytes),   // Data Number
    565                                             Buffer,
    566                                             EnumSpiRegionBios
    567                                             );
    568   }
    569 
    570     AsmWbinvd ();
    571 
    572   return Status;
    573 }
    574 
    575 EFI_STATUS
    576 FlashFdErase (
    577   IN UINTN                                WriteAddress,
    578   IN UINTN                                Address,
    579   IN UINTN                                LbaLength
    580   )
    581 /*++
    582 
    583 Routine Description:
    584   Erase a certain block from address LbaWriteAddress
    585 
    586 Arguments:
    587 
    588 Returns:
    589 
    590 --*/
    591 {
    592   EFI_STATUS  Status;
    593   UINTN       NumBytes;
    594 
    595   NumBytes = LbaLength;
    596 
    597   WriteAddress -= (PcdGet32 (PcdFlashAreaBaseAddress));
    598   if (mInSmmMode == 0 ) { // !(EfiInManagementInterrupt ())) {
    599     Status = mFvbModuleGlobal->SpiProtocol->Execute (
    600                                             mFvbModuleGlobal->SpiProtocol,
    601                                             SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
    602                                             0,                      // PrefixOpcodeIndex
    603                                             FALSE,                  // DataCycle
    604                                             TRUE,                   // Atomic
    605                                             FALSE,                  // ShiftOut
    606                                             WriteAddress,           // Address
    607                                             0,                      // Data Number
    608                                             NULL,
    609                                             EnumSpiRegionBios       // SPI_REGION_TYPE
    610                                             );
    611   } else {
    612     Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
    613                                             mFvbModuleGlobal->SmmSpiProtocol,
    614                                             SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
    615                                             0,                      // PrefixOpcodeIndex
    616                                             FALSE,                  // DataCycle
    617                                             TRUE,                   // Atomic
    618                                             FALSE,                  // ShiftOut
    619                                             WriteAddress,           // Address
    620                                             0,                      // Data Number
    621                                             NULL,
    622                                             EnumSpiRegionBios       // SPI_REGION_TYPE
    623                                             );
    624   }
    625 
    626   AsmWbinvd ();
    627 
    628   return Status;
    629 }
    630 
    631 EFI_STATUS
    632 FvbWriteBlock (
    633   IN UINTN                                Instance,
    634   IN EFI_LBA                              Lba,
    635   IN UINTN                                BlockOffset,
    636   IN OUT UINTN                            *NumBytes,
    637   IN UINT8                                *Buffer,
    638   IN ESAL_FWB_GLOBAL                      *Global,
    639   IN BOOLEAN                              Virtual
    640   )
    641 /*++
    642 
    643 Routine Description:
    644   Writes specified number of bytes from the input buffer to the block
    645 
    646 Arguments:
    647   Instance              - The FV instance to be written to
    648   Lba                   - The starting logical block index to write to
    649   BlockOffset           - Offset into the block at which to begin writing
    650   NumBytes              - Pointer that on input contains the total size of
    651                           the buffer. On output, it contains the total number
    652                           of bytes actually written
    653   Buffer                - Pointer to a caller allocated buffer that contains
    654                           the source for the write
    655   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    656                           instance data
    657   Virtual               - Whether CPU is in virtual or physical mode
    658 
    659 Returns:
    660   EFI_SUCCESS           - The firmware volume was written successfully
    661   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
    662                           NumBytes contains the total number of bytes
    663                           actually written
    664   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    665   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    666                           could not be written
    667   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    668 
    669 --*/
    670 {
    671   EFI_FVB_ATTRIBUTES_2  Attributes;
    672   UINTN               LbaAddress;
    673   UINTN               LbaWriteAddress;
    674   UINTN               LbaLength;
    675   EFI_FW_VOL_INSTANCE *FwhInstance;
    676   EFI_STATUS          Status;
    677   EFI_STATUS          ReturnStatus;
    678 
    679   FwhInstance = NULL;
    680 
    681   //
    682   // Find the right instance of the FVB private data
    683   //
    684   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    685   ASSERT_EFI_ERROR (Status);
    686 
    687   //
    688   // Writes are enabled in the init routine itself
    689   //
    690   if (!FwhInstance->WriteEnabled) {
    691     return EFI_ACCESS_DENIED;
    692   }
    693   //
    694   // Check for invalid conditions
    695   //
    696   if ((NumBytes == NULL) || (Buffer == NULL)) {
    697     return EFI_INVALID_PARAMETER;
    698   }
    699 
    700   if (*NumBytes == 0) {
    701     return EFI_INVALID_PARAMETER;
    702   }
    703 
    704   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);
    705   if (EFI_ERROR (Status)) {
    706     return Status;
    707   }
    708   //
    709   // Check if the FV is write enabled
    710   //
    711   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    712 
    713   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    714     return EFI_ACCESS_DENIED;
    715   }
    716   //
    717   // Perform boundary checks and adjust NumBytes
    718   //
    719   if (BlockOffset > LbaLength) {
    720     return EFI_INVALID_PARAMETER;
    721   }
    722 
    723   if (LbaLength < (*NumBytes + BlockOffset)) {
    724     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    725     Status    = EFI_BAD_BUFFER_SIZE;
    726   }
    727 
    728   ReturnStatus = FlashFdWrite (
    729                   LbaWriteAddress + BlockOffset,
    730                   LbaAddress,
    731                   NumBytes,
    732                   Buffer,
    733                   LbaLength
    734                   );
    735   if (EFI_ERROR (ReturnStatus)) {
    736     return ReturnStatus;
    737   }
    738 
    739   return Status;
    740 }
    741 
    742 EFI_STATUS
    743 FvbEraseBlock (
    744   IN UINTN                                Instance,
    745   IN EFI_LBA                              Lba,
    746   IN ESAL_FWB_GLOBAL                      *Global,
    747   IN BOOLEAN                              Virtual
    748   )
    749 /*++
    750 
    751 Routine Description:
    752   Erases and initializes a firmware volume block
    753 
    754 Arguments:
    755   Instance              - The FV instance to be erased
    756   Lba                   - The logical block index to be erased
    757   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    758                           instance data
    759   Virtual               - Whether CPU is in virtual or physical mode
    760 
    761 Returns:
    762   EFI_SUCCESS           - The erase request was successfully completed
    763   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    764   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    765                           could not be written. Firmware device may have been
    766                           partially erased
    767   EFI_INVALID_PARAMETER - Instance not found
    768 
    769 --*/
    770 {
    771 
    772   EFI_FVB_ATTRIBUTES_2  Attributes;
    773   UINTN               LbaAddress;
    774   UINTN               LbaWriteAddress;
    775   EFI_FW_VOL_INSTANCE *FwhInstance;
    776   UINTN               LbaLength;
    777   EFI_STATUS          Status;
    778   UINTN               SectorNum;
    779   UINTN               Index;
    780 
    781   FwhInstance = NULL;
    782 
    783   //
    784   // Find the right instance of the FVB private data
    785   //
    786   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    787   ASSERT_EFI_ERROR (Status);
    788 
    789   //
    790   // Writes are enabled in the init routine itself
    791   //
    792   if (!FwhInstance->WriteEnabled) {
    793     return EFI_ACCESS_DENIED;
    794   }
    795   //
    796   // Check if the FV is write enabled
    797   //
    798   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    799 
    800   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    801     return EFI_ACCESS_DENIED;
    802   }
    803   //
    804   // Get the starting address of the block for erase. For debug reasons,
    805   // LbaWriteAddress may not be the same as LbaAddress.
    806   //
    807   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);
    808   if (EFI_ERROR (Status)) {
    809     return Status;
    810   }
    811 
    812   SectorNum = LbaLength / SPI_ERASE_SECTOR_SIZE;
    813   for (Index = 0; Index < SectorNum; Index++){
    814     Status = FlashFdErase (
    815                LbaWriteAddress + Index * SPI_ERASE_SECTOR_SIZE,
    816                LbaAddress,
    817                SPI_ERASE_SECTOR_SIZE
    818                );
    819     if (Status != EFI_SUCCESS){
    820       break;
    821     }
    822   }
    823 
    824   return Status;
    825 }
    826 
    827 EFI_STATUS
    828 FvbEraseCustomBlockRange (
    829   IN UINTN                                Instance,
    830   IN EFI_LBA                              StartLba,
    831   IN UINTN                                OffsetStartLba,
    832   IN EFI_LBA                              LastLba,
    833   IN UINTN                                OffsetLastLba,
    834   IN ESAL_FWB_GLOBAL                      *Global,
    835   IN BOOLEAN                              Virtual
    836   )
    837 /*++
    838 
    839 Routine Description:
    840   Erases and initializes a specified range of a firmware volume
    841 
    842 Arguments:
    843   Instance              - The FV instance to be erased
    844   StartLba              - The starting logical block index to be erased
    845   OffsetStartLba        - Offset into the starting block at which to
    846                           begin erasing
    847   LastLba               - The last logical block index to be erased
    848   OffsetStartLba        - Offset into the last block at which to end erasing
    849   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    850                           instance data
    851   Virtual               - Whether CPU is in virtual or physical mode
    852 
    853 Returns:
    854   EFI_SUCCESS           - The firmware volume was erased successfully
    855   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    856   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    857                           could not be written. Firmware device may have been
    858                           partially erased
    859   EFI_INVALID_PARAMETER - Instance not found
    860 
    861 --*/
    862 {
    863   EFI_LBA Index;
    864   UINTN   LbaSize;
    865   UINTN   ScratchLbaSizeData;
    866 
    867   //
    868   // First LBA.
    869   //
    870   FvbGetLbaAddress (Instance, StartLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);
    871 
    872   //
    873   // Use the scratch space as the intermediate buffer to transfer data
    874   // Back up the first LBA in scratch space.
    875   //
    876   FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
    877 
    878   //
    879   // erase now
    880   //
    881   FvbEraseBlock (Instance, StartLba, Global, Virtual);
    882   ScratchLbaSizeData = OffsetStartLba;
    883 
    884   //
    885   // write the data back to the first block
    886   //
    887   if (ScratchLbaSizeData > 0) {
    888     FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);
    889   }
    890   //
    891   // Middle LBAs
    892   //
    893   if (LastLba > (StartLba + 1)) {
    894     for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {
    895       FvbEraseBlock (Instance, Index, Global, Virtual);
    896     }
    897   }
    898   //
    899   // Last LBAs, the same as first LBAs
    900   //
    901   if (LastLba > StartLba) {
    902     FvbGetLbaAddress (Instance, LastLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);
    903     FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
    904     FvbEraseBlock (Instance, LastLba, Global, Virtual);
    905   }
    906 
    907   ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1);
    908 
    909   return FvbWriteBlock (
    910           Instance,
    911           LastLba,
    912           (OffsetLastLba + 1),
    913           &ScratchLbaSizeData,
    914           Global->FvbScratchSpace[Virtual],
    915           Global,
    916           Virtual
    917           );
    918 }
    919 
    920 EFI_STATUS
    921 FvbSetVolumeAttributes (
    922   IN UINTN                                Instance,
    923   IN OUT EFI_FVB_ATTRIBUTES_2               *Attributes,
    924   IN ESAL_FWB_GLOBAL                      *Global,
    925   IN BOOLEAN                              Virtual
    926   )
    927 /*++
    928 
    929 Routine Description:
    930   Modifies the current settings of the firmware volume according to the
    931   input parameter, and returns the new setting of the volume
    932 
    933 Arguments:
    934   Instance              - The FV instance whose attributes is going to be
    935                           modified
    936   Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
    937                           containing the desired firmware volume settings.
    938                           On successful return, it contains the new settings
    939                           of the firmware volume
    940   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    941                           instance data
    942   Virtual               - Whether CPU is in virtual or physical mode
    943 
    944 Returns:
    945   EFI_SUCCESS           - Successfully returns
    946   EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
    947   EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
    948                           in conflict with the capabilities as declared in the
    949                           firmware volume header
    950 
    951 --*/
    952 {
    953   EFI_FW_VOL_INSTANCE *FwhInstance;
    954   EFI_FVB_ATTRIBUTES_2  OldAttributes;
    955   EFI_FVB_ATTRIBUTES_2  *AttribPtr;
    956   UINT32              Capabilities;
    957   UINT32              OldStatus;
    958   UINT32              NewStatus;
    959   EFI_STATUS          Status;
    960 
    961   FwhInstance = NULL;
    962 
    963   //
    964   // Find the right instance of the FVB private data
    965   //
    966   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    967   ASSERT_EFI_ERROR (Status);
    968 
    969   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
    970   OldAttributes = *AttribPtr;
    971   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
    972   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
    973   NewStatus     = *Attributes & EFI_FVB2_STATUS;
    974 
    975   //
    976   // If firmware volume is locked, no status bit can be updated
    977   //
    978   if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
    979     if (OldStatus ^ NewStatus) {
    980       return EFI_ACCESS_DENIED;
    981     }
    982   }
    983   //
    984   // Test read disable
    985   //
    986   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    987     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
    988       return EFI_INVALID_PARAMETER;
    989     }
    990   }
    991   //
    992   // Test read enable
    993   //
    994   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    995     if (NewStatus & EFI_FVB2_READ_STATUS) {
    996       return EFI_INVALID_PARAMETER;
    997     }
    998   }
    999   //
   1000   // Test write disable
   1001   //
   1002   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
   1003     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
   1004       return EFI_INVALID_PARAMETER;
   1005     }
   1006   }
   1007   //
   1008   // Test write enable
   1009   //
   1010   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
   1011     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
   1012       return EFI_INVALID_PARAMETER;
   1013     }
   1014   }
   1015   //
   1016   // Test lock
   1017   //
   1018   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
   1019     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
   1020       return EFI_INVALID_PARAMETER;
   1021     }
   1022   }
   1023 
   1024   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
   1025   *AttribPtr  = (*AttribPtr) | NewStatus;
   1026   *Attributes = *AttribPtr;
   1027 
   1028   return EFI_SUCCESS;
   1029 }
   1030 //
   1031 // FVB protocol APIs
   1032 //
   1033 EFI_STATUS
   1034 EFIAPI
   1035 FvbProtocolGetPhysicalAddress (
   1036   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1037   OUT EFI_PHYSICAL_ADDRESS                          *Address
   1038   )
   1039 /*++
   1040 
   1041 Routine Description:
   1042 
   1043   Retrieves the physical address of the device.
   1044 
   1045 Arguments:
   1046 
   1047   This                  - Calling context
   1048   Address               - Output buffer containing the address.
   1049 
   1050 Returns:
   1051 
   1052 Returns:
   1053   EFI_SUCCESS           - Successfully returns
   1054 
   1055 --*/
   1056 {
   1057   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1058 
   1059   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1060 
   1061   return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
   1062 }
   1063 
   1064 EFI_STATUS
   1065 FvbProtocolGetBlockSize (
   1066   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1067   IN  EFI_LBA                                       Lba,
   1068   OUT UINTN                                         *BlockSize,
   1069   OUT UINTN                                         *NumOfBlocks
   1070   )
   1071 /*++
   1072 
   1073 Routine Description:
   1074   Retrieve the size of a logical block
   1075 
   1076 Arguments:
   1077   This                  - Calling context
   1078   Lba                   - Indicates which block to return the size for.
   1079   BlockSize             - A pointer to a caller allocated UINTN in which
   1080                           the size of the block is returned
   1081   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
   1082                           number of consecutive blocks starting with Lba is
   1083                           returned. All blocks in this range have a size of
   1084                           BlockSize
   1085 
   1086 Returns:
   1087   EFI_SUCCESS           - The firmware volume was read successfully and
   1088                           contents are in Buffer
   1089 
   1090 --*/
   1091 {
   1092   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1093 
   1094   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1095 
   1096   return FvbGetLbaAddress (
   1097           FvbDevice->Instance,
   1098           Lba,
   1099           NULL,
   1100           NULL,
   1101           BlockSize,
   1102           NumOfBlocks,
   1103           mFvbModuleGlobal,
   1104           EfiGoneVirtual ()
   1105           );
   1106 }
   1107 
   1108 EFI_STATUS
   1109 EFIAPI
   1110 FvbProtocolGetAttributes (
   1111   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1112   OUT EFI_FVB_ATTRIBUTES_2                            *Attributes
   1113   )
   1114 /*++
   1115 
   1116 Routine Description:
   1117     Retrieves Volume attributes.  No polarity translations are done.
   1118 
   1119 Arguments:
   1120     This                - Calling context
   1121     Attributes          - output buffer which contains attributes
   1122 
   1123 Returns:
   1124   EFI_SUCCESS           - Successfully returns
   1125 
   1126 --*/
   1127 {
   1128   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1129 
   1130   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1131 
   1132   return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
   1133 }
   1134 
   1135 EFI_STATUS
   1136 EFIAPI
   1137 FvbProtocolSetAttributes (
   1138   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1139   IN OUT EFI_FVB_ATTRIBUTES_2                         *Attributes
   1140   )
   1141 /*++
   1142 
   1143 Routine Description:
   1144   Sets Volume attributes. No polarity translations are done.
   1145 
   1146 Arguments:
   1147   This                  - Calling context
   1148   Attributes            - output buffer which contains attributes
   1149 
   1150 Returns:
   1151   EFI_SUCCESS           - Successfully returns
   1152 
   1153 --*/
   1154 {
   1155   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1156 
   1157   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1158 
   1159   return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
   1160 }
   1161 
   1162 EFI_STATUS
   1163 EFIAPI
   1164 FvbProtocolEraseBlocks (
   1165   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1166   ...
   1167   )
   1168 /*++
   1169 
   1170 Routine Description:
   1171 
   1172   The EraseBlock() function erases one or more blocks as denoted by the
   1173   variable argument list. The entire parameter list of blocks must be verified
   1174   prior to erasing any blocks.  If a block is requested that does not exist
   1175   within the associated firmware volume (it has a larger index than the last
   1176   block of the firmware volume), the EraseBlock() function must return
   1177   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
   1178 
   1179 Arguments:
   1180   This                  - Calling context
   1181   ...                   - Starting LBA followed by Number of Lba to erase.
   1182                           a -1 to terminate the list.
   1183 
   1184 Returns:
   1185   EFI_SUCCESS           - The erase request was successfully completed
   1186   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
   1187   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1188                           could not be written. Firmware device may have been
   1189                           partially erased
   1190 
   1191 --*/
   1192 {
   1193   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1194   EFI_FW_VOL_INSTANCE     *FwhInstance;
   1195   UINTN                   NumOfBlocks;
   1196   VA_LIST                 args;
   1197   EFI_LBA                 StartingLba;
   1198   UINTN                   NumOfLba;
   1199   EFI_STATUS              Status;
   1200 
   1201   FwhInstance = NULL;
   1202   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1203 
   1204   Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
   1205   ASSERT_EFI_ERROR (Status);
   1206 
   1207   NumOfBlocks = FwhInstance->NumOfBlocks;
   1208 
   1209   VA_START (args, This);
   1210 
   1211   do {
   1212     StartingLba = VA_ARG (args, EFI_LBA);
   1213     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
   1214       break;
   1215     }
   1216 
   1217     NumOfLba = VA_ARG (args, UINT32);
   1218 
   1219     //
   1220     // Check input parameters
   1221     //
   1222     if (NumOfLba == 0) {
   1223       VA_END (args);
   1224       return EFI_INVALID_PARAMETER;
   1225     }
   1226 
   1227     if ((StartingLba + NumOfLba) > NumOfBlocks) {
   1228       return EFI_INVALID_PARAMETER;
   1229     }
   1230   } while (TRUE);
   1231 
   1232   VA_END (args);
   1233 
   1234   VA_START (args, This);
   1235   do {
   1236     StartingLba = VA_ARG (args, EFI_LBA);
   1237     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
   1238       break;
   1239     }
   1240 
   1241     NumOfLba = VA_ARG (args, UINT32);
   1242 
   1243     while (NumOfLba > 0) {
   1244       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
   1245       if (EFI_ERROR (Status)) {
   1246         VA_END (args);
   1247         return Status;
   1248       }
   1249 
   1250       StartingLba++;
   1251       NumOfLba--;
   1252     }
   1253 
   1254   } while (TRUE);
   1255 
   1256   VA_END (args);
   1257 
   1258   return EFI_SUCCESS;
   1259 }
   1260 
   1261 EFI_STATUS
   1262 EFIAPI
   1263 FvbProtocolWrite (
   1264   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1265   IN EFI_LBA                                        Lba,
   1266   IN UINTN                                          Offset,
   1267   IN OUT UINTN                                      *NumBytes,
   1268   IN UINT8                                          *Buffer
   1269   )
   1270 /*++
   1271 
   1272 Routine Description:
   1273 
   1274   Writes data beginning at Lba:Offset from FV. The write terminates either
   1275   when *NumBytes of data have been written, or when a block boundary is
   1276   reached.  *NumBytes is updated to reflect the actual number of bytes
   1277   written. The write opertion does not include erase. This routine will
   1278   attempt to write only the specified bytes. If the writes do not stick,
   1279   it will return an error.
   1280 
   1281 Arguments:
   1282   This                  - Calling context
   1283   Lba                   - Block in which to begin write
   1284   Offset                - Offset in the block at which to begin write
   1285   NumBytes              - On input, indicates the requested write size. On
   1286                           output, indicates the actual number of bytes written
   1287   Buffer                - Buffer containing source data for the write.
   1288 
   1289 Returns:
   1290   EFI_SUCCESS           - The firmware volume was written successfully
   1291   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
   1292                           NumBytes contains the total number of bytes
   1293                           actually written
   1294   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
   1295   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1296                           could not be written
   1297   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1298 
   1299 --*/
   1300 {
   1301 
   1302   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1303 
   1304   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1305 
   1306   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1307 }
   1308 
   1309 EFI_STATUS
   1310 EFIAPI
   1311 FvbProtocolRead (
   1312   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1313   IN EFI_LBA                                        Lba,
   1314   IN UINTN                                          Offset,
   1315   IN OUT UINTN                                      *NumBytes,
   1316   IN UINT8                                          *Buffer
   1317   )
   1318 /*++
   1319 
   1320 Routine Description:
   1321 
   1322   Reads data beginning at Lba:Offset from FV. The Read terminates either
   1323   when *NumBytes of data have been read, or when a block boundary is
   1324   reached.  *NumBytes is updated to reflect the actual number of bytes
   1325   written. The write opertion does not include erase. This routine will
   1326   attempt to write only the specified bytes. If the writes do not stick,
   1327   it will return an error.
   1328 
   1329 Arguments:
   1330   This                  - Calling context
   1331   Lba                   - Block in which to begin Read
   1332   Offset                - Offset in the block at which to begin Read
   1333   NumBytes              - On input, indicates the requested write size. On
   1334                           output, indicates the actual number of bytes Read
   1335   Buffer                - Buffer containing source data for the Read.
   1336 
   1337 Returns:
   1338   EFI_SUCCESS           - The firmware volume was read successfully and
   1339                           contents are in Buffer
   1340   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
   1341                           NumBytes contains the total number of bytes returned
   1342                           in Buffer
   1343   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
   1344   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1345                           could not be read
   1346   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1347 
   1348 --*/
   1349 {
   1350 
   1351   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1352   EFI_STATUS              Status;
   1353 
   1354   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1355   Status    = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1356 
   1357   return Status;
   1358 }
   1359 
   1360 EFI_STATUS
   1361 ValidateFvHeader (
   1362   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
   1363   )
   1364 /*++
   1365 
   1366 Routine Description:
   1367   Check the integrity of firmware volume header
   1368 
   1369 Arguments:
   1370   FwVolHeader           - A pointer to a firmware volume header
   1371 
   1372 Returns:
   1373   EFI_SUCCESS           - The firmware volume is consistent
   1374   EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
   1375 
   1376 --*/
   1377 {
   1378   UINT16  *Ptr;
   1379   UINT16  HeaderLength;
   1380   UINT16  Checksum;
   1381 
   1382   //
   1383   // Verify the header revision, header signature, length
   1384   // Length of FvBlock cannot be 2**64-1
   1385   // HeaderLength cannot be an odd number
   1386   //
   1387   #ifndef R864_BUILD
   1388   if (((FwVolHeader->Revision != EFI_FVH_REVISION) && (FwVolHeader->Revision != EFI_FVH_REVISION)) ||
   1389   #else
   1390   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
   1391   #endif
   1392       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
   1393       (FwVolHeader->FvLength == ((UINTN) -1)) ||
   1394       ((FwVolHeader->HeaderLength & 0x01) != 0)
   1395       ) {
   1396     return EFI_NOT_FOUND;
   1397   }
   1398   //
   1399   // Verify the header checksum
   1400   //
   1401   HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
   1402   Ptr           = (UINT16 *) FwVolHeader;
   1403   Checksum      = 0;
   1404   while (HeaderLength > 0) {
   1405     Checksum = Checksum + (*Ptr);
   1406     Ptr++;
   1407     HeaderLength--;
   1408   }
   1409 
   1410   if (Checksum != 0) {
   1411     return EFI_NOT_FOUND;
   1412   }
   1413 
   1414   return EFI_SUCCESS;
   1415 }
   1416 
   1417 EFI_STATUS
   1418 GetFvbHeader (
   1419   VOID                                **HobList,
   1420   OUT EFI_FIRMWARE_VOLUME_HEADER      **FwVolHeader,
   1421   OUT EFI_PHYSICAL_ADDRESS            *BaseAddress,
   1422   OUT BOOLEAN                         *WriteBack
   1423   )
   1424 {
   1425   EFI_STATUS                Status;
   1426 
   1427   Status        = EFI_SUCCESS;
   1428   *WriteBack    = FALSE;
   1429 
   1430   if (*FwVolHeader == NULL) {
   1431     *BaseAddress = PcdGet32 (PcdFlashFvRecoveryBase);
   1432   } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvRecoveryBase)) {
   1433     *BaseAddress = PcdGet32 (PcdFlashFvMainBase);
   1434   } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvMainBase)) {
   1435     *BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
   1436   } else {
   1437     return EFI_NOT_FOUND;
   1438   }
   1439 
   1440   DEBUG((EFI_D_INFO, "Fvb base : %08x\n",*BaseAddress));
   1441 
   1442   *FwVolHeader  = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (*BaseAddress);
   1443   Status        = ValidateFvHeader (*FwVolHeader);
   1444   if (EFI_ERROR (Status)) {
   1445     //
   1446     // Get FvbInfo
   1447     //
   1448     *WriteBack  = TRUE;
   1449 
   1450     Status      = GetFvbInfo (*BaseAddress, FwVolHeader);
   1451     DEBUG(( DEBUG_ERROR, "Through GetFvbInfo: %08x!\n",*BaseAddress));
   1452 
   1453     ASSERT_EFI_ERROR (Status);
   1454   }
   1455 
   1456   return EFI_SUCCESS;
   1457 }
   1458 
   1459 
   1460 EFI_STATUS
   1461 SmmSpiInit (
   1462   VOID
   1463   )
   1464 {
   1465   UINT8       SpiStatus;
   1466   UINT8       FlashIndex;
   1467   UINT8       FlashID[3];
   1468   EFI_STATUS  Status;
   1469 
   1470   //
   1471   // Obtain a handle for ICH SPI Protocol
   1472   //
   1473   ASSERT(mSmst != NULL);
   1474   if (mFvbModuleGlobal->SmmSpiProtocol == NULL){
   1475     Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);
   1476     ASSERT_EFI_ERROR(Status);
   1477   }
   1478   //
   1479   // attempt to identify flash part and initialize spi table
   1480   //
   1481   for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
   1482     Status = mFvbModuleGlobal->SmmSpiProtocol->Init (
   1483                                                 mFvbModuleGlobal->SmmSpiProtocol,
   1484                                                 &(mSpiInitTable[FlashIndex])
   1485                                                 );
   1486     if (!EFI_ERROR (Status)) {
   1487       //
   1488       // read vendor/device IDs to check if flash device is supported
   1489       //
   1490       Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
   1491                                                   mFvbModuleGlobal->SmmSpiProtocol,
   1492                                                   SPI_OPCODE_JEDEC_ID_INDEX,
   1493                                                   SPI_WREN_INDEX,
   1494                                                   TRUE,
   1495                                                   FALSE,
   1496                                                   FALSE,
   1497                                                   0,
   1498                                                   3,
   1499                                                   FlashID,
   1500                                                   EnumSpiRegionAll
   1501                                                   );
   1502       if (!EFI_ERROR (Status)) {
   1503         if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1504                (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||
   1505               ((FlashID[0] == SPI_AT26DF321_ID1) &&
   1506                (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1507                (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {
   1508           //
   1509           // Supported SPI device found
   1510           //
   1511           DEBUG (
   1512               ((EFI_D_INFO),
   1513               "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1514               FlashID[0],
   1515               FlashID[1],
   1516               FlashID[2])
   1517               );
   1518           break;
   1519         }
   1520       }
   1521     }
   1522   }
   1523 
   1524   if (FlashIndex >= EnumSpiFlashMax) {
   1525     Status = EFI_UNSUPPORTED;
   1526     DEBUG (
   1527         (EFI_D_ERROR,
   1528         "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1529         FlashID[0],
   1530         FlashID[1],
   1531         FlashID[2])
   1532         );
   1533     ASSERT_EFI_ERROR (Status);
   1534   }
   1535 
   1536   SpiStatus = 0;
   1537   Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
   1538                                             mFvbModuleGlobal->SmmSpiProtocol,
   1539                                             SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex
   1540                                             1,                        // PrefixOpcodeIndex
   1541                                             TRUE,                     // DataCycle
   1542                                             TRUE,                     // Atomic
   1543                                             TRUE,                     // ShiftOut
   1544                                             0,                        // Address
   1545                                             1,                        // Data Number
   1546                                             &SpiStatus,
   1547                                             EnumSpiRegionAll          // SPI_REGION_TYPE
   1548                                             );
   1549   return Status;
   1550 }
   1551 
   1552 EFI_STATUS
   1553 SmmSpiNotificationFunction (
   1554   IN CONST EFI_GUID  *Protocol,
   1555   IN VOID            *Interface,
   1556   IN EFI_HANDLE      Handle
   1557   )
   1558 {
   1559   return SmmSpiInit();
   1560 }
   1561 
   1562 
   1563 VOID
   1564 EFIAPI
   1565 GetFullDriverPath (
   1566   IN  EFI_HANDLE                  ImageHandle,
   1567   IN  EFI_SYSTEM_TABLE            *SystemTable,
   1568   OUT EFI_DEVICE_PATH_PROTOCOL    **CompleteFilePath
   1569   )
   1570 /*++
   1571 
   1572 Routine Description:
   1573 
   1574   Function is used to get the full device path for this driver.
   1575 
   1576 Arguments:
   1577 
   1578   ImageHandle        - The loaded image handle of this driver.
   1579   SystemTable        - The pointer of system table.
   1580   CompleteFilePath   - The pointer of returned full file path
   1581 
   1582 Returns:
   1583 
   1584   none
   1585 
   1586 --*/
   1587 {
   1588   EFI_STATUS                Status;
   1589   EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
   1590   EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath;
   1591 
   1592 
   1593   Status = gBS->HandleProtocol (
   1594                   ImageHandle,
   1595                   &gEfiLoadedImageProtocolGuid,
   1596                   (VOID **) &LoadedImage
   1597                   );
   1598   ASSERT_EFI_ERROR (Status);
   1599 
   1600   Status = gBS->HandleProtocol (
   1601                   LoadedImage->DeviceHandle,
   1602                   &gEfiDevicePathProtocolGuid,
   1603                   (VOID *) &ImageDevicePath
   1604                   );
   1605   ASSERT_EFI_ERROR (Status);
   1606 
   1607   *CompleteFilePath = AppendDevicePath (
   1608                         ImageDevicePath,
   1609                         LoadedImage->FilePath
   1610                         );
   1611 
   1612   return ;
   1613 }
   1614 
   1615 
   1616 
   1617 EFI_STATUS
   1618 FvbInitialize (
   1619   IN EFI_HANDLE         ImageHandle,
   1620   IN EFI_SYSTEM_TABLE   *SystemTable
   1621   )
   1622 /*++
   1623 
   1624 Routine Description:
   1625   This function does common initialization for FVB services
   1626 
   1627 Arguments:
   1628 
   1629 Returns:
   1630 
   1631 --*/
   1632 {
   1633   EFI_STATUS                          Status;
   1634   EFI_FW_VOL_INSTANCE                 *FwhInstance;
   1635   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
   1636   EFI_FIRMWARE_VOLUME_HEADER          *TempFwVolHeader;
   1637   VOID                                *HobList;
   1638   VOID                                *FirmwareVolumeHobList;
   1639   UINT32                              BufferSize;
   1640   EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
   1641   UINTN                               LbaAddress;
   1642   BOOLEAN                             WriteEnabled;
   1643   BOOLEAN                             WriteLocked;
   1644   EFI_HANDLE                          FwbHandle;
   1645   EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
   1646   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
   1647   EFI_DEVICE_PATH_PROTOCOL            *FwbDevicePath;
   1648   EFI_DEVICE_PATH_PROTOCOL            *TempFwbDevicePath;
   1649   UINT32                              MaxLbaSize;
   1650   EFI_PHYSICAL_ADDRESS                BaseAddress;
   1651   BOOLEAN                             WriteBack;
   1652   UINTN                               NumOfBlocks;
   1653   UINTN                               HeaderLength;
   1654   UINT8                               SpiStatus;
   1655   UINT8                               FlashIndex;
   1656   UINT8                               FlashID[3];
   1657   EFI_DEVICE_PATH_PROTOCOL            *CompleteFilePath;
   1658   UINT8                               PrefixOpcodeIndex;
   1659   BOOLEAN                             InSmm;
   1660   EFI_SMM_BASE2_PROTOCOL              *mSmmBase2;
   1661   EFI_HANDLE                          Handle;
   1662 
   1663   VOID                                *Registration;
   1664   EFI_EVENT                           Event;
   1665 
   1666   CompleteFilePath = NULL;
   1667   GetFullDriverPath (ImageHandle, SystemTable, &CompleteFilePath);
   1668 
   1669  Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
   1670 
   1671   //
   1672   // No FV HOBs found
   1673   //
   1674   ASSERT_EFI_ERROR (Status);
   1675 
   1676 
   1677   //
   1678   // Allocate runtime services data for global variable, which contains
   1679   // the private data of all firmware volume block instances
   1680   //
   1681   mFvbModuleGlobal = (ESAL_FWB_GLOBAL *)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL  ));
   1682   ASSERT(mFvbModuleGlobal);
   1683   mSmmBase2 = NULL;
   1684   Status = gBS->LocateProtocol (
   1685                   &gEfiSmmBase2ProtocolGuid,
   1686                   NULL,
   1687                   (VOID **) &mSmmBase2
   1688                   );
   1689 
   1690   if (mSmmBase2 == NULL) {
   1691     InSmm = FALSE;
   1692   } else {
   1693     mSmmBase2->InSmm (mSmmBase2, &InSmm);
   1694     mSmmBase2->GetSmstLocation (mSmmBase2, &mSmst);
   1695 
   1696   }
   1697 
   1698   if (!InSmm) {
   1699     mInSmmMode = 0;
   1700     //
   1701     // Obtain a handle for ICH SPI Protocol
   1702     //
   1703     Status = gBS->LocateProtocol (&gEfiSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SpiProtocol);
   1704     ASSERT_EFI_ERROR (Status);
   1705 
   1706     //
   1707     // attempt to identify flash part and initialize spi table
   1708     //
   1709     for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
   1710       Status = mFvbModuleGlobal->SpiProtocol->Init (
   1711                                                 mFvbModuleGlobal->SpiProtocol,
   1712                                                 &(mSpiInitTable[FlashIndex])
   1713                                                 );
   1714       if (!EFI_ERROR (Status)) {
   1715         //
   1716         // read vendor/device IDs to check if flash device is supported
   1717         //
   1718         Status = mFvbModuleGlobal->SpiProtocol->Execute (
   1719                                                   mFvbModuleGlobal->SpiProtocol,
   1720                                                   SPI_OPCODE_JEDEC_ID_INDEX,
   1721                                                   SPI_WREN_INDEX,
   1722                                                   TRUE,
   1723                                                   FALSE,
   1724                                                   FALSE,
   1725                                                   0,
   1726                                                   3,
   1727                                                   FlashID,
   1728                                                   EnumSpiRegionAll
   1729                                                   );
   1730         if (!EFI_ERROR (Status)) {
   1731           if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1732                (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||
   1733               ((FlashID[0] == SPI_AT26DF321_ID1) &&
   1734                (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1735                (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {
   1736             //
   1737             // Supported SPI device found
   1738             //
   1739             DEBUG (
   1740               ((EFI_D_INFO),
   1741               "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1742               FlashID[0],
   1743               FlashID[1],
   1744               FlashID[2])
   1745               );
   1746 
   1747             PublishFlashDeviceInfo (&mSpiInitTable[FlashIndex]);
   1748             break;
   1749           }
   1750         }
   1751       }
   1752     }
   1753 
   1754     if (FlashIndex >= EnumSpiFlashMax) {
   1755       Status = EFI_UNSUPPORTED;
   1756       DEBUG (
   1757         (DEBUG_ERROR,
   1758         "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1759         FlashID[0],
   1760         FlashID[1],
   1761         FlashID[2])
   1762         );
   1763       ASSERT_EFI_ERROR (Status);
   1764     }
   1765 
   1766     //
   1767     // Unlock all regions by writing to status register
   1768     // This could be SPI device specific, need to follow the datasheet
   1769     // To write to Write Status Register the Spi PrefixOpcode needs to be:
   1770     //   0 for Atmel parts
   1771     //   0 for Intel parts
   1772     //   0 for Macronix parts
   1773     //   0 for Winbond parts
   1774     //   1 for SST parts
   1775     SpiStatus = 0;
   1776     if (FlashID[0] == SPI_SST25VF016B_ID1) {
   1777       PrefixOpcodeIndex = 1;
   1778     } else {
   1779       PrefixOpcodeIndex = 0;
   1780     }
   1781     Status = mFvbModuleGlobal->SpiProtocol->Execute (
   1782                                               mFvbModuleGlobal->SpiProtocol,
   1783                                               SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex
   1784                                               PrefixOpcodeIndex,        // PrefixOpcodeIndex
   1785                                               TRUE,                     // DataCycle
   1786                                               TRUE,                     // Atomic
   1787                                               TRUE,                     // ShiftOut
   1788                                               0,                        // Address
   1789                                               1,                        // Data Number
   1790                                               &SpiStatus,
   1791                                               EnumSpiRegionAll          // SPI_REGION_TYPE
   1792                                               );
   1793 
   1794 
   1795   } else  {
   1796     mInSmmMode = 1;
   1797 
   1798     Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);
   1799     if (EFI_ERROR(Status)) {
   1800       Registration = NULL;
   1801       Status = mSmst->SmmRegisterProtocolNotify (
   1802                    &gEfiSmmSpiProtocolGuid,
   1803                    SmmSpiNotificationFunction,
   1804                    &Registration
   1805                    );
   1806     } else  {
   1807       Status  = SmmSpiInit();
   1808     }
   1809 
   1810   }
   1811 
   1812   //
   1813   // Calculate the total size for all firmware volume block instances
   1814   //
   1815   BufferSize            = 0;
   1816   FirmwareVolumeHobList = HobList;
   1817   FwVolHeader           = NULL;
   1818   do {
   1819     Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack);
   1820     if (EFI_ERROR (Status)) {
   1821       break;
   1822     }
   1823 
   1824     if (FwVolHeader) {
   1825       BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
   1826     }
   1827   } while (TRUE);
   1828 
   1829   //
   1830   // Only need to allocate once. There is only one copy of physical memory for
   1831   // the private data of each FV instance. But in virtual mode or in physical
   1832   // mode, the address of the the physical memory may be different.
   1833   //
   1834   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
   1835   ASSERT(mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]);
   1836   //
   1837   // Make a virtual copy of the FvInstance pointer.
   1838   //
   1839   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
   1840   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
   1841 
   1842   mFvbModuleGlobal->NumFv                   = 0;
   1843   FirmwareVolumeHobList                     = HobList;
   1844   TempFwVolHeader                           = NULL;
   1845 
   1846   MaxLbaSize = 0;
   1847 
   1848   //
   1849   // Fill in the private data of each firmware volume block instance
   1850   //
   1851   // Foreach Fv HOB in the FirmwareVolumeHobList, loop
   1852   //
   1853   do {
   1854     Status = GetFvbHeader (&FirmwareVolumeHobList, &TempFwVolHeader, &BaseAddress, &WriteBack);
   1855     if (EFI_ERROR (Status)) {
   1856       break;
   1857     }
   1858     FwVolHeader = TempFwVolHeader;
   1859 
   1860     if (!FwVolHeader) {
   1861       continue;
   1862     }
   1863 
   1864 
   1865     CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
   1866     FwVolHeader                       = &(FwhInstance->VolumeHeader);
   1867 
   1868     FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
   1869     FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
   1870 
   1871     //
   1872     // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
   1873     //
   1874     FwhInstance->FvWriteBase[FVB_PHYSICAL]  = (UINTN) BaseAddress;
   1875     WriteEnabled = TRUE;
   1876 
   1877     //
   1878     // Every pointer should have a virtual copy.
   1879     //
   1880     FwhInstance->FvWriteBase[FVB_VIRTUAL] = FwhInstance->FvWriteBase[FVB_PHYSICAL];
   1881 
   1882     FwhInstance->WriteEnabled             = WriteEnabled;
   1883     EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
   1884 
   1885     LbaAddress  = (UINTN) FwhInstance->FvWriteBase[0];
   1886     NumOfBlocks = 0;
   1887     WriteLocked = FALSE;
   1888 
   1889     if (WriteEnabled) {
   1890       for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
   1891         //
   1892         // Get the maximum size of a block. The size will be used to allocate
   1893         // buffer for Scratch space, the intermediate buffer for FVB extension
   1894         // protocol
   1895         //
   1896         if (MaxLbaSize < PtrBlockMapEntry->Length) {
   1897           MaxLbaSize = PtrBlockMapEntry->Length;
   1898         }
   1899 
   1900         NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
   1901       }
   1902       //
   1903       //  Write back a healthy FV header
   1904       //
   1905       if (WriteBack && (!WriteLocked)) {
   1906 
   1907         Status = FlashFdErase (
   1908                   (UINTN) FwhInstance->FvWriteBase[0],
   1909                   (UINTN) BaseAddress,
   1910                   FwVolHeader->BlockMap->Length
   1911                   );
   1912 
   1913         HeaderLength = (UINTN) FwVolHeader->HeaderLength;
   1914         Status = FlashFdWrite (
   1915                   (UINTN) FwhInstance->FvWriteBase[0],
   1916                   (UINTN) BaseAddress,
   1917                   &HeaderLength,
   1918                   (UINT8 *) FwVolHeader,
   1919                   FwVolHeader->BlockMap->Length
   1920                   );
   1921 
   1922       }
   1923     }
   1924     //
   1925     // The total number of blocks in the FV.
   1926     //
   1927     FwhInstance->NumOfBlocks = NumOfBlocks;
   1928 
   1929     //
   1930     // If the FV is write locked, set the appropriate attributes
   1931     //
   1932     if (WriteLocked) {
   1933       //
   1934       // write disabled
   1935       //
   1936       FwhInstance->VolumeHeader.Attributes &= ~EFI_FVB2_WRITE_STATUS;
   1937       //
   1938       // lock enabled
   1939       //
   1940       FwhInstance->VolumeHeader.Attributes |= EFI_FVB2_LOCK_STATUS;
   1941     }
   1942 
   1943     //
   1944     // Allocate and initialize FVB Device in a runtime data buffer
   1945     //
   1946     FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFvbDeviceTemplate);
   1947     ASSERT (FvbDevice);
   1948 
   1949     FvbDevice->Instance = mFvbModuleGlobal->NumFv;
   1950     mFvbModuleGlobal->NumFv++;
   1951 
   1952     //
   1953     // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
   1954     //
   1955     if (FwVolHeader->ExtHeaderOffset == 0) {
   1956       FvbDevice->FvDevicePath.MemMapDevPath.StartingAddress = BaseAddress;
   1957       FvbDevice->FvDevicePath.MemMapDevPath.EndingAddress   = BaseAddress + (FwVolHeader->FvLength - 1);
   1958       FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->FvDevicePath;
   1959     } else {
   1960       CopyGuid (
   1961         &FvbDevice->UefiFvDevicePath.FvDevPath.FvName,
   1962         (EFI_GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
   1963         );
   1964       FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->UefiFvDevicePath;
   1965     }
   1966 
   1967     if (!InSmm) {
   1968       //
   1969       // Find a handle with a matching device path that has supports FW Block protocol
   1970       //
   1971       TempFwbDevicePath = FwbDevicePath;
   1972       Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
   1973       if (EFI_ERROR (Status)) {
   1974         //
   1975         // LocateDevicePath fails so install a new interface and device path
   1976         //
   1977         FwbHandle = NULL;
   1978         Status = gBS->InstallMultipleProtocolInterfaces (
   1979                         &FwbHandle,
   1980                         &gEfiFirmwareVolumeBlockProtocolGuid,
   1981                         &FvbDevice->FwVolBlockInstance,
   1982                         &gEfiDevicePathProtocolGuid,
   1983                         FwbDevicePath,
   1984                         NULL
   1985                         );
   1986         ASSERT_EFI_ERROR (Status);
   1987       } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {
   1988         //
   1989         // Device already exists, so reinstall the FVB protocol
   1990         //
   1991         Status = gBS->HandleProtocol (
   1992                         FwbHandle,
   1993                         &gEfiFirmwareVolumeBlockProtocolGuid,
   1994                         (VOID **) &OldFwbInterface
   1995                         );
   1996         ASSERT_EFI_ERROR (Status);
   1997 
   1998         Status = gBS->ReinstallProtocolInterface (
   1999                         FwbHandle,
   2000                         &gEfiFirmwareVolumeBlockProtocolGuid,
   2001                         OldFwbInterface,
   2002                         &FvbDevice->FwVolBlockInstance
   2003                         );
   2004         ASSERT_EFI_ERROR (Status);
   2005 
   2006       } else {
   2007         //
   2008         // There was a FVB protocol on an End Device Path node
   2009         //
   2010         ASSERT (FALSE);
   2011       }
   2012     } else {
   2013       FwbHandle = NULL;
   2014       Status = mSmst->SmmInstallProtocolInterface (
   2015                 &FwbHandle,
   2016                 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
   2017                 EFI_NATIVE_INTERFACE,
   2018                 &FvbDevice->FwVolBlockInstance
   2019                 );
   2020       ASSERT_EFI_ERROR (Status);
   2021     }
   2022 
   2023     FwhInstance = (EFI_FW_VOL_INSTANCE *)
   2024       (
   2025         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
   2026           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
   2027       );
   2028   } while (TRUE);
   2029 
   2030   //
   2031   // Allocate for scratch space, an intermediate buffer for FVB extention
   2032   //
   2033 
   2034   mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimeZeroPool (MaxLbaSize);
   2035 
   2036   ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]);
   2037 
   2038   mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
   2039 
   2040   if (!InSmm) {
   2041     Status = gBS->CreateEventEx (
   2042                   EVT_NOTIFY_SIGNAL,
   2043                   TPL_NOTIFY,
   2044                  FvbVirtualddressChangeEvent,
   2045                   NULL,
   2046                   &gEfiEventVirtualAddressChangeGuid,
   2047                   &Event
   2048                   );
   2049     ASSERT_EFI_ERROR (Status);
   2050   } else {
   2051     //
   2052     // Inform other platform drivers that SPI device discovered and
   2053     // SPI interface ready for use.
   2054     //
   2055     Handle = NULL;
   2056     Status = gBS->InstallProtocolInterface (
   2057                     &Handle,
   2058                     &gEfiSmmSpiReadyProtocolGuid,
   2059                     EFI_NATIVE_INTERFACE,
   2060                     NULL
   2061                     );
   2062   }
   2063   return EFI_SUCCESS;
   2064 }
   2065