From cd2f00fe2c23538ea9a7d0df658fffa88f6c99fb Mon Sep 17 00:00:00 2001 From: Raghava Gudla Date: Tue, 21 May 2019 17:15:20 -0700 Subject: [PATCH] Add Multiple firmware update capsule image support This patch will add support for updating multiple firmwares using a single capsule image. Following modifications are made for existing firmware update flow 1) Gather and validate capsule image 2) State Machine will be set to capsule processing state. 3) Signature of the capsule image is now stored in reserved region During each reboot until the end of firmware update, stored signature will be compared against the capsule image signature to make sure capsule image is not modified until the end of firmware update. 4) Process Capsule image to gather firmware images 5) Each Firmware image information will be stored in reserved region using FW_UPDATE_COMP_STATUS. Update pending will be marked to update pending state indicating that this image is not processed. 6) Firmware update will use the reserved region comp structures starting with the first image with update pending state, update the comp update pending field to processing and applies the image. After the update, pending field will be updated to Done and updates the status of the update in the component structure and moves on to next image found. 7) After all the component structure in the reserved region updating pending field are set to Done. Firmware update mode is exited. Signed-off-by: Raghava Gudla --- .../Include/Library/FirmwareUpdateLib.h | 131 ++-- .../Library/AcpiInitLib/AcpiInitLib.c | 35 +- PayloadPkg/FirmwareUpdate/FirmwareUpdate.c | 672 ++++++++++++++---- PayloadPkg/FirmwareUpdate/FirmwareUpdate.inf | 3 + PayloadPkg/PayloadPkg.dec | 8 +- .../FirmwareUpdateLib/FirmwareUpdateLib.c | 41 +- .../FirmwareUpdateLib/FirmwareUpdateLib.c | 53 +- .../FirmwareUpdateLib/FirmwareUpdateLib.inf | 2 + 8 files changed, 730 insertions(+), 215 deletions(-) diff --git a/BootloaderCommonPkg/Include/Library/FirmwareUpdateLib.h b/BootloaderCommonPkg/Include/Library/FirmwareUpdateLib.h index 0e458c99..68c71aa8 100644 --- a/BootloaderCommonPkg/Include/Library/FirmwareUpdateLib.h +++ b/BootloaderCommonPkg/Include/Library/FirmwareUpdateLib.h @@ -20,29 +20,34 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#define CMOS_ADDREG 0x70 -#define CMOS_DATAREG 0x71 +#define CMOS_ADDREG 0x70 +#define CMOS_DATAREG 0x71 -#define MAX_UPDATE_REGIONS 4 +#define MAX_UPDATE_REGIONS 4 -#define FW_UPDATE_SM_INIT 0xFF -#define FW_UPDATE_SM_PART_A 0xFE -#define FW_UPDATE_SM_PART_B 0xFD -#define FW_UPDATE_SM_PART_AB 0xFC +#define FW_UPDATE_SM_INIT 0xFF +#define FW_UPDATE_SM_CAP_PROCESSING 0x7F +#define FW_UPDATE_SM_PART_A 0x7E +#define FW_UPDATE_SM_PART_B 0x7D +#define FW_UPDATE_SM_PART_AB 0x7C -#define RTC_PORT_ID 0xC3 -#define PCH_LPC_REG_P2SB_UNHIDE 0xE1 -#define PCH_LPC_REG_P2SB_BAR 0x10 +#define FW_UPDATE_IMAGE_UPDATE_NONE 0xFF +#define FW_UPDATE_IMAGE_UPDATE_PENDING 0xFE +#define FW_UPDATE_IMAGE_UPDATE_PROCESSING 0xFC +#define FW_UPDATE_IMAGE_UPDATE_DONE 0xF8 -#define FW_UPDATE_PARTITION_A 0 -#define FW_UPDATE_PARTITION_B 1 +#define FW_UPDATE_PARTITION_A 0 +#define FW_UPDATE_PARTITION_B 1 -#define MAX_FILE_LEN 16 +#define FW_UPDATE_SIG_LENGTH 256 + +#define MAX_FILE_LEN 16 +#define MAX_FW_COMPONENTS 3 #define CAPSULE_FLAGS_CFG_DATA BIT0 -#define FIRMWARE_UPDATE_STATUS_SIGNATURE SIGNATURE_32 ('F', 'W', 'U', 'S') -#define FIRMWARE_UPDATE_STATUS_VERSION 0x1 +#define FW_UPDATE_STATUS_SIGNATURE SIGNATURE_32 ('F', 'W', 'U', 'S') +#define FW_UPDATE_STATUS_VERSION 0x1 /// /// "FWST" Firmware Update status data Table @@ -50,6 +55,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. /// #define EFI_FIRMWARE_UPDATE_STATUS_TABLE_SIGNATURE SIGNATURE_32('F', 'W', 'S', 'T') +#define ESRT_FIRMWARE_RESOURCE_VERSION 0x1 + +#define CREATOR_INTEL_OEM_ID 'I','N','T','E','L',' ' +#define CREATOR_INTEL_OEM_TABLE_ID SIGNATURE_64('F','W','U','P','D','S','T','S') +#define CREATOR_ID_INTEL 0x4C544E49 // "INTL"(Intel) +#define CREATOR_REV_INTEL 0x20090903 +#define ACPI_FWST_OEM_REV 0x00001000 + typedef enum { TopSwapSet, TopSwapClear @@ -60,16 +73,6 @@ typedef enum { BackupPartition } BOOT_PARTITION; -#define ESRT_FIRMWARE_RESOURCE_VERSION 0x1 -#define ESRT_FIRMWARE_RESOURCE_COUNT 0x1 -#define ESRT_FIRMWARE_RESOURCE_COUNT_MAX 0x1 - -#define CREATOR_INTEL_OEM_ID 'I','N','T','E','L',' ' -#define CREATOR_INTEL_OEM_TABLE_ID SIGNATURE_64('F','W','U','P','D','S','T','S') -#define CREATOR_ID_INTEL 0x4C544E49 // "INTL"(Intel) -#define CREATOR_REV_INTEL 0x20090903 -#define ACPI_FWST_OEM_REV 0x00001000 - #pragma pack(push, 1) // // Firmware Update Status ACPI structure @@ -79,7 +82,7 @@ typedef enum { typedef struct { EFI_ACPI_DESCRIPTION_HEADER Header; EFI_SYSTEM_RESOURCE_TABLE EsrtTablePtr; - EFI_SYSTEM_RESOURCE_ENTRY EsrtTableEntry; + EFI_SYSTEM_RESOURCE_ENTRY EsrtTableEntry[MAX_FW_COMPONENTS]; } EFI_FWST_ACPI_DESCRIPTION_TABLE; // @@ -92,11 +95,18 @@ typedef struct { UINT32 Signature; UINT16 Version; UINT16 Length; + UINT8 CapsuleSig[FW_UPDATE_SIG_LENGTH]; + UINT8 StateMachine; + UINT8 Reserved[7]; +} FW_UPDATE_STATUS; + +typedef struct { + EFI_GUID FirmwareId; UINT32 LastAttemptVersion; UINT32 LastAttemptStatus; - UINT8 StateMachine; + UINT8 UpdatePending; UINT8 Reserved[3]; -} FIRMWARE_UPDATE_STATUS; +} FW_UPDATE_COMP_STATUS; typedef union _FIRMWARE_UPDATE_POLICY { UINT32 Data; @@ -126,6 +136,23 @@ typedef struct { UINT32 Reserved[3]; } FIRMWARE_UPDATE_HEADER; +typedef struct { + UINT32 Version; + UINT16 EmbeddedDriverCount; + UINT16 PayloadItemCount; +// UINT64 ItemOffsetList[]; +} EFI_FW_MGMT_CAP_HEADER; + +typedef struct { + UINT32 Version; + EFI_GUID UpdateImageTypeId; + UINT8 UpdateImageIndex; + UINT8 reserved_bytes[3]; + UINT32 UpdateImageSize; + UINT32 UpdateVendorCodeSize; + UINT64 UpdateHardwareInstance; +} EFI_FW_MGMT_CAP_IMAGE_HEADER; + // // Region information for firmware update // @@ -147,6 +174,9 @@ typedef struct { #pragma pack(pop) #define CAPSULE_IMAGE_SIZE(h) ((h)->HeaderSize + (h)->PubKeySize + (h)->ImageSize + (h)->SignatureSize) +#define COMP_STATUS_OFFSET(x, y) ((x) + sizeof(FW_UPDATE_STATUS) + ((y) * sizeof(FW_UPDATE_COMP_STATUS))) + +typedef VOID (*DRIVER_ENTRY) (VOID *Params); /** Get capsule image for firmware update. @@ -175,7 +205,7 @@ GetCapsuleImage ( Computes offset in the BIOS region from the base address. Then it calculates base address of stage1A in the capsule image. - @param[in] FwImage The firmware update 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 @@ -187,7 +217,7 @@ GetCapsuleImage ( EFI_STATUS EFIAPI PlatformGetStage1AOffset ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN BOOLEAN IsBackupPartition, OUT UINT32 *Base, OUT UINT32 *Size @@ -205,10 +235,9 @@ PlatformGetStage1AOffset ( 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] FwImage The firmware update capsule image. - @param[in] FwPolicy Firmware update policy - @param[out] PartitionInfo The detail informaion on the partition to 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. @@ -216,7 +245,7 @@ PlatformGetStage1AOffset ( EFI_STATUS EFIAPI GetFirmwareUpdateInfo ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN FIRMWARE_UPDATE_POLICY FwPolicy, OUT FIRMWARE_UPDATE_PARTITION **PartitionInfo ); @@ -472,18 +501,40 @@ AfterUpdateEnforceFwUpdatePolicy ( ); /** - This function will be called after the firmware update is complete. - This function will update firmware update status structure in reserved region - - @param[in] LastAttemptVersion Version of last firmware update attempted. - @param[in] LastAttemptStatus Status of last firmware update attempted. + This function will be called after the firmware update is complete. + This function will update firmware update status structure in reserved region + + @param[in] ImageHdr Pointer to Fw update image guid + @param[in] LastAttemptVersion Version of last firmware update attempted. + @param[in] LastAttemptStatus Status of last firmware update attempted. @retval EFI_SUCCESS The operation completed successfully. @retval others There is error happening. **/ EFI_STATUS UpdateStatus ( + IN EFI_GUID *ImageId, IN UINT16 LastAttemptVersion, IN EFI_STATUS LastAttemptStatus ); + +/** + Perform csme Firmware update. + + This function based on the image type id guid from the image header will + call the respective functions to perform capsule update. + + @param[in] CapImage The pointer to the firmware update capsule image. + @param[in] CapImageSize The size of capsule image in bytes. + @param[in] ImageHdr Pointer to fw mgmt capsule Image header + + @retval EFI_SUCCESS Update successful. + @retval other error status from the update routine +**/ +EFI_STATUS +UpdateCsme ( + IN UINT8 *CapImage, + IN UINT32 CapImageSize, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr + ); #endif diff --git a/BootloaderCorePkg/Library/AcpiInitLib/AcpiInitLib.c b/BootloaderCorePkg/Library/AcpiInitLib/AcpiInitLib.c index feb513e7..a209e0b3 100644 --- a/BootloaderCorePkg/Library/AcpiInitLib/AcpiInitLib.c +++ b/BootloaderCorePkg/Library/AcpiInitLib/AcpiInitLib.c @@ -394,14 +394,11 @@ UpdateFwst ( IN UINT8 *Current ) { + UINT8 Count; UINT32 RsvdBase; EFI_STATUS Status; - LOADER_GLOBAL_DATA *LdrGlobal; - BOOT_LOADER_VERSION *Version; - FIRMWARE_UPDATE_STATUS *FwUpdateStatus; EFI_FWST_ACPI_DESCRIPTION_TABLE *FwstAcpiTablePtr; - - LdrGlobal = (LOADER_GLOBAL_DATA *)GetLoaderGlobalDataPointer(); + FW_UPDATE_COMP_STATUS *FwUpdCompStatus; // // We do not need to populate ACPI table during firmware update @@ -423,27 +420,13 @@ UpdateFwst ( // Fill in details for FWST ACPI table // FwstAcpiTablePtr = (EFI_FWST_ACPI_DESCRIPTION_TABLE *)Current; - - CopyMem(&FwstAcpiTablePtr->EsrtTableEntry.FwClass, &gEsrtSystemFirmwareGuid, sizeof (EFI_GUID)); - FwstAcpiTablePtr->EsrtTableEntry.FwType = ESRT_FW_TYPE_SYSTEMFIRMWARE; - - // - // Get current version and lowest supported SVN version - // - if (LdrGlobal->VerInfoPtr != NULL) { - Version = LdrGlobal->VerInfoPtr; - FwstAcpiTablePtr->EsrtTableEntry.FwVersion = Version->ImageVersion.SecureVerNum; - FwstAcpiTablePtr->EsrtTableEntry.LowestSupportedFwVersion = PcdGet32 (PcdLowestSupportedFwVer); - } - - // - // Get status of last firmware update attempt - // - FwUpdateStatus = (FIRMWARE_UPDATE_STATUS *)RsvdBase; - - if (FwUpdateStatus->Signature == FIRMWARE_UPDATE_STATUS_SIGNATURE) { - FwstAcpiTablePtr->EsrtTableEntry.LastAttemptVersion = FwUpdateStatus->LastAttemptVersion; - FwstAcpiTablePtr->EsrtTableEntry.LastAttemptStatus = FwUpdateStatus->LastAttemptStatus; + FwUpdCompStatus = (FW_UPDATE_COMP_STATUS *)(RsvdBase + sizeof(FW_UPDATE_STATUS)); + for (Count = 0; Count < MAX_FW_COMPONENTS; Count ++) { + CopyMem(&(FwstAcpiTablePtr->EsrtTableEntry[Count].FwClass), &(FwUpdCompStatus->FirmwareId), sizeof(EFI_GUID)); + FwstAcpiTablePtr->EsrtTableEntry[Count].FwType = ESRT_FW_TYPE_SYSTEMFIRMWARE; + FwstAcpiTablePtr->EsrtTableEntry[Count].LastAttemptVersion = FwUpdCompStatus->LastAttemptVersion; + FwstAcpiTablePtr->EsrtTableEntry[Count].LastAttemptStatus = FwUpdCompStatus->LastAttemptStatus; + FwUpdCompStatus = (FW_UPDATE_COMP_STATUS *)((UINT32)FwUpdCompStatus + sizeof(FW_UPDATE_COMP_STATUS)); } return EFI_SUCCESS; diff --git a/PayloadPkg/FirmwareUpdate/FirmwareUpdate.c b/PayloadPkg/FirmwareUpdate/FirmwareUpdate.c index 2c7a1d9f..291e62eb 100644 --- a/PayloadPkg/FirmwareUpdate/FirmwareUpdate.c +++ b/PayloadPkg/FirmwareUpdate/FirmwareUpdate.c @@ -348,15 +348,15 @@ GetVersionfromFv ( /** Verify the firmware version to make sure it is no less than current firmware version. - @param[in] FwImage The pointer to the firmware update capsule image. - @param[in] FwPolicy Firmware update policy. + @param[in] ImageHdr Pointer to the fw mgmt capsule image header + @param[in] FwPolicy Firmware update policy. - @retval EFI_SUCCESS The operation completed successfully. - @retval others There is error happening. + @retval EFI_SUCCESS The operation completed successfully. + @retval others There is error happening. **/ EFI_STATUS VerifyFwVersion ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN FIRMWARE_UPDATE_POLICY FwPolicy ) { @@ -393,9 +393,9 @@ VerifyFwVersion ( // Get base address of Stage 1A in capsule Image // if (FwPolicy.Fields.UpdatePartitionB == 0x1) { - Status = PlatformGetStage1AOffset(FwImage, FALSE, &CompBase, &CompSize); + Status = PlatformGetStage1AOffset(ImageHdr, FALSE, &CompBase, &CompSize); } else if (FwPolicy.Fields.UpdatePartitionA == 0x1) { - Status = PlatformGetStage1AOffset(FwImage, TRUE, &CompBase, &CompSize); + Status = PlatformGetStage1AOffset(ImageHdr, TRUE, &CompBase, &CompSize); } if (EFI_ERROR (Status)) { DEBUG((DEBUG_ERROR, "PlatformGetStage1AOffset: %r\n", Status)); @@ -408,7 +408,12 @@ VerifyFwVersion ( return Status; } - Status = UpdateStatus((CapsuleBlVersion->ImageVersion.ProjMajorVersion << 8) | CapsuleBlVersion->ImageVersion.ProjMinorVersion, 0xFFFFFFFF); + // + // Update last update version to the version we are about to update + // + Status = UpdateStatus(&ImageHdr->UpdateImageTypeId, \ + (CapsuleBlVersion->ImageVersion.ProjMajorVersion << 8) | CapsuleBlVersion->ImageVersion.ProjMinorVersion, \ + 0xFFFFFFFF); if (EFI_ERROR (Status)) { DEBUG((DEBUG_ERROR, "Updating status to reserved region failed: %r\n", Status)); return Status; @@ -438,15 +443,15 @@ GetStateMachineFlag ( IN OUT UINT8 *StateMachine ) { - EFI_STATUS Status; - UINT32 FwUpdStatusOffset; - FIRMWARE_UPDATE_STATUS FwUpdStatus; + EFI_STATUS Status; + UINT32 FwUpdStatusOffset; + FW_UPDATE_STATUS FwUpdStatus; // // Read from the reserved region and return state machine // FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase); - Status = BootMediaRead (FwUpdStatusOffset, sizeof(FIRMWARE_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + Status = BootMediaRead (FwUpdStatusOffset, sizeof(FW_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); if (EFI_ERROR (Status)) { *StateMachine = FW_UPDATE_SM_INIT; } else { @@ -458,7 +463,17 @@ GetStateMachineFlag ( Set state machine flag in flash. This function will set state machine flag in the bootloader reserved region - First byte in the booloader reserved region is state machine flag + First byte in the booloader reserved region is state machine flag + + ---------------------------------------------------------------------------------------- + | SM | Operation | + ---------------------------------------------------------------------------------------- + | FW_UPDATE_SM_INIT | Clear whole region, Preserve sig, lenth and version | + | Also preserve update status of all firmwares | + | FW_UPDATE_SM_CAP_PROCESSING | Clear whole region, Preserve FW_UPDATE_STATUS and | + | update state machine to FW_UPDATE_SM_CAP_PROCESSING | + | Anything else | update state machine | + ---------------------------------------------------------------------------------------- @param[in] StateMachine State machine flag byte. @@ -471,55 +486,75 @@ SetStateMachineFlag ( ) { EFI_STATUS Status; + UINT32 UpdateSize; UINT32 FwUpdStatusOffset; - FIRMWARE_UPDATE_STATUS FwUpdStatus; + FW_UPDATE_STATUS FwUpdStatus; + FW_UPDATE_COMP_STATUS FwUpdCompStatus[MAX_FW_COMPONENTS]; DEBUG((DEBUG_INIT, "Set next FWU state: 0x%02X\n", StateMachine)); - - // - // Any value less than 0xFC is invalid - // - if (StateMachine < FW_UPDATE_SM_PART_AB) { - return EFI_INVALID_PARAMETER; - } - - // - // Any value other than 0xFC, 0xFD, 0xFE, 0xFF is invalid - // - if ((StateMachine & FW_UPDATE_SM_PART_AB) != FW_UPDATE_SM_PART_AB) { - return EFI_INVALID_PARAMETER; - } - + FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase); - Status = BootMediaRead (FwUpdStatusOffset, sizeof(FIRMWARE_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + // + // Read the reserved region structure to process state machine + // + Status = BootMediaRead (FwUpdStatusOffset, sizeof(FW_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); if (EFI_ERROR (Status)) { DEBUG((DEBUG_ERROR, "BootMediaRead. FwUpdStatusOffset: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); return Status; } // - // To write 0xFF, erase 4kb block + // If we are to clear state machine, Wipe the whole region and preserve + // the last update status and version for all firmwares + // + // If we are to set the capsule to processing, then this is start of the firmware update + // in this case, clear the whole region. // - if (StateMachine == FW_UPDATE_SM_INIT) { + if ((StateMachine == FW_UPDATE_SM_INIT) || (StateMachine == FW_UPDATE_SM_CAP_PROCESSING)){ + if (StateMachine == FW_UPDATE_SM_INIT) { + Status = BootMediaRead((FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)),\ + MAX_FW_COMPONENTS * sizeof(FW_UPDATE_COMP_STATUS), (UINT8 *)&FwUpdCompStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaRead failed with status %r\n", Status)); + return Status; + } + } + Status = BootMediaErase (FwUpdStatusOffset, EFI_PAGE_SIZE); if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "BootMediaErase. RsvdBase: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); + DEBUG((DEBUG_ERROR, "BootMediaErase failed with status %r\n", Status)); return Status; } - - Status = BootMediaWrite (FwUpdStatusOffset, sizeof(FIRMWARE_UPDATE_STATUS) - sizeof(UINT32), (UINT8 *)&FwUpdStatus); - if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "BootMediaWrite. readaddr: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); - return Status; - } - - return Status; } + // + // Set desired state machine + // FwUpdStatus.StateMachine = StateMachine; - Status = BootMediaWrite (FwUpdStatusOffset, sizeof(FIRMWARE_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + if (StateMachine == FW_UPDATE_SM_INIT) { + // + // If we are resetting state machine, just preserve signature, length and version + // last update status and version for all the firmwares + // + UpdateSize = sizeof(UINT64); + + // + // Write back the firware update status + // + Status = BootMediaWrite((FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)),\ + MAX_FW_COMPONENTS * sizeof(FW_UPDATE_COMP_STATUS), (UINT8 *)&FwUpdCompStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaWrite failed with status %r\n", Status)); + return Status; + } + + } else { + UpdateSize = sizeof(FW_UPDATE_STATUS); + } + + Status = BootMediaWrite (FwUpdStatusOffset, UpdateSize, (UINT8 *)&FwUpdStatus); if (EFI_ERROR (Status)) { DEBUG((DEBUG_ERROR, "BootMediaWrite. readaddr: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); return Status; @@ -558,7 +593,6 @@ EnforceFwUpdatePolicy ( { UINT8 StateMachine; BOOLEAN ResetRequired; - EFI_STATUS Status; LOADER_PLATFORM_INFO *LoaderInfo; ResetRequired = FALSE; @@ -581,7 +615,7 @@ EnforceFwUpdatePolicy ( FwPolicy->Data = 0; switch (StateMachine) { - case FW_UPDATE_SM_INIT: + case FW_UPDATE_SM_CAP_PROCESSING: if (LoaderInfo->BootPartition == FW_UPDATE_PARTITION_A) { FwPolicy->Fields.StateMachine = FW_UPDATE_SM_PART_A; FwPolicy->Fields.UpdatePartitionB = 0x1; @@ -621,11 +655,6 @@ EnforceFwUpdatePolicy ( case FW_UPDATE_SM_PART_AB: if (LoaderInfo->BootPartition == FW_UPDATE_PARTITION_A){ - Status = SetStateMachineFlag (FW_UPDATE_SM_INIT); - if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "Error while setting state machine\n")); - return Status; - } // // This return would end the firmware update // but before retuning would update status and version @@ -701,72 +730,103 @@ AfterUpdateEnforceFwUpdatePolicy ( This function will be called after the firmware update is complete. This function will update firmware update status structure in reserved region + @param[in] ImageHdr Pointer to Fw update image guid @param[in] LastAttemptVersion Version of last firmware update attempted. - @param[in] LastAttemptStatus Status of last firmware update attempted. + @param[in] LastAttemptStatus Status of last firmware update attempted. @retval EFI_SUCCESS The operation completed successfully. @retval others There is error happening. **/ EFI_STATUS UpdateStatus ( + IN EFI_GUID *ImageId, IN UINT16 LastAttemptVersion, IN EFI_STATUS LastAttemptStatus ) { + UINT8 Count; EFI_STATUS Status; UINT32 FwUpdStatusOffset; - FIRMWARE_UPDATE_STATUS FwUpdStatus; + UINT32 ByteOffset; + FW_UPDATE_COMP_STATUS FwUpdCompStatus[MAX_FW_COMPONENTS]; FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase); - Status = BootMediaRead (FwUpdStatusOffset, sizeof(FIRMWARE_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + // + // Read all the component structures + // + Status = BootMediaRead ((FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)), \ + MAX_FW_COMPONENTS * sizeof(FW_UPDATE_COMP_STATUS), (UINT8 *)&FwUpdCompStatus); if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "BootMediaRead. FwUpdStatusOffset: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); + DEBUG((DEBUG_ERROR, "BootMediaRead. offset: 0x%llx, Status = 0x%x\n", (FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)), Status)); return Status; } - if (FwUpdStatus.Signature == 0xFFFFFFFF) { - FwUpdStatus.Signature = FIRMWARE_UPDATE_STATUS_SIGNATURE; - FwUpdStatus.Version = FIRMWARE_UPDATE_STATUS_VERSION; - FwUpdStatus.Length = sizeof(FIRMWARE_UPDATE_STATUS); + // + // Find the required component to update status + // + for (Count = 0; Count < MAX_FW_COMPONENTS; Count ++) { + if (CompareGuid(&(FwUpdCompStatus[Count].FirmwareId), ImageId) == TRUE) { + DEBUG((DEBUG_VERBOSE, "FOund the component to update status\n")); + break; + } + } + + if (Count == MAX_FW_COMPONENTS) { + DEBUG ((DEBUG_ERROR, "Could not find the component to update status\n")); + return EFI_NOT_FOUND; } if (LastAttemptVersion != 0) { - FwUpdStatus.LastAttemptVersion = LastAttemptVersion; + FwUpdCompStatus[Count].LastAttemptVersion = LastAttemptVersion; } if (LastAttemptStatus != 0xFFFFFFFF) { + FwUpdCompStatus[Count].UpdatePending = FW_UPDATE_IMAGE_UPDATE_DONE; if (LastAttemptStatus == EFI_SUCCESS) { - FwUpdStatus.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + FwUpdCompStatus[Count].LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; } else if (LastAttemptStatus == EFI_INCOMPATIBLE_VERSION) { - FwUpdStatus.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; + FwUpdCompStatus[Count].LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; } else if (LastAttemptStatus == EFI_OUT_OF_RESOURCES) { - FwUpdStatus.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; - } else if (LastAttemptStatus == EFI_SECURITY_VIOLATION) { + FwUpdCompStatus[Count].LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; + } else if ((LastAttemptStatus == EFI_SECURITY_VIOLATION) || (LastAttemptStatus == EFI_COMPROMISED_DATA)){ // // If we get security violation, at this point we do not know // version from capsule, instead of keeping the existing version // reset it back to 0 // - FwUpdStatus.LastAttemptVersion = 0; - FwUpdStatus.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR; + FwUpdCompStatus[Count].LastAttemptVersion = 0; + FwUpdCompStatus[Count].LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR; } else { - FwUpdStatus.LastAttemptVersion = 0; - FwUpdStatus.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + FwUpdCompStatus[Count].LastAttemptVersion = 0; + FwUpdCompStatus[Count].LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; } } - Status = BootMediaErase (FwUpdStatusOffset, EFI_PAGE_SIZE); + // + // Update a field at a time, if we loose power in between, we can still have control + // + ByteOffset = COMP_STATUS_OFFSET(FwUpdStatusOffset, Count) + OFFSET_OF(FW_UPDATE_COMP_STATUS, LastAttemptVersion); + Status = BootMediaWrite(ByteOffset, sizeof(UINT32), (UINT8 *)&(FwUpdCompStatus[Count].LastAttemptVersion)); if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "BootMediaErase. RsvdBase: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); + DEBUG((DEBUG_ERROR, "Updating last attempt version failed with status: %r\n", Status)); return Status; } - Status = BootMediaWrite(FwUpdStatusOffset, sizeof(FIRMWARE_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + ByteOffset = COMP_STATUS_OFFSET(FwUpdStatusOffset, Count) + OFFSET_OF(FW_UPDATE_COMP_STATUS, LastAttemptStatus); + Status = BootMediaWrite(ByteOffset, sizeof(UINT32), (UINT8 *)&(FwUpdCompStatus[Count].LastAttemptStatus)); if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "BootMediaWrite. readaddr: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); + DEBUG((DEBUG_ERROR, "Updating last attempt status failed with status: %r\n", Status)); return Status; } + + ByteOffset = COMP_STATUS_OFFSET(FwUpdStatusOffset, Count) + OFFSET_OF(FW_UPDATE_COMP_STATUS, UpdatePending); + Status = BootMediaWrite(ByteOffset, sizeof(UINT8), (UINT8 *)&(FwUpdCompStatus[Count].UpdatePending)); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "Updating updatepending failed with status: %r\n", Status)); + return Status; + } + DEBUG((DEBUG_INIT, "Firmware Update status updated to reserved region \n")); return EFI_SUCCESS; @@ -797,7 +857,10 @@ AuthenticateCapsule ( FIRMWARE_UPDATE_HEADER *Header; UINT8 *Key; UINT8 *Signature; - CHAR8 *Type; + FW_UPDATE_STATUS FwUpdStatus; + UINT32 FwUpdStatusOffset; + + FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase); Header = (FIRMWARE_UPDATE_HEADER *)FwImage; if (!CompareGuid (&Header->FileGuid, &gFirmwareUpdateImageFileGuid)) { @@ -823,22 +886,352 @@ AuthenticateCapsule ( Key = FwImage + Header->PubKeyOffset; Signature = FwImage + Header->SignatureOffset; + + // + // Copy fw update status structure to memory + // + Status = BootMediaRead (FwUpdStatusOffset, sizeof(FW_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaRead failed with status: %r\n", Status)); + return Status; + } + + // + // If capsule signature in flash does not match with capsule signature, + // it indicates that capsule image is modified in between firmware update. + // + if (*(UINT32 *)(FwUpdStatus.CapsuleSig) != 0xFFFFFFFF) { + if (CompareMem(&FwUpdStatus.CapsuleSig, Signature, FW_UPDATE_SIG_LENGTH) != 0) { + return EFI_COMPROMISED_DATA; + } + } + Status = DoRsaVerify (FwImage, Header->SignatureOffset, COMP_TYPE_PUBKEY_FWU, Signature, Key, NULL); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Image verification failed, %r!\n", Status)); return EFI_SECURITY_VIOLATION; } - if ((Header->CapsuleFlags & CAPSULE_FLAGS_CFG_DATA) != 0) { - Type = "CFGDATA"; - } else { - Type = "BOOTLOADER"; - } - DEBUG ((DEBUG_INFO, "The new %a image passed verification\n", Type)); + // + // If this is first time processing the capsule, save the capsule signature in flash until + // the end of firmware update + // + if (*(UINT32 *)(FwUpdStatus.CapsuleSig) != 0xFFFFFFFF) { + CopyMem((VOID *)&FwUpdStatus.CapsuleSig, (VOID *)Signature, sizeof(FW_UPDATE_SIG_LENGTH)); + + Status = BootMediaWrite (FwUpdStatusOffset, sizeof(FW_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaWrite failed with status %r\n", Status)); + return Status; + } + } return EFI_SUCCESS; } +/** + Process capsule image. + + This function will abstract firmware images from the capsule image. for each + of the firmware image found, FW_UPDATE_COMP_STATUS structure will be created + in the reserved region and update pending will be set to pending state. + + This function will create component structures in the order in which they are + found in the capsule image. + + @param[in] FwImage The pointer to the firmware update capsule image. + @param[in] FwSize The size of capsule image in bytes. + + @retval EFI_SUCCESS The operation completed successfully. + @retval others There is error happening. +**/ +EFI_STATUS +ProcessCapsule ( + IN UINT8 *FwImage, + IN UINT32 FwSize + ) +{ + UINT8 Count; + UINT8 TotalPayloadCount; + EFI_STATUS Status; + UINT32 FwUpdStatusOffset; + FW_UPDATE_STATUS FwUpdStatus; + FW_UPDATE_COMP_STATUS FwUpdCompStatus[MAX_FW_COMPONENTS]; + FIRMWARE_UPDATE_HEADER *FwUpdHeader; + EFI_FW_MGMT_CAP_HEADER *CapHeader; + EFI_FW_MGMT_CAP_IMAGE_HEADER *ImgHeader; + + FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase); + + // + // Read reserved region structure + // + Status = BootMediaRead (FwUpdStatusOffset, sizeof(FW_UPDATE_STATUS), (UINT8 *)&FwUpdStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaRead. offset: 0x%llx, Status = 0x%x\n", FwUpdStatusOffset, Status)); + return Status; + } + + // + // If state machine is 0xFF, Capsule is not processed yet + // set SM to capsule processing stage, this will reset back to + // init at the end of firmware update + // + if (FwUpdStatus.StateMachine == FW_UPDATE_SM_INIT) { + SetStateMachineFlag(FW_UPDATE_SM_CAP_PROCESSING); + } else { + return EFI_SUCCESS; + } + + FwUpdHeader = (FIRMWARE_UPDATE_HEADER *)FwImage; + CapHeader = (EFI_FW_MGMT_CAP_HEADER *)((UINTN)FwUpdHeader + FwUpdHeader->ImageOffset); + + // + // If capsule header is NULL or no payloads found in the capsule + // return EFI_NOT_FOUND; + // + if ((CapHeader != NULL) && (CapHeader->PayloadItemCount == 0)) { + ImgHeader = NULL; + return EFI_NOT_FOUND; + } + + TotalPayloadCount = (UINT8)(CapHeader->EmbeddedDriverCount + CapHeader->PayloadItemCount); + + // + // Zero out memory for component structures + // + ZeroMem((VOID *)&FwUpdCompStatus, MAX_FW_COMPONENTS * sizeof(FW_UPDATE_COMP_STATUS)); + + // + // Uninitialized update structure in flash + // initialize it + // + if (FwUpdStatus.Signature == 0xFFFFFFFF) { + FwUpdStatus.Signature = FW_UPDATE_STATUS_SIGNATURE; + FwUpdStatus.Version = FW_UPDATE_STATUS_VERSION; + FwUpdStatus.Length = sizeof(FW_UPDATE_STATUS); + } + + ImgHeader = (EFI_FW_MGMT_CAP_IMAGE_HEADER *)((UINTN)CapHeader + sizeof(EFI_FW_MGMT_CAP_HEADER) + TotalPayloadCount * sizeof (UINT64)); + + // + // Loop through all the payloads + // if matching guid found, return the payload header + // Boundary check to see if image header address exceeds the capsule region + // + for (Count = 0; Count < CapHeader->PayloadItemCount; Count++) { + // + // Create new structure + // + CopyMem((VOID *)&(FwUpdCompStatus[Count].FirmwareId), (VOID *)&(ImgHeader->UpdateImageTypeId), sizeof(EFI_GUID)); + FwUpdCompStatus[Count].LastAttemptVersion = 0xFFFFFFFF; + FwUpdCompStatus[Count].LastAttemptStatus = 0xFFFFFFFF; + FwUpdCompStatus[Count].UpdatePending = FW_UPDATE_IMAGE_UPDATE_PENDING; + + ImgHeader = (EFI_FW_MGMT_CAP_IMAGE_HEADER *)((UINTN)ImgHeader + ImgHeader->UpdateImageSize + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER)); + if ((UINT32)ImgHeader > (UINTN)((UINTN)CapHeader + FwUpdHeader->ImageSize)) { + return EFI_NOT_FOUND; + } + } + + // + // Update the component information to the reserved region + // + Status = BootMediaWrite ((FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)),\ + (MAX_FW_COMPONENTS * sizeof(FW_UPDATE_COMP_STATUS)), (UINT8 *)&FwUpdCompStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaWrite. offset: 0x%llx, Status = 0x%x\n", (FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)), Status)); + return Status; + } + + return Status; +} + +/** + Find payload in the capsule image. + + This function will parse through the capsule image to find the payload + matching the input guid. + + This function if provided with an empty guid will return the first payload + found + + @param[in] ImageId Guid to identify payload in the capsule image + @param[in] CapImage Pointer to the capsule Image + @param[in] CapImageSize Size of the capsule image in bytes + @param[in] ImageHdr Pointer to the capsule Image header + + @retval EFI_SUCCESS Found matching payload in the capsule. + @retval EFI_NOT_FOUND No matching payload found in the capsule. +**/ +EFI_STATUS +FindImage ( + IN EFI_GUID *ImageId, + IN UINT8 *CapImage, + IN UINT32 CapImageSize, + OUT EFI_FW_MGMT_CAP_IMAGE_HEADER **ImageHdr + ) +{ + UINT8 Count; + UINT8 TotalPayloadCount; + EFI_FW_MGMT_CAP_HEADER *CapHeader; + FIRMWARE_UPDATE_HEADER *FwUpdHeader; + EFI_FW_MGMT_CAP_IMAGE_HEADER *CapImageHdr; + + *ImageHdr = NULL; + CapImageHdr = NULL; + + FwUpdHeader = (FIRMWARE_UPDATE_HEADER *)CapImage; + CapHeader = (EFI_FW_MGMT_CAP_HEADER *)((UINTN)FwUpdHeader + FwUpdHeader->ImageOffset); + + // + // If capsule header is NULL or no payloads found in the capsule + // return EFI_NOT_FOUND; + // + if ((CapHeader != NULL) && (CapHeader->PayloadItemCount == 0)) { + return EFI_NOT_FOUND; + } + + TotalPayloadCount = (UINT8)(CapHeader->EmbeddedDriverCount + CapHeader->PayloadItemCount); + + CapImageHdr = (EFI_FW_MGMT_CAP_IMAGE_HEADER *)((UINTN)CapHeader + sizeof(EFI_FW_MGMT_CAP_HEADER) + TotalPayloadCount * sizeof(UINT64)); + + // + // If input guid is NULL, return the first payload header + // + if (ImageId == NULL) { + *ImageHdr = CapImageHdr; + return EFI_SUCCESS; + } + + // + // Loop through all the payloads + // if matching guid, return the payload header + // Boundary check to see if image header address exceeds the capsule region + // + for (Count = 0; Count < CapHeader->PayloadItemCount; Count++) { + if (CompareGuid(&CapImageHdr->UpdateImageTypeId, ImageId) == TRUE) { + *ImageHdr = CapImageHdr; + return EFI_SUCCESS; + } + CapImageHdr = (EFI_FW_MGMT_CAP_IMAGE_HEADER *)((UINTN)CapImageHdr + CapImageHdr->UpdateImageSize + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER)); + if ((UINTN)CapImageHdr > (UINTN)((UINTN)CapHeader + FwUpdHeader->ImageSize)) { + return EFI_NOT_FOUND; + } + } + + return EFI_NOT_FOUND; +} + +/** + Perform system Firmware update. + + This function will update SBL or Configuration data alone. + + @param[in] ImageHdr Pointer to fw mgmt capsule Image header + + @retval EFI_SUCCESS Update successful. + @retval other error occurred during firmware update +**/ +EFI_STATUS +UpdateSystemFirmware ( + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr + ) +{ + EFI_STATUS Status; + FIRMWARE_UPDATE_PARTITION *UpdatePartition; + FIRMWARE_UPDATE_POLICY FwPolicy; + + // + // 1. Enforce firmware update policy. + // + Status = EnforceFwUpdatePolicy (&FwPolicy); + if (EFI_ERROR (Status)) { + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + DEBUG((DEBUG_ERROR, "EnforceFwUpdatePolicy: Status = 0x%x\n", Status)); + return Status; + } + + // + // 2. Check firmware version. + // + Status = VerifyFwVersion (ImageHdr, FwPolicy); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, " VerifyFwVersion failed with Status = 0x%x\n", Status)); + return Status; + } + + // + // 3. Get firmware update required information. + // + Status = GetFirmwareUpdateInfo (ImageHdr, FwPolicy, &UpdatePartition); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "GetFirmwareUpdateInfo, Status = 0x%x\n", Status)); + return Status; + } + + // + // 4. Do boot partition update. + // + Status = UpdateBootPartition (UpdatePartition); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "UpdateBootPartition, Status = 0x%x\n", Status)); + return Status; + } + + // + // 5. After update Enforce firmware update policy + // + Status = AfterUpdateEnforceFwUpdatePolicy(FwPolicy); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AfterUpdateEnforceFwUpdatePolicy failed! Status = %r\n", Status)); + return Status; + } + + return Status; +} + +/** + Perform Firmware update. + + This function based on the image type id guid from the image header will + call the respective functions to perform capsule update. +* + @param[in] CapImage Pointer to the capsule Image + @param[in] CapImageSize Size of the capsule image in bytes +* @param[in] ImageHdr Pointer to fw mgmt capsule Image header +* @param[in] ResetRequired Pointer to boolean reset required + + @retval EFI_SUCCESS Update successful. + @retval other error status from the update routine +**/ +EFI_STATUS +ApplyFwImage ( + IN UINT8 *CapImage, + IN UINT32 CapImageSize, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, + OUT BOOLEAN *ResetRequired + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + if (CompareGuid(&ImageHdr->UpdateImageTypeId, &gSblFWUpdateImageFileGuid) == TRUE) { + Status = UpdateSystemFirmware(ImageHdr); + *ResetRequired = TRUE; + } else if (CompareGuid(&ImageHdr->UpdateImageTypeId, &gCfgFWUpdateImageFileGuid) == TRUE) { + Status = UpdateSystemFirmware(ImageHdr); + *ResetRequired = TRUE; + } else if (CompareGuid(&ImageHdr->UpdateImageTypeId, &gCsmeFWUpdateImageFileGuid) == TRUE) { + Status = UpdateCsme(CapImage, CapImageSize, ImageHdr); + *ResetRequired = TRUE; + } + + return Status; +} /** This is generic function for firmware update. @@ -855,22 +1248,21 @@ InitFirmwareUpdate ( ) { EFI_STATUS Status; + UINT8 Count; VOID *CapsuleImage; UINT32 CapsuleSize; - FIRMWARE_UPDATE_POLICY FwPolicy; - FIRMWARE_UPDATE_PARTITION *UpdatePartition; + UINT32 FwUpdStatusOffset; + UINT32 ByteOffset; + BOOLEAN ResetRequired; + FW_UPDATE_COMP_STATUS FwUpdCompStatus[MAX_FW_COMPONENTS]; + EFI_FW_MGMT_CAP_IMAGE_HEADER *ImgHdr; + + ImgHdr = NULL; + FwUpdStatusOffset = PcdGet32(PcdFwUpdStatusBase); + ResetRequired = FALSE; // - // 1. Enforce firmware update policy. - // - Status = EnforceFwUpdatePolicy (&FwPolicy); - if (EFI_ERROR (Status)) { - DEBUG((DEBUG_ERROR, "EnforceFwUpdatePolicy: Status = 0x%x\n", Status)); - return Status; - } - - // - // 2. Get capsule image. + // 1. Get capsule image. // Status = GetCapsuleImage (&CapsuleImage, &CapsuleSize); if (EFI_ERROR (Status)) { @@ -880,7 +1272,7 @@ InitFirmwareUpdate ( DEBUG ((DEBUG_INFO, "CapsuleImage: 0x%p, CapsuleSize: 0x%X\n", CapsuleImage, CapsuleSize)); // - // 3. Authenticate capsule image. + // 2. Authenticate capsule image. // Status = AuthenticateCapsule (CapsuleImage, CapsuleSize); if (EFI_ERROR (Status)) { @@ -889,39 +1281,93 @@ InitFirmwareUpdate ( } // - // 4. Check firmware version. + // 3. Process capsule image. // - Status = VerifyFwVersion (CapsuleImage, FwPolicy); + Status = ProcessCapsule (CapsuleImage, CapsuleSize); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, " VerifyFwVersion failed with Status = 0x%x\n", Status)); + DEBUG ((DEBUG_ERROR, "ProcessCapsule, Status = 0x%x\n", Status)); return Status; } // - // 5. Get firmware update required information. + // Read the component structure in the reserved region // - Status = GetFirmwareUpdateInfo (CapsuleImage, FwPolicy, &UpdatePartition); - if (EFI_ERROR(Status)) { - DEBUG((DEBUG_ERROR, "GetFirmwareUpdateInfo, Status = 0x%x\n", Status)); + Status = BootMediaRead ((FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)), \ + MAX_FW_COMPONENTS * sizeof(FW_UPDATE_COMP_STATUS), (UINT8 *)&FwUpdCompStatus); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaRead. offset: 0x%llx, Status = 0x%x\n", (FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)), Status)); return Status; } // - // 6. Do boot partition update. + // Loop through the components to perform update // - Status = UpdateBootPartition (UpdatePartition); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "UpdateBootPartition, Status = 0x%x\n", Status)); - return Status; + for (Count = 0; Count < MAX_FW_COMPONENTS; Count ++) { + // + // If the component has pending or processing state + // + if (FwUpdCompStatus[Count].UpdatePending & (BIT0 | BIT1 | BIT2)) { + if (FwUpdCompStatus[Count].UpdatePending == FW_UPDATE_IMAGE_UPDATE_PENDING) { + // + // Set the component to processing state before the update + // + FwUpdCompStatus[Count].UpdatePending = FW_UPDATE_IMAGE_UPDATE_PROCESSING; + + // + // Update component state in the reserved region + // + ByteOffset = COMP_STATUS_OFFSET(FwUpdStatusOffset, Count) + OFFSET_OF(FW_UPDATE_COMP_STATUS, UpdatePending); + Status = BootMediaWrite(ByteOffset, sizeof(UINT8), (UINT8 *)&(FwUpdCompStatus[Count].UpdatePending)); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "BootMediaWrite. offset: 0x%llx, Status = 0x%x\n", (FwUpdStatusOffset + sizeof(FW_UPDATE_STATUS)), Status)); + return Status; + } + } + + // + // Find payload associated with component in the capsule image + // + Status = FindImage(&(FwUpdCompStatus[Count].FirmwareId), CapsuleImage, CapsuleSize, &ImgHdr); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "FindImage failed with Status = %r\n", Status)); + return Status; + } + + // + // Start firmware udpate for the component + // + Status = ApplyFwImage(CapsuleImage, CapsuleSize, ImgHdr, &ResetRequired); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "ApplyFwImage failed with Status = %r\n", Status)); + } + + // + // Update firmware update status of the component in reserved region + // + Status = UpdateStatus(&(ImgHdr->UpdateImageTypeId), (UINT16)ImgHdr->Version, Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "UpdateStatus failed! Status = %r\n", Status)); + DEBUG((DEBUG_ERROR, "Reset required to proceed with the firmware update.\n")); + } + + // + // Reset system if required + // + if (ResetRequired == TRUE) { + ResetSystem (EfiResetCold); + CpuDeadLoop (); + } + } } // - // 7. After update Enforce firmware update policy + // At this point, all the firmware images in the capsule are processed + // Clear the state machine and exit // - Status = AfterUpdateEnforceFwUpdatePolicy(FwPolicy); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "AfterUpdateEnforceFwUpdatePolicy failed! Status = %r\n", Status)); - return Status; + if (Count == MAX_FW_COMPONENTS) { + SetStateMachineFlag(FW_UPDATE_SM_INIT); + } else { + return EFI_ABORTED; } return EFI_SUCCESS; @@ -1035,18 +1481,6 @@ PayloadMain ( } } - // - // Control comes here after the firmware update is complete - // Update Fw update status in reserved region - // - Status = UpdateStatus(0, Status); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "UpdateLastAttemptStatus failed! Status = %r\n", Status)); - DEBUG((DEBUG_ERROR, "Reset required to proceed with the firmware update.\n")); - ResetSystem (EfiResetCold); - CpuDeadLoop (); - } - // // Terminate firmware update // diff --git a/PayloadPkg/FirmwareUpdate/FirmwareUpdate.inf b/PayloadPkg/FirmwareUpdate/FirmwareUpdate.inf index 14645083..058dcb80 100644 --- a/PayloadPkg/FirmwareUpdate/FirmwareUpdate.inf +++ b/PayloadPkg/FirmwareUpdate/FirmwareUpdate.inf @@ -56,6 +56,9 @@ gFirmwareUpdateImageFileGuid gFlashMapInfoGuid gBootLoaderVersionFileGuid + gSblFWUpdateImageFileGuid + gCfgFWUpdateImageFileGuid + gCsmeFWUpdateImageFileGuid [Pcd] gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress diff --git a/PayloadPkg/PayloadPkg.dec b/PayloadPkg/PayloadPkg.dec index 0d874a98..c027e991 100644 --- a/PayloadPkg/PayloadPkg.dec +++ b/PayloadPkg/PayloadPkg.dec @@ -27,9 +27,13 @@ # # GUID defined in package # - gPayloadTokenSpaceGuid = { 0x87cc9b46, 0x6742, 0x40d2, { 0x8b, 0x8b, 0xa4, 0x82, 0x2f, 0xbf, 0x8c, 0x15 } } - gOsLoaderTokenSpaceGuid = { 0x8dfd71db, 0xae65, 0x46d4, {0x88, 0x6c, 0xcc, 0x0e, 0x6d, 0x31, 0xf8, 0x71 } } + gPayloadTokenSpaceGuid = { 0x87cc9b46, 0x6742, 0x40d2, { 0x8b, 0x8b, 0xa4, 0x82, 0x2f, 0xbf, 0x8c, 0x15 } } + gOsLoaderTokenSpaceGuid = { 0x8dfd71db, 0xae65, 0x46d4, {0x88, 0x6c, 0xcc, 0x0e, 0x6d, 0x31, 0xf8, 0x71 } } gFirmwareUpdateImageFileGuid = { 0x1a3eae58, 0xb580, 0x4fef, { 0xac, 0xa3, 0xa1, 0x6d, 0x9e, 0x00, 0xdf, 0x5f } } + gSblFWUpdateImageFileGuid = { 0x605C6813, 0xC2C7, 0x4242, { 0x9C, 0x27, 0x50, 0xA4, 0xC3, 0x63, 0xDB, 0xA4 } } + gCfgFWUpdateImageFileGuid = { 0x66030B7A, 0x47D1, 0x4958, { 0xB7, 0x3D, 0x00, 0xB4, 0x4B, 0x9D, 0xD4, 0xB6 } } + gCsmeFWUpdateImageFileGuid = { 0x43AEF186, 0x0CA5, 0x4230, { 0xB1, 0xBD, 0x19, 0x3F, 0xB4, 0x62, 0x72, 0x01 } } + gCsmeFWUDriverImageFileGuid = { 0x4A467997, 0xA909, 0x4678, { 0x91, 0x0C, 0xE0, 0xFE, 0x1C, 0x90, 0x56, 0xEA } } [PcdsFixedAtBuild, PcdsPatchableInModule] # These will be patched in the FDF file. diff --git a/Silicon/ApollolakePkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c b/Silicon/ApollolakePkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c index b7cd2140..ba20e6bf 100755 --- a/Silicon/ApollolakePkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c +++ b/Silicon/ApollolakePkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c @@ -43,6 +43,29 @@ SPI_FLASH_SERVICE *mFwuSpiService = NULL; +/** + Perform csme Firmware update. + + This function based on the image type id guid from the image header will + call the respective functions to perform capsule update. + + @param[in] CapImage The pointer to the firmware update capsule image. + @param[in] CapImageSize The size of capsule image in bytes. + @param[in] ImageHdr Pointer to fw mgmt capsule Image header + + @retval EFI_SUCCESS Update successful. + @retval other error status from the update routine +**/ +EFI_STATUS +UpdateCsme ( + IN UINT8 *CapImage, + IN UINT32 CapImageSize, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr + ) +{ + return EFI_UNSUPPORTED; +} + /** This function initialized boot media. @@ -177,7 +200,7 @@ MarkBootParitionBpdt ( Computes offset in the BIOS region from the base address. Then it calculates base address of stage1A in the capsule image. - @param[in] FwImage The firmware update 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 @@ -189,14 +212,13 @@ MarkBootParitionBpdt ( EFI_STATUS EFIAPI PlatformGetStage1AOffset ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN BOOLEAN IsBackupPartition, OUT UINT32 *Base, OUT UINT32 *Size ) { EFI_STATUS Status; - FIRMWARE_UPDATE_HEADER *FwUpdHeader; UINT32 Offset; UINT8 *Ptr; UINT32 Index; @@ -218,10 +240,9 @@ PlatformGetStage1AOffset ( // Search for Flash Map signature in image FlashMapPtr = NULL; - FwUpdHeader = (FIRMWARE_UPDATE_HEADER *)FwImage; - Ptr = (UINT8 *)(FwImage + FwUpdHeader->ImageOffset); + Ptr = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER)); BpOffset = IsBackupPartition ? (RgnSize >> 1) : 0; - for (Offset = BpOffset; Offset < FwUpdHeader->ImageSize; Offset += SIZE_4KB) { + for (Offset = BpOffset; Offset < ImageHdr->UpdateImageSize; Offset += SIZE_4KB) { if (*(UINT32 *)(Ptr + Offset + FLASH_MAP_IN_FV_OFFSET) == FLASH_MAP_SIG_HEADER) { // This is flash map FlashMapPtr = (FLASH_MAP *)(Ptr + Offset + FLASH_MAP_IN_FV_OFFSET); @@ -263,7 +284,7 @@ PlatformGetStage1AOffset ( 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] FwImage The firmware update capsule image. + @param[in] ImageHdr Pointer to Fw Mgmt capsule Image header @param[in] FwPolicy Firmware update policy. @param[out] PartitionInfo The detail informaion on the partition to update @@ -273,13 +294,12 @@ PlatformGetStage1AOffset ( EFI_STATUS EFIAPI GetFirmwareUpdateInfo ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN FIRMWARE_UPDATE_POLICY FwPolicy, OUT FIRMWARE_UPDATE_PARTITION **PartitionInfo ) { EFI_STATUS Status; - FIRMWARE_UPDATE_HEADER *Header; FIRMWARE_UPDATE_PARTITION *UpdatePartition; UINT32 AllocateSize; UINT32 ToUpdateAddress; @@ -305,13 +325,12 @@ GetFirmwareUpdateInfo ( return Status; } - Header = (FIRMWARE_UPDATE_HEADER *)FwImage; if (FwPolicy.Fields.UpdatePartitionA == 1) { ToUpdateAddress = 0; } else { ToUpdateAddress = RgnSize >> 1; } - BiosAddress = (UINT8 *)(FwImage + Header->ImageOffset + ToUpdateAddress); + BiosAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + ToUpdateAddress); // // Mark BPDT header to RED, so if update fails in between, we will have a corrupted partition diff --git a/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c b/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c index 06d4dc40..9e5e1613 100644 --- a/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c +++ b/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.c @@ -33,6 +33,29 @@ SPI_FLASH_SERVICE *mFwuSpiService = NULL; UINT32 mFlashSize; +/** + Perform csme Firmware update. + + This function based on the image type id guid from the image header will + call the respective functions to perform capsule update. + + @param[in] CapImage The pointer to the firmware update capsule image. + @param[in] CapImageSize The size of capsule image in bytes. + @param[in] ImageHdr Pointer to fw mgmt capsule Image header + + @retval EFI_SUCCESS Update successful. + @retval other error status from the update routine +**/ +EFI_STATUS +UpdateCsme ( + IN UINT8 *CapImage, + IN UINT32 CapImageSize, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr + ) +{ + return EFI_UNSUPPORTED; +} + /** Platform code to get capsule image for firmware update. @@ -156,7 +179,7 @@ BootMediaErase ( Computes offset in the BIOS region from the base address. Then it calculates base address of stage1A in the capsule image. - @param[in] FwImage The firmware update 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 @@ -168,7 +191,7 @@ BootMediaErase ( EFI_STATUS EFIAPI PlatformGetStage1AOffset ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN BOOLEAN IsBackupPartition, OUT UINT32 *Base, OUT UINT32 *Size @@ -176,7 +199,6 @@ PlatformGetStage1AOffset ( { EFI_STATUS Status; FLASH_MAP *FlashMap; - FIRMWARE_UPDATE_HEADER *FwUpdHeader; if ((Base == NULL) || (Size == NULL)) { return EFI_INVALID_PARAMETER; @@ -205,12 +227,11 @@ PlatformGetStage1AOffset ( // *Base = (UINT32)(FlashMap->RomSize - (0x100000000ULL - *Base)); - FwUpdHeader = (FIRMWARE_UPDATE_HEADER *)FwImage; // // Calculate base address of the component in the capsule image // Capsule image address + bios region offset + offset of the component // - *Base = (UINT32)(FwImage + FwUpdHeader->ImageOffset + *Base); + *Base = (UINT32)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + *Base); return EFI_SUCCESS; } @@ -227,7 +248,7 @@ PlatformGetStage1AOffset ( 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] FwImage The firmware update capsule image. + @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 @@ -237,7 +258,7 @@ PlatformGetStage1AOffset ( EFI_STATUS EFIAPI GetFirmwareUpdateInfo ( - IN UINT8 *FwImage, + IN EFI_FW_MGMT_CAP_IMAGE_HEADER *ImageHdr, IN FIRMWARE_UPDATE_POLICY FwPolicy, OUT FIRMWARE_UPDATE_PARTITION **PartitionInfo ) @@ -253,7 +274,6 @@ GetFirmwareUpdateInfo ( UINT32 CfgDataBase; UINT32 CfgDataSize; UINT8 BootPartition; - FIRMWARE_UPDATE_HEADER *Header; FIRMWARE_UPDATE_PARTITION *UpdatePartition; FIRMWARE_UPDATE_REGION *UpdateRegion; UINT8 Idx; @@ -272,8 +292,7 @@ GetFirmwareUpdateInfo ( ASSERT (UpdatePartition != NULL); UpdatePartition->RegionCount = RegionNumber; - Header = (FIRMWARE_UPDATE_HEADER *)FwImage; - if (Header->CapsuleFlags & CAPSULE_FLAGS_CFG_DATA) { + if (CompareGuid(&ImageHdr->UpdateImageTypeId, &gCfgFWUpdateImageFileGuid) == TRUE) { // // Update CfgData // @@ -286,20 +305,20 @@ GetFirmwareUpdateInfo ( return Status; } - if (Header->ImageSize & 0xFFF) { + if (ImageHdr->UpdateImageSize & 0xFFF) { DEBUG ((DEBUG_INFO, "CFGDATA capsule payload size is not block aligned!")); return EFI_UNSUPPORTED; } - if (Header->ImageSize > CfgDataSize) { + if (ImageHdr->UpdateImageSize > CfgDataSize) { DEBUG ((DEBUG_INFO, "CFGDATA capsule payload size is too big for the region on flash!")); return EFI_UNSUPPORTED; } UpdateRegion = &UpdatePartition->FwRegion[0]; UpdateRegion->ToUpdateAddress = FlashMap->RomSize + CfgDataBase; - UpdateRegion->UpdateSize = Header->ImageSize; - UpdateRegion->SourceAddress = FwImage + Header->ImageOffset; + UpdateRegion->UpdateSize = ImageHdr->UpdateImageSize; + UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER)); UpdatePartition->RegionCount = 1; } else { @@ -347,19 +366,19 @@ GetFirmwareUpdateInfo ( UpdateRegion->ToUpdateAddress = TopSwapRegionOffset - TopSwapRegionSize; } UpdateRegion->UpdateSize = TopSwapRegionSize; - UpdateRegion->SourceAddress = FwImage + Header->ImageOffset + TopSwapRegionOffset; + UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + TopSwapRegionOffset); // Redundant region UpdateRegion = &UpdatePartition->FwRegion[1]; UpdateRegion->ToUpdateAddress = RedundantRegionOffset; UpdateRegion->UpdateSize = RedundantRegionSize; - UpdateRegion->SourceAddress = FwImage + Header->ImageOffset + RedundantRegionOffset; + UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + RedundantRegionOffset); // Non-redundant region UpdateRegion = &UpdatePartition->FwRegion[2]; UpdateRegion->ToUpdateAddress = NonRedundantRegionOffset; UpdateRegion->UpdateSize = NonRedundantRegionSize; - UpdateRegion->SourceAddress = FwImage + Header->ImageOffset + NonRedundantRegionOffset; + UpdateRegion->SourceAddress = (UINT8 *)((UINTN)ImageHdr + sizeof(EFI_FW_MGMT_CAP_IMAGE_HEADER) + NonRedundantRegionOffset); if (BootPartition == 0) { UpdatePartition->RegionCount = 3; diff --git a/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.inf b/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.inf index 30697d54..3d83267a 100644 --- a/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.inf +++ b/Silicon/QemuSocPkg/Library/FirmwareUpdateLib/FirmwareUpdateLib.inf @@ -1,3 +1,4 @@ + ### @file # Boot Partition Descriptor Table library. # @@ -45,6 +46,7 @@ [Guids] gEfiPartTypeSystemPartGuid gOsBootOptionGuid + gCfgFWUpdateImageFileGuid [Pcd] gPlatformModuleTokenSpaceGuid.PcdTopSwapRegionSize