Exemplo n.º 1
0
/**
  Get the EFI_FVB_ATTRIBUTES_2 of a FV.

  @param[in]  The index of the EFI_FW_VOL_INSTANCE.

  @return     EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.

**/
STATIC
EFI_FVB_ATTRIBUTES_2
FvbGetVolumeAttributes (
  IN UINTN                                Instance
  )
{
  return GetFvbInstance (Instance)->VolumeHeader.Attributes;
}
Exemplo n.º 2
0
/**
  Erases and initializes a firmware volume block

  @param[in]    Instance           The FV instance to be erased
  @param[in]    Lba                The logical block index to be erased

  @retval   EFI_SUCCESS            The erase request was successfully completed
  @retval   EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state
  @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
                                   could not be written. Firmware device may have been
                                   partially erased
  @retval   EFI_INVALID_PARAMETER  Instance not found

**/
EFI_STATUS
FvbEraseBlock (
  IN UINTN                                Instance,
  IN EFI_LBA                              Lba
  )
{
  EFI_FVB_ATTRIBUTES_2                    Attributes;
  UINTN                                   LbaAddress;
  EFI_FW_VOL_INSTANCE                     *FwhInstance;
  UINTN                                   LbaLength;
  EFI_STATUS                              Status;
  EFI_STATUS                              Status1;
  UINTN                                   FlashAddress;

  //
  // Find the right instance of the FVB private data
  //
  FwhInstance = GetFvbInstance (Instance);

  //
  // Check if the FV is write enabled
  //
  Attributes = FvbGetVolumeAttributes (Instance);
  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    return EFI_ACCESS_DENIED;
  }

  //
  // Get the starting address of the block for erase.
  //
  Status = FvbGetLbaAddress (Instance, Lba, &FlashAddress, &LbaAddress, &LbaLength, NULL);
  if (EFI_ERROR (Status)) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Perform erase.
  //
  mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, FALSE);
  Status1 = mSpiDeviceProtocol->SpiErase (FlashAddress, LbaLength);
  mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, TRUE);
  WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);

  //
  // Check to see if the erase was successful.  If not return a device error to
  // meet PI required return values.
  //
  if (Status1 == EFI_DEVICE_ERROR) {
    return Status1;
  }

  return EFI_SUCCESS;
}
Exemplo n.º 3
0
/**
  Retrieves the physical address of the device.

  @param[in]  This          A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
  @param[out] Address       Output buffer containing the address.

  retval      EFI_SUCCESS   The function always return successfully.

**/
EFI_STATUS
EFIAPI
FvbProtocolGetPhysicalAddress (
  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
  OUT EFI_PHYSICAL_ADDRESS               *Address
  )
{
  EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;

  FvbDevice = FVB_DEVICE_FROM_THIS (This);
  *Address = GetFvbInstance (FvbDevice->Instance)->FvBase;

  return EFI_SUCCESS;
}
Exemplo n.º 4
0
VOID
EFIAPI
FvbVirtualddressChangeEvent (
  IN EFI_EVENT                          Event,
  IN VOID                               *Context
  )
{
  EFI_FW_VOL_INSTANCE                   *FwhInstance;
  UINTN                                 Index;

  //
  // Convert the base address of all the instances.
  //
  for (Index = 0; Index < mFvbModuleGlobal.NumFv; Index++) {
    FwhInstance = GetFvbInstance (Index);
    EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase);
  }

  EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal.FvInstance);
}
Exemplo n.º 5
0
EFI_STATUS
FvbGetPhysicalAddress (
  IN UINTN                                Instance,
  OUT EFI_PHYSICAL_ADDRESS                *Address,
  IN ESAL_FWB_GLOBAL                      *Global,
  IN BOOLEAN                              Virtual
  )
/*++

Routine Description:
  Retrieves the physical address of a memory mapped FV

Arguments:
  Instance              - The FV instance whose base address is going to be
                          returned
  Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
                          that on successful return, contains the base address
                          of the firmware volume.
  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
                          instance data
  Virtual               - Whether CPU is in virtual or physical mode

Returns:
  EFI_SUCCESS           - Successfully returns
  EFI_INVALID_PARAMETER - Instance not found

**/
{
  EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
  EFI_STATUS          Status;

  //
  // Find the right instance of the FVB private data
  //
  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
  ASSERT_EFI_ERROR (Status);
  *Address = FwhInstance->FvBase[Virtual];

  return EFI_SUCCESS;
}
Exemplo n.º 6
0
EFI_STATUS
FvbGetVolumeAttributes (
  IN UINTN                                Instance,
  OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
  IN ESAL_FWB_GLOBAL                      *Global,
  IN BOOLEAN                              Virtual
  )
