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