Home | History | Annotate | Download | only in FvbRuntimeService
      1 /**@file
      2 Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR>
      3 This program and the accompanying materials
      4 are licensed and made available under the terms and conditions of the BSD License
      5 which accompanies this distribution.  The full text of the license may be found at
      6 http://opensource.org/licenses/bsd-license.php
      7 
      8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
      9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     10 
     11 Module Name:
     12 
     13   FWBlockService.c
     14 
     15 Abstract:
     16 
     17 Revision History
     18 
     19 **/
     20 #include "FWBlockService.h"
     21 #include "EfiFlashMap.h"
     22 #include "FileIo.h"
     23 #include "FlashLayout.h"
     24 
     25 ESAL_FWB_GLOBAL       *mFvbModuleGlobal;
     26 VOID                  *mSFSRegistration;
     27 #define TRY_ASSIGN(var, value)  if(var != NULL) {*var = value;}
     28 
     29 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
     30   FVB_DEVICE_SIGNATURE,
     31   {
     32     {
     33       {
     34         HARDWARE_DEVICE_PATH,
     35         HW_MEMMAP_DP,
     36         {
     37           sizeof (MEMMAP_DEVICE_PATH),
     38           0
     39         }
     40       },
     41       EfiMemoryMappedIO,
     42       0,
     43       0,
     44     },
     45     {
     46       END_DEVICE_PATH_TYPE,
     47       END_ENTIRE_DEVICE_PATH_SUBTYPE,
     48       {
     49         sizeof (EFI_DEVICE_PATH_PROTOCOL),
     50         0
     51       }
     52     }
     53   },
     54   0,
     55   {
     56     FvbProtocolGetAttributes,
     57     FvbProtocolSetAttributes,
     58     FvbProtocolGetPhysicalAddress,
     59     FvbProtocolGetBlockSize,
     60     FvbProtocolRead,
     61     FvbProtocolWrite,
     62     FvbProtocolEraseBlocks,
     63     NULL
     64   }
     65 };
     66 
     67 
     68 EFI_STATUS
     69 FlashFdWrite (
     70   IN     UINTN                            Address,
     71   IN     EFI_FW_VOL_INSTANCE              *FwhInstance,
     72   IN OUT UINTN                            *NumBytes,
     73   IN     UINT8                            *Buffer
     74   )
     75 /*++
     76 
     77 Routine Description:
     78   Writes specified number of bytes from the input buffer to the address
     79 
     80 Arguments:
     81 
     82 Returns:
     83 
     84 --*/
     85 {
     86   EFI_STATUS          Status;
     87   EFI_FILE_PROTOCOL   *File;
     88   UINTN               FileOffset;
     89   UINTN               BufferForFile;
     90   UINTN               Length;
     91 
     92   Status = EFI_SUCCESS;
     93   CopyMem ((VOID *) Address, Buffer, *NumBytes);
     94 
     95   if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {
     96     Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
     97     ASSERT_EFI_ERROR (Status);
     98     if (!EFI_ERROR (Status)) {
     99       if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {
    100         FileOffset = 0;
    101         BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;
    102         Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));
    103       } else {
    104         FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;
    105         BufferForFile = Address;
    106         Length = *NumBytes;
    107       }
    108 
    109       Status = FileWrite (File, FileOffset, BufferForFile, Length);
    110       ASSERT_EFI_ERROR (Status);
    111       FileClose (File);
    112     }
    113   }
    114   return Status;
    115 }
    116 
    117 EFI_STATUS
    118 FlashFdErase (
    119   IN UINTN                                Address,
    120   IN EFI_FW_VOL_INSTANCE                  *FwhInstance,
    121   IN UINTN                                LbaLength
    122   )
    123 /*++
    124 
    125 Routine Description:
    126   Erase a certain block from address LbaWriteAddress
    127 
    128 Arguments:
    129 
    130 Returns:
    131 
    132 --*/
    133 {
    134   EFI_STATUS           Status;
    135   EFI_FILE_PROTOCOL    *File;
    136   UINTN                FileOffset;
    137   UINTN                BufferForFile;
    138   UINTN                Length;
    139 
    140   Status = EFI_SUCCESS;
    141 
    142   SetMem ((VOID *)Address, LbaLength, 0xff);
    143 
    144   if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {
    145     Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
    146     ASSERT_EFI_ERROR (Status);
    147     if (!EFI_ERROR (Status)) {
    148       if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {
    149         FileOffset = 0;
    150         BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;
    151         Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));
    152       } else {
    153         FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;
    154         BufferForFile = Address;
    155         Length = LbaLength;
    156       }
    157 
    158       Status = FileWrite (File, FileOffset, BufferForFile, Length);
    159       ASSERT_EFI_ERROR (Status);
    160       FileClose (File);
    161     }
    162   }
    163   return Status;
    164 }
    165 
    166 VOID
    167 EFIAPI
    168 FvbVirtualddressChangeEvent (
    169   IN EFI_EVENT        Event,
    170   IN VOID             *Context
    171   )
    172 /*++
    173 
    174 Routine Description:
    175 
    176   Fixup internal data so that EFI and SAL can be call in virtual mode.
    177   Call the passed in Child Notify event and convert the mFvbModuleGlobal
    178   date items to there virtual address.
    179 
    180   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]  - Physical copy of instance data
    181   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]   - Virtual pointer to common
    182                                                 instance data.
    183 
    184 Arguments:
    185 
    186   (Standard EFI notify event - EFI_EVENT_NOTIFY)
    187 
    188 Returns:
    189 
    190   None
    191 
    192 --*/
    193 {
    194   EFI_FW_VOL_INSTANCE *FwhInstance;
    195   UINTN               Index;
    196 
    197   EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
    198 
    199   //
    200   // Convert the base address of all the instances
    201   //
    202   Index       = 0;
    203   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
    204   while (Index < mFvbModuleGlobal->NumFv) {
    205     EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
    206     FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength
    207                     + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
    208     Index++;
    209   }
    210 
    211   EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
    212   EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal);
    213 }
    214 
    215 EFI_STATUS
    216 GetFvbInstance (
    217   IN  UINTN                               Instance,
    218   IN  ESAL_FWB_GLOBAL                     *Global,
    219   OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
    220   IN BOOLEAN                              Virtual
    221   )
    222 /*++
    223 
    224 Routine Description:
    225   Retrieves the physical address of a memory mapped FV
    226 
    227 Arguments:
    228   Instance              - The FV instance whose base address is going to be
    229                           returned
    230   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    231                           instance data
    232   FwhInstance           - The EFI_FW_VOL_INSTANCE fimrware instance structure
    233   Virtual               - Whether CPU is in virtual or physical mode
    234 
    235 Returns:
    236   EFI_SUCCESS           - Successfully returns
    237   EFI_INVALID_PARAMETER - Instance not found
    238 
    239 --*/
    240 {
    241   EFI_FW_VOL_INSTANCE *FwhRecord;
    242 
    243   if (Instance >= Global->NumFv) {
    244     return EFI_INVALID_PARAMETER;
    245   }
    246   //
    247   // Find the right instance of the FVB private data
    248   //
    249   FwhRecord = Global->FvInstance[Virtual];
    250   while (Instance > 0) {
    251     FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength
    252                      + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
    253     Instance--;
    254   }
    255 
    256   *FwhInstance = FwhRecord;
    257 
    258   return EFI_SUCCESS;
    259 }
    260 
    261 EFI_STATUS
    262 FvbGetPhysicalAddress (
    263   IN UINTN                                Instance,
    264   OUT EFI_PHYSICAL_ADDRESS                *Address,
    265   IN ESAL_FWB_GLOBAL                      *Global,
    266   IN BOOLEAN                              Virtual
    267   )
    268 /*++
    269 
    270 Routine Description:
    271   Retrieves the physical address of a memory mapped FV
    272 
    273 Arguments:
    274   Instance              - The FV instance whose base address is going to be
    275                           returned
    276   Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
    277                           that on successful return, contains the base address
    278                           of the firmware volume.
    279   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    280                           instance data
    281   Virtual               - Whether CPU is in virtual or physical mode
    282 
    283 Returns:
    284   EFI_SUCCESS           - Successfully returns
    285   EFI_INVALID_PARAMETER - Instance not found
    286 
    287 --*/
    288 {
    289   EFI_FW_VOL_INSTANCE *FwhInstance;
    290   EFI_STATUS          Status;
    291 
    292   //
    293   // Find the right instance of the FVB private data
    294   //
    295   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    296   ASSERT_EFI_ERROR (Status);
    297   *Address = FwhInstance->FvBase[Virtual];
    298 
    299   return EFI_SUCCESS;
    300 }
    301 
    302 EFI_STATUS
    303 FvbGetVolumeAttributes (
    304   IN UINTN                                Instance,
    305   OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
    306   IN ESAL_FWB_GLOBAL                      *Global,
    307   IN BOOLEAN                              Virtual
    308   )
    309 /*++
    310 
    311 Routine Description:
    312   Retrieves attributes, insures positive polarity of attribute bits, returns
    313   resulting attributes in output parameter
    314 
    315 Arguments:
    316   Instance              - The FV instance whose attributes is going to be
    317                           returned
    318   Attributes            - Output buffer which contains attributes
    319   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    320                           instance data
    321   Virtual               - Whether CPU is in virtual or physical mode
    322 
    323 Returns:
    324   EFI_SUCCESS           - Successfully returns
    325   EFI_INVALID_PARAMETER - Instance not found
    326 
    327 --*/
    328 {
    329   EFI_FW_VOL_INSTANCE *FwhInstance;
    330   EFI_STATUS          Status;
    331 
    332   //
    333   // Find the right instance of the FVB private data
    334   //
    335   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    336   ASSERT_EFI_ERROR (Status);
    337   *Attributes = FwhInstance->VolumeHeader.Attributes;
    338 
    339   return EFI_SUCCESS;
    340 }
    341 
    342 EFI_STATUS
    343 FvbGetLbaAddress (
    344   IN  UINTN                               Instance,
    345   IN  EFI_LBA                             Lba,
    346   OUT UINTN                               *LbaAddress  OPTIONAL,
    347   OUT UINTN                               *LbaLength   OPTIONAL,
    348   OUT UINTN                               *NumOfBlocks OPTIONAL,
    349   IN  ESAL_FWB_GLOBAL                     *Global,
    350   IN  BOOLEAN                             Virtual
    351   )
    352 /*++
    353 
    354 Routine Description:
    355   Retrieves the starting address of an LBA in an FV
    356 
    357 Arguments:
    358   Instance              - The FV instance which the Lba belongs to
    359   Lba                   - The logical block address
    360   LbaAddress            - On output, contains the physical starting address
    361                           of the Lba for writing
    362   LbaLength             - On output, contains the length of the block
    363   NumOfBlocks           - A pointer to a caller allocated UINTN in which the
    364                           number of consecutive blocks starting with Lba is
    365                           returned. All blocks in this range have a size of
    366                           BlockSize
    367   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    368                           instance data
    369   Virtual               - Whether CPU is in virtual or physical mode
    370 
    371 Returns:
    372   EFI_SUCCESS           - Successfully returns
    373   EFI_INVALID_PARAMETER - Instance not found
    374 
    375 --*/
    376 {
    377   UINT32                  NumBlocks;
    378   UINT32                  BlockLength;
    379   UINTN                   Offset;
    380   EFI_LBA                 StartLba;
    381   EFI_LBA                 NextLba;
    382   EFI_FW_VOL_INSTANCE     *FwhInstance;
    383   EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
    384   EFI_STATUS              Status;
    385 
    386   //
    387   // Find the right instance of the FVB private data
    388   //
    389   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    390   ASSERT_EFI_ERROR (Status);
    391 
    392   StartLba  = 0;
    393   Offset    = 0;
    394   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
    395 
    396   //
    397   // Parse the blockmap of the FV to find which map entry the Lba belongs to
    398   //
    399   while (TRUE) {
    400     NumBlocks   = BlockMap->NumBlocks;
    401     BlockLength = BlockMap->Length;
    402 
    403     if (NumBlocks == 0 || BlockLength == 0) {
    404       return EFI_INVALID_PARAMETER;
    405     }
    406 
    407     NextLba = StartLba + NumBlocks;
    408 
    409     //
    410     // The map entry found
    411     //
    412     if (Lba >= StartLba && Lba < NextLba) {
    413       Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
    414 
    415       if (LbaAddress) {
    416         *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
    417       }
    418 
    419       if (LbaLength) {
    420         *LbaLength = BlockLength;
    421       }
    422 
    423       if (NumOfBlocks) {
    424         *NumOfBlocks = (UINTN) (NextLba - Lba);
    425       }
    426 
    427       return EFI_SUCCESS;
    428     }
    429 
    430     StartLba  = NextLba;
    431     Offset    = Offset + NumBlocks * BlockLength;
    432     BlockMap++;
    433   }
    434 }
    435 
    436 EFI_STATUS
    437 FvbReadBlock (
    438   IN UINTN                                Instance,
    439   IN EFI_LBA                              Lba,
    440   IN UINTN                                BlockOffset,
    441   IN OUT UINTN                            *NumBytes,
    442   IN UINT8                                *Buffer,
    443   IN ESAL_FWB_GLOBAL                      *Global,
    444   IN BOOLEAN                              Virtual
    445   )
    446 /*++
    447 
    448 Routine Description:
    449   Reads specified number of bytes into a buffer from the specified block
    450 
    451 Arguments:
    452   Instance              - The FV instance to be read from
    453   Lba                   - The logical block address to be read from
    454   BlockOffset           - Offset into the block at which to begin reading
    455   NumBytes              - Pointer that on input contains the total size of
    456                           the buffer. On output, it contains the total number
    457                           of bytes read
    458   Buffer                - Pointer to a caller allocated buffer that will be
    459                           used to hold the data read
    460   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    461                           instance data
    462   Virtual               - Whether CPU is in virtual or physical mode
    463 
    464 Returns:
    465   EFI_SUCCESS           - The firmware volume was read successfully and
    466                           contents are in Buffer
    467   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
    468                           NumBytes contains the total number of bytes returned
    469                           in Buffer
    470   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
    471   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    472                           could not be read
    473   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    474 
    475 --*/
    476 {
    477   EFI_FVB_ATTRIBUTES_2  Attributes;
    478   UINTN                 LbaAddress;
    479   UINTN                 LbaLength;
    480   EFI_STATUS            Status;
    481 
    482   //
    483   // Check for invalid conditions
    484   //
    485   if ((NumBytes == NULL) || (Buffer == NULL)) {
    486     return EFI_INVALID_PARAMETER;
    487   }
    488 
    489   if (*NumBytes == 0) {
    490     return EFI_INVALID_PARAMETER;
    491   }
    492 
    493   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
    494   if (EFI_ERROR (Status)) {
    495     return Status;
    496   }
    497   //
    498   // Check if the FV is read enabled
    499   //
    500   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    501 
    502   if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
    503     return EFI_ACCESS_DENIED;
    504   }
    505   //
    506   // Perform boundary checks and adjust NumBytes
    507   //
    508   if (BlockOffset > LbaLength) {
    509     return EFI_INVALID_PARAMETER;
    510   }
    511 
    512   if (LbaLength < (*NumBytes + BlockOffset)) {
    513     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    514     Status    = EFI_BAD_BUFFER_SIZE;
    515   }
    516 
    517   CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes);
    518 
    519   return Status;
    520 }
    521 EFI_STATUS
    522 FvbWriteBlock (
    523   IN UINTN                                Instance,
    524   IN EFI_LBA                              Lba,
    525   IN UINTN                                BlockOffset,
    526   IN OUT UINTN                            *NumBytes,
    527   IN UINT8                                *Buffer,
    528   IN ESAL_FWB_GLOBAL                      *Global,
    529   IN BOOLEAN                              Virtual
    530   )
    531 /*++
    532 
    533 Routine Description:
    534   Writes specified number of bytes from the input buffer to the block
    535 
    536 Arguments:
    537   Instance              - The FV instance to be written to
    538   Lba                   - The starting logical block index to write to
    539   BlockOffset           - Offset into the block at which to begin writing
    540   NumBytes              - Pointer that on input contains the total size of
    541                           the buffer. On output, it contains the total number
    542                           of bytes actually written
    543   Buffer                - Pointer to a caller allocated buffer that contains
    544                           the source for the write
    545   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    546                           instance data
    547   Virtual               - Whether CPU is in virtual or physical mode
    548 
    549 Returns:
    550   EFI_SUCCESS           - The firmware volume was written successfully
    551   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
    552                           NumBytes contains the total number of bytes
    553                           actually written
    554   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    555   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    556                           could not be written
    557   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
    558 
    559 --*/
    560 {
    561   EFI_FVB_ATTRIBUTES_2  Attributes;
    562   UINTN                 LbaAddress;
    563   UINTN                 LbaLength;
    564   EFI_FW_VOL_INSTANCE   *FwhInstance;
    565   EFI_STATUS            Status;
    566   EFI_STATUS            ReturnStatus;
    567 
    568   //
    569   // Find the right instance of the FVB private data
    570   //
    571   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    572   ASSERT_EFI_ERROR (Status);
    573 
    574   //
    575   // Writes are enabled in the init routine itself
    576   //
    577   if (!FwhInstance->WriteEnabled) {
    578     return EFI_ACCESS_DENIED;
    579   }
    580   //
    581   // Check for invalid conditions
    582   //
    583   if ((NumBytes == NULL) || (Buffer == NULL)) {
    584     return EFI_INVALID_PARAMETER;
    585   }
    586 
    587   if (*NumBytes == 0) {
    588     return EFI_INVALID_PARAMETER;
    589   }
    590 
    591   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
    592   if (EFI_ERROR (Status)) {
    593     return Status;
    594   }
    595   //
    596   // Check if the FV is write enabled
    597   //
    598   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    599 
    600   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    601     return EFI_ACCESS_DENIED;
    602   }
    603   //
    604   // Perform boundary checks and adjust NumBytes
    605   //
    606   if (BlockOffset > LbaLength) {
    607     return EFI_INVALID_PARAMETER;
    608   }
    609 
    610   if (LbaLength < (*NumBytes + BlockOffset)) {
    611     *NumBytes = (UINT32) (LbaLength - BlockOffset);
    612     Status    = EFI_BAD_BUFFER_SIZE;
    613   }
    614 
    615   ReturnStatus = FlashFdWrite (
    616                   LbaAddress + BlockOffset,
    617                   FwhInstance,
    618                   NumBytes,
    619                   Buffer
    620                   );
    621   if (EFI_ERROR (ReturnStatus)) {
    622     return ReturnStatus;
    623   }
    624 
    625   return Status;
    626 }
    627 
    628 EFI_STATUS
    629 FvbEraseBlock (
    630   IN UINTN                                Instance,
    631   IN EFI_LBA                              Lba,
    632   IN ESAL_FWB_GLOBAL                      *Global,
    633   IN BOOLEAN                              Virtual
    634   )
    635 /*++
    636 
    637 Routine Description:
    638   Erases and initializes a firmware volume block
    639 
    640 Arguments:
    641   Instance              - The FV instance to be erased
    642   Lba                   - The logical block index to be erased
    643   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    644                           instance data
    645   Virtual               - Whether CPU is in virtual or physical mode
    646 
    647 Returns:
    648   EFI_SUCCESS           - The erase request was successfully completed
    649   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    650   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    651                           could not be written. Firmware device may have been
    652                           partially erased
    653   EFI_INVALID_PARAMETER - Instance not found
    654 
    655 --*/
    656 {
    657 
    658   EFI_FVB_ATTRIBUTES_2  Attributes;
    659   UINTN                 LbaAddress;
    660   EFI_FW_VOL_INSTANCE   *FwhInstance;
    661   UINTN                 LbaLength;
    662   EFI_STATUS            Status;
    663 
    664   //
    665   // Find the right instance of the FVB private data
    666   //
    667   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    668   ASSERT_EFI_ERROR (Status);
    669 
    670   //
    671   // Writes are enabled in the init routine itself
    672   //
    673   if (!FwhInstance->WriteEnabled) {
    674     return EFI_ACCESS_DENIED;
    675   }
    676   //
    677   // Check if the FV is write enabled
    678   //
    679   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
    680 
    681   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    682     return EFI_ACCESS_DENIED;
    683   }
    684   //
    685   // Get the starting address of the block for erase. For debug reasons,
    686   // LbaWriteAddress may not be the same as LbaAddress.
    687   //
    688   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
    689   if (EFI_ERROR (Status)) {
    690     return Status;
    691   }
    692 
    693   return FlashFdErase (
    694           LbaAddress,
    695           FwhInstance,
    696           LbaLength
    697           );
    698 }
    699 
    700 EFI_STATUS
    701 FvbSetVolumeAttributes (
    702   IN UINTN                                Instance,
    703   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes,
    704   IN ESAL_FWB_GLOBAL                      *Global,
    705   IN BOOLEAN                              Virtual
    706   )
    707 /*++
    708 
    709 Routine Description:
    710   Modifies the current settings of the firmware volume according to the
    711   input parameter, and returns the new setting of the volume
    712 
    713 Arguments:
    714   Instance              - The FV instance whose attributes is going to be
    715                           modified
    716   Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
    717                           containing the desired firmware volume settings.
    718                           On successful return, it contains the new settings
    719                           of the firmware volume
    720   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
    721                           instance data
    722   Virtual               - Whether CPU is in virtual or physical mode
    723 
    724 Returns:
    725   EFI_SUCCESS           - Successfully returns
    726   EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
    727   EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
    728                           in conflict with the capabilities as declared in the
    729                           firmware volume header
    730 
    731 --*/
    732 {
    733   EFI_FW_VOL_INSTANCE   *FwhInstance;
    734   EFI_FVB_ATTRIBUTES_2  OldAttributes;
    735   EFI_FVB_ATTRIBUTES_2  *AttribPtr;
    736   UINT32                Capabilities;
    737   UINT32                OldStatus;
    738   UINT32                NewStatus;
    739   EFI_STATUS            Status;
    740 
    741   //
    742   // Find the right instance of the FVB private data
    743   //
    744   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
    745   ASSERT_EFI_ERROR (Status);
    746 
    747   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
    748   OldAttributes = *AttribPtr;
    749   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
    750   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
    751   NewStatus     = *Attributes & EFI_FVB2_STATUS;
    752 
    753   //
    754   // If firmware volume is locked, no status bit can be updated
    755   //
    756   if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
    757     if (OldStatus ^ NewStatus) {
    758       return EFI_ACCESS_DENIED;
    759     }
    760   }
    761   //
    762   // Test read disable
    763   //
    764   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    765     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
    766       return EFI_INVALID_PARAMETER;
    767     }
    768   }
    769   //
    770   // Test read enable
    771   //
    772   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    773     if (NewStatus & EFI_FVB2_READ_STATUS) {
    774       return EFI_INVALID_PARAMETER;
    775     }
    776   }
    777   //
    778   // Test write disable
    779   //
    780   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    781     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
    782       return EFI_INVALID_PARAMETER;
    783     }
    784   }
    785   //
    786   // Test write enable
    787   //
    788   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    789     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
    790       return EFI_INVALID_PARAMETER;
    791     }
    792   }
    793   //
    794   // Test lock
    795   //
    796   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    797     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
    798       return EFI_INVALID_PARAMETER;
    799     }
    800   }
    801 
    802   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
    803   *AttribPtr  = (*AttribPtr) | NewStatus;
    804   *Attributes = *AttribPtr;
    805 
    806   return EFI_SUCCESS;
    807 }
    808 //
    809 // FVB protocol APIs
    810 //
    811 EFI_STATUS
    812 EFIAPI
    813 FvbProtocolGetPhysicalAddress (
    814   IN  CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL          *This,
    815   OUT       EFI_PHYSICAL_ADDRESS                        *Address
    816   )
    817 /*++
    818 
    819 Routine Description:
    820 
    821   Retrieves the physical address of the device.
    822 
    823 Arguments:
    824 
    825   This                  - Calling context
    826   Address               - Output buffer containing the address.
    827 
    828 Returns:
    829 
    830 Returns:
    831   EFI_SUCCESS           - Successfully returns
    832 
    833 --*/
    834 {
    835   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    836 
    837   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    838 
    839   return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
    840 }
    841 
    842 EFI_STATUS
    843 EFIAPI
    844 FvbProtocolGetBlockSize (
    845   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
    846   IN  EFI_LBA                                     Lba,
    847   OUT UINTN                                       *BlockSize,
    848   OUT UINTN                                       *NumOfBlocks
    849   )
    850 /*++
    851 
    852 Routine Description:
    853   Retrieve the size of a logical block
    854 
    855 Arguments:
    856   This                  - Calling context
    857   Lba                   - Indicates which block to return the size for.
    858   BlockSize             - A pointer to a caller allocated UINTN in which
    859                           the size of the block is returned
    860   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
    861                           number of consecutive blocks starting with Lba is
    862                           returned. All blocks in this range have a size of
    863                           BlockSize
    864 
    865 Returns:
    866   EFI_SUCCESS           - The firmware volume was read successfully and
    867                           contents are in Buffer
    868 
    869 --*/
    870 {
    871   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    872 
    873   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    874 
    875   return FvbGetLbaAddress (
    876           FvbDevice->Instance,
    877           Lba,
    878           NULL,
    879           BlockSize,
    880           NumOfBlocks,
    881           mFvbModuleGlobal,
    882           EfiGoneVirtual ()
    883           );
    884 }
    885 
    886 EFI_STATUS
    887 EFIAPI
    888 FvbProtocolGetAttributes (
    889   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL          *This,
    890   OUT      EFI_FVB_ATTRIBUTES_2                        *Attributes
    891   )
    892 /*++
    893 
    894 Routine Description:
    895     Retrieves Volume attributes.  No polarity translations are done.
    896 
    897 Arguments:
    898     This                - Calling context
    899     Attributes          - output buffer which contains attributes
    900 
    901 Returns:
    902   EFI_SUCCESS           - Successfully returns
    903 
    904 --*/
    905 {
    906   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    907 
    908   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    909 
    910   return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
    911 }
    912 
    913 EFI_STATUS
    914 EFIAPI
    915 FvbProtocolSetAttributes (
    916   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
    917   IN OUT   EFI_FVB_ATTRIBUTES_2                     *Attributes
    918   )
    919 /*++
    920 
    921 Routine Description:
    922   Sets Volume attributes. No polarity translations are done.
    923 
    924 Arguments:
    925   This                  - Calling context
    926   Attributes            - output buffer which contains attributes
    927 
    928 Returns:
    929   EFI_SUCCESS           - Successfully returns
    930 
    931 --*/
    932 {
    933   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    934 
    935   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    936 
    937   return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
    938 }
    939 
    940 EFI_STATUS
    941 EFIAPI
    942 FvbProtocolEraseBlocks (
    943   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
    944   ...
    945   )
    946 /*++
    947 
    948 Routine Description:
    949 
    950   The EraseBlock() function erases one or more blocks as denoted by the
    951   variable argument list. The entire parameter list of blocks must be verified
    952   prior to erasing any blocks.  If a block is requested that does not exist
    953   within the associated firmware volume (it has a larger index than the last
    954   block of the firmware volume), the EraseBlock() function must return
    955   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
    956 
    957 Arguments:
    958   This                  - Calling context
    959   ...                   - Starting LBA followed by Number of Lba to erase.
    960                           a -1 to terminate the list.
    961 
    962 Returns:
    963   EFI_SUCCESS           - The erase request was successfully completed
    964   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
    965   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
    966                           could not be written. Firmware device may have been
    967                           partially erased
    968 
    969 --*/
    970 {
    971   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
    972   EFI_FW_VOL_INSTANCE     *FwhInstance;
    973   UINTN                   NumOfBlocks;
    974   VA_LIST                 args;
    975   EFI_LBA                 StartingLba;
    976   UINTN                   NumOfLba;
    977   EFI_STATUS              Status;
    978 
    979   FvbDevice = FVB_DEVICE_FROM_THIS (This);
    980 
    981   Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
    982   ASSERT_EFI_ERROR (Status);
    983 
    984   NumOfBlocks = FwhInstance->NumOfBlocks;
    985 
    986   VA_START (args, This);
    987 
    988   do {
    989     StartingLba = VA_ARG (args, EFI_LBA);
    990     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
    991       break;
    992     }
    993 
    994     NumOfLba = VA_ARG (args, UINT32);
    995 
    996     //
    997     // Check input parameters
    998     //
    999     if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
   1000       VA_END (args);
   1001       return EFI_INVALID_PARAMETER;
   1002     }
   1003   } while (1);
   1004 
   1005   VA_END (args);
   1006 
   1007   VA_START (args, This);
   1008   do {
   1009     StartingLba = VA_ARG (args, EFI_LBA);
   1010     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
   1011       break;
   1012     }
   1013 
   1014     NumOfLba = VA_ARG (args, UINT32);
   1015 
   1016     while (NumOfLba > 0) {
   1017       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
   1018       if (EFI_ERROR (Status)) {
   1019         VA_END (args);
   1020         return Status;
   1021       }
   1022 
   1023       StartingLba++;
   1024       NumOfLba--;
   1025     }
   1026 
   1027   } while (1);
   1028 
   1029   VA_END (args);
   1030 
   1031   return EFI_SUCCESS;
   1032 }
   1033 
   1034 EFI_STATUS
   1035 EFIAPI
   1036 FvbProtocolWrite (
   1037   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *This,
   1038   IN EFI_LBA                                      Lba,
   1039   IN UINTN                                        Offset,
   1040   IN OUT UINTN                                    *NumBytes,
   1041   IN UINT8                                        *Buffer
   1042   )
   1043 /*++
   1044 
   1045 Routine Description:
   1046 
   1047   Writes data beginning at Lba:Offset from FV. The write terminates either
   1048   when *NumBytes of data have been written, or when a block boundary is
   1049   reached.  *NumBytes is updated to reflect the actual number of bytes
   1050   written. The write opertion does not include erase. This routine will
   1051   attempt to write only the specified bytes. If the writes do not stick,
   1052   it will return an error.
   1053 
   1054 Arguments:
   1055   This                  - Calling context
   1056   Lba                   - Block in which to begin write
   1057   Offset                - Offset in the block at which to begin write
   1058   NumBytes              - On input, indicates the requested write size. On
   1059                           output, indicates the actual number of bytes written
   1060   Buffer                - Buffer containing source data for the write.
   1061 
   1062 Returns:
   1063   EFI_SUCCESS           - The firmware volume was written successfully
   1064   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
   1065                           NumBytes contains the total number of bytes
   1066                           actually written
   1067   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
   1068   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1069                           could not be written
   1070   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1071 
   1072 --*/
   1073 {
   1074 
   1075   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1076 
   1077   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1078 
   1079   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1080 }
   1081 
   1082 EFI_STATUS
   1083 EFIAPI
   1084 FvbProtocolRead (
   1085   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *This,
   1086   IN EFI_LBA                                      Lba,
   1087   IN UINTN                                        Offset,
   1088   IN OUT UINTN                                    *NumBytes,
   1089   IN UINT8                                        *Buffer
   1090   )
   1091 /*++
   1092 
   1093 Routine Description:
   1094 
   1095   Reads data beginning at Lba:Offset from FV. The Read terminates either
   1096   when *NumBytes of data have been read, or when a block boundary is
   1097   reached.  *NumBytes is updated to reflect the actual number of bytes
   1098   written. The write opertion does not include erase. This routine will
   1099   attempt to write only the specified bytes. If the writes do not stick,
   1100   it will return an error.
   1101 
   1102 Arguments:
   1103   This                  - Calling context
   1104   Lba                   - Block in which to begin Read
   1105   Offset                - Offset in the block at which to begin Read
   1106   NumBytes              - On input, indicates the requested write size. On
   1107                           output, indicates the actual number of bytes Read
   1108   Buffer                - Buffer containing source data for the Read.
   1109 
   1110 Returns:
   1111   EFI_SUCCESS           - The firmware volume was read successfully and
   1112                           contents are in Buffer
   1113   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
   1114                           NumBytes contains the total number of bytes returned
   1115                           in Buffer
   1116   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
   1117   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
   1118                           could not be read
   1119   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
   1120 
   1121 --*/
   1122 {
   1123 
   1124   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
   1125 
   1126   FvbDevice = FVB_DEVICE_FROM_THIS (This);
   1127 
   1128   return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
   1129 }
   1130 
   1131 EFI_STATUS
   1132 ValidateFvHeader (
   1133   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
   1134   )
   1135 /*++
   1136 
   1137 Routine Description:
   1138   Check the integrity of firmware volume header
   1139 
   1140 Arguments:
   1141   FwVolHeader           - A pointer to a firmware volume header
   1142 
   1143 Returns:
   1144   EFI_SUCCESS           - The firmware volume is consistent
   1145   EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
   1146 
   1147 --*/
   1148 {
   1149   UINT16  *Ptr;
   1150   UINT16  HeaderLength;
   1151   UINT16  Checksum;
   1152 
   1153   //
   1154   // Verify the header revision, header signature, length
   1155   // Length of FvBlock cannot be 2**64-1
   1156   // HeaderLength cannot be an odd number
   1157   //
   1158   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
   1159       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
   1160       (FwVolHeader->FvLength == ((UINTN) -1)) ||
   1161       ((FwVolHeader->HeaderLength & 0x01) != 0)
   1162       ) {
   1163     return EFI_NOT_FOUND;
   1164   }
   1165   //
   1166   // Verify the header checksum
   1167   //
   1168   HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
   1169   Ptr           = (UINT16 *) FwVolHeader;
   1170   Checksum      = 0;
   1171   while (HeaderLength > 0) {
   1172     Checksum = Checksum + (*Ptr);
   1173     HeaderLength--;
   1174     Ptr++;
   1175   }
   1176 
   1177   if (Checksum != 0) {
   1178     return EFI_NOT_FOUND;
   1179   }
   1180 
   1181   return EFI_SUCCESS;
   1182 }
   1183 
   1184 
   1185 EFI_STATUS
   1186 GetFvbHeader (
   1187   IN OUT EFI_PEI_HOB_POINTERS           *HobList,
   1188   OUT    EFI_FIRMWARE_VOLUME_HEADER     **FwVolHeader,
   1189   OUT    EFI_PHYSICAL_ADDRESS           *BaseAddress     OPTIONAL,
   1190   OUT    UINT32                         *VolumeId        OPTIONAL,
   1191   OUT    CHAR16                         **MappedFile     OPTIONAL,
   1192   OUT    UINT32                         *ActuralSize     OPTIONAL,
   1193   OUT    UINT32                         *Offset          OPTIONAL,
   1194   OUT    BOOLEAN                        *WriteBack       OPTIONAL
   1195   )
   1196 {
   1197   EFI_STATUS                  Status;
   1198   EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry;
   1199   EFI_FLASH_SUBAREA_ENTRY     *FlashMapSubEntry;
   1200 
   1201   Status        = EFI_SUCCESS;
   1202   *FwVolHeader  = NULL;
   1203   TRY_ASSIGN (WriteBack, FALSE);
   1204 
   1205   DEBUG ((EFI_D_INFO, "Hob start is 0x%x\n", (UINTN)(*HobList).Raw));
   1206   (*HobList).Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, (*HobList).Raw);
   1207   if ((*HobList).Raw == NULL) {
   1208     return EFI_NOT_FOUND;
   1209   }
   1210 
   1211   FlashMapEntry     = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA ((*HobList).Guid);
   1212   FlashMapSubEntry  = &FlashMapEntry->Entries[0];
   1213 
   1214   //
   1215   // Check if it is a "FVB" area
   1216   //
   1217   if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) {
   1218     return Status;
   1219   }
   1220   //
   1221   // Check if it is a "real" flash
   1222   //
   1223   if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) {
   1224     return Status;
   1225   }
   1226 
   1227   TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base);
   1228 
   1229   //
   1230   // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver
   1231   //
   1232   TRY_ASSIGN (VolumeId,    FlashMapEntry->VolumeId);
   1233   TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize);
   1234   TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath));
   1235   TRY_ASSIGN (Offset,      FlashMapEntry->Offset);
   1236 
   1237   DEBUG ((
   1238     EFI_D_INFO,
   1239     "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n",
   1240     (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length,
   1241     (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset
   1242   ));
   1243   DEBUG ((
   1244     EFI_D_INFO,
   1245     "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n",
   1246     (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath
   1247   ));
   1248   *FwVolHeader  = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base);
   1249   Status        = ValidateFvHeader (*FwVolHeader);
   1250   if (EFI_ERROR (Status)) {
   1251     //
   1252     // Get FvbInfo
   1253     //
   1254     TRY_ASSIGN (WriteBack, TRUE);
   1255     Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader);
   1256     DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status));
   1257     ASSERT_EFI_ERROR (Status);
   1258   }
   1259 
   1260   return EFI_SUCCESS;
   1261 }
   1262 
   1263 VOID
   1264 EFIAPI
   1265 OnSimpleFileSystemInstall (
   1266   IN EFI_EVENT        Event,
   1267   IN VOID             *Context
   1268   )
   1269 {
   1270   EFI_STATUS                Status;
   1271   UINTN                     HandleSize;
   1272   EFI_HANDLE                Handle;
   1273   UINTN                     Instance;
   1274   EFI_DEVICE_PATH_PROTOCOL  *Device;
   1275   EFI_FILE_PROTOCOL         *File;
   1276   EFI_FW_VOL_INSTANCE       *FwhInstance;
   1277   while (TRUE) {
   1278     HandleSize = sizeof (EFI_HANDLE);
   1279     Status = gBS->LocateHandle (
   1280                     ByRegisterNotify,
   1281                     NULL,
   1282                     mSFSRegistration,
   1283                     &HandleSize,
   1284                     &Handle
   1285                     );
   1286     if (Status == EFI_NOT_FOUND) {
   1287       break;
   1288     }
   1289     DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n"));
   1290     ASSERT_EFI_ERROR (Status);
   1291     //
   1292     // Check if this is the storage we care about, and store it in FwhInstance
   1293     //
   1294     for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) {
   1295       Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE);
   1296       ASSERT_EFI_ERROR (Status);
   1297 
   1298       if (FwhInstance->MappedFile[0] == L'\0') {
   1299         //
   1300         // The instance of FVB isn't mapped to file.
   1301         //
   1302         continue;
   1303       }
   1304 
   1305       if ((FwhInstance->Device != NULL) &&
   1306           !EFI_ERROR (CheckStoreExists (FwhInstance->Device))
   1307           ) {
   1308         //
   1309         // The instance of FVB has already associated to a device
   1310         //  and the device is not removed from system.
   1311         //
   1312         DEBUG ((
   1313               EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n",
   1314               (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
   1315               (UINTN) FwhInstance->Offset
   1316               ));
   1317         continue;
   1318       }
   1319 
   1320       Status = CheckStore (Handle, FwhInstance->VolumeId, &Device);
   1321       if (!EFI_ERROR (Status)) {
   1322         //
   1323         // Write back memory content to file
   1324         //
   1325         Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE);
   1326         ASSERT_EFI_ERROR (Status);
   1327         if (!EFI_ERROR (Status)) {
   1328           DEBUG ((
   1329                 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n",
   1330                 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
   1331                 (UINTN) FwhInstance->Offset
   1332                 ));
   1333           Status = FileWrite (
   1334                      File,
   1335                      0,
   1336                      FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset,
   1337                      FwhInstance->ActuralSize - FwhInstance->Offset
   1338                      );
   1339           ASSERT_EFI_ERROR (Status);
   1340           if (!EFI_ERROR (Status)) {
   1341             if (FwhInstance->Device != NULL) {
   1342               gBS->FreePool (FwhInstance->Device);
   1343             }
   1344             FwhInstance->Device = Device;
   1345             DEBUG ((
   1346                   EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n",
   1347                   (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
   1348                   (UINTN) FwhInstance->Offset
   1349                   ));
   1350           }
   1351           FileClose (File);
   1352         }
   1353       }
   1354     }
   1355   }
   1356 }
   1357 
   1358 VOID
   1359 FvbInstallSfsNotify (
   1360   VOID
   1361 )
   1362 {
   1363   EFI_STATUS Status;
   1364   EFI_EVENT  Event;
   1365 
   1366   Status = gBS->CreateEvent (
   1367                   EVT_NOTIFY_SIGNAL,
   1368                   TPL_CALLBACK,
   1369                   OnSimpleFileSystemInstall,
   1370                   NULL,
   1371                   &Event
   1372                   );
   1373   ASSERT_EFI_ERROR (Status);
   1374 
   1375   Status = gBS->RegisterProtocolNotify (
   1376                   &gEfiSimpleFileSystemProtocolGuid,
   1377                   Event,
   1378                   &mSFSRegistration
   1379                   );
   1380   ASSERT_EFI_ERROR (Status);
   1381 }
   1382 
   1383 
   1384 EFI_STATUS
   1385 EFIAPI
   1386 FvbInitialize (
   1387   IN EFI_HANDLE         ImageHandle,
   1388   IN EFI_SYSTEM_TABLE   *SystemTable
   1389   )
   1390 /*++
   1391 
   1392 Routine Description:
   1393   This function does common initialization for FVB services
   1394 
   1395 Arguments:
   1396 
   1397 Returns:
   1398 
   1399 --*/
   1400 {
   1401   EFI_STATUS                          Status;
   1402   EFI_FW_VOL_INSTANCE                 *FwhInstance;
   1403   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
   1404   EFI_PEI_HOB_POINTERS                FirmwareVolumeHobList;
   1405   UINT32                              BufferSize;
   1406   EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
   1407   UINTN                               LbaAddress;
   1408   EFI_HANDLE                          FwbHandle;
   1409   EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
   1410   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
   1411   EFI_DEVICE_PATH_PROTOCOL            *TempFwbDevicePath;
   1412   FV_DEVICE_PATH                      TempFvbDevicePathData;
   1413   UINT32                              MaxLbaSize;
   1414   EFI_PHYSICAL_ADDRESS                BaseAddress;
   1415   UINT32                              VolumeId;
   1416   CHAR16                              *MappedFile;
   1417   UINT32                              ActuralSize;
   1418   UINT32                              Offset;
   1419   BOOLEAN                             WriteBack;
   1420   UINTN                               NumOfBlocks;
   1421   UINTN                               HeaderLength;
   1422   BOOLEAN                             InstallSfsNotify;
   1423 
   1424   HeaderLength     = 0;
   1425   InstallSfsNotify = FALSE;
   1426 
   1427   //
   1428   // Allocate runtime services data for global variable, which contains
   1429   // the private data of all firmware volume block instances
   1430   //
   1431   Status = gBS->AllocatePool (
   1432                   EfiRuntimeServicesData,
   1433                   sizeof (ESAL_FWB_GLOBAL),
   1434                   &mFvbModuleGlobal
   1435                   );
   1436   ASSERT_EFI_ERROR (Status);
   1437   //
   1438   // Calculate the total size for all firmware volume block instances
   1439   //
   1440   BufferSize            = 0;
   1441   FirmwareVolumeHobList.Raw = GetHobList();
   1442   do {
   1443     Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL);
   1444     if (EFI_ERROR (Status)) {
   1445       break;
   1446     }
   1447     FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);
   1448 
   1449     if (FwVolHeader) {
   1450       BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
   1451     }
   1452   } while (TRUE);
   1453 
   1454   //
   1455   // Only need to allocate once. There is only one copy of physical memory for
   1456   // the private data of each FV instance. But in virtual mode or in physical
   1457   // mode, the address of the the physical memory may be different.
   1458   //
   1459   Status = gBS->AllocatePool (
   1460                   EfiRuntimeServicesData,
   1461                   BufferSize,
   1462                   &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
   1463                   );
   1464   ASSERT_EFI_ERROR (Status);
   1465 
   1466   //
   1467   // Make a virtual copy of the FvInstance pointer.
   1468   //
   1469   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
   1470   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
   1471 
   1472   mFvbModuleGlobal->NumFv     = 0;
   1473   FirmwareVolumeHobList.Raw   = GetHobList();
   1474   MaxLbaSize                  = 0;
   1475 
   1476   //
   1477   // Fill in the private data of each firmware volume block instance
   1478   //
   1479   do {
   1480     Status = GetFvbHeader (
   1481                &FirmwareVolumeHobList, &FwVolHeader,
   1482                &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset,
   1483                &WriteBack
   1484              );
   1485     if (EFI_ERROR (Status)) {
   1486       break;
   1487     }
   1488     FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);
   1489 
   1490     if (!FwVolHeader) {
   1491       continue;
   1492     }
   1493 
   1494     CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
   1495     FwVolHeader                       = &(FwhInstance->VolumeHeader);
   1496 
   1497     FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
   1498     FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
   1499     FwhInstance->Device               = NULL;
   1500     FwhInstance->Offset               = Offset;
   1501 
   1502     if (*MappedFile != '\0') {
   1503       FwhInstance->VolumeId             = VolumeId;
   1504       FwhInstance->ActuralSize          = ActuralSize;
   1505       StrCpy (FwhInstance->MappedFile, MappedFile);
   1506 
   1507       InstallSfsNotify = TRUE;
   1508     } else {
   1509       FwhInstance->VolumeId             = (UINT32) -1;
   1510       FwhInstance->ActuralSize          = (UINT32) -1;
   1511       FwhInstance->MappedFile[0]        = L'\0';
   1512     }
   1513 
   1514     DEBUG ((EFI_D_INFO, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n",
   1515            (UINTN) BaseAddress, VolumeId, MappedFile, ActuralSize));
   1516     //
   1517     // We may expose readonly FVB in future.
   1518     //
   1519     FwhInstance->WriteEnabled         = TRUE; // Ken: Why enable write?
   1520     EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
   1521 
   1522     LbaAddress  = (UINTN) FwhInstance->FvBase[0];
   1523     NumOfBlocks = 0;
   1524 
   1525     if (FwhInstance->WriteEnabled) {
   1526       for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
   1527 
   1528         LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length;
   1529         //
   1530         // Get the maximum size of a block. The size will be used to allocate
   1531         // buffer for Scratch space, the intermediate buffer for FVB extension
   1532         // protocol
   1533         //
   1534         if (MaxLbaSize < PtrBlockMapEntry->Length) {
   1535           MaxLbaSize = PtrBlockMapEntry->Length;
   1536         }
   1537 
   1538         NumOfBlocks += PtrBlockMapEntry->NumBlocks;
   1539       }
   1540       //
   1541       //  Write back a healthy FV header
   1542       //
   1543       if (WriteBack) {
   1544         Status = FlashFdErase (
   1545                   (UINTN) FwhInstance->FvBase[0],
   1546                   FwhInstance,
   1547                   FwVolHeader->BlockMap->Length
   1548                   );
   1549 
   1550         HeaderLength = (UINTN) FwVolHeader->HeaderLength;
   1551 
   1552         Status = FlashFdWrite (
   1553                   (UINTN) FwhInstance->FvBase[0],
   1554                   FwhInstance,
   1555                   (UINTN *) &HeaderLength,
   1556                   (UINT8 *) FwVolHeader
   1557                   );
   1558 
   1559         FwVolHeader->HeaderLength = (UINT16) HeaderLength;
   1560 
   1561         DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status));
   1562       }
   1563     }
   1564     //
   1565     // The total number of blocks in the FV.
   1566     //
   1567     FwhInstance->NumOfBlocks = NumOfBlocks;
   1568 
   1569     //
   1570     // Add a FVB Protocol Instance
   1571     //
   1572     Status = gBS->AllocatePool (
   1573                     EfiRuntimeServicesData,
   1574                     sizeof (EFI_FW_VOL_BLOCK_DEVICE),
   1575                     &FvbDevice
   1576                     );
   1577     ASSERT_EFI_ERROR (Status);
   1578 
   1579     CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
   1580 
   1581     FvbDevice->Instance = mFvbModuleGlobal->NumFv;
   1582     mFvbModuleGlobal->NumFv++;
   1583 
   1584     //
   1585     // Set up the devicepath
   1586     //
   1587     FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
   1588     FvbDevice->DevicePath.MemMapDevPath.EndingAddress   = BaseAddress + (FwVolHeader->FvLength - 1);
   1589 
   1590     //
   1591     // Find a handle with a matching device path that has supports FW Block protocol
   1592     //
   1593     TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
   1594     CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
   1595     Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
   1596     if (EFI_ERROR (Status)) {
   1597       //
   1598       // LocateDevicePath fails so install a new interface and device path
   1599       //
   1600       FwbHandle = NULL;
   1601       Status = gBS->InstallMultipleProtocolInterfaces (
   1602                       &FwbHandle,
   1603                       &gEfiFirmwareVolumeBlockProtocolGuid,
   1604                       &FvbDevice->FwVolBlockInstance,
   1605                       &gEfiDevicePathProtocolGuid,
   1606                       &FvbDevice->DevicePath,
   1607                       NULL
   1608                       );
   1609       ASSERT_EFI_ERROR (Status);
   1610     } else if (IsDevicePathEnd (TempFwbDevicePath)) {
   1611       //
   1612       // Device allready exists, so reinstall the FVB protocol
   1613       //
   1614       Status = gBS->HandleProtocol (
   1615                       FwbHandle,
   1616                       &gEfiFirmwareVolumeBlockProtocolGuid,
   1617                       &OldFwbInterface
   1618                       );
   1619       ASSERT_EFI_ERROR (Status);
   1620 
   1621       Status = gBS->ReinstallProtocolInterface (
   1622                       FwbHandle,
   1623                       &gEfiFirmwareVolumeBlockProtocolGuid,
   1624                       OldFwbInterface,
   1625                       &FvbDevice->FwVolBlockInstance
   1626                       );
   1627       ASSERT_EFI_ERROR (Status);
   1628 
   1629     } else {
   1630       //
   1631       // There was a FVB protocol on an End Device Path node
   1632       //
   1633       ASSERT (FALSE);
   1634     }
   1635 
   1636     FwhInstance = (EFI_FW_VOL_INSTANCE *)
   1637       (
   1638         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
   1639           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
   1640       );
   1641   } while (TRUE);
   1642 
   1643   //
   1644   // Allocate for scratch space, an intermediate buffer for FVB extention
   1645   //
   1646   Status = gBS->AllocatePool (
   1647                   EfiRuntimeServicesData,
   1648                   MaxLbaSize,
   1649                   &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]
   1650                   );
   1651   ASSERT_EFI_ERROR (Status);
   1652 
   1653   mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
   1654 
   1655   if (InstallSfsNotify) {
   1656     FvbInstallSfsNotify ();
   1657   }
   1658   return EFI_SUCCESS;
   1659 }
   1660