/*++

Routine Description:
  Retrieves attributes, insures positive polarity of attribute bits, returns
  resulting attributes in output parameter

Arguments:
  Instance              - The FV instance whose attributes is going to be
                          returned
  Attributes            - Output buffer which contains attributes
  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
                          instance data
  Virtual               - Whether CPU is in virtual or physical mode

Returns:
  EFI_SUCCESS           - Successfully returns
  EFI_INVALID_PARAMETER - Instance not found

**/
{
  EFI_FW_VOL_INSTANCE *FwhInstance = NULL;
  EFI_STATUS          Status;

  //
  // Find the right instance of the FVB private data
  //
  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
  ASSERT_EFI_ERROR (Status);
  *Attributes = FwhInstance->VolumeHeader.Attributes;

  return EFI_SUCCESS;
}
Exemplo n.º 7
0
EFI_STATUS
EFIAPI
FvbProtocolEraseBlocks (
  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
  ...
  )
/*++

Routine Description:

  The EraseBlock() function erases one or more blocks as denoted by the
  variable argument list. The entire parameter list of blocks must be verified
  prior to erasing any blocks.  If a block is requested that does not exist
  within the associated firmware volume (it has a larger index than the last
  block of the firmware volume), the EraseBlock() function must return
  EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.

Arguments:
  This                  - Calling context
  ...                   - Starting LBA followed by Number of Lba to erase.
                          a -1 to terminate the list.

Returns:
  EFI_SUCCESS           - The erase request was successfully completed
  EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
  EFI_DEVICE_ERROR      - The block device is not functioning correctly and
                          could not be written. Firmware device may have been
                          partially erased

**/
{
  EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  EFI_FW_VOL_INSTANCE     *FwhInstance = NULL;
  UINTN                   NumOfBlocks;
  VA_LIST                 args;
  EFI_LBA                 StartingLba;
  UINTN                   NumOfLba;
  EFI_STATUS              Status;

  FvbDevice = FVB_DEVICE_FROM_THIS (This);

  Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
  ASSERT_EFI_ERROR (Status);

  NumOfBlocks = FwhInstance->NumOfBlocks;

  VA_START (args, This);

  do {
    StartingLba = VA_ARG (args, EFI_LBA);
    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
      break;
    }

    NumOfLba = VA_ARG (args, UINTN);

    //
    // Check input parameters
    //
    if (NumOfLba == 0 || (StartingLba + NumOfLba) > NumOfBlocks) {
      VA_END (args);
      return EFI_INVALID_PARAMETER;
    }
  } while (1);

  VA_END (args);

  VA_START (args, This);
  do {
    StartingLba = VA_ARG (args, EFI_LBA);
    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
      break;
    }

    NumOfLba = VA_ARG (args, UINTN);

    while (NumOfLba > 0) {
      Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
      if (EFI_ERROR (Status)) {
        VA_END (args);
        return Status;
      }

      StartingLba++;
      NumOfLba--;
    }

  } while (1);

  VA_END (args);

  return EFI_SUCCESS;
}
Exemplo n.º 8
0
EFI_STATUS
FvbSetVolumeAttributes (
  IN UINTN                                Instance,
  IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes,
  IN ESAL_FWB_GLOBAL                      *Global,
  IN BOOLEAN                              Virtual
  )
