From: Duke Zhai <duke.z...@amd.com> BZ #:4640 In V3: Improve coding style follow edk2 C coding standard. 1.Remove macro definition extra underscores. 2.Putting some AMD copyright in the right place.
In V2: Improve coding style. 1.Remove the leading underscore and use double underscore at trailing in C header files. 2.Remove old tianocore licenses and redundant license description. 3.Improve coding style. For example: remove space between @param. In V1: Initial SignedCapsule module for Signed Capsule. Produce FMP instance to update system firmware. Signed-off-by: Ken Yao <ken....@amd.com> Cc: Eric Xing <eric.x...@amd.com> Cc: Duke Zhai <duke.z...@amd.com> Cc: Igniculus Fu <igniculus...@amd.com> Cc: Abner Chang <abner.ch...@amd.com> --- .../BaseTools/Source/Python/GenFds/Capsule.py | 253 +++ .../SystemFirmwareUpdate/ParseConfigProfile.c | 217 +++ .../SystemFirmwareCommonDxe.c | 371 +++++ .../SystemFirmwareUpdate/SystemFirmwareDxe.h | 421 +++++ .../SystemFirmwareUpdateDxe.c | 1426 +++++++++++++++++ .../SystemFirmwareUpdateDxe.inf | 77 + .../SystemFirmwareUpdateDxe.uni | 15 + .../SystemFirmwareUpdateDxeExtra.uni | 15 + 8 files changed, 2795 insertions(+) create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/BaseTools/Source/Python/GenFds/Capsule.py create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/ParseConfigProfile.c create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareCommonDxe.c create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareDxe.h create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.inf create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.uni create mode 100644 Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxeExtra.uni diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/BaseTools/Source/Python/GenFds/Capsule.py b/Platform/AMD/VanGoghBoard/Override/edk2/BaseTools/Source/Python/GenFds/Capsule.py new file mode 100644 index 0000000000..0ec0b3ca43 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/BaseTools/Source/Python/GenFds/Capsule.py @@ -0,0 +1,253 @@ +## @file +# generate capsule +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from .GenFdsGlobalVariable import GenFdsGlobalVariable, FindExtendTool +from CommonDataClass.FdfClass import CapsuleClassObject +import Common.LongFilePathOs as os +from io import BytesIO +from Common.Misc import SaveFileOnChange, PackGUID +import uuid +from struct import pack +from Common import EdkLogger +from Common.BuildToolError import GENFDS_ERROR +from Common.DataType import TAB_LINE_BREAK + +WIN_CERT_REVISION = 0x0200 +WIN_CERT_TYPE_EFI_GUID = 0x0EF1 +EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID('{4aafd29d-68df-49ee-8aa9-347d375665a7}') +EFI_CERT_TYPE_RSA2048_SHA256_GUID = uuid.UUID('{a7717414-c616-4977-9420-844712a735bf}') + +## create inf file describes what goes into capsule and call GenFv to generate capsule +# +# +class Capsule (CapsuleClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + CapsuleClassObject.__init__(self) + # For GenFv + self.BlockSize = None + # For GenFv + self.BlockNum = None + self.CapsuleName = None + + ## Generate FMP capsule + # + # @retval string Generated Capsule file path + # + def GenFmpCapsule(self): + # + # Generate capsule header + # typedef struct { + # EFI_GUID CapsuleGuid; + # UINT32 HeaderSize; + # UINT32 Flags; + # UINT32 CapsuleImageSize; + # } EFI_CAPSULE_HEADER; + # + Header = BytesIO() + # + # Use FMP capsule GUID: 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A + # + Header.write(PackGUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A'.split('-'))) + HdrSize = 0 + if 'CAPSULE_HEADER_SIZE' in self.TokensDict: + Header.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16))) + HdrSize = int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16) + else: + Header.write(pack('=I', 0x20)) + HdrSize = 0x20 + Flags = 0 + if 'CAPSULE_FLAGS' in self.TokensDict: + for flag in self.TokensDict['CAPSULE_FLAGS'].split(','): + flag = flag.strip() + if flag == 'PopulateSystemTable': + Flags |= 0x00010000 | 0x00020000 + elif flag == 'PersistAcrossReset': + Flags |= 0x00010000 + elif flag == 'InitiateReset': + Flags |= 0x00040000 + if 'OEM_CAPSULE_FLAGS' in self.TokensDict: + Flags |= int(self.TokensDict['OEM_CAPSULE_FLAGS'],16) + Header.write(pack('=I', Flags)) + # + # typedef struct { + # UINT32 Version; + # UINT16 EmbeddedDriverCount; + # UINT16 PayloadItemCount; + # // UINT64 ItemOffsetList[]; + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER; + # + FwMgrHdr = BytesIO() + if 'CAPSULE_HEADER_INIT_VERSION' in self.TokensDict: + FwMgrHdr.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_INIT_VERSION'], 16))) + else: + FwMgrHdr.write(pack('=I', 0x00000001)) + FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList))) + FwMgrHdrSize = 4+2+2+8*(len(self.CapsuleDataList)+len(self.FmpPayloadList)) + + # + # typedef struct _WIN_CERTIFICATE { + # UINT32 dwLength; + # UINT16 wRevision; + # UINT16 wCertificateType; + # //UINT8 bCertificate[ANYSIZE_ARRAY]; + # } WIN_CERTIFICATE; + # + # typedef struct _WIN_CERTIFICATE_UEFI_GUID { + # WIN_CERTIFICATE Hdr; + # EFI_GUID CertType; + # //UINT8 CertData[ANYSIZE_ARRAY]; + # } WIN_CERTIFICATE_UEFI_GUID; + # + # typedef struct { + # UINT64 MonotonicCount; + # WIN_CERTIFICATE_UEFI_GUID AuthInfo; + # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; + # + # typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 { + # EFI_GUID HashType; + # UINT8 PublicKey[256]; + # UINT8 Signature[256]; + # } EFI_CERT_BLOCK_RSA_2048_SHA256; + # + + PreSize = FwMgrHdrSize + Content = BytesIO() + for driver in self.CapsuleDataList: + FileName = driver.GenCapsuleSubItem() + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += os.path.getsize(FileName) + File = open(FileName, 'rb') + Content.write(File.read()) + File.close() + for fmp in self.FmpPayloadList: + if fmp.Existed: + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += len(fmp.Buffer) + Content.write(fmp.Buffer) + continue + if fmp.ImageFile: + for Obj in fmp.ImageFile: + fmp.ImageFile = Obj.GenCapsuleSubItem() + if fmp.VendorCodeFile: + for Obj in fmp.VendorCodeFile: + fmp.VendorCodeFile = Obj.GenCapsuleSubItem() + if fmp.Certificate_Guid: + ExternalTool, ExternalOption = FindExtendTool([], GenFdsGlobalVariable.ArchList, fmp.Certificate_Guid) + CmdOption = '' + CapInputFile = fmp.ImageFile + if not os.path.isabs(fmp.ImageFile): + CapInputFile = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, fmp.ImageFile) + CapOutputTmp = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.tmp' + if ExternalTool is None: + EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % fmp.Certificate_Guid) + else: + CmdOption += ExternalTool + if ExternalOption: + CmdOption = CmdOption + ' ' + ExternalOption + CmdOption += ' -e ' + ' --monotonic-count ' + str(fmp.MonotonicCount) + ' -o ' + CapOutputTmp + ' ' + CapInputFile + CmdList = CmdOption.split() + GenFdsGlobalVariable.CallExternalTool(CmdList, "Failed to generate FMP auth capsule") + if uuid.UUID(fmp.Certificate_Guid) == EFI_CERT_TYPE_PKCS7_GUID: + dwLength = 4 + 2 + 2 + 16 + os.path.getsize(CapOutputTmp) - os.path.getsize(CapInputFile) + else: + dwLength = 4 + 2 + 2 + 16 + 16 + 256 + 256 + fmp.ImageFile = CapOutputTmp + AuthData = [fmp.MonotonicCount, dwLength, WIN_CERT_REVISION, WIN_CERT_TYPE_EFI_GUID, fmp.Certificate_Guid] + fmp.Buffer = fmp.GenCapsuleSubItem(AuthData) + else: + fmp.Buffer = fmp.GenCapsuleSubItem() + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += len(fmp.Buffer) + Content.write(fmp.Buffer) + BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue()) + Header.write(pack('=I', HdrSize + BodySize)) + # + # The real capsule header structure is 28 bytes + # + Header.write(b'\x00'*(HdrSize-28)) + Header.write(FwMgrHdr.getvalue()) + Header.write(Content.getvalue()) + # + # Generate FMP capsule file + # + CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.Cap' + SaveFileOnChange(CapOutputFile, Header.getvalue(), True) + return CapOutputFile + + ## Generate capsule + # + # @param self The object pointer + # @retval string Generated Capsule file path + # + def GenCapsule(self): + if self.UiCapsuleName.upper() + 'cap' in GenFdsGlobalVariable.ImageBinDict: + return GenFdsGlobalVariable.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] + + GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName) + if ('CAPSULE_GUID' in self.TokensDict and + uuid.UUID(self.TokensDict['CAPSULE_GUID']) == uuid.UUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')): + return self.GenFmpCapsule() + + CapInfFile = self.GenCapInf() + CapInfFile.append("[files]" + TAB_LINE_BREAK) + CapFileList = [] + for CapsuleDataObj in self.CapsuleDataList: + CapsuleDataObj.CapsuleName = self.CapsuleName + FileName = CapsuleDataObj.GenCapsuleSubItem() + CapsuleDataObj.CapsuleName = None + CapFileList.append(FileName) + CapInfFile.append("EFI_FILE_NAME = " + \ + FileName + \ + TAB_LINE_BREAK) + SaveFileOnChange(self.CapInfFileName, ''.join(CapInfFile), False) + # + # Call GenFv tool to generate capsule + # + CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + CapOutputFile = CapOutputFile + '.Cap' + GenFdsGlobalVariable.GenerateFirmwareVolume( + CapOutputFile, + [self.CapInfFileName], + Capsule=True, + FfsList=CapFileList + ) + + GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s Capsule Successfully" %self.UiCapsuleName) + GenFdsGlobalVariable.SharpCounter = 0 + GenFdsGlobalVariable.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] = CapOutputFile + return CapOutputFile + + ## Generate inf file for capsule + # + # @param self The object pointer + # @retval file inf file object + # + def GenCapInf(self): + self.CapInfFileName = os.path.join(GenFdsGlobalVariable.FvDir, + self.UiCapsuleName + "_Cap" + '.inf') + CapInfFile = [] + + CapInfFile.append("[options]" + TAB_LINE_BREAK) + + for Item in self.TokensDict: + CapInfFile.append("EFI_" + \ + Item + \ + ' = ' + \ + self.TokensDict[Item] + \ + TAB_LINE_BREAK) + + return CapInfFile diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/ParseConfigProfile.c b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/ParseConfigProfile.c new file mode 100644 index 0000000000..bfd4e876f3 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/ParseConfigProfile.c @@ -0,0 +1,217 @@ +/** @file + Implements ParseConfigProfile.c + Parse the INI configuration file and pass the information to the update driver + so that the driver can perform update accordingly. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SystemFirmwareDxe.h" +#include <Library/IniParsingLib.h> +#include <Library/PrintLib.h> + +#define MAX_LINE_LENGTH 512 + +/** + Parse Config data file to get the updated data array. + + @param[in] DataBuffer Config raw file buffer. + @param[in] BufferSize Size of raw buffer. + @param[in, out] ConfigHeader Pointer to the config header. + @param[in, out] UpdateArray Pointer to the config of update data. + + @retval EFI_NOT_FOUND No config data is found. + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Parse the config file successfully. + +**/ +EFI_STATUS +ParseUpdateDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT CONFIG_HEADER *ConfigHeader, + IN OUT UPDATE_CONFIG_DATA **UpdateArray + ) +{ + EFI_STATUS Status; + CHAR8 *SectionName; + CHAR8 Entry[MAX_LINE_LENGTH]; + UINTN Num; + UINT64 Num64; + UINTN Index; + EFI_GUID FileGuid; + VOID *Context; + + // + // First process the data buffer and get all sections and entries + // + Context = OpenIniFile (DataBuffer, BufferSize); + if (Context == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Now get NumOfUpdate + // + Status = GetDecimalUintnFromDataFile ( + Context, + "Head", + "NumOfUpdate", + &Num + ); + if (EFI_ERROR (Status) || (Num == 0)) { + DEBUG ((DEBUG_ERROR, "NumOfUpdate not found\n")); + CloseIniFile (Context); + return EFI_NOT_FOUND; + } + + ConfigHeader->NumOfUpdates = Num; + *UpdateArray = AllocateZeroPool ((sizeof (UPDATE_CONFIG_DATA) * Num)); + if (*UpdateArray == NULL) { + CloseIniFile (Context); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < ConfigHeader->NumOfUpdates; Index++) { + // + // Get the section name of each update + // + AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update"); + AsciiValueToStringS ( + Entry + AsciiStrnLenS (Entry, MAX_LINE_LENGTH), + MAX_LINE_LENGTH - AsciiStrnLenS (Entry, MAX_LINE_LENGTH), + 0, + Index, + 0 + ); + Status = GetStringFromDataFile ( + Context, + "Head", + Entry, + &SectionName + ); + if (EFI_ERROR (Status) || (SectionName == NULL)) { + DEBUG ((DEBUG_ERROR, "[%d] %a not found\n", Index, Entry)); + CloseIniFile (Context); + return EFI_NOT_FOUND; + } + + // + // The section name of this update has been found. + // Now looks for all the config data of this update + // + (*UpdateArray)[Index].Index = Index; + + // + // FirmwareType + // + Status = GetDecimalUintnFromDataFile ( + Context, + SectionName, + "FirmwareType", + &Num + ); + if (EFI_ERROR (Status)) { + CloseIniFile (Context); + DEBUG ((DEBUG_ERROR, "[%d] FirmwareType not found\n", Index)); + return EFI_NOT_FOUND; + } + + (*UpdateArray)[Index].FirmwareType = (PLATFORM_FIRMWARE_TYPE)Num; + + // + // AddressType + // + Status = GetDecimalUintnFromDataFile ( + Context, + SectionName, + "AddressType", + &Num + ); + if (EFI_ERROR (Status)) { + CloseIniFile (Context); + DEBUG ((DEBUG_ERROR, "[%d] AddressType not found\n", Index)); + return EFI_NOT_FOUND; + } + + (*UpdateArray)[Index].AddressType = (FLASH_ADDRESS_TYPE)Num; + + // + // BaseAddress + // + Status = GetHexUint64FromDataFile ( + Context, + SectionName, + "BaseAddress", + &Num64 + ); + if (EFI_ERROR (Status)) { + CloseIniFile (Context); + DEBUG ((DEBUG_ERROR, "[%d] BaseAddress not found\n", Index)); + return EFI_NOT_FOUND; + } + + (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS)Num64; + + // + // FileBuid + // + Status = GetGuidFromDataFile ( + Context, + SectionName, + "FileGuid", + &FileGuid + ); + if (EFI_ERROR (Status)) { + CloseIniFile (Context); + DEBUG ((DEBUG_ERROR, "[%d] FileGuid not found\n", Index)); + return EFI_NOT_FOUND; + } + + CopyGuid (&((*UpdateArray)[Index].FileGuid), &FileGuid); + + // + // Length + // + Status = GetHexUintnFromDataFile ( + Context, + SectionName, + "Length", + &Num + ); + if (EFI_ERROR (Status)) { + CloseIniFile (Context); + DEBUG ((DEBUG_ERROR, "[%d] Length not found\n", Index)); + return EFI_NOT_FOUND; + } + + (*UpdateArray)[Index].Length = (UINTN)Num; + + // + // ImageOffset + // + Status = GetHexUintnFromDataFile ( + Context, + SectionName, + "ImageOffset", + &Num + ); + if (EFI_ERROR (Status)) { + CloseIniFile (Context); + DEBUG ((DEBUG_ERROR, "[%d] ImageOffset not found\n", Index)); + return EFI_NOT_FOUND; + } + + (*UpdateArray)[Index].ImageOffset = (UINTN)Num; + } + + // + // Now all configuration data got. Free those temporary buffers + // + CloseIniFile (Context); + + return EFI_SUCCESS; +} diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareCommonDxe.c b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareCommonDxe.c new file mode 100644 index 0000000000..05a36162d3 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareCommonDxe.c @@ -0,0 +1,371 @@ +/** @file + Produce FMP instance for system firmware. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SystemFirmwareDxe.h" + +EFI_GUID gSystemFmpLastAttemptVariableGuid = SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_GUID; +EFI_GUID gSystemFmpProtocolGuid = SYSTEM_FMP_PROTOCOL_GUID; + +EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = { + FmpGetImageInfo, + FmpGetImage, + FmpSetImage, + FmpCheckImage, + FmpGetPackageInfo, + FmpSetPackageInfo +}; + +/** + Returns information about the current firmware image(s) of the device. + + This function allows a copy of the current firmware image to be created and saved. + The saved copy could later been used, for example, in firmware image recovery or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer. + On input, this is the size of the buffer allocated by the caller. + On output, it is the size of the buffer returned by the firmware + if the buffer was large enough, or the size of the buffer needed + to contain the image(s) information if the buffer was too small. + @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s) + information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number + associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] DescriptorCount A pointer to the location in which firmware returns the number of + descriptors or firmware images within this device. + @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes, + of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] PackageVersion A version number that represents all the firmware images in the device. + The format is vendor specific and new version must have a greater value + than the old version. If PackageVersion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison + is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates + that package version update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the + package version name. The buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility to free it with a call + to FreePool(). + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size + needed to hold the image(s) information is returned in ImageInfoSize. + @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL. + @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image. + +**/ +EFI_STATUS +EFIAPI +FmpGetImageInfo ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN OUT UINTN *ImageInfoSize, + IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + OUT UINT32 *DescriptorVersion, + OUT UINT8 *DescriptorCount, + OUT UINTN *DescriptorSize, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName + ) +{ + SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate; + EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor; + + SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP (This); + + if (ImageInfoSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*ImageInfoSize < sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR) * SystemFmpPrivate->DescriptorCount) { + *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR) * SystemFmpPrivate->DescriptorCount; + return EFI_BUFFER_TOO_SMALL; + } + + if ((ImageInfo == NULL) || + (DescriptorVersion == NULL) || + (DescriptorCount == NULL) || + (DescriptorSize == NULL) || + (PackageVersion == NULL) || + (PackageVersionName == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR) * SystemFmpPrivate->DescriptorCount; + *DescriptorSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR); + *DescriptorCount = SystemFmpPrivate->DescriptorCount; + *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; + + // + // supports 1 ImageInfo descriptor + // + ImageDescriptor = SystemFmpPrivate->ImageDescriptor; + ImageInfo->ImageIndex = ImageDescriptor->ImageIndex; + CopyGuid (&ImageInfo->ImageTypeId, &ImageDescriptor->ImageTypeId); + ImageInfo->ImageId = ImageDescriptor->ImageId; + if (ImageDescriptor->ImageIdNameStringOffset != 0) { + ImageInfo->ImageIdName = (CHAR16 *)((UINTN)ImageDescriptor + ImageDescriptor->ImageIdNameStringOffset); + } else { + ImageInfo->ImageIdName = NULL; + } + + ImageInfo->Version = ImageDescriptor->Version; + if (ImageDescriptor->VersionNameStringOffset != 0) { + ImageInfo->VersionName = (CHAR16 *)((UINTN)ImageDescriptor + ImageDescriptor->VersionNameStringOffset); + } else { + ImageInfo->VersionName = NULL; + } + + ImageInfo->Size = (UINTN)ImageDescriptor->Size; + ImageInfo->AttributesSupported = ImageDescriptor->AttributesSupported; + ImageInfo->AttributesSetting = ImageDescriptor->AttributesSetting; + ImageInfo->Compatibilities = ImageDescriptor->Compatibilities; + ImageInfo->LowestSupportedImageVersion = ImageDescriptor->LowestSupportedImageVersion; + ImageInfo->LastAttemptVersion = SystemFmpPrivate->LastAttempt.LastAttemptVersion; + ImageInfo->LastAttemptStatus = SystemFmpPrivate->LastAttempt.LastAttemptStatus; + ImageInfo->HardwareInstance = ImageDescriptor->HardwareInstance; + + // + // package version + // + *PackageVersion = ImageDescriptor->PackageVersion; + if (ImageDescriptor->PackageVersionNameStringOffset != 0) { + *PackageVersionName = (VOID *)((UINTN)ImageDescriptor + ImageDescriptor->PackageVersionNameStringOffset); + *PackageVersionName = AllocateCopyPool (StrSize (*PackageVersionName), *PackageVersionName); + } else { + *PackageVersionName = NULL; + } + + return EFI_SUCCESS; +} + +/** + Retrieves a copy of the current firmware image of the device. + + This function allows a copy of the current firmware image to be created and saved. + The saved copy could later been used, for example, in firmware image recovery or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] ImageIndex A unique number identifying the firmware image(s) within the device. + The number is between 1 and DescriptorCount. + @param[in,out] Image Points to the buffer where the current image is copied to. + @param[in,out] ImageSize On entry, points to the size of the buffer pointed to by Image, in bytes. + On return, points to the length of the image, in bytes. + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the + image. The current buffer size needed to hold the image is returned + in ImageSize. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_NOT_FOUND The current image is not copied to the buffer. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpGetImage ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Checks if the firmware image is valid for the device. + + This function allows firmware update application to validate the firmware image without + invoking the SetImage() first. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] ImageIndex A unique number identifying the firmware image(s) within the device. + The number is between 1 and DescriptorCount. + @param[in] Image Points to the new image. + @param[in] ImageSize Size of the new image in bytes. + @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides, + if available, additional information if the image is invalid. + + @retval EFI_SUCCESS The image was successfully checked. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpCheckImage ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *ImageUpdatable + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Returns information about the firmware package. + + This function returns package information. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[out] PackageVersion A version number that represents all the firmware images in the device. + The format is vendor specific and new version must have a greater value + than the old version. If PackageVersion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version + comparison is to be performed using PackageVersionName. A value of + 0xFFFFFFFD indicates that package version update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing + the package version name. The buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility to free it with a + call to FreePool(). + @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of + package version name. A value of 0 indicates the device does not support + update of package version name. Length is the number of Unicode characters, + including the terminating null character. + @param[out] AttributesSupported Package attributes that are supported by this device. See 'Package Attribute + Definitions' for possible returned values of this parameter. A value of 1 + indicates the attribute is supported and the current setting value is + indicated in AttributesSetting. A value of 0 indicates the attribute is not + supported and the current setting value in AttributesSetting is meaningless. + @param[out] AttributesSetting Package attributes. See 'Package Attribute Definitions' for possible returned + values of this parameter + + @retval EFI_SUCCESS The package information was successfully returned. + @retval EFI_UNSUPPORTED The operation is not supported. + +**/ +EFI_STATUS +EFIAPI +FmpGetPackageInfo ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName, + OUT UINT32 *PackageVersionNameMaxLen, + OUT UINT64 *AttributesSupported, + OUT UINT64 *AttributesSetting + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Updates information about the firmware package. + + This function updates package information. + This function returns EFI_UNSUPPORTED if the package information is not updatable. + VendorCode enables vendor to implement vendor-specific package information update policy. + Null if the caller did not specify this policy or use the default policy. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] Image Points to the authentication image. + Null if authentication is not required. + @param[in] ImageSize Size of the authentication image in bytes. + 0 if authentication is not required. + @param[in] VendorCode This enables vendor to implement vendor-specific firmware + image update policy. + Null indicates the caller did not specify this policy or use + the default policy. + @param[in] PackageVersion The new package version. + @param[in] PackageVersionName A pointer to the new null-terminated Unicode string representing + the package version name. + The string length is equal to or less than the value returned in + PackageVersionNameMaxLen. + + @retval EFI_SUCCESS The device was successfully updated with the new package + information. + @retval EFI_INVALID_PARAMETER The PackageVersionName length is longer than the value + returned in PackageVersionNameMaxLen. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpSetPackageInfo ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN UINT32 PackageVersion, + IN CONST CHAR16 *PackageVersionName + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Initialize SystemFmpDriver private data structure. + + @param[in] SystemFmpPrivate private data structure to be initialized. + + @return EFI_SUCCESS private data is initialized. +**/ +EFI_STATUS +InitializePrivateData ( + IN SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate + ) +{ + EFI_STATUS VarStatus; + UINTN VarSize; + + SystemFmpPrivate->Signature = SYSTEM_FMP_PRIVATE_DATA_SIGNATURE; + SystemFmpPrivate->Handle = NULL; + SystemFmpPrivate->DescriptorCount = 1; + CopyMem (&SystemFmpPrivate->Fmp, &mFirmwareManagementProtocol, sizeof (EFI_FIRMWARE_MANAGEMENT_PROTOCOL)); + + SystemFmpPrivate->ImageDescriptor = PcdGetPtr (PcdEdkiiSystemFirmwareImageDescriptor); + + SystemFmpPrivate->LastAttempt.LastAttemptVersion = 0x0; + SystemFmpPrivate->LastAttempt.LastAttemptStatus = 0x0; + VarSize = sizeof (SystemFmpPrivate->LastAttempt); + VarStatus = gRT->GetVariable ( + SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME, + &gSystemFmpLastAttemptVariableGuid, + NULL, + &VarSize, + &SystemFmpPrivate->LastAttempt + ); + DEBUG ((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus)); + DEBUG ((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus)); + + return EFI_SUCCESS; +} + +/** + Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo. + + @param[in] FmpImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR + + @retval TRUE It is a system FMP. + @retval FALSE It is a device FMP. +**/ +BOOLEAN +IsSystemFmp ( + IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfo + ) +{ + GUID *Guid; + UINTN Count; + UINTN Index; + + Guid = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid); + Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof (GUID); + + for (Index = 0; Index < Count; Index++, Guid++) { + if (CompareGuid (&FmpImageInfo->ImageTypeId, Guid)) { + return TRUE; + } + } + + return FALSE; +} diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareDxe.h b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareDxe.h new file mode 100644 index 0000000000..431d725914 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareDxe.h @@ -0,0 +1,421 @@ +/** @file + System Firmware update header file. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SYSTEM_FIRMWARE_UPDATE_H_ +#define SYSTEM_FIRMWARE_UPDATE_H_ + +#include <PiDxe.h> + +#include <Guid/SystemResourceTable.h> +#include <Guid/FirmwareContentsSigned.h> +#include <Guid/WinCertificate.h> +#include <Guid/EdkiiSystemFmpCapsule.h> + +#include <Protocol/FirmwareManagement.h> +#include <Protocol/FirmwareVolumeBlock.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/DevicePathLib.h> +#include <Library/HobLib.h> +#include <Library/DxeServicesLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/PlatformFlashAccessLib.h> +#include <Library/EdkiiSystemCapsuleLib.h> +#include <Library/AmdPspBaseLibV2.h> +#include <OtaCapsuleUpdate.h> + +typedef struct { + UINT32 LastAttemptVersion; + UINT32 LastAttemptStatus; +} SYSTEM_FMP_LAST_ATTEMPT_VARIABLE; + +#define SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME L"SystemLastAttempVar" + +#define SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_GUID {0x2f564d6f, 0xcc2c, 0x4838, { 0xb9, 0xa8, 0xbe, 0x59, 0x48, 0xb0, 0x3d, 0x59 }} + +#define SYSTEM_FMP_PRIVATE_DATA_SIGNATURE SIGNATURE_32('S', 'Y', 'S', 'F') + +#define SYSTEM_FMP_PROTOCOL_GUID {0x6d16624a, 0x26a6, 0x4cb4, { 0x84, 0xfa, 0x6, 0x78, 0x5a, 0x7e, 0x82, 0x6a }} + +// +// SYSTEM FMP private data structure. +// + +struct _SYSTEM_FMP_PRIVATE_DATA { + UINT32 Signature; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL Fmp; + EFI_HANDLE Handle; + UINT8 DescriptorCount; + EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor; + SYSTEM_FMP_LAST_ATTEMPT_VARIABLE LastAttempt; +}; + +typedef struct _SYSTEM_FMP_PRIVATE_DATA SYSTEM_FMP_PRIVATE_DATA; + +/** + Returns a pointer to the SYSTEM_FMP_PRIVATE_DATA structure from the input a as Fmp. + + If the signatures matches, then a pointer to the data structure that contains + a specified field of that data structure is returned. + + @param a Pointer to the field specified by ServiceBinding within + a data structure of type SYSTEM_FMP_PRIVATE_DATA. + +**/ +#define SYSTEM_FMP_PRIVATE_DATA_FROM_FMP(a) \ + CR ( \ + (a), \ + SYSTEM_FMP_PRIVATE_DATA, \ + Fmp, \ + SYSTEM_FMP_PRIVATE_DATA_SIGNATURE \ + ) + +// +// Update data +// + +typedef struct { + UINTN NumOfUpdates; +} CONFIG_HEADER; + +typedef struct { + UINTN Index; + PLATFORM_FIRMWARE_TYPE FirmwareType; + FLASH_ADDRESS_TYPE AddressType; + EFI_GUID FileGuid; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINTN Length; + UINTN ImageOffset; +} UPDATE_CONFIG_DATA; + +// +// System Firmware Update SMM Communication +// + +#define SYSTEM_FIRMWARE_UPDATE_COMMUNICATION_FUNCTION_SET_IMAGE 1 + +typedef struct { + UINTN Function; + EFI_STATUS ReturnStatus; + // UINT8 Data[]; +} SYSTEM_FIRMWARE_UPDATE_COMMUNICATION_HEAD; + +#define ABORT_REASON_MAX_SIZE 0x40 // UnicodeStringSize including final L'\0' + +#define CAPSULE_IMAGE_ADDITIONAL_MAX_SIZE (0x20020 + 0xA0000) // Addtional size for Capsule Header, FV block alignment + DispatchImage. + +typedef struct { + UINT8 ImageIndex; + UINTN ImageSize; + UINTN AbortReasonSize; + UINT32 LastAttemptVersion; + UINT32 LastAttemptStatus; + // UINT8 Data[AbortReasonMaxSize + ImageSize]; +} SYSTEM_FIRMWARE_UPDATE_COMMUNICATION_SET_IMAGE; + +/* +Name Offset(byte) Size(byte) Comments +SlotA_Priority 0x0 4 Read and Write the Slot A priority +SlotA_UpdateRetries 0x4 4 Read and Write the Slot A retries +SlotA_GlitchRetries 0x8 4 Read only, Slot A glitch +SlotB_Priority 0xC 4 Read and Write the Slot B priority +SlotB_UpdateRetries 0x10 4 Read and Write the Slot B retries +SlotB_GlitchRetries 0x14 4 Read only, Slot B glitch + +*/ +typedef struct { + UINT32 SlotA_Priority; + UINT32 SlotA_UpdateRetries; + UINT32 SlotA_GlitchRetries; + UINT32 SlotB_Priority; + UINT32 SlotB_UpdateRetries; + UINT32 SlotB_GlitchRetries; +} IMAGE_SLOT_HEADER_INFO; + +/** + Returns information about the current firmware image(s) of the device. + + This function allows a copy of the current firmware image to be created and saved. + The saved copy could later been used, for example, in firmware image recovery or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer. + On input, this is the size of the buffer allocated by the caller. + On output, it is the size of the buffer returned by the firmware + if the buffer was large enough, or the size of the buffer needed + to contain the image(s) information if the buffer was too small. + @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s) + information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number + associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] DescriptorCount A pointer to the location in which firmware returns the number of + descriptors or firmware images within this device. + @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes, + of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] PackageVersion A version number that represents all the firmware images in the device. + The format is vendor specific and new version must have a greater value + than the old version. If PackageVersion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison + is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates + that package version update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the + package version name. The buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility to free it with a call + to FreePool(). + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size + needed to hold the image(s) information is returned in ImageInfoSize. + @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL. + @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image. + +**/ +EFI_STATUS +EFIAPI +FmpGetImageInfo ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN OUT UINTN *ImageInfoSize, + IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + OUT UINT32 *DescriptorVersion, + OUT UINT8 *DescriptorCount, + OUT UINTN *DescriptorSize, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName + ); + +/** + Retrieves a copy of the current firmware image of the device. + + This function allows a copy of the current firmware image to be created and saved. + The saved copy could later been used, for example, in firmware image recovery or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] ImageIndex A unique number identifying the firmware image(s) within the device. + The number is between 1 and DescriptorCount. + @param[in,out] Image Points to the buffer where the current image is copied to. + @param[in,out] ImageSize On entry, points to the size of the buffer pointed to by Image, in bytes. + On return, points to the length of the image, in bytes. + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the + image. The current buffer size needed to hold the image is returned + in ImageSize. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_NOT_FOUND The current image is not copied to the buffer. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpGetImage ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ); + +/** + Updates the firmware image of the device. + + This function updates the hardware with the new firmware image. + This function returns EFI_UNSUPPORTED if the firmware image is not updatable. + If the firmware image is updatable, the function should perform the following minimal validations + before proceeding to do the firmware image update. + - Validate the image authentication if image has attribute + IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns + EFI_SECURITY_VIOLATION if the validation fails. + - Validate the image is a supported image for this device. The function returns EFI_ABORTED if + the image is unsupported. The function can optionally provide more detailed information on + why the image is not a supported image. + - Validate the data from VendorCode if not null. Image validation must be performed before + VendorCode data validation. VendorCode data is ignored or considered invalid if image + validation failed. The function returns EFI_ABORTED if the data is invalid. + + VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if + the caller did not specify the policy or use the default policy. As an example, vendor can implement + a policy to allow an option to force a firmware image update when the abort reason is due to the new + firmware image version is older than the current firmware image version or bad image checksum. + Sensitive operations such as those wiping the entire firmware image and render the device to be + non-functional should be encoded in the image itself rather than passed with the VendorCode. + AbortReason enables vendor to have the option to provide a more detailed description of the abort + reason to the caller. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] ImageIndex A unique number identifying the firmware image(s) within the device. + The number is between 1 and DescriptorCount. + @param[in] Image Points to the new image. + @param[in] ImageSize Size of the new image in bytes. + @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy. + Null indicates the caller did not specify the policy or use the default policy. + @param[in] Progress A function used by the driver to report the progress of the firmware update. + @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more + details for the aborted operation. The buffer is allocated by this function + with AllocatePool(), and it is the caller's responsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_ABORTED The operation is aborted. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpSetImage ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, + OUT CHAR16 **AbortReason + ); + +/** + Checks if the firmware image is valid for the device. + + This function allows firmware update application to validate the firmware image without + invoking the SetImage() first. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] ImageIndex A unique number identifying the firmware image(s) within the device. + The number is between 1 and DescriptorCount. + @param[in] Image Points to the new image. + @param[in] ImageSize Size of the new image in bytes. + @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides, + if available, additional information if the image is invalid. + + @retval EFI_SUCCESS The image was successfully checked. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpCheckImage ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *ImageUpdatable + ); + +/** + Returns information about the firmware package. + + This function returns package information. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[out] PackageVersion A version number that represents all the firmware images in the device. + The format is vendor specific and new version must have a greater value + than the old version. If PackageVersion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version + comparison is to be performed using PackageVersionName. A value of + 0xFFFFFFFD indicates that package version update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing + the package version name. The buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility to free it with a + call to FreePool(). + @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of + package version name. A value of 0 indicates the device does not support + update of package version name. Length is the number of Unicode characters, + including the terminating null character. + @param[out] AttributesSupported Package attributes that are supported by this device. See 'Package Attribute + Definitions' for possible returned values of this parameter. A value of 1 + indicates the attribute is supported and the current setting value is + indicated in AttributesSetting. A value of 0 indicates the attribute is not + supported and the current setting value in AttributesSetting is meaningless. + @param[out] AttributesSetting Package attributes. See 'Package Attribute Definitions' for possible returned + values of this parameter + + @retval EFI_SUCCESS The package information was successfully returned. + @retval EFI_UNSUPPORTED The operation is not supported. + +**/ +EFI_STATUS +EFIAPI +FmpGetPackageInfo ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + OUT UINT32 *PackageVersion, + OUT CHAR16 **PackageVersionName, + OUT UINT32 *PackageVersionNameMaxLen, + OUT UINT64 *AttributesSupported, + OUT UINT64 *AttributesSetting + ); + +/** + Updates information about the firmware package. + + This function updates package information. + This function returns EFI_UNSUPPORTED if the package information is not updatable. + VendorCode enables vendor to implement vendor-specific package information update policy. + Null if the caller did not specify this policy or use the default policy. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] Image Points to the authentication image. + Null if authentication is not required. + @param[in] ImageSize Size of the authentication image in bytes. + 0 if authentication is not required. + @param[in] VendorCode This enables vendor to implement vendor-specific firmware + image update policy. + Null indicates the caller did not specify this policy or use + the default policy. + @param[in] PackageVersion The new package version. + @param[in] PackageVersionName A pointer to the new null-terminated Unicode string representing + the package version name. + The string length is equal to or less than the value returned in + PackageVersionNameMaxLen. + + @retval EFI_SUCCESS The device was successfully updated with the new package + information. + @retval EFI_INVALID_PARAMETER The PackageVersionName length is longer than the value + returned in PackageVersionNameMaxLen. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpSetPackageInfo ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN UINT32 PackageVersion, + IN CONST CHAR16 *PackageVersionName + ); + +/** + Initialize SystemFmpDriver private data structure. + + @param[in] SystemFmpPrivate private data structure to be initialized. + + @return EFI_SUCCESS private data is initialized. +**/ +EFI_STATUS +InitializePrivateData ( + IN SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate + ); + +extern EFI_GUID gSystemFmpLastAttemptVariableGuid; +extern EFI_GUID mCurrentImageTypeId; +extern EFI_GUID gSystemFmpProtocolGuid; + +#endif diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c new file mode 100644 index 0000000000..894d363de0 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c @@ -0,0 +1,1426 @@ +/** @file + SetImage instance to update system firmware. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SystemFirmwareDxe.h" + +// +// SystemFmp driver private data +// +SYSTEM_FMP_PRIVATE_DATA *mSystemFmpPrivate = NULL; + +EFI_GUID mCurrentImageTypeId; + +BOOLEAN mNvRamUpdated = FALSE; + +UINT8 mUpdateSlot = 0; + +/** + Parse Config data file to get the updated data array. + + @param[in] DataBuffer Config raw file buffer. + @param[in] BufferSize Size of raw buffer. + @param[in, out] ConfigHeader Pointer to the config header. + @param[in, out] UpdateArray Pointer to the config of update data. + + @retval EFI_NOT_FOUND No config data is found. + @retval EFI_OUT_OF_RESOURCES No enough memory is allocated. + @retval EFI_SUCCESS Parse the config file successfully. + +**/ +EFI_STATUS +ParseUpdateDataFile ( + IN UINT8 *DataBuffer, + IN UINTN BufferSize, + IN OUT CONFIG_HEADER *ConfigHeader, + IN OUT UPDATE_CONFIG_DATA **UpdateArray + ); + +/** + Update System Firmware image component. + + @param[in] SystemFirmwareImage Points to the System Firmware image. + @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes. + @param[in] ConfigData Points to the component configuration structure. + @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] Progress A function used by the driver to report the progress of the firmware update. + @param[in] StartPercentage The start completion percentage value that may be used to report progress during the flash write operation. + @param[in] EndPercentage The end completion percentage value that may be used to report progress during the flash write operation. + + @retval EFI_SUCCESS The System Firmware image is updated. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +PerformUpdate ( + IN VOID *SystemFirmwareImage, + IN UINTN SystemFirmwareImageSize, + IN UPDATE_CONFIG_DATA *ConfigData, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, + IN UINTN StartPercentage, + IN UINTN EndPercentage + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "PlatformUpdate:")); + DEBUG ((DEBUG_INFO, " BaseAddress - 0x%lx,", ConfigData->BaseAddress)); + DEBUG ((DEBUG_INFO, " ImageOffset - 0x%x,", ConfigData->ImageOffset)); + DEBUG ((DEBUG_INFO, " Legnth - 0x%x\n", ConfigData->Length)); + if (Progress != NULL) { + Progress (StartPercentage); + } + + Status = PerformFlashWriteWithProgress ( + ConfigData->FirmwareType, + ConfigData->BaseAddress, + ConfigData->AddressType, + (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset), + ConfigData->Length, + Progress, + StartPercentage, + EndPercentage + ); + if (Progress != NULL) { + Progress (EndPercentage); + } + + if (!EFI_ERROR (Status)) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + if (ConfigData->FirmwareType == PlatformFirmwareTypeNvRam) { + mNvRamUpdated = TRUE; + } + } else { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + + return Status; +} + +/** + Get layout of system firmware image. + + @param[in] SystemFirmwareImage Points to the System firmware image. + @param[out] SlotAOffset Points to the offste of slot A image. + @param[out] SlotBOffset Points to the offste of slot B image. + + @retval EFI_SUCCESS Get system firmware image layout successfully. + @retval others Some error occurs when executing this routine. + +**/ +EFI_STATUS +GetImageLayout ( + IN VOID *SystemFirmwareImage, + OUT UINT32 *SlotAOffset, + OUT UINT32 *SlotBOffset, + OUT UINT8 *ActiveSlot + ) +{ + FIRMWARE_ENTRY_TABLEV2 *EfsAddressPtr; + PSP_DIRECTORY *PspL1DirectoryPtr; + UINT32 SlotCount; + UINT32 Index; + IMAGE_SLOT_HEADER *IshSlotAInfoPtr; + IMAGE_SLOT_HEADER *IshSlotBInfoPtr; + + if (SystemFirmwareImage == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((SlotAOffset == NULL) || (SlotBOffset == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check EFS structure of firmware image + // + EfsAddressPtr = (FIRMWARE_ENTRY_TABLEV2 *)(UINTN)((UINT8 *)SystemFirmwareImage + EFS_LOCATION); + if (EfsAddressPtr->Signature != FIRMWARE_TABLE_SIGNATURE) { + DEBUG ((DEBUG_ERROR, "EFS signature incorrect.\n")); + return EFI_NOT_FOUND; + } + + // + // Check PSP_L1_DIRECTORY of firmware image + // + DEBUG ((DEBUG_INFO, "Base Address for PSP directory: 0x%x\n", EfsAddressPtr->PspDirBase)); + PspL1DirectoryPtr = (PSP_DIRECTORY *)(UINTN)((UINT8 *)SystemFirmwareImage + EfsAddressPtr->PspDirBase); + if ((PspL1DirectoryPtr->Header.Cookie != PSP_DIRECTORY_HEADER_SIGNATURE) || + (!IS_VALID_ADDR32 (EfsAddressPtr->PspDirBase)) || + (!ALIGN_4K_CHECK (EfsAddressPtr->PspDirBase)) || + (PspL1DirectoryPtr->Header.TotalEntries == 0) || + (PspL1DirectoryPtr->Header.TotalEntries > MAX_IMAGE_SLOT_COUNT) + ) + { + DEBUG ((DEBUG_ERROR, "PSP L1 directory address, slot count or signature error!\n")); + return EFI_NOT_FOUND; + } + + // + // Check Image Slot entries of firmware image + // + SlotCount = PspL1DirectoryPtr->Header.TotalEntries; + for (Index = 0; Index < SlotCount; Index++) { + if (((PspL1DirectoryPtr->PspEntry[Index].Type.Value != PSP_REGION_A_DIR) && + (PspL1DirectoryPtr->PspEntry[Index].Type.Value != PSP_REGION_B_DIR)) || + (!IS_VALID_ADDR32 (PspL1DirectoryPtr->PspEntry[Index].Location)) || + (!ALIGN_4K_CHECK (PspL1DirectoryPtr->PspEntry[Index].Location)) || + (((PspL1DirectoryPtr->PspEntry[Index].Location) & 0xFFFFFFFF00000000) != 0) + ) + { + DEBUG ((DEBUG_ERROR, "PSP L1 directory slot %d data error!\n", Index)); + return EFI_NOT_FOUND; + } + } + + // + // Get offset of specific slot + // + IshSlotAInfoPtr = (IMAGE_SLOT_HEADER *)(UINTN)((UINT8 *)SystemFirmwareImage + PspL1DirectoryPtr->PspEntry[0].Location); + *SlotAOffset = IshSlotAInfoPtr->ImageSlotAddr; + DEBUG ((DEBUG_ERROR, "Slot A image offset: 0x%x\n", *SlotAOffset)); + + IshSlotBInfoPtr = (IMAGE_SLOT_HEADER *)(UINTN)((UINT8 *)SystemFirmwareImage + PspL1DirectoryPtr->PspEntry[1].Location); + *SlotBOffset = IshSlotBInfoPtr->ImageSlotAddr; + DEBUG ((DEBUG_ERROR, "Slot B image offset: 0x%x\n", *SlotBOffset)); + + if ((*SlotAOffset == 0) || (*SlotBOffset == 0)) { + return EFI_NOT_FOUND; + } + + if (ActiveSlot != NULL) { + if (IshSlotAInfoPtr->Priority > IshSlotBInfoPtr->Priority) { + *ActiveSlot = SLOT_A; + } else { + *ActiveSlot = SLOT_B; + } + } + + return EFI_SUCCESS; +} + +/** + Verify layout of OTA Capsule firmware image, and return offset and size of required update slot. + + @param[in] SystemFirmwareImage Points to the System firmware image. + @param[in] UpdateSlot The slot number need to be updated. + @param[out] UpdateOffset The firmware image offset need to updated. + @param[out] UpdateSize The firmware image size need to updated. + + @retval EFI_SUCCESS Verify OTA capsule image and get updated offset/size successfully. + @retval others Some error occurs when executing this routine. + +**/ +EFI_STATUS +VerifyImageLayout ( + IN VOID *SystemFirmwareImage, + IN UINT8 UpdateSlot, + OUT UINT32 *UpdateOffset, + OUT UINT32 *UpdateSize + ) +{ + EFI_STATUS Status; + UINT32 OtaSlotAOffset; + UINT32 OtaSlotBOffset; + UINT32 FlashSlotAOffset; + UINT32 FlashSlotBOffset; + UINT8 CurrentActiveSlot; + + if (SystemFirmwareImage == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((UpdateOffset == NULL) || (UpdateSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + OtaSlotAOffset = 0; + OtaSlotBOffset = 0; + FlashSlotAOffset = 0; + FlashSlotBOffset = 0; + + // + // Get image layout of OTA Capsule + // + DEBUG ((DEBUG_INFO, "Get image layout of OTA Capsule.\n")); + Status = GetImageLayout (SystemFirmwareImage, &OtaSlotAOffset, &OtaSlotBOffset, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetImageLayout of Capsule failed: %r\n", Status)); + return Status; + } + + // + // Get image layout of firmware in flash ROM + // + DEBUG ((DEBUG_INFO, "Get image layout of flash ROM.\n")); + Status = GetImageLayout ((VOID *)(UINTN)(PcdGet32 (PcdFlashAreaBaseAddress)), &FlashSlotAOffset, &FlashSlotBOffset, &CurrentActiveSlot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetImageLayout of Flash failed: %r\n", Status)); + return Status; + } + + // + // Check current active slot and update slot + // + // - if (CurrentActiveSlot == mUpdateSlot) { + // - DEBUG ((DEBUG_ERROR, "Can't update Capsule on current active slot. CurrentActiveSlot: %d, UpdateSlot: %d\n", CurrentActiveSlot, mUpdateSlot)); + // - return EFI_INVALID_PARAMETER; + // - } + // + // Compare layout of OTA capsule image and flash firmware + // + if ((OtaSlotAOffset != FlashSlotAOffset) || (OtaSlotBOffset != FlashSlotBOffset)) { + DEBUG ((DEBUG_ERROR, "Layout is different between Capsule and Flash.\n")); + return EFI_NOT_FOUND; + } + + if (UpdateSlot == SLOT_A) { + *UpdateOffset = OtaSlotAOffset; + } else if (UpdateSlot == SLOT_B) { + *UpdateOffset = OtaSlotBOffset; + } else { + DEBUG ((DEBUG_ERROR, "Invalid update slot number: %d\n", UpdateSlot)); + return EFI_INVALID_PARAMETER; + } + + // - *UpdateSize = (UINT32) DivU64x64Remainder ((UINTN) PcdGet32 (PcdFlashAreaSize) - OtaSlotAOffset, 2, NULL); + *UpdateSize = (UINT32)((UINTN)PcdGet32 (PcdFlashAreaSize) - OtaSlotAOffset); + + return EFI_SUCCESS; +} + +/** + Get OTA Capsule firmware image info. + + @param[in] SystemFirmwareImage Points to the System firmware image. + @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes. + @param[out] OtaCapsuleOffset The firmware image offset need to updated. + @param[out] OtaCapsuleSize The firmware image size need to updated. + + @retval EFI_SUCCESS Get OTA Capsule firmware image info successfully. + @retval others Some error occurs when executing this routine. + +**/ +EFI_STATUS +GetOtaCapsuleInfo ( + IN VOID *SystemFirmwareImage, + IN UINTN SystemFirmwareImageSize, + OUT UINT32 *OtaCapsuleOffset, + OUT UINT32 *OtaCapsuleSize + ) +{ + EFI_STATUS Status; + OTA_CAPSULE_UPDATE OtaCapsuleUpdateVal; + // - UINTN VarSize; + UINT32 UpdateOffset; + UINT32 UpdateSize; + + if ((OtaCapsuleOffset == NULL) || (OtaCapsuleSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "GetOtaCapsuleInfo:")); + DEBUG ((DEBUG_INFO, " Legnth - 0x%x\n", SystemFirmwareImageSize)); + + // - if (SystemFirmwareImageSize != (UINTN) PcdGet32 (PcdFlashAreaSize)) { + // - return EFI_INVALID_PARAMETER; + // - } + if (SystemFirmwareImageSize != (UINTN)(PcdGet32 (PcdFlashAreaSize)*2)) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&OtaCapsuleUpdateVal, sizeof (OTA_CAPSULE_UPDATE)); + + /* + VarSize = sizeof (OTA_CAPSULE_UPDATE); + Status = gRT->GetVariable ( + OTA_CAPSULE_VAR_NAME, + &gOtaCapsuleUpdateGuid, + NULL, + &VarSize, + (VOID *) &OtaCapsuleUpdateVal + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetOtaCapsuleInfo: GetVariable failed: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "UpdateFlag: 0x%x, UpdateSlot: 0x%x\n", OtaCapsuleUpdateVal.UpdateFlag, OtaCapsuleUpdateVal.UpdateSlot)); + + mUpdateSlot = OtaCapsuleUpdateVal.UpdateSlot; + if (mUpdateSlot >= MAX_SLOT_NUM) { + DEBUG ((DEBUG_ERROR, "Invalid Slot number: %d\n", mUpdateSlot)); + return EFI_NOT_FOUND; + } + */ + mUpdateSlot = 0; + + Status = VerifyImageLayout (SystemFirmwareImage, mUpdateSlot, &UpdateOffset, &UpdateSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "VerifyImageLayout failed: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "UpdateSlot: %d, UpdateOffset: 0x%x, UpdateSize: 0x%x\n", mUpdateSlot, UpdateOffset, UpdateSize)); + + *OtaCapsuleOffset = UpdateOffset; + *OtaCapsuleSize = UpdateSize; + + return EFI_SUCCESS; +} + +/** + Get OTA Capsule firmware image info. + + @param[in] SystemFirmwareImage Points to the System firmware image. + @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes. + @param[out] OtaCapsuleOffset The firmware image offset need to updated. + @param[out] OtaCapsuleSize The firmware image size need to updated. + + @retval EFI_SUCCESS Get OTA Capsule firmware image info successfully. + @retval others Some error occurs when executing this routine. + +**/ +EFI_STATUS +GetOtaCapsuleInfoSlotB ( + IN VOID *SystemFirmwareImage, + IN UINTN SystemFirmwareImageSize, + OUT UINT32 *OtaCapsuleOffset, + OUT UINT32 *OtaCapsuleSize + ) +{ + EFI_STATUS Status; + OTA_CAPSULE_UPDATE OtaCapsuleUpdateVal; + // - UINTN VarSize; + UINT32 UpdateOffset; + UINT32 UpdateSize; + + // - if ((OtaCapsuleOffset == NULL) || (OtaCapsuleSize == NULL)) { + // - return EFI_INVALID_PARAMETER; + // - } + + DEBUG ((DEBUG_INFO, "GetOtaCapsuleInfo:")); + DEBUG ((DEBUG_INFO, " Legnth - 0x%x\n", SystemFirmwareImageSize)); + // - if (SystemFirmwareImageSize != (UINTN) PcdGet32 (PcdFlashAreaSize)) { + // - return EFI_INVALID_PARAMETER; + // - } + // - if (SystemFirmwareImageSize != (UINTN) (PcdGet32 (PcdFlashAreaSize)*2)) { + // - return EFI_INVALID_PARAMETER; + // - } + ZeroMem (&OtaCapsuleUpdateVal, sizeof (OTA_CAPSULE_UPDATE)); + + /* + VarSize = sizeof (OTA_CAPSULE_UPDATE); + Status = gRT->GetVariable ( + OTA_CAPSULE_VAR_NAME, + &gOtaCapsuleUpdateGuid, + NULL, + &VarSize, + (VOID *) &OtaCapsuleUpdateVal + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetOtaCapsuleInfo: GetVariable failed: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "UpdateFlag: 0x%x, UpdateSlot: 0x%x\n", OtaCapsuleUpdateVal.UpdateFlag, OtaCapsuleUpdateVal.UpdateSlot)); + + mUpdateSlot = OtaCapsuleUpdateVal.UpdateSlot; + if (mUpdateSlot >= MAX_SLOT_NUM) { + DEBUG ((DEBUG_ERROR, "Invalid Slot number: %d\n", mUpdateSlot)); + return EFI_NOT_FOUND; + } + */ + mUpdateSlot = 1; + + Status = VerifyImageLayout (SystemFirmwareImage, mUpdateSlot, &UpdateOffset, &UpdateSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "VerifyImageLayout failed: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "UpdateSlot: %d, UpdateOffset: 0x%x, UpdateSize: 0x%x\n", mUpdateSlot, UpdateOffset, UpdateSize)); + + *OtaCapsuleOffset = UpdateOffset; + *OtaCapsuleSize = UpdateSize; + + return EFI_SUCCESS; +} + +/** + Update active slot information in ISH. + + @param[in] SlotNum The slot number will be set as active. + + @retval EFI_SUCCESS Set active slto successfully. + @retval others Some error occurs when executing this routine. + +**/ +EFI_STATUS +UpdateAbActiveSlot ( + IN UINT8 SlotNum + ) +{ + EFI_STATUS Status; + IMAGE_SLOT_HEADER_INFO IshInfo; + UINTN VarSize; + + DEBUG ((DEBUG_INFO, "UpdateAbActiveSlot...\n")); + + if (SlotNum >= MAX_SLOT_NUM) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&IshInfo, sizeof (IMAGE_SLOT_HEADER_INFO)); + + VarSize = sizeof (IMAGE_SLOT_HEADER_INFO); + Status = gRT->GetVariable ( + ISH_VAR_NAME, + &gABSupportUpdateIshGuid, + NULL, + &VarSize, + (VOID *)&IshInfo + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Get A/B slot info failed: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "Get IshInfo.SlotA_Priority: 0x%x\n", IshInfo.SlotA_Priority)); + DEBUG ((DEBUG_INFO, "Get IshInfo.SlotA_UpdateRetries: 0x%x\n", IshInfo.SlotA_UpdateRetries)); + DEBUG ((DEBUG_INFO, "Get IshInfo.SlotA_GlitchRetries: 0x%x\n", IshInfo.SlotA_GlitchRetries)); + DEBUG ((DEBUG_INFO, "Get IshInfo.SlotB_Priority: 0x%x\n", IshInfo.SlotB_Priority)); + DEBUG ((DEBUG_INFO, "Get IshInfo.SlotB_UpdateRetries: 0x%x\n", IshInfo.SlotB_UpdateRetries)); + DEBUG ((DEBUG_INFO, "Get IshInfo.SlotB_GlitchRetries: 0x%x\n\n", IshInfo.SlotB_GlitchRetries)); + + if (SlotNum == SLOT_A) { + // Slot A + if (IshInfo.SlotB_Priority == MAX_UINT32) { + IshInfo.SlotA_Priority = PcdGet32 (PcdFlashAbImageSlotDefaultPriority); + IshInfo.SlotB_Priority = IshInfo.SlotA_Priority - 1; + } else { + IshInfo.SlotA_Priority = MAX (IshInfo.SlotA_Priority, IshInfo.SlotB_Priority) + 1; + } + + IshInfo.SlotA_UpdateRetries = 0xFF; + } else if (SlotNum == SLOT_B) { + // Slot B + if (IshInfo.SlotA_Priority == MAX_UINT32) { + IshInfo.SlotB_Priority = PcdGet32 (PcdFlashAbImageSlotDefaultPriority); + IshInfo.SlotA_Priority = IshInfo.SlotB_Priority - 1; + } else { + IshInfo.SlotB_Priority = MAX (IshInfo.SlotA_Priority, IshInfo.SlotB_Priority) + 1; + } + + IshInfo.SlotB_UpdateRetries = 0xFF; + } + + DEBUG ((DEBUG_INFO, "Set IshInfo.SlotA_Priority: 0x%x\n", IshInfo.SlotA_Priority)); + DEBUG ((DEBUG_INFO, "Set IshInfo.SlotA_UpdateRetries: 0x%x\n", IshInfo.SlotA_UpdateRetries)); + DEBUG ((DEBUG_INFO, "Set IshInfo.SlotA_GlitchRetries: 0x%x\n", IshInfo.SlotA_GlitchRetries)); + DEBUG ((DEBUG_INFO, "Set IshInfo.SlotB_Priority: 0x%x\n", IshInfo.SlotB_Priority)); + DEBUG ((DEBUG_INFO, "Set IshInfo.SlotB_UpdateRetries: 0x%x\n", IshInfo.SlotB_UpdateRetries)); + DEBUG ((DEBUG_INFO, "Set IshInfo.SlotB_GlitchRetries: 0x%x\n", IshInfo.SlotB_GlitchRetries)); + + Status = gRT->SetVariable ( + ISH_VAR_NAME, + &gABSupportUpdateIshGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (IMAGE_SLOT_HEADER_INFO), + (VOID *)&IshInfo + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Set Slot info failed: %r\n", Status)); + return Status; + } + + return Status; +} + +/** + Update System Firmware image. + + @param[in] SystemFirmwareImage Points to the System Firmware image. + @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes. + @param[in] ConfigImage Points to the config file image. + @param[in] ConfigImageSize The length of the config file image in bytes. + @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] Progress A function used by the driver to report the progress of the firmware update. + + @retval EFI_SUCCESS The System Firmware image is updated. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +UpdateImage ( + IN VOID *SystemFirmwareImage, + IN UINTN SystemFirmwareImageSize, + IN VOID *ConfigImage, + IN UINTN ConfigImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress + ) +{ + EFI_STATUS Status; + UPDATE_CONFIG_DATA *ConfigData; + UPDATE_CONFIG_DATA *UpdateConfigData; + CONFIG_HEADER ConfigHeader; + UINTN Index; + UINTN TotalSize; + UINTN BytesWritten; + UINTN StartPercentage; + UINTN EndPercentage; + UINT32 OtaCapsuleOffset; + UINT32 OtaCapsuleSize; + UINT32 ECImageSize; + UINT32 ECImageOffset; + + if (ConfigImage == NULL) { + DEBUG ((DEBUG_INFO, "PlatformUpdate (NoConfig):")); + // ASSUME the whole System Firmware include NVRAM region. + StartPercentage = 0; + EndPercentage = 100; + if (Progress != NULL) { + Progress (StartPercentage); + } + + ECImageSize = 0x20000; + ECImageOffset = 0x0; + + DEBUG ((DEBUG_INFO, " BaseAddress - 0x%x,", ECImageOffset)); + DEBUG ((DEBUG_INFO, " Length - 0x%x\n", ECImageSize)); + + Status = PerformFlashWriteWithProgress ( + PlatformFirmwareTypeNvRam, + (EFI_PHYSICAL_ADDRESS)ECImageOffset, + FlashAddressTypeRelativeAddress, + (VOID *)((UINT8 *)SystemFirmwareImage + ECImageOffset), + ECImageSize, + Progress, + StartPercentage, + EndPercentage + ); + if (Progress != NULL) { + Progress (EndPercentage); + } + + if (!EFI_ERROR (Status)) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + mNvRamUpdated = TRUE; + } else { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + + StartPercentage = 0; + EndPercentage = 100; + if (Progress != NULL) { + Progress (StartPercentage); + } + + Status = GetOtaCapsuleInfo (SystemFirmwareImage, SystemFirmwareImageSize, &OtaCapsuleOffset, &OtaCapsuleSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetOtaCapsuleInfo failed: %r\n", Status)); + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + return Status; + } + + DEBUG ((DEBUG_INFO, " BaseAddress - 0x%x,", OtaCapsuleOffset)); + DEBUG ((DEBUG_INFO, " Length - 0x%x\n", OtaCapsuleSize)); + + Status = PerformFlashWriteWithProgress ( + PlatformFirmwareTypeNvRam, + (EFI_PHYSICAL_ADDRESS)OtaCapsuleOffset, + FlashAddressTypeRelativeAddress, + (VOID *)((UINT8 *)SystemFirmwareImage + OtaCapsuleOffset), + OtaCapsuleSize, + Progress, + StartPercentage, + EndPercentage + ); + if (Progress != NULL) { + Progress (EndPercentage); + } + + if (!EFI_ERROR (Status)) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + mNvRamUpdated = TRUE; + } else { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + + Status = GetOtaCapsuleInfoSlotB (SystemFirmwareImage, SystemFirmwareImageSize, &OtaCapsuleOffset, &OtaCapsuleSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetOtaCapsuleInfo failed: %r\n", Status)); + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + return Status; + } + + DEBUG ((DEBUG_INFO, " BaseAddress - 0x%x,", OtaCapsuleOffset)); + DEBUG ((DEBUG_INFO, " Length - 0x%x\n", OtaCapsuleSize)); + + Status = PerformFlashWriteWithProgress ( + PlatformFirmwareTypeNvRam, + (EFI_PHYSICAL_ADDRESS)OtaCapsuleOffset, + FlashAddressTypeRelativeAddress, + (VOID *)((UINT8 *)SystemFirmwareImage + OtaCapsuleOffset), + OtaCapsuleSize, + Progress, + StartPercentage, + EndPercentage + ); + if (Progress != NULL) { + Progress (EndPercentage); + } + + if (!EFI_ERROR (Status)) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; + mNvRamUpdated = TRUE; + } else { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + + return Status; + } + + DEBUG ((DEBUG_INFO, "PlatformUpdate (With Config):\n")); + ConfigData = NULL; + ZeroMem (&ConfigHeader, sizeof (ConfigHeader)); + Status = ParseUpdateDataFile ( + ConfigImage, + ConfigImageSize, + &ConfigHeader, + &ConfigData + ); + DEBUG ((DEBUG_INFO, "ParseUpdateDataFile - %r\n", Status)); + if (EFI_ERROR (Status)) { + *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "ConfigHeader.NumOfUpdates - 0x%x\n", ConfigHeader.NumOfUpdates)); + DEBUG ((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))); + + TotalSize = 0; + for (Index = 0; Index < ConfigHeader.NumOfUpdates; Index++) { + if (CompareGuid (&ConfigData[Index].FileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))) { + TotalSize = TotalSize + ConfigData[Index].Length; + } + } + + BytesWritten = 0; + Index = 0; + UpdateConfigData = ConfigData; + while (Index < ConfigHeader.NumOfUpdates) { + if (CompareGuid (&UpdateConfigData->FileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))) { + DEBUG ((DEBUG_INFO, "FileGuid - %g (processing)\n", &UpdateConfigData->FileGuid)); + StartPercentage = (BytesWritten * 100) / TotalSize; + EndPercentage = ((BytesWritten + UpdateConfigData->Length) * 100) / TotalSize; + Status = PerformUpdate ( + SystemFirmwareImage, + SystemFirmwareImageSize, + UpdateConfigData, + LastAttemptVersion, + LastAttemptStatus, + Progress, + StartPercentage, + EndPercentage + ); + // + // Shall updates be serialized so that if an update is not successfully completed, + // the remaining updates won't be performed. + // + if (EFI_ERROR (Status)) { + break; + } + } else { + DEBUG ((DEBUG_INFO, "FileGuid - %g (ignored)\n", &UpdateConfigData->FileGuid)); + } + + BytesWritten += UpdateConfigData->Length; + + Index++; + UpdateConfigData++; + } + + return Status; +} + +/** + Authenticate and update System Firmware image. + + Caution: This function may receive untrusted input. + + @param[in] Image The EDKII system FMP capsule image. + @param[in] ImageSize The size of the EDKII system FMP capsule image in bytes. + @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] Progress A function used by the driver to report the progress of the firmware update. + + @retval EFI_SUCCESS EDKII system FMP capsule passes authentication and the System Firmware image is updated. + @retval EFI_SECURITY_VIOLATION EDKII system FMP capsule fails authentication and the System Firmware image is not updated. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +SystemFirmwareAuthenticatedUpdate ( + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress + ) +{ + EFI_STATUS Status; + VOID *SystemFirmwareImage; + UINTN SystemFirmwareImageSize; + VOID *ConfigImage; + UINTN ConfigImageSize; + VOID *AuthenticatedImage; + UINTN AuthenticatedImageSize; + + AuthenticatedImage = NULL; + AuthenticatedImageSize = 0; + + DEBUG ((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate...\n")); + + Status = CapsuleAuthenticateSystemFirmware (Image, ImageSize, FALSE, LastAttemptVersion, LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "SystemFirmwareAuthenticateImage - %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "ExtractSystemFirmwareImage ...\n")); + ExtractSystemFirmwareImage (AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize); + DEBUG ((DEBUG_INFO, "ExtractConfigImage ...\n")); + ExtractConfigImage (AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize); + + DEBUG ((DEBUG_INFO, "UpdateImage ...\n")); + Status = UpdateImage (SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus, Progress); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "UpdateImage - %r\n", Status)); + return Status; + } + + #if 0 + // DO NOT KNOW THE REASON to update A/B Active Slot. + // Removed FOR NOW. + + // + // Update A/B active slot info + // + Status = UpdateAbActiveSlot (mUpdateSlot); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "UpdateAbActiveSlot failed: %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate Done\n")); + #endif + return Status; +} + +/** + + This code finds variable in storage blocks (Volatile or Non-Volatile). + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[out] Attributes Attribute value of the variable found. + @param[in, out] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[out] Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +GetVariableHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + DEBUG ((DEBUG_INFO, "GetVariableHook - %S, %g\n", VariableName, VendorGuid)); + return EFI_NOT_AVAILABLE_YET; +} + +/** + + This code Finds the Next available variable. + + @param[in, out] VariableNameSize Size of the variable name. + @param[in, out] VariableName Pointer to variable name. + @param[in, out] VendorGuid Variable Vendor Guid. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +GetNextVariableNameHook ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + DEBUG ((DEBUG_INFO, "GetNextVariableNameHook - %S, %g\n", VariableName, VendorGuid)); + return EFI_NOT_AVAILABLE_YET; +} + +/** + + This code sets variable in storage blocks (Volatile or Non-Volatile). + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Attributes Attribute value of the variable found + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Set successfully. + @return EFI_OUT_OF_RESOURCES Resource not enough to set variable. + @return EFI_NOT_FOUND Not found. + @return EFI_WRITE_PROTECTED Variable is read-only. + +**/ +EFI_STATUS +EFIAPI +SetVariableHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + DEBUG ((DEBUG_INFO, "SetVariableHook - %S, %g, 0x%x (0x%x)\n", VariableName, VendorGuid, Attributes, DataSize)); + return EFI_NOT_AVAILABLE_YET; +} + +/** + + This code returns information about the EFI variables. + + @param[in] Attributes Attributes bitmask to specify the type of variables + on which to return information. + @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available + for the EFI variables associated with the attributes specified. + @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available + for EFI variables associated with the attributes specified. + @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables + associated with the attributes specified. + + @return EFI_SUCCESS Query successfully. + +**/ +EFI_STATUS +EFIAPI +QueryVariableInfoHook ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +{ + DEBUG ((DEBUG_INFO, "QueryVariableInfoHook - 0x%x\n", Attributes)); + return EFI_NOT_AVAILABLE_YET; +} + +/** + Updates the firmware image of the device. + + This function updates the hardware with the new firmware image. + This function returns EFI_UNSUPPORTED if the firmware image is not updatable. + If the firmware image is updatable, the function should perform the following minimal validations + before proceeding to do the firmware image update. + - Validate the image authentication if image has attribute + IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns + EFI_SECURITY_VIOLATION if the validation fails. + - Validate the image is a supported image for this device. The function returns EFI_ABORTED if + the image is unsupported. The function can optionally provide more detailed information on + why the image is not a supported image. + - Validate the data from VendorCode if not null. Image validation must be performed before + VendorCode data validation. VendorCode data is ignored or considered invalid if image + validation failed. The function returns EFI_ABORTED if the data is invalid. + + VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if + the caller did not specify the policy or use the default policy. As an example, vendor can implement + a policy to allow an option to force a firmware image update when the abort reason is due to the new + firmware image version is older than the current firmware image version or bad image checksum. + Sensitive operations such as those wiping the entire firmware image and render the device to be + non-functional should be encoded in the image itself rather than passed with the VendorCode. + AbortReason enables vendor to have the option to provide a more detailed description of the abort + reason to the caller. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance. + @param[in] ImageIndex A unique number identifying the firmware image(s) within the device. + The number is between 1 and DescriptorCount. + @param[in] Image Points to the new image. + @param[in] ImageSize Size of the new image in bytes. + @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy. + Null indicates the caller did not specify the policy or use the default policy. + @param[in] Progress A function used by the driver to report the progress of the firmware update. + @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more + details for the aborted operation. The buffer is allocated by this function + with AllocatePool(), and it is the caller's responsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The device was successfully updated with the new image. + @retval EFI_ABORTED The operation is aborted. + @retval EFI_INVALID_PARAMETER The Image was NULL. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +FmpSetImage ( + IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This, + IN UINT8 ImageIndex, + IN CONST VOID *Image, + IN UINTN ImageSize, + IN CONST VOID *VendorCode, + IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, + OUT CHAR16 **AbortReason + ) +{ + EFI_STATUS Status; + EFI_STATUS VarStatus; + SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate; + + if ((Image == NULL) || (ImageSize == 0) || (AbortReason == NULL)) { + return EFI_INVALID_PARAMETER; + } + + SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP (This); + *AbortReason = NULL; + + if ((ImageIndex == 0) || (ImageIndex > SystemFmpPrivate->DescriptorCount)) { + return EFI_INVALID_PARAMETER; + } + + Status = SystemFirmwareAuthenticatedUpdate ((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus, Progress); + DEBUG ((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus)); + + // + // If NVRAM is updated, we should no longer touch variable services, because + // the current variable driver may not manage the new NVRAM region. + // + if (mNvRamUpdated) { + DEBUG ((DEBUG_INFO, "NvRamUpdated, Update Variable Serivces\n")); + gRT->GetVariable = GetVariableHook; + gRT->GetNextVariableName = GetNextVariableNameHook; + gRT->SetVariable = SetVariableHook; + gRT->QueryVariableInfo = QueryVariableInfoHook; + + gRT->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ( + (UINT8 *)&gRT->Hdr, + gRT->Hdr.HeaderSize, + &gRT->Hdr.CRC32 + ); + } + + VarStatus = gRT->SetVariable ( + SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME, + &gSystemFmpLastAttemptVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (SystemFmpPrivate->LastAttempt), + &SystemFmpPrivate->LastAttempt + ); + DEBUG ((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus)); + + return Status; +} + +/** + Get the set of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures from an FMP Protocol. + + @param[in] Handle Handle with an FMP Protocol or a System FMP + Protocol. + @param[in] ProtocolGuid Pointer to the FMP Protocol GUID or System FMP + Protocol GUID. + @param[out] FmpImageInfoCount Pointer to the number of + EFI_FIRMWARE_IMAGE_DESCRIPTOR structures. + @param[out] DescriptorSize Pointer to the size, in bytes, of each + EFI_FIRMWARE_IMAGE_DESCRIPTOR structure. + + @return NULL No EFI_FIRMWARE_IMAGE_DESCRIPTOR structures found. + @return !NULL Pointer to a buffer of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures + allocated using AllocatePool(). Caller must free buffer with + FreePool(). +**/ +EFI_FIRMWARE_IMAGE_DESCRIPTOR * +GetFmpImageDescriptors ( + IN EFI_HANDLE Handle, + IN EFI_GUID *ProtocolGuid, + OUT UINT8 *FmpImageInfoCount, + OUT UINTN *DescriptorSize + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + UINTN ImageInfoSize; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINT32 FmpImageInfoDescriptorVer; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + + *FmpImageInfoCount = 0; + *DescriptorSize = 0; + + Status = gBS->HandleProtocol ( + Handle, + ProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + // + // Determine the size required for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + // + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, // FMP Pointer + &ImageInfoSize, // Buffer Size (in this case 0) + NULL, // NULL so we can get size + &FmpImageInfoDescriptorVer, // DescriptorVersion + FmpImageInfoCount, // DescriptorCount + DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Unexpected Failure. Status = %r\n", Status)); + return NULL; + } + + // + // Allocate buffer for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + // + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failed to allocate memory for descriptors.\n")); + return NULL; + } + + // + // Retrieve the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + // + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + FmpImageInfoCount, // DescriptorCount + DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // Free unused PackageVersionName return buffer + // + if (PackageVersionName != NULL) { + FreePool (PackageVersionName); + PackageVersionName = NULL; + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failure in GetImageInfo. Status = %r\n", Status)); + if (FmpImageInfoBuf != NULL) { + FreePool (FmpImageInfoBuf); + } + + return NULL; + } + + return FmpImageInfoBuf; +} + +/** + Search for handles with an FMP protocol whose EFI_FIRMWARE_IMAGE_DESCRIPTOR + ImageTypeId matches the ImageTypeId produced by this module. + + @param[in] ProtocolGuid Pointer to the GUID of the protocol to search. + @param[out] HandleCount Pointer to the number of returned handles. + + @return NULL No matching handles found. + @return !NULL Pointer to a buffer of handles allocated using AllocatePool(). + Caller must free buffer with FreePool(). +**/ +EFI_HANDLE * +FindMatchingFmpHandles ( + IN EFI_GUID *ProtocolGuid, + OUT UINTN *HandleCount + ) +{ + EFI_STATUS Status; + UINTN TempHandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + UINTN Index2; + UINTN Index3; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *OriginalFmpImageInfoBuf; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + BOOLEAN MatchFound; + + *HandleCount = 0; + TempHandleCount = 0; + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + ProtocolGuid, + NULL, + &TempHandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + for (Index = 0; Index < TempHandleCount; Index++) { + OriginalFmpImageInfoBuf = GetFmpImageDescriptors ( + HandleBuffer[Index], + ProtocolGuid, + &FmpImageInfoCount, + &DescriptorSize + ); + + // + // Loop through the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + // + MatchFound = FALSE; + if (OriginalFmpImageInfoBuf != NULL) { + FmpImageInfoBuf = OriginalFmpImageInfoBuf; + + for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) { + for (Index3 = 0; Index3 < mSystemFmpPrivate->DescriptorCount; Index3++) { + MatchFound = CompareGuid ( + &FmpImageInfoBuf->ImageTypeId, + &mSystemFmpPrivate->ImageDescriptor[Index3].ImageTypeId + ); + if (MatchFound) { + break; + } + } + + if (MatchFound) { + break; + } + + // + // Increment the buffer pointer ahead by the size of the descriptor + // + FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize); + } + + if (MatchFound) { + HandleBuffer[*HandleCount] = HandleBuffer[Index]; + (*HandleCount)++; + } + + FreePool (OriginalFmpImageInfoBuf); + } + } + + if ((*HandleCount) == 0) { + // + // No any matching handle. + // + FreePool (HandleBuffer); + return NULL; + } + + return HandleBuffer; +} + +/** + Uninstall System FMP Protocol instances that may have been installed by + SystemFirmwareUpdateDxe drivers dispatches by other capsules. + + @retval EFI_SUCCESS All System FMP Protocols found were uninstalled. + @return Other One or more System FMP Protocols could not be uninstalled. + +**/ +EFI_STATUS +UninstallMatchingSystemFmpProtocols ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *SystemFmp; + + // + // Uninstall SystemFmpProtocol instances that may have been produced by + // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules. + // + HandleBuffer = FindMatchingFmpHandles ( + &gSystemFmpProtocolGuid, + &HandleCount + ); + DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Found %d matching System FMP instances\n", HandleCount)); + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gSystemFmpProtocolGuid, + (VOID **)&SystemFmp + ); + if (EFI_ERROR (Status)) { + continue; + } + + DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Uninstall SystemFmp produced by another capsule\n")); + Status = gBS->UninstallProtocolInterface ( + HandleBuffer[Index], + &gSystemFmpProtocolGuid, + SystemFmp + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failed to uninstall SystemFmp %r. Exiting.\n", Status)); + FreePool (HandleBuffer); + return Status; + } + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; +} + +/** + System FMP module entrypoint + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS System FMP module is initialized. + @retval EFI_OUT_OF_RESOURCES There are not enough resources avaulable to + initialize this module. + @retval Other System FMP Protocols could not be uninstalled. + @retval Other System FMP Protocol could not be installed. + @retval Other FMP Protocol could not be installed. +**/ +EFI_STATUS +EFIAPI +SystemFirmwareUpdateMainDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + + // + // Initialize SystemFmpPrivateData + // + mSystemFmpPrivate = AllocateZeroPool (sizeof (SYSTEM_FMP_PRIVATE_DATA)); + if (mSystemFmpPrivate == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = InitializePrivateData (mSystemFmpPrivate); + if (EFI_ERROR (Status)) { + FreePool (mSystemFmpPrivate); + mSystemFmpPrivate = NULL; + return Status; + } + + // + // Uninstall SystemFmpProtocol instances that may have been produced by + // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules. + // + Status = UninstallMatchingSystemFmpProtocols (); + if (EFI_ERROR (Status)) { + FreePool (mSystemFmpPrivate); + mSystemFmpPrivate = NULL; + return Status; + } + + // + // Look for a handle with matching Firmware Management Protocol + // + HandleCount = 0; + HandleBuffer = FindMatchingFmpHandles ( + &gEfiFirmwareManagementProtocolGuid, + &HandleCount + ); + DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Found %d matching FMP instances\n", HandleCount)); + + switch (HandleCount) { + case 0: + // + // Install FMP protocol onto a new handle. + // + DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Install FMP onto a new handle\n")); + Status = gBS->InstallMultipleProtocolInterfaces ( + &mSystemFmpPrivate->Handle, + &gEfiFirmwareManagementProtocolGuid, + &mSystemFmpPrivate->Fmp, + NULL + ); + break; + case 1: + // + // Install System FMP protocol onto handle with matching FMP Protocol + // + DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Install System FMP onto matching FMP handle\n")); + mSystemFmpPrivate->Handle = HandleBuffer[0]; + Status = gBS->InstallMultipleProtocolInterfaces ( + &HandleBuffer[0], + &gSystemFmpProtocolGuid, + &mSystemFmpPrivate->Fmp, + NULL + ); + break; + default: + // + // More than one matching handle is not expected. Unload driver. + // + DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: More than one matching FMP handle. Unload driver.\n")); + Status = EFI_DEVICE_ERROR; + break; + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (EFI_ERROR (Status)) { + FreePool (mSystemFmpPrivate); + mSystemFmpPrivate = NULL; + } + + return Status; +} diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.inf b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.inf new file mode 100644 index 0000000000..6e990f7e4e --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.inf @@ -0,0 +1,77 @@ +## @file +# System Firmware Update Dxe +# Produce FMP instance to update system firmware. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> +# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SystemFirmwareUpdateDxe + MODULE_UNI_FILE = SystemFirmwareUpdateDxe.uni + FILE_GUID = 0A2FBD15-1C25-407E-8915-60C5652BC2AA + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SystemFirmwareUpdateMainDxe + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +[Sources] + SystemFirmwareDxe.h + SystemFirmwareCommonDxe.c + SystemFirmwareUpdateDxe.c + ParseConfigProfile.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + VanGoghCommonPkg/AmdCommonPkg.dec + SignedCapsulePkg/SignedCapsulePkg.dec + ChachaniBoardPkg/Project.dec + AgesaPublic/AgesaPublic.dec + +[LibraryClasses] + BaseLib + UefiLib + BaseMemoryLib + DebugLib + PcdLib + MemoryAllocationLib + UefiBootServicesTableLib + HobLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + DxeServicesLib + EdkiiSystemCapsuleLib + PlatformFlashAccessLib + IniParsingLib + PrintLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSystemFmpCapsuleImageTypeIdGuid ## CONSUMES + gEfiSignedCapsulePkgTokenSpaceGuid.PcdEdkiiSystemFirmwareFileGuid ## CONSUMES + gEfiSignedCapsulePkgTokenSpaceGuid.PcdEdkiiSystemFirmwareImageDescriptor ## CONSUMES + gPlatformPkgTokenSpaceGuid.PcdFlashAreaBaseAddress ## CONSUMES + gPlatformPkgTokenSpaceGuid.PcdFlashAreaSize ## CONSUMES + gPlatformPkgTokenSpaceGuid.PcdFlashAbImageSlotDefaultPriority ## CONSUMES + +[Guids] + gOtaCapsuleUpdateGuid + gABSupportUpdateIshGuid + +[Protocols] + gEfiFirmwareManagementProtocolGuid ## PRODUCES + +[Depex] + gEfiVariableArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SystemFirmwareUpdateDxeExtra.uni + diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.uni b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.uni new file mode 100644 index 0000000000..e6bd18b249 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.uni @@ -0,0 +1,15 @@ +// /** @file +// SystemFirmware FMP update driver. +// +// Produce FMP instance to update system firmware. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> +// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "SystemFirmware FMP update driver." + +#string STR_MODULE_DESCRIPTION #language en-US "Produce FMP instance to update system firmware." diff --git a/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxeExtra.uni b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxeExtra.uni new file mode 100644 index 0000000000..c549f017a4 --- /dev/null +++ b/Platform/AMD/VanGoghBoard/Override/edk2/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxeExtra.uni @@ -0,0 +1,15 @@ +// /** @file +// SystemFirmwareUpdateDxeExtra Localized Strings and Content +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> +// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"SystemFirmwareUpdate DXE Driver" + + -- 2.31.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#114597): https://edk2.groups.io/g/devel/message/114597 Mute This Topic: https://groups.io/mt/103975474/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-