Home | History | Annotate | Download | only in SpiFvbServices
      1 /** @file
      2 
      3 Copyright (c) 2013-2016 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 
    594   WriteAddress -= (PcdGet32 (PcdFlashAreaBaseAddress));
    595   if (mInSmmMode == 0 ) { // !(EfiInManagementInterrupt ())) {
    596     Status = mFvbModuleGlobal->SpiProtocol->Execute (
    597                                             mFvbModuleGlobal->SpiProtocol,
    598                                             SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
    599                                             0,                      // PrefixOpcodeIndex
    600                                             FALSE,                  // DataCycle
    601                                             TRUE,                   // Atomic
    602                                             FALSE,                  // ShiftOut
    603                                             WriteAddress,           // Address
    604                                             0,                      // Data Number
    605                                             NULL,
    606                                             EnumSpiRegionBios       // SPI_REGION_TYPE
    607                                             );
    608   } else {
    609     Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
    610                                             mFvbModuleGlobal->SmmSpiProtocol,
    611                                             SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
    612                                             0,                      // PrefixOpcodeIndex
    613                                             FALSE,                  // DataCycle
    614                                             TRUE,                   // Atomic
    615                                             FALSE,                  // ShiftOut
    616                                             WriteAddress,           // Address
    617                                             0,                      // Data Number
    618                                             NULL,
    619                                             EnumSpiRegionBios       // SPI_REGION_TYPE
    620                                             );
    621   }
    622 
    623   AsmWbinvd ();
    624 
    625   return Status;
    626 }
    627 
    628 EFI_STATUS
    629 FvbWriteBlock (
    630   IN UINTN                                Instance,
    631   IN EFI_LBA                              Lba,
    632   IN UINTN                                BlockOffset,
    633   IN OUT UINTN                            *NumBytes,
    634   IN UINT8                                *Buffer,
    635   IN ESAL_FWB_GLOBAL                      *Global,
    636   IN BOOLEAN                              Virtual
    637   )
    638 /*++
    639 
    640 Routine Description:
    641   Writes specified number of bytes from the input buffer to the block
    642 
    643 Arguments:
    644   Instance              - The FV instance to be written to
    645   Lba                   - The starting logical block index to write to
    646   BlockOffset           - Offset into the block at which to begin writing
    647   NumBytes              - Pointer that on input contains the total size of
    648                           the buffer. On output, it contains the total number
    649                           of bytes actually written
    650   Buffer                - Pointer to a caller allocated buffer that contains
    651                           the source for the write
    652   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    653                           instance data
    654   Virtual               - Whether CPU is in virtual or physical mode
    655 
    656 Returns:
    657   EFI_SUCCESS           - The firmware volume was written successfully
    658   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
    659                           NumBytes contains the total number of bytes
    660                           actually written
    661   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    662   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    663                           could not be written
    664   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    665 
    666 --*/
    667 {
    668   EFI_FVB_ATTRIBUTES_2  Attributes;
    669   UINTN               LbaAddress;
    670   UINTN               LbaWriteAddress;
    671   UINTN               LbaLength;
    672   EFI_FW_VOL_INSTANCE *FwhInstance;
    673   EFI_STATUS          Status;
    674   EFI_STATUS          ReturnStatus;
    675 
    676   FwhInstance = NULL;
    677 
    678   //
    679   // Find the right instance of the FVB private data
    680   //
    681   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    682   ASSERT_EFI_ERROR (Status);
    683 
    684   //
    685   // Writes are enabled in the init routine itself
    686   //
    687   if (!FwhInstance->WriteEnabled) {
    688     return EFI_ACCESS_DENIED;
    689   }
    690   //
    691   // Check for invalid conditions
    692   //
    693   if ((NumBytes == NULL) || (Buffer == NULL)) {
    694     return EFI_INVALID_PARAMETER;
    695   }
    696 
    697   if (*NumBytes == 0) {
    698     return EFI_INVALID_PARAMETER;
    699   }
    700 
    701   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);
    702   if (EFI_ERROR (Status)) {
    703     return Status;
    704   }
    705   //
    706   // Check if the FV is write enabled
    707   //
    708   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    709 
    710   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    711     return EFI_ACCESS_DENIED;
    712   }
    713   //
    714   // Perform boundary checks and adjust NumBytes
    715   //
    716   if (BlockOffset > LbaLength) {
    717     return EFI_INVALID_PARAMETER;
    718   }
    719 
    720   if (LbaLength < (*NumBytes + BlockOffset)) {
    721     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    722     Status    = EFI_BAD_BUFFER_SIZE;
    723   }
    724 
    725   ReturnStatus = FlashFdWrite (
    726                   LbaWriteAddress + BlockOffset,
    727                   LbaAddress,
    728                   NumBytes,
    729                   Buffer,
    730                   LbaLength
    731                   );
    732   if (EFI_ERROR (ReturnStatus)) {
    733     return ReturnStatus;
    734   }
    735 
    736   return Status;
    737 }
    738 
    739 EFI_STATUS
    740 FvbEraseBlock (
    741   IN UINTN                                Instance,
    742   IN EFI_LBA                              Lba,
    743   IN ESAL_FWB_GLOBAL                      *Global,
    744   IN BOOLEAN                              Virtual
    745   )
    746 /*++
    747 
    748 Routine Description:
    749   Erases and initializes a firmware volume block
    750 
    751 Arguments:
    752   Instance              - The FV instance to be erased
    753   Lba                   - The logical block index to be erased
    754   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    755                           instance data
    756   Virtual               - Whether CPU is in virtual or physical mode
    757 
    758 Returns:
    759   EFI_SUCCESS           - The erase request was successfully completed
    760   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    761   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    762                           could not be written. Firmware device may have been
    763                           partially erased
    764   EFI_INVALID_PARAMETER - Instance not found
    765 
    766 --*/
    767 {
    768 
    769   EFI_FVB_ATTRIBUTES_2  Attributes;
    770   UINTN               LbaAddress;
    771   UINTN               LbaWriteAddress;
    772   EFI_FW_VOL_INSTANCE *FwhInstance;
    773   UINTN               LbaLength;
    774   EFI_STATUS          Status;
    775   UINTN               SectorNum;
    776   UINTN               Index;
    777 
    778   FwhInstance = NULL;
    779 
    780   //
    781   // Find the right instance of the FVB private data
    782   //
    783   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    784   ASSERT_EFI_ERROR (Status);
    785 
    786   //
    787   // Writes are enabled in the init routine itself
    788   //
    789   if (!FwhInstance->WriteEnabled) {
    790     return EFI_ACCESS_DENIED;
    791   }
    792   //
    793   // Check if the FV is write enabled
    794   //
    795   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    796 
    797   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    798     return EFI_ACCESS_DENIED;
    799   }
    800   //
    801   // Get the starting address of the block for erase. For debug reasons,
    802   // LbaWriteAddress may not be the same as LbaAddress.
    803   //
    804   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);
    805   if (EFI_ERROR (Status)) {
    806     return Status;
    807   }
    808 
    809   SectorNum = LbaLength / SPI_ERASE_SECTOR_SIZE;
    810   for (Index = 0; Index < SectorNum; Index++){
    811     Status = FlashFdErase (
    812                LbaWriteAddress + Index * SPI_ERASE_SECTOR_SIZE,
    813                LbaAddress,
    814                SPI_ERASE_SECTOR_SIZE
    815                );
    816     if (Status != EFI_SUCCESS){
    817       break;
    818     }
    819   }
    820 
    821   return Status;
    822 }
    823 
    824 EFI_STATUS
    825 FvbEraseCustomBlockRange (
    826   IN UINTN                                Instance,
    827   IN EFI_LBA                              StartLba,
    828   IN UINTN                                OffsetStartLba,
    829   IN EFI_LBA                              LastLba,
    830   IN UINTN                                OffsetLastLba,
    831   IN ESAL_FWB_GLOBAL                      *Global,
    832   IN BOOLEAN                              Virtual
    833   )
    834 /*++
    835 
    836 Routine Description:
    837   Erases and initializes a specified range of a firmware volume
    838 
    839 Arguments:
    840   Instance              - The FV instance to be erased
    841   StartLba              - The starting logical block index to be erased
    842   OffsetStartLba        - Offset into the starting block at which to
    843                           begin erasing
    844   LastLba               - The last logical block index to be erased
    845   OffsetStartLba        - Offset into the last block at which to end erasing
    846   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    847                           instance data
    848   Virtual               - Whether CPU is in virtual or physical mode
    849 
    850 Returns:
    851   EFI_SUCCESS           - The firmware volume was erased successfully
    852   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    853   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    854                           could not be written. Firmware device may have been
    855                           partially erased
    856   EFI_INVALID_PARAMETER - Instance not found
    857 
    858 --*/
    859 {
    860   EFI_LBA Index;
    861   UINTN   LbaSize;
    862   UINTN   ScratchLbaSizeData;
    863 
    864   //
    865   // First LBA.
    866   //
    867   FvbGetLbaAddress (Instance, StartLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);
    868 
    869   //
    870   // Use the scratch space as the intermediate buffer to transfer data
    871   // Back up the first LBA in scratch space.
    872   //
    873   FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
    874 
    875   //
    876   // erase now
    877   //
    878   FvbEraseBlock (Instance, StartLba, Global, Virtual);
    879   ScratchLbaSizeData = OffsetStartLba;
    880 
    881   //
    882   // write the data back to the first block
    883   //
    884   if (ScratchLbaSizeData > 0) {
    885     FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);
    886   }
    887   //
    888   // Middle LBAs
    889   //
    890   if (LastLba > (StartLba + 1)) {
    891     for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {
    892       FvbEraseBlock (Instance, Index, Global, Virtual);
    893     }
    894   }
    895   //
    896   // Last LBAs, the same as first LBAs
    897   //
    898   if (LastLba > StartLba) {
    899     FvbGetLbaAddress (Instance, LastLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);
    900     FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
    901     FvbEraseBlock (Instance, LastLba, Global, Virtual);
    902   }
    903 
    904   ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1);
    905 
    906   return FvbWriteBlock (
    907           Instance,
    908           LastLba,
    909           (OffsetLastLba + 1),
    910           &ScratchLbaSizeData,
    911           Global->FvbScratchSpace[Virtual],
    912           Global,
    913           Virtual
    914           );
    915 }
    916 
    917 EFI_STATUS
    918 FvbSetVolumeAttributes (
    919   IN UINTN                                Instance,
    920   IN OUT EFI_FVB_ATTRIBUTES_2               *Attributes,
    921   IN ESAL_FWB_GLOBAL                      *Global,
    922   IN BOOLEAN                              Virtual
    923   )
    924 /*++
    925 
    926 Routine Description:
    927   Modifies the current settings of the firmware volume according to the
    928   input parameter, and returns the new setting of the volume
    929 
    930 Arguments:
    931   Instance              - The FV instance whose attributes is going to be
    932                           modified
    933   Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
    934                           containing the desired firmware volume settings.
    935                           On successful return, it contains the new settings
    936                           of the firmware volume
    937   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    938                           instance data
    939   Virtual               - Whether CPU is in virtual or physical mode
    940 
    941 Returns:
    942   EFI_SUCCESS           - Successfully returns
    943   EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
    944   EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
    945                           in conflict with the capabilities as declared in the
    946                           firmware volume header
    947 
    948 --*/
    949 {
    950   EFI_FW_VOL_INSTANCE *FwhInstance;
    951   EFI_FVB_ATTRIBUTES_2  OldAttributes;
    952   EFI_FVB_ATTRIBUTES_2  *AttribPtr;
    953   UINT32              Capabilities;
    954   UINT32              OldStatus;
    955   UINT32              NewStatus;
    956   EFI_STATUS          Status;
    957 
    958   FwhInstance = NULL;
    959 
    960   //
    961   // Find the right instance of the FVB private data
    962   //
    963   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    964   ASSERT_EFI_ERROR (Status);
    965 
    966   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
    967   OldAttributes = *AttribPtr;
    968   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
    969   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
    970   NewStatus     = *Attributes & EFI_FVB2_STATUS;
    971 
    972   //
    973   // If firmware volume is locked, no status bit can be updated
    974   //
    975   if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
    976     if (OldStatus ^ NewStatus) {
    977       return EFI_ACCESS_DENIED;
    978     }
    979   }
    980   //
    981   // Test read disable
    982   //
    983   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    984     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
    985       return EFI_INVALID_PARAMETER;
    986     }
    987   }
    988   //
    989   // Test read enable
    990   //
    991   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    992     if (NewStatus & EFI_FVB2_READ_STATUS) {
    993       return EFI_INVALID_PARAMETER;
    994     }
    995   }
    996   //
    997   // Test write disable
    998   //
    999   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
   1000     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
   1001       return EFI_INVALID_PARAMETER;
   1002     }
   1003   }
   1004   //
   1005   // Test write enable
   1006   //
   1007   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
   1008     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
   1009       return EFI_INVALID_PARAMETER;
   1010     }
   1011   }
   1012   //
   1013   // Test lock
   1014   //
   1015   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
   1016     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
   1017       return EFI_INVALID_PARAMETER;
   1018     }
   1019   }
   1020 
   1021   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
   1022   *AttribPtr  = (*AttribPtr) | NewStatus;
   1023   *Attributes = *AttribPtr;
   1024 
   1025   return EFI_SUCCESS;
   1026 }
   1027 //
   1028 // FVB protocol APIs
   1029 //
   1030 EFI_STATUS
   1031 EFIAPI
   1032 FvbProtocolGetPhysicalAddress (
   1033   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1034   OUT EFI_PHYSICAL_ADDRESS                          *Address
   1035   )
   1036 /*++
   1037 
   1038 Routine Description:
   1039 
   1040   Retrieves the physical address of the device.
   1041 
   1042 Arguments:
   1043 
   1044   This                  - Calling context
   1045   Address               - Output buffer containing the address.
   1046 
   1047 Returns:
   1048 
   1049 Returns:
   1050   EFI_SUCCESS           - Successfully returns
   1051 
   1052 --*/
   1053 {
   1054   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1055 
   1056   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1057 
   1058   return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
   1059 }
   1060 
   1061 EFI_STATUS
   1062 FvbProtocolGetBlockSize (
   1063   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1064   IN  EFI_LBA                                       Lba,
   1065   OUT UINTN                                         *BlockSize,
   1066   OUT UINTN                                         *NumOfBlocks
   1067   )
   1068 /*++
   1069 
   1070 Routine Description:
   1071   Retrieve the size of a logical block
   1072 
   1073 Arguments:
   1074   This                  - Calling context
   1075   Lba                   - Indicates which block to return the size for.
   1076   BlockSize             - A pointer to a caller allocated UINTN in which
   1077                           the size of the block is returned
   1078   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
   1079                           number of consecutive blocks starting with Lba is
   1080                           returned. All blocks in this range have a size of
   1081                           BlockSize
   1082 
   1083 Returns:
   1084   EFI_SUCCESS           - The firmware volume was read successfully and
   1085                           contents are in Buffer
   1086 
   1087 --*/
   1088 {
   1089   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1090 
   1091   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1092 
   1093   return FvbGetLbaAddress (
   1094           FvbDevice->Instance,
   1095           Lba,
   1096           NULL,
   1097           NULL,
   1098           BlockSize,
   1099           NumOfBlocks,
   1100           mFvbModuleGlobal,
   1101           EfiGoneVirtual ()
   1102           );
   1103 }
   1104 
   1105 EFI_STATUS
   1106 EFIAPI
   1107 FvbProtocolGetAttributes (
   1108   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1109   OUT EFI_FVB_ATTRIBUTES_2                            *Attributes
   1110   )
   1111 /*++
   1112 
   1113 Routine Description:
   1114     Retrieves Volume attributes.  No polarity translations are done.
   1115 
   1116 Arguments:
   1117     This                - Calling context
   1118     Attributes          - output buffer which contains attributes
   1119 
   1120 Returns:
   1121   EFI_SUCCESS           - Successfully returns
   1122 
   1123 --*/
   1124 {
   1125   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1126 
   1127   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1128 
   1129   return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
   1130 }
   1131 
   1132 EFI_STATUS
   1133 EFIAPI
   1134 FvbProtocolSetAttributes (
   1135   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1136   IN OUT EFI_FVB_ATTRIBUTES_2                         *Attributes
   1137   )
   1138 /*++
   1139 
   1140 Routine Description:
   1141   Sets Volume attributes. No polarity translations are done.
   1142 
   1143 Arguments:
   1144   This                  - Calling context
   1145   Attributes            - output buffer which contains attributes
   1146 
   1147 Returns:
   1148   EFI_SUCCESS           - Successfully returns
   1149 
   1150 --*/
   1151 {
   1152   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1153 
   1154   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1155 
   1156   return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
   1157 }
   1158 
   1159 EFI_STATUS
   1160 EFIAPI
   1161 FvbProtocolEraseBlocks (
   1162   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1163   ...
   1164   )
   1165 /*++
   1166 
   1167 Routine Description:
   1168 
   1169   The EraseBlock() function erases one or more blocks as denoted by the
   1170   variable argument list. The entire parameter list of blocks must be verified
   1171   prior to erasing any blocks.  If a block is requested that does not exist
   1172   within the associated firmware volume (it has a larger index than the last
   1173   block of the firmware volume), the EraseBlock() function must return
   1174   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
   1175 
   1176 Arguments:
   1177   This                  - Calling context
   1178   ...                   - Starting LBA followed by Number of Lba to erase.
   1179                           a -1 to terminate the list.
   1180 
   1181 Returns:
   1182   EFI_SUCCESS           - The erase request was successfully completed
   1183   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
   1184   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1185                           could not be written. Firmware device may have been
   1186                           partially erased
   1187 
   1188 --*/
   1189 {
   1190   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1191   EFI_FW_VOL_INSTANCE     *FwhInstance;
   1192   UINTN                   NumOfBlocks;
   1193   VA_LIST                 args;
   1194   EFI_LBA                 StartingLba;
   1195   UINTN                   NumOfLba;
   1196   EFI_STATUS              Status;
   1197 
   1198   FwhInstance = NULL;
   1199   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1200 
   1201   Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
   1202   ASSERT_EFI_ERROR (Status);
   1203 
   1204   NumOfBlocks = FwhInstance->NumOfBlocks;
   1205 
   1206   VA_START (args, This);
   1207 
   1208   do {
   1209     StartingLba = VA_ARG (args, EFI_LBA);
   1210     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
   1211       break;
   1212     }
   1213 
   1214     NumOfLba = VA_ARG (args, UINT32);
   1215 
   1216     //
   1217     // Check input parameters
   1218     //
   1219     if (NumOfLba == 0) {
   1220       VA_END (args);
   1221       return EFI_INVALID_PARAMETER;
   1222     }
   1223 
   1224     if ((StartingLba + NumOfLba) > NumOfBlocks) {
   1225       return EFI_INVALID_PARAMETER;
   1226     }
   1227   } while (TRUE);
   1228 
   1229   VA_END (args);
   1230 
   1231   VA_START (args, This);
   1232   do {
   1233     StartingLba = VA_ARG (args, EFI_LBA);
   1234     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
   1235       break;
   1236     }
   1237 
   1238     NumOfLba = VA_ARG (args, UINT32);
   1239 
   1240     while (NumOfLba > 0) {
   1241       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
   1242       if (EFI_ERROR (Status)) {
   1243         VA_END (args);
   1244         return Status;
   1245       }
   1246 
   1247       StartingLba++;
   1248       NumOfLba--;
   1249     }
   1250 
   1251   } while (TRUE);
   1252 
   1253   VA_END (args);
   1254 
   1255   return EFI_SUCCESS;
   1256 }
   1257 
   1258 EFI_STATUS
   1259 EFIAPI
   1260 FvbProtocolWrite (
   1261   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1262   IN EFI_LBA                                        Lba,
   1263   IN UINTN                                          Offset,
   1264   IN OUT UINTN                                      *NumBytes,
   1265   IN UINT8                                          *Buffer
   1266   )
   1267 /*++
   1268 
   1269 Routine Description:
   1270 
   1271   Writes data beginning at Lba:Offset from FV. The write terminates either
   1272   when *NumBytes of data have been written, or when a block boundary is
   1273   reached.  *NumBytes is updated to reflect the actual number of bytes
   1274   written. The write opertion does not include erase. This routine will
   1275   attempt to write only the specified bytes. If the writes do not stick,
   1276   it will return an error.
   1277 
   1278 Arguments:
   1279   This                  - Calling context
   1280   Lba                   - Block in which to begin write
   1281   Offset                - Offset in the block at which to begin write
   1282   NumBytes              - On input, indicates the requested write size. On
   1283                           output, indicates the actual number of bytes written
   1284   Buffer                - Buffer containing source data for the write.
   1285 
   1286 Returns:
   1287   EFI_SUCCESS           - The firmware volume was written successfully
   1288   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
   1289                           NumBytes contains the total number of bytes
   1290                           actually written
   1291   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
   1292   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1293                           could not be written
   1294   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1295 
   1296 --*/
   1297 {
   1298 
   1299   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1300 
   1301   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1302 
   1303   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1304 }
   1305 
   1306 EFI_STATUS
   1307 EFIAPI
   1308 FvbProtocolRead (
   1309   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
   1310   IN EFI_LBA                                        Lba,
   1311   IN UINTN                                          Offset,
   1312   IN OUT UINTN                                      *NumBytes,
   1313   IN UINT8                                          *Buffer
   1314   )
   1315 /*++
   1316 
   1317 Routine Description:
   1318 
   1319   Reads data beginning at Lba:Offset from FV. The Read terminates either
   1320   when *NumBytes of data have been read, or when a block boundary is
   1321   reached.  *NumBytes is updated to reflect the actual number of bytes
   1322   written. The write opertion does not include erase. This routine will
   1323   attempt to write only the specified bytes. If the writes do not stick,
   1324   it will return an error.
   1325 
   1326 Arguments:
   1327   This                  - Calling context
   1328   Lba                   - Block in which to begin Read
   1329   Offset                - Offset in the block at which to begin Read
   1330   NumBytes              - On input, indicates the requested write size. On
   1331                           output, indicates the actual number of bytes Read
   1332   Buffer                - Buffer containing source data for the Read.
   1333 
   1334 Returns:
   1335   EFI_SUCCESS           - The firmware volume was read successfully and
   1336                           contents are in Buffer
   1337   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
   1338                           NumBytes contains the total number of bytes returned
   1339                           in Buffer
   1340   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
   1341   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1342                           could not be read
   1343   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1344 
   1345 --*/
   1346 {
   1347 
   1348   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1349   EFI_STATUS              Status;
   1350 
   1351   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1352   Status    = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1353 
   1354   return Status;
   1355 }
   1356 
   1357 EFI_STATUS
   1358 ValidateFvHeader (
   1359   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
   1360   )
   1361 /*++
   1362 
   1363 Routine Description:
   1364   Check the integrity of firmware volume header
   1365 
   1366 Arguments:
   1367   FwVolHeader           - A pointer to a firmware volume header
   1368 
   1369 Returns:
   1370   EFI_SUCCESS           - The firmware volume is consistent
   1371   EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
   1372 
   1373 --*/
   1374 {
   1375   UINT16  *Ptr;
   1376   UINT16  HeaderLength;
   1377   UINT16  Checksum;
   1378 
   1379   //
   1380   // Verify the header revision, header signature, length
   1381   // Length of FvBlock cannot be 2**64-1
   1382   // HeaderLength cannot be an odd number
   1383   //
   1384   #ifndef R864_BUILD
   1385   if (((FwVolHeader->Revision != EFI_FVH_REVISION) && (FwVolHeader->Revision != EFI_FVH_REVISION)) ||
   1386   #else
   1387   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
   1388   #endif
   1389       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
   1390       (FwVolHeader->FvLength == ((UINTN) -1)) ||
   1391       ((FwVolHeader->HeaderLength & 0x01) != 0)
   1392       ) {
   1393     return EFI_NOT_FOUND;
   1394   }
   1395   //
   1396   // Verify the header checksum
   1397   //
   1398   HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
   1399   Ptr           = (UINT16 *) FwVolHeader;
   1400   Checksum      = 0;
   1401   while (HeaderLength > 0) {
   1402     Checksum = Checksum + (*Ptr);
   1403     Ptr++;
   1404     HeaderLength--;
   1405   }
   1406 
   1407   if (Checksum != 0) {
   1408     return EFI_NOT_FOUND;
   1409   }
   1410 
   1411   return EFI_SUCCESS;
   1412 }
   1413 
   1414 EFI_STATUS
   1415 GetFvbHeader (
   1416   VOID                                **HobList,
   1417   OUT EFI_FIRMWARE_VOLUME_HEADER      **FwVolHeader,
   1418   OUT EFI_PHYSICAL_ADDRESS            *BaseAddress,
   1419   OUT BOOLEAN                         *WriteBack
   1420   )
   1421 {
   1422   EFI_STATUS                Status;
   1423 
   1424   Status        = EFI_SUCCESS;
   1425   *WriteBack    = FALSE;
   1426 
   1427   if (*FwVolHeader == NULL) {
   1428     *BaseAddress = PcdGet32 (PcdFlashFvRecoveryBase);
   1429   } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvRecoveryBase)) {
   1430     *BaseAddress = PcdGet32 (PcdFlashFvMainBase);
   1431   } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvMainBase)) {
   1432     *BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
   1433   } else {
   1434     return EFI_NOT_FOUND;
   1435   }
   1436 
   1437   DEBUG((EFI_D_INFO, "Fvb base : %08x\n",*BaseAddress));
   1438 
   1439   *FwVolHeader  = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (*BaseAddress);
   1440   Status        = ValidateFvHeader (*FwVolHeader);
   1441   if (EFI_ERROR (Status)) {
   1442     //
   1443     // Get FvbInfo
   1444     //
   1445     *WriteBack  = TRUE;
   1446 
   1447     Status      = GetFvbInfo (*BaseAddress, FwVolHeader);
   1448     DEBUG(( DEBUG_ERROR, "Through GetFvbInfo: %08x!\n",*BaseAddress));
   1449 
   1450     ASSERT_EFI_ERROR (Status);
   1451   }
   1452 
   1453   return EFI_SUCCESS;
   1454 }
   1455 
   1456 
   1457 EFI_STATUS
   1458 SmmSpiInit (
   1459   VOID
   1460   )
   1461 {
   1462   UINT8       SpiStatus;
   1463   UINT8       FlashIndex;
   1464   UINT8       FlashID[3];
   1465   EFI_STATUS  Status;
   1466 
   1467   //
   1468   // Obtain a handle for ICH SPI Protocol
   1469   //
   1470   ASSERT(mSmst != NULL);
   1471   if (mFvbModuleGlobal->SmmSpiProtocol == NULL){
   1472     Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);
   1473     ASSERT_EFI_ERROR(Status);
   1474   }
   1475   //
   1476   // attempt to identify flash part and initialize spi table
   1477   //
   1478   for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
   1479     Status = mFvbModuleGlobal->SmmSpiProtocol->Init (
   1480                                                 mFvbModuleGlobal->SmmSpiProtocol,
   1481                                                 &(mSpiInitTable[FlashIndex])
   1482                                                 );
   1483     if (!EFI_ERROR (Status)) {
   1484       //
   1485       // read vendor/device IDs to check if flash device is supported
   1486       //
   1487       Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
   1488                                                   mFvbModuleGlobal->SmmSpiProtocol,
   1489                                                   SPI_OPCODE_JEDEC_ID_INDEX,
   1490                                                   SPI_WREN_INDEX,
   1491                                                   TRUE,
   1492                                                   FALSE,
   1493                                                   FALSE,
   1494                                                   0,
   1495                                                   3,
   1496                                                   FlashID,
   1497                                                   EnumSpiRegionAll
   1498                                                   );
   1499       if (!EFI_ERROR (Status)) {
   1500         if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1501                (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||
   1502               ((FlashID[0] == SPI_AT26DF321_ID1) &&
   1503                (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1504                (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {
   1505           //
   1506           // Supported SPI device found
   1507           //
   1508           DEBUG (
   1509               ((EFI_D_INFO),
   1510               "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1511               FlashID[0],
   1512               FlashID[1],
   1513               FlashID[2])
   1514               );
   1515           break;
   1516         }
   1517       }
   1518     }
   1519   }
   1520 
   1521   if (FlashIndex >= EnumSpiFlashMax) {
   1522     Status = EFI_UNSUPPORTED;
   1523     DEBUG (
   1524         (EFI_D_ERROR,
   1525         "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1526         FlashID[0],
   1527         FlashID[1],
   1528         FlashID[2])
   1529         );
   1530     ASSERT_EFI_ERROR (Status);
   1531   }
   1532 
   1533   SpiStatus = 0;
   1534   Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
   1535                                             mFvbModuleGlobal->SmmSpiProtocol,
   1536                                             SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex
   1537                                             1,                        // PrefixOpcodeIndex
   1538                                             TRUE,                     // DataCycle
   1539                                             TRUE,                     // Atomic
   1540                                             TRUE,                     // ShiftOut
   1541                                             0,                        // Address
   1542                                             1,                        // Data Number
   1543                                             &SpiStatus,
   1544                                             EnumSpiRegionAll          // SPI_REGION_TYPE
   1545                                             );
   1546   return Status;
   1547 }
   1548 
   1549 EFI_STATUS
   1550 SmmSpiNotificationFunction (
   1551   IN CONST EFI_GUID  *Protocol,
   1552   IN VOID            *Interface,
   1553   IN EFI_HANDLE      Handle
   1554   )
   1555 {
   1556   return SmmSpiInit();
   1557 }
   1558 
   1559 
   1560 VOID
   1561 EFIAPI
   1562 GetFullDriverPath (
   1563   IN  EFI_HANDLE                  ImageHandle,
   1564   IN  EFI_SYSTEM_TABLE            *SystemTable,
   1565   OUT EFI_DEVICE_PATH_PROTOCOL    **CompleteFilePath
   1566   )
   1567 /*++
   1568 
   1569 Routine Description:
   1570 
   1571   Function is used to get the full device path for this driver.
   1572 
   1573 Arguments:
   1574 
   1575   ImageHandle        - The loaded image handle of this driver.
   1576   SystemTable        - The pointer of system table.
   1577   CompleteFilePath   - The pointer of returned full file path
   1578 
   1579 Returns:
   1580 
   1581   none
   1582 
   1583 --*/
   1584 {
   1585   EFI_STATUS                Status;
   1586   EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
   1587   EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath;
   1588 
   1589 
   1590   Status = gBS->HandleProtocol (
   1591                   ImageHandle,
   1592                   &gEfiLoadedImageProtocolGuid,
   1593                   (VOID **) &LoadedImage
   1594                   );
   1595   ASSERT_EFI_ERROR (Status);
   1596 
   1597   Status = gBS->HandleProtocol (
   1598                   LoadedImage->DeviceHandle,
   1599                   &gEfiDevicePathProtocolGuid,
   1600                   (VOID *) &ImageDevicePath
   1601                   );
   1602   ASSERT_EFI_ERROR (Status);
   1603 
   1604   *CompleteFilePath = AppendDevicePath (
   1605                         ImageDevicePath,
   1606                         LoadedImage->FilePath
   1607                         );
   1608 
   1609   return ;
   1610 }
   1611 
   1612 
   1613 
   1614 EFI_STATUS
   1615 FvbInitialize (
   1616   IN EFI_HANDLE         ImageHandle,
   1617   IN EFI_SYSTEM_TABLE   *SystemTable
   1618   )
   1619 /*++
   1620 
   1621 Routine Description:
   1622   This function does common initialization for FVB services
   1623 
   1624 Arguments:
   1625 
   1626 Returns:
   1627 
   1628 --*/
   1629 {
   1630   EFI_STATUS                          Status;
   1631   EFI_FW_VOL_INSTANCE                 *FwhInstance;
   1632   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
   1633   EFI_FIRMWARE_VOLUME_HEADER          *TempFwVolHeader;
   1634   VOID                                *HobList;
   1635   VOID                                *FirmwareVolumeHobList;
   1636   UINT32                              BufferSize;
   1637   EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
   1638   BOOLEAN                             WriteEnabled;
   1639   BOOLEAN                             WriteLocked;
   1640   EFI_HANDLE                          FwbHandle;
   1641   EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
   1642   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
   1643   EFI_DEVICE_PATH_PROTOCOL            *FwbDevicePath;
   1644   EFI_DEVICE_PATH_PROTOCOL            *TempFwbDevicePath;
   1645   UINT32                              MaxLbaSize;
   1646   EFI_PHYSICAL_ADDRESS                BaseAddress;
   1647   BOOLEAN                             WriteBack;
   1648   UINTN                               NumOfBlocks;
   1649   UINTN                               HeaderLength;
   1650   UINT8                               SpiStatus;
   1651   UINT8                               FlashIndex;
   1652   UINT8                               FlashID[3];
   1653   EFI_DEVICE_PATH_PROTOCOL            *CompleteFilePath;
   1654   UINT8                               PrefixOpcodeIndex;
   1655   BOOLEAN                             InSmm;
   1656   EFI_SMM_BASE2_PROTOCOL              *mSmmBase2;
   1657   EFI_HANDLE                          Handle;
   1658 
   1659   VOID                                *Registration;
   1660   EFI_EVENT                           Event;
   1661 
   1662   CompleteFilePath = NULL;
   1663   GetFullDriverPath (ImageHandle, SystemTable, &CompleteFilePath);
   1664 
   1665  Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
   1666 
   1667   //
   1668   // No FV HOBs found
   1669   //
   1670   ASSERT_EFI_ERROR (Status);
   1671 
   1672 
   1673   //
   1674   // Allocate runtime services data for global variable, which contains
   1675   // the private data of all firmware volume block instances
   1676   //
   1677   mFvbModuleGlobal = (ESAL_FWB_GLOBAL *)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL  ));
   1678   ASSERT(mFvbModuleGlobal);
   1679   mSmmBase2 = NULL;
   1680   Status = gBS->LocateProtocol (
   1681                   &gEfiSmmBase2ProtocolGuid,
   1682                   NULL,
   1683                   (VOID **) &mSmmBase2
   1684                   );
   1685 
   1686   if (mSmmBase2 == NULL) {
   1687     InSmm = FALSE;
   1688   } else {
   1689     mSmmBase2->InSmm (mSmmBase2, &InSmm);
   1690     mSmmBase2->GetSmstLocation (mSmmBase2, &mSmst);
   1691 
   1692   }
   1693 
   1694   if (!InSmm) {
   1695     mInSmmMode = 0;
   1696     //
   1697     // Obtain a handle for ICH SPI Protocol
   1698     //
   1699     Status = gBS->LocateProtocol (&gEfiSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SpiProtocol);
   1700     ASSERT_EFI_ERROR (Status);
   1701 
   1702     //
   1703     // attempt to identify flash part and initialize spi table
   1704     //
   1705     for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
   1706       Status = mFvbModuleGlobal->SpiProtocol->Init (
   1707                                                 mFvbModuleGlobal->SpiProtocol,
   1708                                                 &(mSpiInitTable[FlashIndex])
   1709                                                 );
   1710       if (!EFI_ERROR (Status)) {
   1711         //
   1712         // read vendor/device IDs to check if flash device is supported
   1713         //
   1714         Status = mFvbModuleGlobal->SpiProtocol->Execute (
   1715                                                   mFvbModuleGlobal->SpiProtocol,
   1716                                                   SPI_OPCODE_JEDEC_ID_INDEX,
   1717                                                   SPI_WREN_INDEX,
   1718                                                   TRUE,
   1719                                                   FALSE,
   1720                                                   FALSE,
   1721                                                   0,
   1722                                                   3,
   1723                                                   FlashID,
   1724                                                   EnumSpiRegionAll
   1725                                                   );
   1726         if (!EFI_ERROR (Status)) {
   1727           if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1728                (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||
   1729               ((FlashID[0] == SPI_AT26DF321_ID1) &&
   1730                (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
   1731                (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {
   1732             //
   1733             // Supported SPI device found
   1734             //
   1735             DEBUG (
   1736               ((EFI_D_INFO),
   1737               "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1738               FlashID[0],
   1739               FlashID[1],
   1740               FlashID[2])
   1741               );
   1742 
   1743             PublishFlashDeviceInfo (&mSpiInitTable[FlashIndex]);
   1744             break;
   1745           }
   1746         }
   1747       }
   1748     }
   1749 
   1750     if (FlashIndex >= EnumSpiFlashMax) {
   1751       Status = EFI_UNSUPPORTED;
   1752       DEBUG (
   1753         (DEBUG_ERROR,
   1754         "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
   1755         FlashID[0],
   1756         FlashID[1],
   1757         FlashID[2])
   1758         );
   1759       ASSERT_EFI_ERROR (Status);
   1760     }
   1761 
   1762     //
   1763     // Unlock all regions by writing to status register
   1764     // This could be SPI device specific, need to follow the datasheet
   1765     // To write to Write Status Register the Spi PrefixOpcode needs to be:
   1766     //   0 for Atmel parts
   1767     //   0 for Intel parts
   1768     //   0 for Macronix parts
   1769     //   0 for Winbond parts
   1770     //   1 for SST parts
   1771     SpiStatus = 0;
   1772     if (FlashID[0] == SPI_SST25VF016B_ID1) {
   1773       PrefixOpcodeIndex = 1;
   1774     } else {
   1775       PrefixOpcodeIndex = 0;
   1776     }
   1777     Status = mFvbModuleGlobal->SpiProtocol->Execute (
   1778                                               mFvbModuleGlobal->SpiProtocol,
   1779                                               SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex
   1780                                               PrefixOpcodeIndex,        // PrefixOpcodeIndex
   1781                                               TRUE,                     // DataCycle
   1782                                               TRUE,                     // Atomic
   1783                                               TRUE,                     // ShiftOut
   1784                                               0,                        // Address
   1785                                               1,                        // Data Number
   1786                                               &SpiStatus,
   1787                                               EnumSpiRegionAll          // SPI_REGION_TYPE
   1788                                               );
   1789 
   1790 
   1791   } else  {
   1792     mInSmmMode = 1;
   1793 
   1794     Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);
   1795     if (EFI_ERROR(Status)) {
   1796       Registration = NULL;
   1797       Status = mSmst->SmmRegisterProtocolNotify (
   1798                    &gEfiSmmSpiProtocolGuid,
   1799                    SmmSpiNotificationFunction,
   1800                    &Registration
   1801                    );
   1802     } else  {
   1803       Status  = SmmSpiInit();
   1804     }
   1805 
   1806   }
   1807 
   1808   //
   1809   // Calculate the total size for all firmware volume block instances
   1810   //
   1811   BufferSize            = 0;
   1812   FirmwareVolumeHobList = HobList;
   1813   FwVolHeader           = NULL;
   1814   do {
   1815     Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack);
   1816     if (EFI_ERROR (Status)) {
   1817       break;
   1818     }
   1819 
   1820     if (FwVolHeader) {
   1821       BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
   1822     }
   1823   } while (TRUE);
   1824 
   1825   //
   1826   // Only need to allocate once. There is only one copy of physical memory for
   1827   // the private data of each FV instance. But in virtual mode or in physical
   1828   // mode, the address of the the physical memory may be different.
   1829   //
   1830   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
   1831   ASSERT(mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]);
   1832   //
   1833   // Make a virtual copy of the FvInstance pointer.
   1834   //
   1835   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
   1836   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
   1837 
   1838   mFvbModuleGlobal->NumFv                   = 0;
   1839   FirmwareVolumeHobList                     = HobList;
   1840   TempFwVolHeader                           = NULL;
   1841 
   1842   MaxLbaSize = 0;
   1843 
   1844   //
   1845   // Fill in the private data of each firmware volume block instance
   1846   //
   1847   // Foreach Fv HOB in the FirmwareVolumeHobList, loop
   1848   //
   1849   do {
   1850     Status = GetFvbHeader (&FirmwareVolumeHobList, &TempFwVolHeader, &BaseAddress, &WriteBack);
   1851     if (EFI_ERROR (Status)) {
   1852       break;
   1853     }
   1854     FwVolHeader = TempFwVolHeader;
   1855 
   1856     if (!FwVolHeader) {
   1857       continue;
   1858     }
   1859 
   1860 
   1861     CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
   1862     FwVolHeader                       = &(FwhInstance->VolumeHeader);
   1863 
   1864     FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
   1865     FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
   1866 
   1867     //
   1868     // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
   1869     //
   1870     FwhInstance->FvWriteBase[FVB_PHYSICAL]  = (UINTN) BaseAddress;
   1871     WriteEnabled = TRUE;
   1872 
   1873     //
   1874     // Every pointer should have a virtual copy.
   1875     //
   1876     FwhInstance->FvWriteBase[FVB_VIRTUAL] = FwhInstance->FvWriteBase[FVB_PHYSICAL];
   1877 
   1878     FwhInstance->WriteEnabled             = WriteEnabled;
   1879     EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
   1880 
   1881     NumOfBlocks = 0;
   1882     WriteLocked = FALSE;
   1883 
   1884     if (WriteEnabled) {
   1885       for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
   1886         //
   1887         // Get the maximum size of a block. The size will be used to allocate
   1888         // buffer for Scratch space, the intermediate buffer for FVB extension
   1889         // protocol
   1890         //
   1891         if (MaxLbaSize < PtrBlockMapEntry->Length) {
   1892           MaxLbaSize = PtrBlockMapEntry->Length;
   1893         }
   1894 
   1895         NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
   1896       }
   1897       //
   1898       //  Write back a healthy FV header
   1899       //
   1900       if (WriteBack && (!WriteLocked)) {
   1901 
   1902         Status = FlashFdErase (
   1903                   (UINTN) FwhInstance->FvWriteBase[0],
   1904                   (UINTN) BaseAddress,
   1905                   FwVolHeader->BlockMap->Length
   1906                   );
   1907 
   1908         HeaderLength = (UINTN) FwVolHeader->HeaderLength;
   1909         Status = FlashFdWrite (
   1910                   (UINTN) FwhInstance->FvWriteBase[0],
   1911                   (UINTN) BaseAddress,
   1912                   &HeaderLength,
   1913                   (UINT8 *) FwVolHeader,
   1914                   FwVolHeader->BlockMap->Length
   1915                   );
   1916 
   1917       }
   1918     }
   1919     //
   1920     // The total number of blocks in the FV.
   1921     //
   1922     FwhInstance->NumOfBlocks = NumOfBlocks;
   1923 
   1924     //
   1925     // If the FV is write locked, set the appropriate attributes
   1926     //
   1927     if (WriteLocked) {
   1928       //
   1929       // write disabled
   1930       //
   1931       FwhInstance->VolumeHeader.Attributes &= ~EFI_FVB2_WRITE_STATUS;
   1932       //
   1933       // lock enabled
   1934       //
   1935       FwhInstance->VolumeHeader.Attributes |= EFI_FVB2_LOCK_STATUS;
   1936     }
   1937 
   1938     //
   1939     // Allocate and initialize FVB Device in a runtime data buffer
   1940     //
   1941     FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFvbDeviceTemplate);
   1942     ASSERT (FvbDevice);
   1943 
   1944     FvbDevice->Instance = mFvbModuleGlobal->NumFv;
   1945     mFvbModuleGlobal->NumFv++;
   1946 
   1947     //
   1948     // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
   1949     //
   1950     if (FwVolHeader->ExtHeaderOffset == 0) {
   1951       FvbDevice->FvDevicePath.MemMapDevPath.StartingAddress = BaseAddress;
   1952       FvbDevice->FvDevicePath.MemMapDevPath.EndingAddress   = BaseAddress + (FwVolHeader->FvLength - 1);
   1953       FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->FvDevicePath;
   1954     } else {
   1955       CopyGuid (
   1956         &FvbDevice->UefiFvDevicePath.FvDevPath.FvName,
   1957         (EFI_GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
   1958         );
   1959       FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->UefiFvDevicePath;
   1960     }
   1961 
   1962     if (!InSmm) {
   1963       //
   1964       // Find a handle with a matching device path that has supports FW Block protocol
   1965       //
   1966       TempFwbDevicePath = FwbDevicePath;
   1967       Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
   1968       if (EFI_ERROR (Status)) {
   1969         //
   1970         // LocateDevicePath fails so install a new interface and device path
   1971         //
   1972         FwbHandle = NULL;
   1973         Status = gBS->InstallMultipleProtocolInterfaces (
   1974                         &FwbHandle,
   1975                         &gEfiFirmwareVolumeBlockProtocolGuid,
   1976                         &FvbDevice->FwVolBlockInstance,
   1977                         &gEfiDevicePathProtocolGuid,
   1978                         FwbDevicePath,
   1979                         NULL
   1980                         );
   1981         ASSERT_EFI_ERROR (Status);
   1982       } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {
   1983         //
   1984         // Device already exists, so reinstall the FVB protocol
   1985         //
   1986         Status = gBS->HandleProtocol (
   1987                         FwbHandle,
   1988                         &gEfiFirmwareVolumeBlockProtocolGuid,
   1989                         (VOID **) &OldFwbInterface
   1990                         );
   1991         ASSERT_EFI_ERROR (Status);
   1992 
   1993         Status = gBS->ReinstallProtocolInterface (
   1994                         FwbHandle,
   1995                         &gEfiFirmwareVolumeBlockProtocolGuid,
   1996                         OldFwbInterface,
   1997                         &FvbDevice->FwVolBlockInstance
   1998                         );
   1999         ASSERT_EFI_ERROR (Status);
   2000 
   2001       } else {
   2002         //
   2003         // There was a FVB protocol on an End Device Path node
   2004         //
   2005         ASSERT (FALSE);
   2006       }
   2007     } else {
   2008       FwbHandle = NULL;
   2009       Status = mSmst->SmmInstallProtocolInterface (
   2010                 &FwbHandle,
   2011                 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
   2012                 EFI_NATIVE_INTERFACE,
   2013                 &FvbDevice->FwVolBlockInstance
   2014                 );
   2015       ASSERT_EFI_ERROR (Status);
   2016     }
   2017 
   2018     FwhInstance = (EFI_FW_VOL_INSTANCE *)
   2019       (
   2020         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
   2021           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
   2022       );
   2023   } while (TRUE);
   2024 
   2025   //
   2026   // Allocate for scratch space, an intermediate buffer for FVB extention
   2027   //
   2028 
   2029   mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimeZeroPool (MaxLbaSize);
   2030 
   2031   ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]);
   2032 
   2033   mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
   2034 
   2035   if (!InSmm) {
   2036     Status = gBS->CreateEventEx (
   2037                   EVT_NOTIFY_SIGNAL,
   2038                   TPL_NOTIFY,
   2039                  FvbVirtualddressChangeEvent,
   2040                   NULL,
   2041                   &gEfiEventVirtualAddressChangeGuid,
   2042                   &Event
   2043                   );
   2044     ASSERT_EFI_ERROR (Status);
   2045   } else {
   2046     //
   2047     // Inform other platform drivers that SPI device discovered and
   2048     // SPI interface ready for use.
   2049     //
   2050     Handle = NULL;
   2051     Status = gBS->InstallProtocolInterface (
   2052                     &Handle,
   2053                     &gEfiSmmSpiReadyProtocolGuid,
   2054                     EFI_NATIVE_INTERFACE,
   2055                     NULL
   2056                     );
   2057   }
   2058   return EFI_SUCCESS;
   2059 }
   2060