/*++

Routine Description:
  Modifies the current settings of the firmware volume according to the
  input parameter, and returns the new setting of the volume

Arguments:
  Instance              - The FV instance whose attributes is going to be
                          modified
  Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
                          containing the desired firmware volume settings.
                          On successful return, it contains the new settings
                          of the firmware volume
  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
                          instance data
  Virtual               - Whether CPU is in virtual or physical mode

Returns:
  EFI_SUCCESS           - Successfully returns
  EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
  EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
                          in conflict with the capabilities as declared in the
                          firmware volume header

**/
{
  EFI_FW_VOL_INSTANCE   *FwhInstance = NULL;
  EFI_FVB_ATTRIBUTES_2  OldAttributes;
  EFI_FVB_ATTRIBUTES_2  *AttribPtr;
  UINT32                Capabilities;
  UINT32                OldStatus;
  UINT32                NewStatus;
  EFI_STATUS            Status;
  EFI_FVB_ATTRIBUTES_2  UnchangedAttributes;


  //
  // Find the right instance of the FVB private data
  //
  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
  ASSERT_EFI_ERROR (Status);

  AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
  OldAttributes = *AttribPtr;
  Capabilities  = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
                                   EFI_FVB2_READ_ENABLED_CAP | \
                                   EFI_FVB2_WRITE_DISABLED_CAP | \
                                   EFI_FVB2_WRITE_ENABLED_CAP | \
                                   EFI_FVB2_LOCK_CAP \
                                   );

  OldStatus     = OldAttributes & EFI_FVB2_STATUS;
  NewStatus     = *Attributes & EFI_FVB2_STATUS;
  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
                        EFI_FVB2_READ_ENABLED_CAP   | \
                        EFI_FVB2_WRITE_DISABLED_CAP | \
                        EFI_FVB2_WRITE_ENABLED_CAP  | \
                        EFI_FVB2_LOCK_CAP           | \
                        EFI_FVB2_STICKY_WRITE       | \
                        EFI_FVB2_MEMORY_MAPPED      | \
                        EFI_FVB2_ERASE_POLARITY     | \
                        EFI_FVB2_READ_LOCK_CAP      | \
                        EFI_FVB2_WRITE_LOCK_CAP     | \
                        EFI_FVB2_ALIGNMENT;

  //
  // Some attributes of FV is read only can *not* be set
  //
  if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // If firmware volume is locked, no status bit can be updated
  //
  if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
    if (OldStatus ^ NewStatus) {
      return EFI_ACCESS_DENIED;
    }
  }
  //
  // Test read disable
  //
  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test read enable
  //
  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    if (NewStatus & EFI_FVB2_READ_STATUS) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test write disable
  //
  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test write enable
  //
  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    if (NewStatus & EFI_FVB2_WRITE_STATUS) {
      return EFI_INVALID_PARAMETER;
    }
  }
  //
  // Test lock
  //
  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    if (NewStatus & EFI_FVB2_LOCK_STATUS) {
      return EFI_INVALID_PARAMETER;
    }
  }

  *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
  *AttribPtr  = (*AttribPtr) | NewStatus;
  *Attributes = *AttribPtr;

  return EFI_SUCCESS;
}
Exemplo n.º 9
0
EFI_STATUS
FvbGetLbaAddress (
  IN  UINTN                               Instance,
  IN  EFI_LBA                             Lba,
  OUT UINTN                               *LbaAddress,
  OUT UINTN                               *LbaLength,
  OUT UINTN                               *NumOfBlocks,
  IN  ESAL_FWB_GLOBAL                     *Global,
  IN  BOOLEAN                             Virtual
  )
