Files
slimbootloader/Silicon/ArrowlakePkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c
T
Guo Dong 69e9996e56 ARL: clean up the code
Remove unused file, definitions or libraries.

Signed-off-by: Guo Dong <guo.dong@intel.com>
2024-09-29 16:26:50 -07:00

426 lines
13 KiB
C

/** @file
This file contains the implementation of FirmwareUpdateLib library.
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Base.h>
#include <PiPei.h>
#include <RegAccess.h>
#include <Uefi/UefiBaseType.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/IoLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/TimerLib.h>
#include <Library/FirmwareUpdateLib.h>
#include <Library/BootloaderCommonLib.h>
#include <Library/PchSbiAccessLib.h>
#include <Library/HeciInitLib.h>
#include <Register/PchRegsPcr.h>
#include <Register/PchRegsLpc.h>
#include <Register/PchBdfAssignment.h>
#include <Service/HeciService.h>
#include <CsmeUpdateDriver.h>
#include <PlatformBase.h>
#include <Library/WatchDogTimerLib.h>
#define FWU_BOOT_MODE_OFFSET 0x40
#define FWU_BOOT_MODE_VALUE 0x5A
/**
Initializes input structure for csme update driver.
This function will initialize input structure for csme
update driver. Since HECI functionality is avaiable to access
only in silicon driver, this init is done in silicon package.
@retval Pointer to intialized input data structure.
@retval NULL if csme update is not supported.
**/
VOID *
InitCsmeUpdInputData (
VOID
)
{
CSME_UPDATE_DRIVER_INPUT *CsmeUpdDriverInput;
HECI_SERVICE *HeciService;
HeciService = NULL;
HeciService = (HECI_SERVICE *)GetServiceBySignature (HECI_SERVICE_SIGNATURE);
CsmeUpdDriverInput = (CSME_UPDATE_DRIVER_INPUT *)AllocateZeroPool (sizeof(CSME_UPDATE_DRIVER_INPUT));
if (CsmeUpdDriverInput != NULL) {
CsmeUpdDriverInput->AllocatePool = (VOID *)((UINTN)AllocatePool);
CsmeUpdDriverInput->AllocateZeroPool = (VOID *)((UINTN)AllocateZeroPool);
CsmeUpdDriverInput->FreePool = (VOID *)((UINTN)FreePool);
CsmeUpdDriverInput->CopyMem = (VOID *)((UINTN)CopyMem);
CsmeUpdDriverInput->SetMem = (VOID *)((UINTN)SetMem);
CsmeUpdDriverInput->CompareMem = (VOID *)((UINTN)CompareMem);
CsmeUpdDriverInput->Stall = (VOID *)((UINTN)MicroSecondDelay);
CsmeUpdDriverInput->PciRead = (VOID *)((UINTN)CsmePciReadBuffer);
if (HeciService != NULL) {
CsmeUpdDriverInput->HeciReadMessage = (VOID *)((UINTN)HeciService->HeciReceive);
CsmeUpdDriverInput->HeciSendMessage = (VOID *)((UINTN)HeciService->HeciSend);
CsmeUpdDriverInput->HeciReset = (VOID *)((UINTN)HeciService->HeciResetInterface);
}
if ((CsmeUpdDriverInput->HeciReadMessage == NULL) ||
(CsmeUpdDriverInput->HeciSendMessage == NULL) ||
(CsmeUpdDriverInput->HeciReset == NULL)) {
FreePool(CsmeUpdDriverInput);
return NULL;
}
}
return CsmeUpdDriverInput;
}
/**
Switch between the boot partitions.
This function will use platform specific method of switching
between primary and backup partitions.
@param[in] Partition Partition to select
@retval EFI_SUCCESS Switched to desired partition successfully.
@retval others Error happening.
**/
EFI_STATUS
SetBootPartition (
IN BOOT_PARTITION Partition
)
{
// Need to signal for TS back to other partition in SG1B, since TS
// is blocked from being performed in FWU payload
if (GetCurrentBootPartition () != Partition) {
SetTopSwapTrigger ();
}
return EFI_SUCCESS;
}
/**
Get offset of Stage 1A in the capsule image
This function will get stage 1A base address from flash map.
Computes offset in the BIOS region from the base address.
Then it calculates base address of stage1A in the capsule image.
@param[in] ImageHdr Pointer to Fw Mgmt capsule Image header
@param[in] IsBackupPartition TRUE for Back up copy, FALSE for primary copy
@param[out] Base Base address of the component
@param[out] Size Size of the component
@retval EFI_SUCCESS Image offset returned successfully.
@retval EFI_NOT_FOUND Could not get component information from flash map.
@retval others Error happening when updating.
**/
EFI_STATUS
EFIAPI
PlatformGetStage1AOffset (
IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr,
IN BOOLEAN IsBackupPartition,
OUT UINT32 *Base,
OUT UINT32 *Size
)
{
return EFI_UNSUPPORTED;
}
/**
Get details information on how to update a boot partition.
Platform knows the capsule image and the boot device layout. By parsing capsule
Image and boot media, the platform could produce a list of regions to be updated.
Platform could set partition flag to decide if a reboot is required after a boot
partition is updated.
Platform could set region flag to indicate if the source image is the final image
to write to boot media. If the flag is set, that source will be used to check if
the source is same before doing firmware update.
@param[in] ImageHdr Pointer to Fw Mgmt capsule Image header
@param[in] FwPolicy Firmware update policy.
@param[out] PartitionInfo The detail information on the partition to update
@retval EFI_SUCCESS Update successfully.
@retval others Error happening when updating.
**/
EFI_STATUS
EFIAPI
GetFirmwareUpdateInfo (
IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr,
IN FIRMWARE_UPDATE_POLICY FwPolicy,
OUT FIRMWARE_UPDATE_PARTITION **PartitionInfo
)
{
UINT32 AllocateSize;
UINT32 TopSwapRegionSize;
UINT32 RedundantRegionSize;
UINT32 NonRedundantRegionSize;
UINT32 TopSwapRegionOffset;
UINT32 RedundantRegionOffset;
UINT32 NonRedundantRegionOffset;
UINT32 CompBase;
UINT32 CompSize;
FIRMWARE_UPDATE_PARTITION *UpdatePartition;
FIRMWARE_UPDATE_REGION *UpdateRegion;
UINT8 Idx;
FLASH_MAP *FlashMap;
BOOLEAN IsBackup;
EFI_STATUS Status;
TopSwapRegionOffset = 0;
RedundantRegionOffset = 0;
NonRedundantRegionOffset = 0;
FlashMap = GetFlashMapPtr();
if (FlashMap == NULL) {
return EFI_NOT_FOUND;
}
AllocateSize = sizeof (FIRMWARE_UPDATE_PARTITION) + (MAX_UPDATE_REGIONS - 1) * sizeof(FIRMWARE_UPDATE_REGION);
UpdatePartition = (FIRMWARE_UPDATE_PARTITION *) AllocateZeroPool(AllocateSize);
ASSERT (UpdatePartition != NULL);
UpdatePartition->RegionCount = 0;
if (CompareGuid(&ImageHdr->UpdateImageTypeId, &gSblCompFWUpdateImageFileGuid)) {
//
// Update SblComponent
//
// Get SBL component
IsBackup = (FwPolicy.Fields.UpdatePartitionB == 1) ? TRUE : FALSE;
Status = GetComponentInfoByPartition ((UINT32)ImageHdr->UpdateHardwareInstance, IsBackup, &CompBase, &CompSize);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "No SBL component found !"));
FreePool(UpdatePartition);
return Status;
}
if (ImageHdr->UpdateImageSize > CompSize) {
DEBUG ((DEBUG_INFO, "capsule payload size is too big for the region on flash!"));
FreePool(UpdatePartition);
return EFI_UNSUPPORTED;
}
UpdateRegion = &UpdatePartition->FwRegion[0];
UpdateRegion->ToUpdateAddress = FlashMap->RomSize + CompBase;
UpdateRegion->UpdateSize = ImageHdr->UpdateImageSize;
UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER));
UpdatePartition->RegionCount = 1;
} else {
//
// Update Bootloader
//
// Get Region sizes from flash map
GetRegionInfo (&TopSwapRegionSize, &RedundantRegionSize, &NonRedundantRegionSize);
// BIOS region layout is as below.
//
// +-------------------------+
// + Top Swap +
// +-------------------------+
// + Top Swap Backup +
// +-------------------------+
// + Redundant Region +
// +-------------------------+
// + Redundant Region Backup +
// +-------------------------+
// + Non Redundant Region +
// +-------------------------+
NonRedundantRegionOffset = \
FlashMap->RomSize - (TopSwapRegionSize + RedundantRegionSize) * 2 - NonRedundantRegionSize;
TopSwapRegionOffset = FlashMap->RomSize - TopSwapRegionSize;
RedundantRegionOffset = TopSwapRegionOffset - TopSwapRegionSize - RedundantRegionSize;
if (FwPolicy.Fields.UpdatePartitionB == 1) {
TopSwapRegionOffset -= TopSwapRegionSize;
RedundantRegionOffset -= RedundantRegionSize;
}
DEBUG ((DEBUG_INFO, "TopSwapRegion Offset/Size = 0x%08X/0x%X\n", TopSwapRegionOffset, TopSwapRegionSize));
DEBUG ((DEBUG_INFO, "RedundantRegion Offset/Size = 0x%08X/0x%X\n", RedundantRegionOffset, RedundantRegionSize));
DEBUG ((DEBUG_INFO, "NonRedundantRegion Offset/Size = 0x%08X/0x%X\n", NonRedundantRegionOffset,
NonRedundantRegionSize));
//
// Top Swap region
//
UpdateRegion = &UpdatePartition->FwRegion[0];
UpdateRegion->ToUpdateAddress = TopSwapRegionOffset;
UpdateRegion->UpdateSize = TopSwapRegionSize;
UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER)+ (UINTN)UpdateRegion->ToUpdateAddress);
UpdatePartition->RegionCount += 1;
//
// Redundant region
//
UpdateRegion = &UpdatePartition->FwRegion[1];
UpdateRegion->ToUpdateAddress = RedundantRegionOffset;
UpdateRegion->UpdateSize = RedundantRegionSize;
UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + (UINTN)UpdateRegion->ToUpdateAddress);
UpdatePartition->RegionCount += 1;
if ((FwPolicy.Fields.StateMachine == FW_UPDATE_SM_PART_A) ||
(FwPolicy.Fields.StateMachine == FW_UPDATE_SM_PART_B)) {
//
// Non-redundant region
//
UpdateRegion = &UpdatePartition->FwRegion[2];
UpdateRegion->ToUpdateAddress = NonRedundantRegionOffset;
UpdateRegion->UpdateSize = NonRedundantRegionSize;
UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + NonRedundantRegionOffset);
UpdatePartition->RegionCount += 1;
}
}
for (Idx = 0; Idx < UpdatePartition->RegionCount; Idx++) {
UpdateRegion = &UpdatePartition->FwRegion[Idx];
DEBUG((DEBUG_INFO, "Region %d\n", Idx));
DEBUG((DEBUG_INFO, " ToUpdateAddress: = 0x%08x\n", UpdateRegion->ToUpdateAddress));
DEBUG((DEBUG_INFO, " UpdateSize: = 0x%08x\n", UpdateRegion->UpdateSize));
DEBUG((DEBUG_INFO, " SourceAddress: = 0x%08x\n", UpdateRegion->SourceAddress));
}
*PartitionInfo = UpdatePartition;
return EFI_SUCCESS;
}
/**
Platform hook point before starting to write a boot partition.
This function will do some platform specific things before starting to write
data to boot media. e.g. Send other component message it is going to do boot
media update.
@param[in] UpdatePartition Pointer to update partition structure.
@retval EFI_SUCCESS Update successfully.
**/
EFI_STATUS
EFIAPI
PrepareRegionsUpdate (
IN FIRMWARE_UPDATE_PARTITION *UpdatePartition
)
{
return EFI_SUCCESS;
}
/**
Platform hook point to clear firmware update trigger.
This function is responsible for clearing firmware update trigger.
**/
VOID
EFIAPI
ClearFwUpdateTrigger (
VOID
)
{
ClearUpdateTrigger ();
}
/**
Platform hook point after firmware update is done.
This function will do some platform specific things after all new firmware
is written to boot media. e.g. set boot mode to normal boot mode if platform
support it.
@retval EFI_SUCCESS Update successfully.
@retval others Error happening end firmware update.
**/
EFI_STATUS
EFIAPI
PlatformEndFirmwareUpdate (
VOID
)
{
return EFI_SUCCESS;
}
/**
Flash descriptor region lock
This function will do some command buffer parsing and check
for additional parameters
@param[in] CmdDataBuf Pointer to command buffer.
@param[in] CmdDataSize size of command data.
@retval EFI_SUCCESS Flash descriptor lock successfully.
@retval others Error happening when updating.
**/
EFI_STATUS
EFIAPI
SetFlashDescriptorLock (
IN CHAR8 *CmdDataBuf,
IN UINTN CmdDataSize
)
{
return EFI_UNSUPPORTED;
}
/**
Anti Rollback Svn Commit
@param[in] CmdDataBuf Pointer to command buffer.
@param[in] CmdDataSize size of command data.
@retval EFI_SUCCESS Svn commit successfully.
@retval others Error happening when updating.
**/
EFI_STATUS
EFIAPI
SetArbSvnCommit (
IN CHAR8 *CmdDataBuf,
IN UINTN CmdDataSize
)
{
return EFI_UNSUPPORTED;
}
/**
Oem Key Revocation
@param[in] CmdDataBuf Pointer to command buffer.
@param[in] CmdDataSize size of command data.
@retval EFI_SUCCESS Oem Key Revocation is successful.
@retval others Error happening when updating.
**/
EFI_STATUS
EFIAPI
SetOemKeyRevocation (
IN CHAR8 *CmdDataBuf,
IN UINTN CmdDataSize
)
{
EFI_STATUS Status;
Status = HeciRevokeOemKey ();
if (EFI_ERROR (Status)) {
DEBUG((DEBUG_ERROR, "Oem Revoke Key status - %r\n", Status));
}
return Status;
}