Exemplo n.º 1
0
EFI_STATUS
EFIAPI
FvbInitialize (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
/*++

Routine Description:
  This function does common initialization for FVB services

Arguments:

Returns:

**/
{
  EFI_STATUS                          Status;
  EFI_FW_VOL_INSTANCE                 *FwhInstance = NULL;
  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
  EFI_DXE_SERVICES                    *DxeServices;
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR     Descriptor;
  UINT32                              BufferSize;
  EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
  EFI_HANDLE                          FwbHandle;
  EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
  EFI_DEVICE_PATH_PROTOCOL            *TempFwbDevicePath;
  FV_DEVICE_PATH                      TempFvbDevicePathData;
  UINT32                              MaxLbaSize;
  EFI_PHYSICAL_ADDRESS                BaseAddress;
  UINT64                              Length;
  UINTN                               NumOfBlocks;
  EFI_PEI_HOB_POINTERS                FvHob;

   //
  // Get the DXE services table
  //
  DxeServices = gDS;

  //
  // Allocate runtime services data for global variable, which contains
  // the private data of all firmware volume block instances
  //
  Status = gBS->AllocatePool (
                  EfiRuntimeServicesData,
                  sizeof (ESAL_FWB_GLOBAL),
                  (VOID**) &mFvbModuleGlobal
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Calculate the total size for all firmware volume block instances
  //
  BufferSize            = 0;

  FvHob.Raw = GetHobList ();
  while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
    BaseAddress = FvHob.FirmwareVolume->BaseAddress;
    Length      = FvHob.FirmwareVolume->Length;
    //
    // Check if it is a "real" flash
    //
    Status = DxeServices->GetMemorySpaceDescriptor (
                            BaseAddress,
                            &Descriptor
                            );
    if (EFI_ERROR (Status)) {
      break;
    }

    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
      FvHob.Raw = GET_NEXT_HOB (FvHob);
      continue;
    }

    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
    Status      = ValidateFvHeader (FwVolHeader);
    if (EFI_ERROR (Status)) {
      //
      // Get FvbInfo
      //
      Status = GetFvbInfo (Length, &FwVolHeader);
      if (EFI_ERROR (Status)) {
        FvHob.Raw = GET_NEXT_HOB (FvHob);
        continue;
      }
    }

    BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
    FvHob.Raw = GET_NEXT_HOB (FvHob);
  }

  //
  // Only need to allocate once. There is only one copy of physical memory for
  // the private data of each FV instance. But in virtual mode or in physical
  // mode, the address of the the physical memory may be different.
  //
  Status = gBS->AllocatePool (
                  EfiRuntimeServicesData,
                  BufferSize,
                  (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
                  );
  ASSERT_EFI_ERROR (Status);

  //
  // Make a virtual copy of the FvInstance pointer.
  //
  FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
  mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;

  mFvbModuleGlobal->NumFv                   = 0;
  MaxLbaSize = 0;

  FvHob.Raw = GetHobList ();
  while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
    BaseAddress = FvHob.FirmwareVolume->BaseAddress;
    Length      = FvHob.FirmwareVolume->Length;
    //
    // Check if it is a "real" flash
    //
    Status = DxeServices->GetMemorySpaceDescriptor (
                            BaseAddress,
                            &Descriptor
                            );
    if (EFI_ERROR (Status)) {
      break;
    }

    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
      FvHob.Raw = GET_NEXT_HOB (FvHob);
      continue;
    }

    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
    Status      = ValidateFvHeader (FwVolHeader);
    if (EFI_ERROR (Status)) {
      //
      // Get FvbInfo to provide in FwhInstance.
      //
      Status = GetFvbInfo (Length, &FwVolHeader);
      if (EFI_ERROR (Status)) {
        FvHob.Raw = GET_NEXT_HOB (FvHob);
        continue;
      }
      //
      //  Write healthy FV header back.
      //
      CopyMem (
        (VOID *) (UINTN) BaseAddress,
        (VOID *) FwVolHeader,
        FwVolHeader->HeaderLength
        );
    }

    FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
    FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;

    CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
    FwVolHeader = &(FwhInstance->VolumeHeader);
    EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);

    NumOfBlocks = 0;

    for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
      //
      // Get the maximum size of a block. The size will be used to allocate
      // buffer for Scratch space, the intermediate buffer for FVB extension
      // protocol
      //
      if (MaxLbaSize < PtrBlockMapEntry->Length) {
        MaxLbaSize = PtrBlockMapEntry->Length;
      }

      NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
    }
    //
    // The total number of blocks in the FV.
    //
    FwhInstance->NumOfBlocks = NumOfBlocks;

    //
    // Add a FVB Protocol Instance
    //
    Status = gBS->AllocatePool (
                    EfiRuntimeServicesData,
                    sizeof (EFI_FW_VOL_BLOCK_DEVICE),
                    (VOID**) &FvbDevice
                    );
    ASSERT_EFI_ERROR (Status);

    CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));

    FvbDevice->Instance = mFvbModuleGlobal->NumFv;
    mFvbModuleGlobal->NumFv++;

    //
    // Set up the devicepath
    //
    FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
    FvbDevice->DevicePath.MemMapDevPath.EndingAddress   = BaseAddress + (FwVolHeader->FvLength - 1);

    //
    // Find a handle with a matching device path that has supports FW Block protocol
    //
    TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
    CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
    Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
    if (EFI_ERROR (Status)) {
      //
      // LocateDevicePath fails so install a new interface and device path
      //
      FwbHandle = NULL;
      Status = gBS->InstallMultipleProtocolInterfaces (
                      &FwbHandle,
                      &gEfiFirmwareVolumeBlockProtocolGuid,
                      &FvbDevice->FwVolBlockInstance,
                      &gEfiDevicePathProtocolGuid,
                      &FvbDevice->DevicePath,
                      NULL
                      );
      ASSERT_EFI_ERROR (Status);
    } else if (IsDevicePathEnd (TempFwbDevicePath)) {
      //
      // Device allready exists, so reinstall the FVB protocol
      //
      Status = gBS->HandleProtocol (
                      FwbHandle,
                      &gEfiFirmwareVolumeBlockProtocolGuid,
                      (VOID**)&OldFwbInterface
                      );
      ASSERT_EFI_ERROR (Status);

      Status = gBS->ReinstallProtocolInterface (
                      FwbHandle,
                      &gEfiFirmwareVolumeBlockProtocolGuid,
                      OldFwbInterface,
                      &FvbDevice->FwVolBlockInstance
                      );
      ASSERT_EFI_ERROR (Status);

    } else {
      //
      // There was a FVB protocol on an End Device Path node
      //
      ASSERT (FALSE);
    }

    FwhInstance = (EFI_FW_VOL_INSTANCE *)
      (
        (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
          (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
      );

    FvHob.Raw = GET_NEXT_HOB (FvHob);
  }

  return EFI_SUCCESS;
}
Exemplo n.º 2
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;
}