/*++

Routine Description:
  Retrieves the starting address of an LBA in an FV

Arguments:
  Instance              - The FV instance which the Lba belongs to
  Lba                   - The logical block address
  LbaAddress            - On output, contains the physical starting address
                          of the Lba
  LbaLength             - On output, contains the length of the block
  NumOfBlocks           - A pointer to a caller allocated UINTN in which the
                          number of consecutive blocks starting with Lba is
                          returned. All blocks in this range have a size of
                          BlockSize
  Global                - Pointer to ESAL_FWB_GLOBAL that contains all
                          instance data
  Virtual               - Whether CPU is in virtual or physical mode

Returns:
  EFI_SUCCESS           - Successfully returns
  EFI_INVALID_PARAMETER - Instance not found

**/
{
  UINT32                  NumBlocks;
  UINT32                  BlockLength;
  UINTN                   Offset;
  EFI_LBA                 StartLba;
  EFI_LBA                 NextLba;
  EFI_FW_VOL_INSTANCE     *FwhInstance = NULL;
  EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
  EFI_STATUS              Status;

  //
  // Find the right instance of the FVB private data
  //
  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
  ASSERT_EFI_ERROR (Status);

  StartLba  = 0;
  Offset    = 0;
  BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);

  //
  // Parse the blockmap of the FV to find which map entry the Lba belongs to
  //
  while (TRUE) {
    NumBlocks   = BlockMap->NumBlocks;
    BlockLength = BlockMap->Length;

    if (NumBlocks == 0 || BlockLength == 0) {
      return EFI_INVALID_PARAMETER;
    }

    NextLba = StartLba + NumBlocks;

    //
    // The map entry found
    //
    if (Lba >= StartLba && Lba < NextLba) {
      Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
      if (LbaAddress != NULL) {
        *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
      }

      if (LbaLength != NULL) {
        *LbaLength = BlockLength;
      }

      if (NumOfBlocks != NULL) {
        *NumOfBlocks = (UINTN) (NextLba - Lba);
      }

      return EFI_SUCCESS;
    }

    StartLba  = NextLba;
    Offset    = Offset + NumBlocks * BlockLength;
    BlockMap++;
  }
}
Exemplo n.º 10
0
/**
  The driver entry point for Firmware Volume Block Driver.

  The function does the necessary initialization work
  Firmware Volume Block Driver.

  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
  @param[in]  SystemTable       A pointer to the EFI system table.

  @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
                                It will ASSERT on errors.

**/
EFI_STATUS
FvbInitialize (
  )
{
  EFI_FW_VOL_INSTANCE                   *FwhInstance;
  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;
  EFI_FV_BLOCK_MAP_ENTRY                *PtrBlockMapEntry;
  EFI_PHYSICAL_ADDRESS                  BaseAddress;
  EFI_STATUS                            Status;
  UINTN                                 BufferSize;
  UINTN                                 TmpHeaderLength;
  UINTN                                 Idx;
  UINT32                                MaxLbaSize;
  BOOLEAN                               FvHeaderValid;
  UINTN                                 FvFlashLinearAddress;
  EFI_BOOT_MODE                         BootMode;
  UINT32                                Index;
  UINT32                                PlatformFvBaseAddress[5];
  UINT32                                PlatformFvBaseAddressCount;
  UINT32                                PlatformFvLockList[4];
  UINT32                                PlatformFvLockListCount;
  
  //
  // This platform driver knows there are 3 FVs on
  // FD, which are FvRecovery, FvMain and FvNvStorage.
  //
  BootMode = GetBootModeHob ();
  if (BootMode == BOOT_IN_RECOVERY_MODE) {
    //
    // On recovery boot, don't report any firmware FV images except payload, because their data can't be trusted.
    //
    PlatformFvBaseAddressCount = 2;
    PlatformFvBaseAddress[0]   = PcdGet32 (PcdFlashNvStorageVariableBase);
    PlatformFvBaseAddress[1]   = PcdGet32 (PcdFlashPayloadBase);
  } else {
    PlatformFvBaseAddressCount = 5;
    PlatformFvBaseAddress[0]   = PcdGet32 (PcdFlashFvMainBase);
    PlatformFvBaseAddress[1]   = PcdGet32 (PcdFlashNvStorageVariableBase);
    PlatformFvBaseAddress[2]   = PcdGet32 (PcdFlashFvRecoveryBase);
    PlatformFvBaseAddress[3]   = PcdGet32 (PcdFlashFvRecovery2Base);
    PlatformFvBaseAddress[4]   = PcdGet32 (PcdFlashPayloadBase);
  }

  //
  // List of FVs that should be write protected on normal boots.
  //
  PlatformFvLockListCount = 4;
  PlatformFvLockList[0]   = PcdGet32 (PcdFlashFvMainBase);
  PlatformFvLockList[1]   = PcdGet32 (PcdFlashFvRecoveryBase);
  PlatformFvLockList[2]   = PcdGet32 (PcdFlashFvRecovery2Base);
  PlatformFvLockList[3]   = PcdGet32 (PcdFlashPayloadBase);

  //
  // Calculate the total size for all firmware volume block instances and
  // allocate a buffer to store them in.
  //
  BufferSize = 0;
  for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) {
    FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PlatformFvBaseAddress[Idx];
    if (FvHeader == NULL) {
      continue;
    }
    BufferSize +=  (FvHeader->HeaderLength +
                    sizeof (EFI_FW_VOL_INSTANCE) -
                    sizeof (EFI_FIRMWARE_VOLUME_HEADER)
                   );
  }
  mFvbModuleGlobal.FvInstance =  (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
  ASSERT (NULL != mFvbModuleGlobal.FvInstance);

  //
  // Perform other variable initialization.
  //
  MaxLbaSize = 0;
  FwhInstance = mFvbModuleGlobal.FvInstance;
  mFvbModuleGlobal.NumFv   = 0;

  for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) {
  
    if ((BootMode == BOOT_ASSUMING_NO_CONFIGURATION_CHANGES) && PlatformFvBaseAddress[Idx]!= PcdGet32 (PcdFlashNvStorageVariableBase) && PlatformFvBaseAddress[Idx]!= PcdGet32 (PcdFlashPayloadBase)) {
      continue;
    }
    //
    // Get base address information.
    //
    BaseAddress = PlatformFvBaseAddress[Idx];
    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
    if (FwVolHeader == NULL) {
      continue;
    }
    //
    // Find the flash linear address of the current FV.
    //
    FvFlashLinearAddress = (UINTN) FLASH_LINEAR_ADDRESS(BaseAddress);

    if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) {
      FvHeaderValid = FALSE;

      //
      // If not valid, get FvbInfo from the information carried in
      // FVB driver.
      //
      DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress));
      Status = GetFvbInfo (BaseAddress, &FwVolHeader);
      ASSERT_EFI_ERROR(Status);

      //
      //  Write back a healthy FV header.
      //
      DEBUG ((EFI_D_INFO, "FwBlockService.c: Writing back healthy FV header\n"));
      mSpiDeviceProtocol->SpiLock (FvFlashLinearAddress, FwVolHeader->BlockMap->Length, FALSE);

      Status = mSpiDeviceProtocol->SpiErase (FvFlashLinearAddress, FwVolHeader->BlockMap->Length);

      TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength;
      Status = mSpiDeviceProtocol->SpiWrite (
                                     FvFlashLinearAddress,
                                     &TmpHeaderLength,
                                     (UINT8 *) FwVolHeader
                                     );

      mSpiDeviceProtocol->SpiLock (FvFlashLinearAddress, FwVolHeader->BlockMap->Length, TRUE);

      WriteBackInvalidateDataCacheRange (
        (VOID *) (UINTN) BaseAddress,
        FwVolHeader->BlockMap->Length
        );

    }

    //
    // Copy FV header into local storage and assign base address.
    //
    CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);
    FwVolHeader = &(FwhInstance->VolumeHeader);
    FwhInstance->FvBase = (UINTN)BaseAddress;
    FwhInstance->FvFlashLinearAddress = FvFlashLinearAddress;

    //
    // In some cases the Recovery and Main FVs should be considered locked from
    // write access by this protocol.  Only in the case of flash updates and
    // configuration mode should they be left unlocked.
    //
    if (BootMode != BOOT_IN_RECOVERY_MODE &&
        BootMode != BOOT_ON_FLASH_UPDATE) {
      for (Index = 0; Index < PlatformFvLockListCount; Index++) {
        if (FwhInstance->FvBase == PlatformFvLockList[Index]) {
          //
          // For all FVs in the lock list we need to clear the write status bit
          // and lock write status updates.  This will make sure this protocol
          // will not attempt to write to the FV.
          //
          FwhInstance->VolumeHeader.Attributes &= (UINT64) ~EFI_FVB2_WRITE_STATUS;
          FwhInstance->VolumeHeader.Attributes |= (EFI_FVB2_LOCK_STATUS | EFI_FVB2_WRITE_LOCK_STATUS);
        }
      }
    }

    //
    // Process the block map for each FV
    //
    FwhInstance->NumOfBlocks   = 0;
    for (PtrBlockMapEntry = FwVolHeader->BlockMap;
         PtrBlockMapEntry->NumBlocks != 0;
         PtrBlockMapEntry++) {
      //
      // Get the maximum size of a block.
      //
      if (MaxLbaSize < PtrBlockMapEntry->Length) {
        MaxLbaSize  = PtrBlockMapEntry->Length;
      }
      FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
    }

    //
    // Add a FVB Protocol Instance
    //
    mFvbModuleGlobal.NumFv++;
    InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);

    //
    // Move on to the next FwhInstance
    //
    FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) +
                                          FwVolHeader->HeaderLength +
                                          (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
  }

  if ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) == 0) || (PcdGet32 (PcdFlashNvStorageFtwSpareBase) == 0)) {
    return EFI_SUCCESS;
  }
  
  //
  // Install FVB protocols for FTW spare space and FTW working space.
  // These is no FV header for these 2 spaces.
  //
  mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) ReallocateRuntimePool (
                                  BufferSize, 
                                  BufferSize + (sizeof (EFI_FW_VOL_INSTANCE) + sizeof (EFI_FV_BLOCK_MAP_ENTRY)) * 2, 
                                  mFvbModuleGlobal.FvInstance
                                  );
  ASSERT (NULL != mFvbModuleGlobal.FvInstance);
  PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
  PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashNvStorageFtwSpareBase);
  
  for (Idx = 0; Idx < 2; Idx++) {
    BaseAddress = PlatformFvBaseAddress[Idx];
    Status = GetFtwFvbInfo (BaseAddress, &FwVolHeader);
    ASSERT_EFI_ERROR(Status);
  
    //
    // Copy FV header into local storage and assign base address.
    //
    mFvbModuleGlobal.NumFv++;
    FwhInstance = GetFvbInstance (mFvbModuleGlobal.NumFv - 1);
    CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);
    FwVolHeader = &(FwhInstance->VolumeHeader);

    //
    // Process the block map for each FV
    //
    FwhInstance->NumOfBlocks   = 0;
    for (PtrBlockMapEntry = FwVolHeader->BlockMap;
         PtrBlockMapEntry->NumBlocks != 0;
         PtrBlockMapEntry++) {
      FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;
    }

    FwhInstance->FvBase = (UINTN)BaseAddress;
    FwhInstance->FvFlashLinearAddress = (UINTN) FLASH_LINEAR_ADDRESS(BaseAddress);

    InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);
  }    
  
  return EFI_SUCCESS;
}
Exemplo n.º 11
0
/**
  The EraseBlock() function erases one or more blocks as denoted by the
  variable argument list. The entire parameter list of blocks must be verified
  prior to erasing any blocks.  If a block is requested that does not exist
  within the associated firmware volume (it has a larger index than the last
  block of the firmware volume), the EraseBlock() function must return
  EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.

  @param[in] This           Calling context
  @param[in] ...            Starting LBA followed by Number of Lba to erase.
                            a -1 to terminate the list.

  @retval EFI_SUCCESS       The erase request was successfully completed
  @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
  @retval EFI_DEVICE_ERROR  The block device is not functioning correctly and
                            could not be written. Firmware device may have been
                            partially erased

**/
EFI_STATUS
EFIAPI
FvbProtocolEraseBlocks (
  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
  ...
  )
{
  EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
  EFI_FW_VOL_INSTANCE                   *FwhInstance;
  UINTN                                 NumOfBlocks;
  VA_LIST                               args;
  EFI_LBA                               StartingLba;
  UINTN                                 NumOfLba;
  EFI_STATUS                            Status;
  EFI_FVB_ATTRIBUTES_2                  Attributes;

  //
  // Initialize data.
  //
  FvbDevice = FVB_DEVICE_FROM_THIS (This);
  FwhInstance = GetFvbInstance (FvbDevice->Instance);
  NumOfBlocks = FwhInstance->NumOfBlocks;

  //
  // Check if this FV can be written to.
  //
  Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
    return EFI_ACCESS_DENIED;
  }

  //
  // Validate LBA information passed in by caller.
  //
  VA_START (args, This);
  do {
    //
    // Check for last entry in variable argument list.
    //
    StartingLba = VA_ARG (args, EFI_LBA);
    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
      break;
    }

    //
    // Get parameter from stack.
    //
    NumOfLba = VA_ARG (args, UINT32);

    //
    // Check input parameters
    //
    if (NumOfLba == 0) {
      VA_END (args);
      return EFI_INVALID_PARAMETER;
    }
    if ((StartingLba + NumOfLba) > NumOfBlocks) {
      VA_END (args);
      return EFI_INVALID_PARAMETER;
    }
  } while (1);
  VA_END (args);

  //
  // Perform erase operation on all selected LBA.
  //
  VA_START (args, This);
  do {
    //
    // Check for last entry in variable argument list.
    //
    StartingLba = VA_ARG (args, EFI_LBA);
    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
      break;
    }

    //
    // Get parameter from stack.
    //
    NumOfLba = VA_ARG (args, UINT32);

    //
    // Perform the erase operation for the specific LBA.
    //
    while (NumOfLba > 0) {
      Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
      if (EFI_ERROR (Status)) {
        VA_END (args);
        return Status;
      }
      StartingLba ++;
      NumOfLba --;
    }
  } while (1);
  VA_END (args);

  return EFI_SUCCESS;
}
Exemplo n.º 12
0
/**
  Modifies the current settings of the firmware volume according to the
  input parameter, and returns the new setting of the volume

  @param[in]  Instance              The FV instance whose attributes is going to be
                                    modified
  @param[in]  Attributes            On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
                                    containing the desired firmware volume settings.
                                    On successful return, it contains the new settings
                                    of the firmware volume

  @retval     EFI_SUCCESS           Successfully returns
  @retval     EFI_ACCESS_DENIED     The volume setting is locked and cannot be modified
  @retval     EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
                                    in conflict with the capabilities as declared in the
                                    firmware volume header

**/
STATIC
EFI_STATUS
FvbSetVolumeAttributes (
  IN UINTN                                Instance,
  IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes
  )
{
  EFI_FW_VOL_INSTANCE                       *FwhInstance;
  EFI_FVB_ATTRIBUTES_2                      OldAttributes;
  EFI_FVB_ATTRIBUTES_2                      *AttribPtr;
  EFI_FVB_ATTRIBUTES_2                      UnchangedAttributes;
  UINT32                                    Capabilities;
  UINT32                                    OldStatus, NewStatus;

  //
  // Find the right instance of the FVB private data
  //
  FwhInstance = GetFvbInstance (Instance);

  AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
  OldAttributes = *AttribPtr;
  Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
  OldStatus     = OldAttributes & EFI_FVB2_STATUS;
  NewStatus     = *Attributes & EFI_FVB2_STATUS;

  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
                        EFI_FVB2_READ_ENABLED_CAP   | \
                        EFI_FVB2_WRITE_DISABLED_CAP | \
                        EFI_FVB2_WRITE_ENABLED_CAP  | \
                        EFI_FVB2_LOCK_CAP           | \
                        EFI_FVB2_STICKY_WRITE       | \
                        EFI_FVB2_MEMORY_MAPPED      | \
                        EFI_FVB2_ERASE_POLARITY     | \
                        EFI_FVB2_READ_LOCK_CAP      | \
                        EFI_FVB2_WRITE_LOCK_CAP     | \
                        EFI_FVB2_ALIGNMENT;

  //
  // Some attributes of FV is read only can *not* be set
  //
  if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // If firmware volume is locked, no status bit can be updated
  //
  if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {
    if ( OldStatus ^ NewStatus ) {
      return EFI_ACCESS_DENIED;
    }
  }

  //
  // Test read disable
  //
  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }

  //
  // Test read enable
  //
  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
    if (NewStatus & EFI_FVB2_READ_STATUS) {
      return EFI_INVALID_PARAMETER;
    }
  }

  //
  // Test write disable
  //
  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
      return EFI_INVALID_PARAMETER;
    }
  }

  //
  // Test write enable
  //
  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
    if (NewStatus & EFI_FVB2_WRITE_STATUS) {
      return EFI_INVALID_PARAMETER;
    }
  }

  //
  // Test lock
  //
  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
    if (NewStatus & EFI_FVB2_LOCK_STATUS) {
      return EFI_INVALID_PARAMETER;
    }
  }

  *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
  *AttribPtr  = (*AttribPtr) | NewStatus;
  *Attributes = *AttribPtr;

  return EFI_SUCCESS;
}
Exemplo n.º 13
0
/**
  Writes specified number of bytes from the input buffer to the block

  @param[in]  Instance               The FV instance to be written to
  @param[in]  Lba                    The starting logical block index to write to
  @param[in]  BlockOffset            Offset into the block at which to begin writing
  @param[in]  NumBytes               Pointer that on input contains the total size of
                                     the buffer. On output, it contains the total number
                                     of bytes actually written
  @param[in]  Buffer                 Pointer to a caller allocated buffer that contains
                                     the source for the write
  @retval     EFI_SUCCESS            The firmware volume was written successfully
  @retval     EFI_BAD_BUFFER_SIZE    Write attempted across a LBA boundary. On output,
                                     NumBytes contains the total number of bytes
                                     actually written
  @retval     EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state
  @retval     EFI_DEVICE_ERROR       The block device is not functioning correctly and
                                     could not be written
  @retval     EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL

**/
EFI_STATUS
FvbWriteBlock (
  IN UINTN                                Instance,
  IN EFI_LBA                              Lba,
  IN UINTN                                BlockOffset,
  IN OUT UINTN                            *NumBytes,
  IN UINT8                                *Buffer
  )
{
  EFI_FVB_ATTRIBUTES_2                    Attributes;
  UINTN                                   LbaAddress;
  UINTN                                   LbaLength;
  EFI_FW_VOL_INSTANCE                     *FwhInstance;
  EFI_STATUS                              Status;
  EFI_STATUS                              Status1;
  UINTN                                   FlashAddress;

  //
  // Validate input parameters.
  //
  if ((NumBytes == NULL) || (Buffer == NULL)) {
    return (EFI_INVALID_PARAMETER);
  }
  if (*NumBytes == 0) {
    return (EFI_INVALID_PARAMETER);
  }

  //
  // Get the information for the FV specified.
  //
  FwhInstance = GetFvbInstance (Instance);
  Status = FvbGetLbaAddress (Instance, Lba, &FlashAddress, &LbaAddress, &LbaLength, NULL);
  if (EFI_ERROR (Status)) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Check if the FV is write enabled
  //
  Attributes = FvbGetVolumeAttributes (Instance);
  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)  {
    return EFI_ACCESS_DENIED;
  }

  //
  // Perform boundary checks and adjust NumBytes if needed.
  //
  if (BlockOffset > LbaLength) {
    return EFI_INVALID_PARAMETER;
  }
  if ( LbaLength < ( *NumBytes + BlockOffset ) ) {
    *NumBytes = (UINT32) (LbaLength - BlockOffset);
    Status = EFI_BAD_BUFFER_SIZE;
  }

  //
  // Perform the write and flush the cache.
  //
  mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, FALSE);
  Status1 = mSpiDeviceProtocol->SpiWrite (FlashAddress + BlockOffset, NumBytes, Buffer);
  mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, TRUE);
  WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);

  //
  // Determine the error to return based on PI spec.
  //
  if (Status1 == EFI_DEVICE_ERROR) {
    return Status1;
  }

  return Status;
}
Exemplo n.º 14
0
/**
  Retrieves the starting address of an LBA in an FV. It also
  return a few other attribut of the FV.

  @param[in]  Instance             The index of the EFI_FW_VOL_INSTANCE.
  @param[in]  Lba                  The logical block address
  @param[out] FlashLinearAddress   Provides the linear address into the flash device.
  @param[out] LbaAddress           On output, contains the physical starting address
                                   of the Lba
  @param[out] LbaLength            On output, contains the length of the block
  @param[out] NumOfBlocks          A pointer to a caller allocated UINTN in which the
                                   number of consecutive blocks starting with Lba is
                                   returned. All blocks in this range have a size of
                                   BlockSize

  @retval   EFI_SUCCESS            Successfully returns
  @retval   EFI_INVALID_PARAMETER  Instance not found

**/
STATIC
EFI_STATUS
FvbGetLbaAddress (
  IN  UINTN                               Instance,
  IN  EFI_LBA                             Lba,
  OUT UINTN                               *FlashLinearAddress,
  OUT UINTN                               *LbaAddress,
  OUT UINTN                               *LbaLength,
  OUT UINTN                               *NumOfBlocks
  )
{
  UINT32                                  NumBlocks;
  UINT32                                  BlockLength;
  UINTN                                   Offset;
  EFI_LBA                                 StartLba;
  EFI_LBA                                 NextLba;
  EFI_FW_VOL_INSTANCE                     *FwhInstance;
  EFI_FV_BLOCK_MAP_ENTRY                  *BlockMap;

  //
  // Find the right instance of the FVB private data
  //
  FwhInstance = GetFvbInstance (Instance);

  StartLba  = 0;
  Offset    = 0;
  BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);

  //
  // Parse the blockmap of the FV to find which map entry the Lba belongs to
  //
  while (TRUE) {
    NumBlocks   = BlockMap->NumBlocks;
    BlockLength = BlockMap->Length;

    if (NumBlocks == 0 || BlockLength == 0) {
      return EFI_INVALID_PARAMETER;
    }

    NextLba = StartLba + NumBlocks;

    //
    // The map entry found
    //
    if (Lba >= StartLba && Lba < NextLba) {
      Offset = Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength);
      if (FlashLinearAddress) {
        *FlashLinearAddress = FwhInstance->FvFlashLinearAddress + Offset;
      }

      if (LbaAddress) {
        *LbaAddress = FwhInstance->FvBase + Offset;
      }

      if (LbaLength) {
        *LbaLength = BlockLength;
      }

      if (NumOfBlocks) {
        *NumOfBlocks = (UINTN)(NextLba - Lba);
      }
      return EFI_SUCCESS;
    }

    StartLba  = NextLba;
    Offset    = Offset + NumBlocks * BlockLength;
    BlockMap++;
  }
}