From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) (using TLSv1 with cipher CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 686791A1E15 for ; Tue, 27 Sep 2016 01:41:17 -0700 (PDT) Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga101.fm.intel.com with ESMTP; 27 Sep 2016 01:41:17 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.30,404,1470726000"; d="scan'208";a="13611359" Received: from fmsmsx105.amr.corp.intel.com ([10.18.124.203]) by fmsmga006.fm.intel.com with ESMTP; 27 Sep 2016 01:41:16 -0700 Received: from fmsmsx126.amr.corp.intel.com (10.18.125.43) by FMSMSX105.amr.corp.intel.com (10.18.124.203) with Microsoft SMTP Server (TLS) id 14.3.248.2; Tue, 27 Sep 2016 01:41:16 -0700 Received: from shsmsx152.ccr.corp.intel.com (10.239.6.52) by FMSMSX126.amr.corp.intel.com (10.18.125.43) with Microsoft SMTP Server (TLS) id 14.3.248.2; Tue, 27 Sep 2016 01:41:15 -0700 Received: from shsmsx102.ccr.corp.intel.com ([169.254.2.15]) by SHSMSX152.ccr.corp.intel.com ([169.254.6.95]) with mapi id 14.03.0248.002; Tue, 27 Sep 2016 16:41:13 +0800 From: "Fan, Jeff" To: "Yao, Jiewen" , "edk2-devel@lists.01.org" CC: "Tian, Feng" , "Zeng, Star" , "Kinney, Michael D" , "Gao, Liming" , "Zhang, Chao B" Thread-Topic: [PATCH 27/45] UefiCpuPkg/MicrocodeUpdate: Add MicrocodeUpdate component. Thread-Index: AQHSE9P+IpOxyEsQq02vSM2t9HURsaCNCWsA Date: Tue, 27 Sep 2016 08:41:12 +0000 Message-ID: <542CF652F8836A4AB8DBFAAD40ED192A4A28BE63@shsmsx102.ccr.corp.intel.com> References: <1474440326-9292-1-git-send-email-jiewen.yao@intel.com> <1474440326-9292-28-git-send-email-jiewen.yao@intel.com> In-Reply-To: <1474440326-9292-28-git-send-email-jiewen.yao@intel.com> Accept-Language: zh-CN, en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiYmRkYzllNmItNzA3My00OWEzLThiMWMtYzVlMTlmY2I5OWZjIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE1LjkuNi42IiwiVHJ1c3RlZExhYmVsSGFzaCI6IjRTaEpkUTd3Z1JvTlFrZkhOVWtodXNDOGJySjVFQ0RNZlJibDNSaEZGN3c9In0= x-ctpclassification: CTP_IC x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH 27/45] UefiCpuPkg/MicrocodeUpdate: Add MicrocodeUpdate component. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Sep 2016 08:41:17 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Jiewen, 1. Could you move structure definitions (like MICROCODE_FMP_LAST_ATTEMPT_V= ARIABLE, etc ) and function declarations reference (like GetMicrocodeInfo, = etc) from MicrocodeFmp.c to MicrocodeUpdate.h? 2. Correct EFI_D_ERROR to EFI_D_INFO on following DEBUG (). DEBUG((EFI_D_ERROR, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodeP= atchAddress, MicrocodePatchRegionSize)); The others part on UefiCpuPkg are good to me! Reviewed-by: Jeff Fan Jeff -----Original Message----- From: Yao, Jiewen=20 Sent: Wednesday, September 21, 2016 2:45 PM To: edk2-devel@lists.01.org Cc: Fan, Jeff; Tian, Feng; Zeng, Star; Kinney, Michael D; Gao, Liming; Zhan= g, Chao B Subject: [PATCH 27/45] UefiCpuPkg/MicrocodeUpdate: Add MicrocodeUpdate comp= onent. MicrocodeUpdate supports update Microcode region via UEFI FMP capsule. MicrocodeUpdate SetImage() will perform the Microcode version, ProcessorSignature/ProcessorFlag, and try to load microcode. If and only if the Microcode is loaded successfully, and new Microcode will be updated to system flash region. Cc: Jeff Fan Cc: Feng Tian Cc: Star Zeng Cc: Michael D Kinney Cc: Liming Gao Cc: Chao Zhang Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao --- UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c | 641 +++++++++++++= +++ UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c | 775 +++++++++++++= +++++++ UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h | 299 ++++++++ UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf | 68 ++ UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni | 21 + UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni | 20 + 6 files changed, 1824 insertions(+) diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c b/UefiCpuPkg/Microco= deUpdate/MicrocodeFmp.c new file mode 100644 index 0000000..ee94b41 --- /dev/null +++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c @@ -0,0 +1,641 @@ +/** @file + Produce FMP instance for Microcode. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMP= LIED. + +**/ + +#include "MicrocodeUpdate.h" + +#define MICROCODE_FMP_PRIVATE_DATA_SIGNATURE SIGNATURE_32('M', 'C', 'U', = 'F') + +// +// Microcode FMP private data structure. +// + +typedef struct { + UINT32 LastAttemptVersion; + UINT32 LastAttemptStatus; +} MICROCODE_FMP_LAST_ATTEMPT_VARIABLE; + +struct _MICROCODE_FMP_PRIVATE_DATA { + UINT32 Signature; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL Fmp; + EFI_HANDLE Handle; + UINT8 DescriptorCount; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + MICROCODE_FMP_LAST_ATTEMPT_VARIABLE LastAttempt; +}; + +typedef struct _MICROCODE_FMP_PRIVATE_DATA MICROCODE_FMP_PRIVATE_DATA; + +#define MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME L"MicrocodeLastAttempVar= " + +/** + Returns a pointer to the MICROCODE_FMP_PRIVATE_DATA structure from the i= nput a as Fmp. + + If the signatures matches, then a pointer to the data structure that con= tains + a specified field of that data structure is returned. + + @param a Pointer to the field specified by ServiceBinding = within + a data structure of type MICROCODE_FMP_PRIVATE_DA= TA. + +**/ +#define MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(a) \ + CR ( \ + (a), \ + MICROCODE_FMP_PRIVATE_DATA, \ + Fmp, \ + MICROCODE_FMP_PRIVATE_DATA_SIGNATURE \ + ) + +// +// MicrocodeFmp driver private data +// +MICROCODE_FMP_PRIVATE_DATA *mMicrocodeFmpPrivate =3D NULL; + +EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol =3D { + FmpGetImageInfo, + FmpGetImage, + FmpSetImage, + FmpCheckImage, + FmpGetPackageInfo, + FmpSetPackageInfo +}; + +/** + Get current Microcode information. + + @param[out] ImageDescriptor Microcode ImageDescriptor + @param[in] DescriptorCount The count of Microcode ImageDescriptor all= ocated. + + @return Microcode count +**/ +UINTN +GetMicrocodeInfo( + OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL + IN UINTN DescriptorCount OPTIONAL + ); + +/** + Read Microcode. + + @param ImageIndex The index of Microcode image. + @param Image The Microcode image buffer. + @param ImageSize The size of Microcode image buffer in bytes. + + @retval EFI_SUCCESS The Microcode image is read. + @retval EFI_NOT_FOUND The Microcode image is not found. +**/ +EFI_STATUS +MicrocodeRead( + IN UINTN ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ); + +/** + Write Microcode. + + @param ImageIndex The index of Microcode image. + @param Image The Microcode image buffer. + @param ImageSize The size of Microcode image buffer in bytes. + @param LastAttemptVersion The last attempt version, which will be recor= ded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param LastAttemptStatus The last attempt status, which will be record= ed in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param AbortReason A pointer to a pointer to a null-terminated s= tring providing more + details for the aborted operation. The buffer= is allocated by this function + with AllocatePool(), and it is the caller's r= esponsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The Microcode image is written. + @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. + @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. + @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +MicrocodeWrite( + IN UINTN ImageIndex, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ); + +/** + Initialize Microcode Descriptor. + + @param MicrocodeFmpPrivate private data structure to be initialized. + + @return EFI_SUCCESS Microcode Descriptor is initialized. +**/ +EFI_STATUS +InitializeMicrocodeDescriptor( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate + ); + +/** + 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 rec= overy or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEM= ENT_PROTOCOL instance. + @param[in, out] ImageInfoSize A pointer to the size, in bytes, of t= he ImageInfo buffer. + On input, this is the size of the buf= fer allocated by the caller. + On output, it is the size of the buff= er returned by the firmware + if the buffer was large enough, or th= e size of the buffer needed + to contain the image(s) information i= f the buffer was too small. + @param[in, out] ImageInfo A pointer to the buffer in which firm= ware places the current image(s) + information. The information is an ar= ray of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + @param[out] DescriptorVersion A pointer to the location in which fi= rmware returns the version number + associated with the EFI_FIRMWARE_IMAG= E_DESCRIPTOR. + @param[out] DescriptorCount A pointer to the location in which fi= rmware returns the number of + descriptors or firmware images within= this device. + @param[out] DescriptorSize A pointer to the location in which fi= rmware returns the size, in bytes, + of an individual EFI_FIRMWARE_IMAGE_D= ESCRIPTOR. + @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 PackageVersi= on is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE ind= icates that package version comparison + is to be performed using PackageVersi= onName. A value of 0xFFFFFFFD indicates + that package version update is in pro= gress. + @param[out] PackageVersionName A pointer to a pointer to a null-term= inated string representing the + package version name. The buffer is a= llocated 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 w= ith the new image. + @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. T= he current buffer size + needed to hold the image(s) informati= on is returned in ImageInfoSize. + @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL. + @retval EFI_DEVICE_ERROR Valid information could not be return= ed. 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 + ) +{ + MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate; + UINTN Index; + + MicrocodeFmpPrivate =3D MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This); + + if(ImageInfoSize =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*ImageInfoSize < sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFm= pPrivate->DescriptorCount) { + *ImageInfoSize =3D sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFm= pPrivate->DescriptorCount; + return EFI_BUFFER_TOO_SMALL; + } + + if (ImageInfo =3D=3D NULL || + DescriptorVersion =3D=3D NULL || + DescriptorCount =3D=3D NULL || + DescriptorSize =3D=3D NULL || + PackageVersion =3D=3D NULL || + PackageVersionName =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + *ImageInfoSize =3D sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * Microcod= eFmpPrivate->DescriptorCount; + *DescriptorSize =3D sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR); + *DescriptorCount =3D MicrocodeFmpPrivate->DescriptorCount; + *DescriptorVersion =3D EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; + + // + // supports 1 ImageInfo descriptor + // + CopyMem(&ImageInfo[0], MicrocodeFmpPrivate->ImageDescriptor, sizeof(EFI_= FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount); + for (Index =3D 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++)= { + if ((ImageInfo[Index].AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) !=3D= 0) { + ImageInfo[Index].LastAttemptVersion =3D MicrocodeFmpPrivate->LastAtt= empt.LastAttemptVersion; + ImageInfo[Index].LastAttemptStatus =3D MicrocodeFmpPrivate->LastAtte= mpt.LastAttemptStatus; + } + } + + // + // package version + // + *PackageVersion =3D MicrocodeFmpPrivate->PackageVersion; + if (MicrocodeFmpPrivate->PackageVersionName !=3D NULL) { + *PackageVersionName =3D AllocateCopyPool(StrSize(MicrocodeFmpPrivate->= PackageVersionName), MicrocodeFmpPrivate->PackageVersionName); + } + + 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 rec= overy 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 DescriptorCou= nt. + @param[in,out] Image Points to the buffer where the current im= age is copied to. + @param[in,out] ImageSize On entry, points to the size of the buffe= r pointed to by Image, in bytes. + On return, points to the length of the im= age, 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 bu= ffer. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATIO 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 + ) +{ + MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate; + EFI_STATUS Status; + + if (Image =3D=3D NULL || ImageSize =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + MicrocodeFmpPrivate =3D MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This); + + if (ImageIndex =3D=3D 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorC= ount || ImageSize =3D=3D NULL || Image =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D MicrocodeRead(ImageIndex, (VOID *)Image, ImageSize); + return Status; +} + +/** + 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 updat= able. + If the firmware image is updatable, the function should perform the foll= owing 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 det= ailed information on + why the image is not a supported image. + - Validate the data from VendorCode if not null. Image validation must b= e performed before + VendorCode data validation. VendorCode data is ignored or considered i= nvalid if image + validation failed. The function returns EFI_ABORTED if the data is inv= alid. + + VendorCode enables vendor to implement vendor-specific firmware image up= date policy. Null if + the caller did not specify the policy or use the default policy. As an e= xample, vendor can implement + a policy to allow an option to force a firmware image update when the ab= ort 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 DescriptorCou= nt. + @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-s= pecific 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 t= he progress of the firmware update. + @param[out] AbortReason A pointer to a pointer to a null-terminat= ed string providing more + details for the aborted operation. The bu= ffer 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_VIOLATIO 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; + MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate; + + if (Image =3D=3D NULL || AbortReason =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + MicrocodeFmpPrivate =3D MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This); + *AbortReason =3D NULL; + + if (ImageIndex =3D=3D 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorC= ount || Image =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D MicrocodeWrite(ImageIndex, (VOID *)Image, ImageSize, &Microco= deFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAtt= empt.LastAttemptStatus, AbortReason); + DEBUG((EFI_D_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n= ", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate= ->LastAttempt.LastAttemptStatus)); + VarStatus =3D gRT->SetVariable( + MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_= ACCESS, + sizeof(MicrocodeFmpPrivate->LastAttempt), + &MicrocodeFmpPrivate->LastAttempt + ); + DEBUG((EFI_D_INFO, "SetLastAttemp - %r\n", VarStatus)); + + if (!EFI_ERROR(Status)) { + InitializeMicrocodeDescriptor(MicrocodeFmpPrivate); + } + + return Status; +} + +/** + Checks if the firmware image is valid for the device. + + This function allows firmware update application to validate the firmwar= e 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 DescriptorCou= nt. + @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 u= pdate. It also provides, + if available, additional information if t= he 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_VIOLATIO 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_MANAG= EMENT_PROTOCOL instance. + @param[out] PackageVersion A version number that represents al= l the firmware images in the device. + The format is vendor specific and n= ew version must have a greater value + than the old version. If PackageVer= sion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE i= ndicates that package version + comparison is to be performed using= PackageVersionName. A value of + 0xFFFFFFFD indicates that package v= ersion update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-te= rminated string representing + the package version name. The buffe= r is allocated by this function with + AllocatePool(), and it is the calle= r's responsibility to free it with a + call to FreePool(). + @param[out] PackageVersionNameMaxLen The maximum length of package versi= on name if device supports update of + package version name. A value of 0 = indicates the device does not support + update of package version name. Len= gth is the number of Unicode characters, + including the terminating null char= acter. + @param[out] AttributesSupported Package attributes that are support= ed by this device. See 'Package Attribute + Definitions' for possible returned = values of this parameter. A value of 1 + indicates the attribute is supporte= d and the current setting value is + indicated in AttributesSetting. A v= alue of 0 indicates the attribute is not + supported and the current setting v= alue in AttributesSetting is meaningless. + @param[out] AttributesSetting Package attributes. See 'Package At= tribute Definitions' for possible returned + values of this parameter + + @retval EFI_SUCCESS The package information was success= fully 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 informati= on 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-s= pecific 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 Unic= ode string representing + the package version name. + The string length is equal to or less tha= n 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 t= han the value + returned in PackageVersionNameMaxLen. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATIO 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 Microcode Descriptor. + + @param MicrocodeFmpPrivate private data structure to be initialized. + + @return EFI_SUCCESS Microcode Descriptor is initialized. +**/ +EFI_STATUS +InitializeMicrocodeDescriptor ( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate + ) +{ + UINT8 CurrentMicrocodeCount; + + CurrentMicrocodeCount =3D (UINT8)GetMicrocodeInfo(NULL, 0); + + if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) { + if (MicrocodeFmpPrivate->ImageDescriptor !=3D NULL) { + FreePool(MicrocodeFmpPrivate->ImageDescriptor); + MicrocodeFmpPrivate->ImageDescriptor =3D NULL; + } + } else { + ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->Des= criptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)); + } + + MicrocodeFmpPrivate->DescriptorCount =3D CurrentMicrocodeCount; + + if (MicrocodeFmpPrivate->ImageDescriptor =3D=3D NULL) { + MicrocodeFmpPrivate->ImageDescriptor =3D AllocateZeroPool(MicrocodeFmp= Private->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)); + if (MicrocodeFmpPrivate->ImageDescriptor =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + CurrentMicrocodeCount =3D (UINT8)GetMicrocodeInfo(MicrocodeFmpPrivate->I= mageDescriptor, MicrocodeFmpPrivate->DescriptorCount); + ASSERT(CurrentMicrocodeCount =3D=3D MicrocodeFmpPrivate->DescriptorCount= ); + + return EFI_SUCCESS; +} + +/** + Initialize MicrocodeFmpDriver private data structure. + + @param MicrocodeFmpPrivate private data structure to be initialized. + + @return EFI_SUCCESS private data is initialized. +**/ +EFI_STATUS +InitializePrivateData( + IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate + ) +{ + EFI_STATUS Status; + EFI_STATUS VarStatus; + UINTN VarSize; + + MicrocodeFmpPrivate->Signature =3D MICROCODE_FMP_PRIVATE_DATA_SIGN= ATURE; + MicrocodeFmpPrivate->Handle =3D NULL; + CopyMem(&MicrocodeFmpPrivate->Fmp, &mFirmwareManagementProtocol, sizeof(= EFI_FIRMWARE_MANAGEMENT_PROTOCOL)); + + MicrocodeFmpPrivate->PackageVersion =3D 0x1; + MicrocodeFmpPrivate->PackageVersionName =3D L"Microcode"; + + MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion =3D 0x0; + MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus =3D 0x0; + VarSize =3D sizeof(MicrocodeFmpPrivate->LastAttempt); + VarStatus =3D gRT->GetVariable( + MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME, + &gEfiCallerIdGuid, + NULL, + &VarSize, + &MicrocodeFmpPrivate->LastAttempt + ); + DEBUG((EFI_D_INFO, "GetLastAttemp - %r\n", VarStatus)); + DEBUG((EFI_D_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", Micro= codeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAt= tempt.LastAttemptStatus)); + + Status =3D InitializeMicrocodeDescriptor(MicrocodeFmpPrivate); + + return Status; +} + +/** + Microcode FMP module entrypoint + + @param ImageHandle The firmware allocated handle for the EFI imag= e. + @param SystemTable A pointer to the EFI System Table. + + @return EFI_SUCCESS Microcode FMP module is initialized. +**/ +EFI_STATUS +EFIAPI +MicrocodeFmpMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Initialize MicrocodeFmpPrivateData + // + mMicrocodeFmpPrivate =3D AllocateZeroPool (sizeof(MICROCODE_FMP_PRIVATE_= DATA)); + if (mMicrocodeFmpPrivate =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D InitializePrivateData(mMicrocodeFmpPrivate); + if (EFI_ERROR(Status)) { + FreePool(mMicrocodeFmpPrivate); + mMicrocodeFmpPrivate =3D NULL; + return Status; + } + + // + // Install FMP protocol. + // + Status =3D gBS->InstallProtocolInterface ( + &mMicrocodeFmpPrivate->Handle, + &gEfiFirmwareManagementProtocolGuid, + EFI_NATIVE_INTERFACE, + &mMicrocodeFmpPrivate->Fmp + ); + if (EFI_ERROR (Status)) { + FreePool(mMicrocodeFmpPrivate); + mMicrocodeFmpPrivate =3D NULL; + return Status; + } + + return Status; +} diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c b/UefiCpuPkg/Micr= ocodeUpdate/MicrocodeUpdate.c new file mode 100644 index 0000000..d19eca9 --- /dev/null +++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c @@ -0,0 +1,775 @@ +/** @file + SetImage instance to update Microcode. + + Caution: This module requires additional review when modified. + This module will have external input - capsule image. + This external input must be validated carefully to avoid security issue = like + buffer overflow, integer overflow. + + MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and = do basic validation. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMP= LIED. + +**/ + +#include "MicrocodeUpdate.h" + +/** + Get Microcode Region. + + @param[out] MicrocodePatchAddress The address of Microcode + @param[out] MicrocodePatchRegionSize The region size of Microcode + + @retval TRUE The Microcode region is returned. + @retval FALSE No Microcode region. +**/ +BOOLEAN +GetMicrocodeRegion( + OUT UINT64 *MicrocodePatchAddress, + OUT UINT64 *MicrocodePatchRegionSize + ) +{ + *MicrocodePatchAddress =3D PcdGet64(PcdCpuMicrocodePatchAddress); + *MicrocodePatchRegionSize =3D PcdGet64(PcdCpuMicrocodePatchRegionSize); + + if ((*MicrocodePatchAddress =3D=3D 0) || (*MicrocodePatchRegionSize =3D= =3D 0)) { + return FALSE; + } + + return TRUE; +} + +/** + Get Microcode update signature of currently loaded Microcode update. + + @return Microcode signature. + +**/ +UINT32 +GetCurrentMicrocodeSignature( + VOID + ) +{ + UINT64 Signature; + + AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0); + AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL); + Signature =3D AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID); + return (UINT32)RShiftU64(Signature, 32); +} + +/** + Get current processor signature. + + @return current processor signature. +**/ +UINT32 +GetCurrentProcessorSignature( + VOID + ) +{ + UINT32 RegEax; + AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL); + return RegEax; +} + +/** + Get current platform ID. + + @return current platform ID. +**/ +UINT8 +GetCurrentPlatformId( + VOID + ) +{ + UINT8 PlatformId; + + PlatformId =3D (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52)= ; + return PlatformId; +} + +/** + Load new Microcode. + + @param Address The address of new Microcode. + + @return Loaded Microcode signature. + +**/ +UINT32 +LoadMicrocode( + IN UINT64 Address + ) +{ + AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address); + return GetCurrentMicrocodeSignature(); +} + +/** + Get current Microcode information. + + @param[out] ImageDescriptor Microcode ImageDescriptor + @param[in] DescriptorCount The count of Microcode ImageDescriptor all= ocated. + + @return Microcode count +**/ +UINTN +GetMicrocodeInfo( + OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageDescriptor, OPTIONAL + IN UINTN DescriptorCount OPTIONAL + ) +{ + BOOLEAN Result; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + UINT64 ImageAttributes; + UINT32 CurrentRevision; + + Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); + if (!Result) { + DEBUG((EFI_D_ERROR, "Fail to get Microcode Region\n")); + return 0; + } + DEBUG((EFI_D_ERROR, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatch= Address, MicrocodePatchRegionSize)); + + Count =3D 0; + CurrentRevision =3D GetCurrentMicrocodeSignature(); + + MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchA= ddress; + do { + if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { + // + // It is the microcode header. It is not the padding data between mi= crocode patches + // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + TotalSize =3D 2048; + } else { + TotalSize =3D MicrocodeEntryPoint->TotalSize; + } + + if (ImageDescriptor !=3D NULL && DescriptorCount > Count) { + ImageDescriptor[Count].ImageIndex =3D (UINT8)(Count + 1); + CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImage= TypeIdGuid); + ImageDescriptor[Count].ImageId =3D LShiftU64(MicrocodeEntryPoint->= ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32; + ImageDescriptor[Count].ImageIdName =3D NULL; + ImageDescriptor[Count].Version =3D MicrocodeEntryPoint->UpdateRevi= sion; + ImageDescriptor[Count].VersionName =3D NULL; + ImageDescriptor[Count].Size =3D TotalSize; + ImageAttributes =3D IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIB= UTE_RESET_REQUIRED; + if (CurrentRevision =3D=3D MicrocodeEntryPoint->UpdateRevision) { + ImageAttributes |=3D IMAGE_ATTRIBUTE_IN_USE; + } + ImageDescriptor[Count].AttributesSupported =3D ImageAttributes | I= MAGE_ATTRIBUTE_IN_USE; + ImageDescriptor[Count].AttributesSetting =3D ImageAttributes; + ImageDescriptor[Count].Compatibilities =3D 0; + ImageDescriptor[Count].LowestSupportedImageVersion =3D MicrocodeEn= tryPoint->UpdateRevision; // do not support rollback + ImageDescriptor[Count].LastAttemptVersion =3D 0; + ImageDescriptor[Count].LastAttemptStatus =3D 0; + ImageDescriptor[Count].HardwareInstance =3D 0; + } + } else { + // + // It is the padding data between the microcode patches for microcod= e patches alignment. + // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not + // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode + // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to + // find the next possible microcode patch header. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *) (((UINTN) Microcode= EntryPoint) + SIZE_1KB); + continue; + } + + Count++; + ASSERT(Count < 0xFF); + + // + // Get the next patch. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEn= tryPoint) + TotalSize); + } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); + + return Count; +} + +/** + Read Microcode. + + @param ImageIndex The index of Microcode image. + @param Image The Microcode image buffer. + @param ImageSize The size of Microcode image buffer in bytes. + + @retval EFI_SUCCESS The Microcode image is read. + @retval EFI_NOT_FOUND The Microcode image is not found. +**/ +EFI_STATUS +MicrocodeRead( + IN UINTN ImageIndex, + IN OUT VOID *Image, + IN OUT UINTN *ImageSize + ) +{ + BOOLEAN Result; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + + Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); + if (!Result) { + DEBUG((EFI_D_ERROR, "Fail to get Microcode Region\n")); + return EFI_NOT_FOUND; + } + DEBUG((EFI_D_ERROR, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatch= Address, MicrocodePatchRegionSize)); + + Count =3D 0; + + MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAdd= ress; + do { + if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { + // + // It is the microcode header. It is not the padding data between mi= crocode patches + // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + TotalSize =3D 2048; + } else { + TotalSize =3D MicrocodeEntryPoint->TotalSize; + } + + } else { + // + // It is the padding data between the microcode patches for microcod= e patches alignment. + // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not + // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode + // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to + // find the next possible microcode patch header. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEn= tryPoint) + SIZE_1KB); + continue; + } + + Count++; + ASSERT(Count < 0xFF); + + // + // Get the next patch. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntr= yPoint) + TotalSize); + } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); + + return EFI_NOT_FOUND; +} + +/** + Verify Microcode. + + @param Image The Microcode image buffer. + @param ImageSize The size of Microcode image buffer in bytes. + @param TryLoad Try to load Microcode or not. + @param LastAttemptStatus The last attempt status, which will be record= ed in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param AbortReason A pointer to a pointer to a null-terminated s= tring providing more + details for the aborted operation. The buffer= is allocated by this function + with AllocatePool(), and it is the caller's r= esponsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The Microcode image passes verificatio= n. + @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. + @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. + @retval EFI_UNSUPPORTED The Microcode ProcessorSignature or Pr= ocessorFlags is incorrect. + @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. +**/ +EFI_STATUS +VerifyMicrocode( + IN VOID *Image, + IN UINTN ImageSize, + IN BOOLEAN TryLoad, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ) +{ + UINTN Index; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN TotalSize; + UINTN DataSize; + UINT32 CurrentRevision; + UINT32 CurrentProcessorSignature; + UINT8 CurrentPlatformId; + UINT32 CheckSum32; + UINTN ExtendedTableLength; + UINT32 ExtendedTableCount; + CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; + CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; + BOOLEAN CorrectMicrocode; + + // + // Check HeaderVersion + // + MicrocodeEntryPoint =3D Image; + if (MicrocodeEntryPoint->HeaderVersion !=3D 0x1) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on HeaderVersion\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L= "InvalidHeaderVersion"); + } + return EFI_INCOMPATIBLE_VERSION; + } + // + // Check LoaderRevision + // + if (MicrocodeEntryPoint->LoaderRevision !=3D 0x1) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on LoaderRevision\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L= "InvalidLoaderVersion"); + } + return EFI_INCOMPATIBLE_VERSION; + } + // + // Check Size + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + TotalSize =3D 2048; + } else { + TotalSize =3D MicrocodeEntryPoint->TotalSize; + } + if (TotalSize <=3D sizeof(CPU_MICROCODE_HEADER)) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - TotalSize too small\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"Inv= alidTotalSize"); + } + return EFI_VOLUME_CORRUPTED; + } + if (TotalSize !=3D ImageSize) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on TotalSize\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"Inv= alidTotalSize"); + } + return EFI_VOLUME_CORRUPTED; + } + // + // Check CheckSum32 + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + DataSize =3D 2048 - sizeof(CPU_MICROCODE_HEADER); + } else { + DataSize =3D MicrocodeEntryPoint->DataSize; + } + if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - DataSize too big\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidDataSize"), L"Inva= lidDataSize"); + } + return EFI_VOLUME_CORRUPTED; + } + if ((DataSize & 0x3) !=3D 0) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - DataSize not aligned\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidDataSize"), L"Inva= lidDataSize"); + } + return EFI_VOLUME_CORRUPTED; + } + CheckSum32 =3D CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + = sizeof(CPU_MICROCODE_HEADER)); + if (CheckSum32 !=3D 0) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on CheckSum32\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidChecksum"), L"Inva= lidChecksum"); + } + return EFI_VOLUME_CORRUPTED; + } + + // + // Check ProcessorSignature/ProcessorFlags + // + CorrectMicrocode =3D FALSE; + CurrentProcessorSignature =3D GetCurrentProcessorSignature(); + CurrentPlatformId =3D GetCurrentPlatformId(); + if ((MicrocodeEntryPoint->ProcessorSignature.Uint32 !=3D CurrentProcesso= rSignature) || + ((MicrocodeEntryPoint->ProcessorFlags & (1 << CurrentPlatformId)) = =3D=3D 0)) { + ExtendedTableLength =3D TotalSize - (DataSize + sizeof(CPU_MICROCODE_H= EADER)); + if (ExtendedTableLength !=3D 0) { + // + // Extended Table exist, check if the CPU in support list + // + ExtendedTableHeader =3D (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UIN= T8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER)); + // + // Calculate Extended Checksum + // + if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADE= R)) && ((ExtendedTableLength & 0x3) !=3D 0)) { + CheckSum32 =3D CalculateSum32((UINT32 *)ExtendedTableHeader, Exten= dedTableLength); + if (CheckSum32 =3D=3D 0) { + // + // Checksum correct + // + ExtendedTableCount =3D ExtendedTableHeader->ExtendedSignatureCou= nt; + if (ExtendedTableCount <=3D (ExtendedTableLength - sizeof(CPU_MI= CROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) { + ExtendedTable =3D (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTab= leHeader + 1); + for (Index =3D 0; Index < ExtendedTableCount; Index++) { + CheckSum32 =3D CalculateSum32((UINT32 *)ExtendedTable, sizeo= f(CPU_MICROCODE_EXTENDED_TABLE)); + if (CheckSum32 =3D=3D 0) { + // + // Verify Header + // + if ((ExtendedTable->ProcessorSignature.Uint32 =3D=3D Curre= ntProcessorSignature) && + (ExtendedTable->ProcessorFlag & (1 << CurrentPlatformI= d))) { + // + // Find one + // + CorrectMicrocode =3D TRUE; + break; + } + } + ExtendedTable++; + } + } + } + } + } + if (!CorrectMicrocode) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on CurrentProcessorSigna= ture/ProcessorFlags\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; + if (AbortReason !=3D NULL) { + if (MicrocodeEntryPoint->ProcessorSignature.Uint32 !=3D CurrentPro= cessorSignature) { + *AbortReason =3D AllocateCopyPool(sizeof(L"UnsupportedProcessSig= nature"), L"UnsupportedProcessSignature"); + } else { + *AbortReason =3D AllocateCopyPool(sizeof(L"UnsupportedProcessorF= lags"), L"UnsupportedProcessorFlags"); + } + } + return EFI_UNSUPPORTED; + } + } + + // + // Check UpdateRevision + // + CurrentRevision =3D GetCurrentMicrocodeSignature(); + if (MicrocodeEntryPoint->UpdateRevision < CurrentRevision) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on UpdateRevision\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"IncorrectRevision"), L"In= correctRevision"); + } + return EFI_INCOMPATIBLE_VERSION; + } + + // + // try load MCU + // + if (TryLoad) { + CurrentRevision =3D LoadMicrocode((UINTN)MicrocodeEntryPoint + sizeof(= CPU_MICROCODE_HEADER)); + if (MicrocodeEntryPoint->UpdateRevision !=3D CurrentRevision) { + DEBUG((EFI_D_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR; + if (AbortReason !=3D NULL) { + *AbortReason =3D AllocateCopyPool(sizeof(L"InvalidData"), L"Invali= dData"); + } + return EFI_SECURITY_VIOLATION; + } + } + + return EFI_SUCCESS; +} + +/** + Get current Microcode in used. + + @return current Microcode in used. +**/ +VOID * +GetCurrentMicrocodeInUse( + VOID + ) +{ + BOOLEAN Result; + EFI_STATUS Status; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + UINT32 AttemptStatus; + + Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); + if (!Result) { + DEBUG((EFI_D_ERROR, "Fail to get Microcode Region\n")); + return NULL; + } + DEBUG((EFI_D_ERROR, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatch= Address, MicrocodePatchRegionSize)); + + Count =3D 0; + + MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAdd= ress; + do { + if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { + // + // It is the microcode header. It is not the padding data between mi= crocode patches + // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + TotalSize =3D 2048; + } else { + TotalSize =3D MicrocodeEntryPoint->TotalSize; + } + Status =3D VerifyMicrocode(MicrocodeEntryPoint, TotalSize, FALSE, &A= ttemptStatus, NULL); + if (!EFI_ERROR(Status)) { + return MicrocodeEntryPoint; + } + + } else { + // + // It is the padding data between the microcode patches for microcod= e patches alignment. + // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not + // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode + // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to + // find the next possible microcode patch header. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEn= tryPoint) + SIZE_1KB); + continue; + } + + Count++; + ASSERT(Count < 0xFF); + + // + // Get the next patch. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntr= yPoint) + TotalSize); + } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); + + return NULL; +} + +/** + Get current Microcode used region size. + + @return current Microcode used region size. +**/ +UINTN +GetCurrentMicrocodeUsedRegionSize( + VOID + ) +{ + BOOLEAN Result; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *MicrocodeEntryPoint; + UINTN MicrocodeEnd; + UINTN TotalSize; + UINTN Count; + UINTN MicrocodeUsedEnd; + + Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); + if (!Result) { + DEBUG((EFI_D_ERROR, "Fail to get Microcode Region\n")); + return 0; + } + DEBUG((EFI_D_ERROR, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatch= Address, MicrocodePatchRegionSize)); + + MicrocodeUsedEnd =3D (UINTN)MicrocodePatchAddress; + Count =3D 0; + + MicrocodeEnd =3D (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSiz= e); + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAdd= ress; + do { + if (MicrocodeEntryPoint->HeaderVersion =3D=3D 0x1 && MicrocodeEntryPoi= nt->LoaderRevision =3D=3D 0x1) { + // + // It is the microcode header. It is not the padding data between mi= crocode patches + // becasue the padding data should not include 0x00000001 and it sho= uld be the repeated + // byte format (like 0xXYXYXYXY....). + // + if (MicrocodeEntryPoint->DataSize =3D=3D 0) { + TotalSize =3D 2048; + } else { + TotalSize =3D MicrocodeEntryPoint->TotalSize; + } + + } else { + // + // It is the padding data between the microcode patches for microcod= e patches alignment. + // Because the microcode patch is the multiple of 1-KByte, the paddi= ng data should not + // exist if the microcode patch alignment value is not larger than 1= -KByte. So, the microcode + // alignment value should be larger than 1-KByte. We could skip SIZE= _1KB padding data to + // find the next possible microcode patch header. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEn= tryPoint) + SIZE_1KB); + continue; + } + + Count++; + ASSERT(Count < 0xFF); + MicrocodeUsedEnd =3D (UINTN)MicrocodeEntryPoint; + + // + // Get the next patch. + // + MicrocodeEntryPoint =3D (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntr= yPoint) + TotalSize); + } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); + + return MicrocodeUsedEnd - (UINTN)MicrocodePatchAddress; +} + +/** + Update Microcode. + + @param Address The flash address of Microcode. + @param Image The Microcode image buffer. + @param ImageSize The size of Microcode image buffer in bytes. + @param LastAttemptStatus The last attempt status, which will be record= ed in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + + @retval EFI_SUCCESS The Microcode image is updated. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +UpdateMicrocode( + IN UINT64 Address, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptStatus + ) +{ + EFI_STATUS Status; + + DEBUG((EFI_D_INFO, "PlatformUpdate:")); + DEBUG((EFI_D_INFO, " Address - 0x%lx,", Address)); + DEBUG((EFI_D_INFO, " Legnth - 0x%x\n", ImageSize)); + + Status =3D MicrocodeFlashWrite ( + Address, + Image, + ImageSize + ); + if (!EFI_ERROR(Status)) { + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_SUCCESS; + } else { + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + } + return Status; +} + +/** + Write Microcode. + + @param ImageIndex The index of Microcode image. + @param Image The Microcode image buffer. + @param ImageSize The size of Microcode image buffer in bytes. + @param LastAttemptVersion The last attempt version, which will be recor= ded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param LastAttemptStatus The last attempt status, which will be record= ed in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param AbortReason A pointer to a pointer to a null-terminated s= tring providing more + details for the aborted operation. The buffer= is allocated by this function + with AllocatePool(), and it is the caller's r= esponsibility to free it with a + call to FreePool(). + + @retval EFI_SUCCESS The Microcode image is written. + @retval EFI_VOLUME_CORRUPTED The Microcode image is corrupt. + @retval EFI_INCOMPATIBLE_VERSION The Microcode image version is incorre= ct. + @retval EFI_SECURITY_VIOLATION The Microcode image fails to load. + @retval EFI_WRITE_PROTECTED The flash device is read only. +**/ +EFI_STATUS +MicrocodeWrite( + IN UINTN ImageIndex, + IN VOID *Image, + IN UINTN ImageSize, + OUT UINT32 *LastAttemptVersion, + OUT UINT32 *LastAttemptStatus, + OUT CHAR16 **AbortReason + ) +{ + BOOLEAN Result; + EFI_STATUS Status; + UINT64 MicrocodePatchAddress; + UINT64 MicrocodePatchRegionSize; + CPU_MICROCODE_HEADER *CurrentMicrocodeEntryPoint; + UINTN CurrentTotalSize; + UINTN UsedRegionSize; + VOID *AlignedImage; + + Result =3D GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchReg= ionSize); + if (!Result) { + DEBUG((EFI_D_ERROR, "Fail to get Microcode Region\n")); + return EFI_NOT_FOUND; + } + + CurrentTotalSize =3D 0; + CurrentMicrocodeEntryPoint =3D GetCurrentMicrocodeInUse(); + if (CurrentMicrocodeEntryPoint !=3D NULL) { + if (CurrentMicrocodeEntryPoint->DataSize =3D=3D 0) { + CurrentTotalSize =3D 2048; + } else { + CurrentTotalSize =3D CurrentMicrocodeEntryPoint->TotalSize; + } + } + + // + // MCU must be 16 bytes aligned + // + AlignedImage =3D AllocateCopyPool(ImageSize, Image); + + *LastAttemptVersion =3D ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision; + Status =3D VerifyMicrocode(AlignedImage, ImageSize, TRUE, LastAttemptSta= tus, AbortReason); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "Fail to verify Microcode Region\n")); + FreePool(AlignedImage); + return Status; + } + DEBUG((EFI_D_INFO, "Pass VerifyMicrocode\n")); + + if (CurrentTotalSize < ImageSize) { + UsedRegionSize =3D GetCurrentMicrocodeUsedRegionSize(); + if (MicrocodePatchRegionSize - UsedRegionSize >=3D ImageSize) { + // + // Append + // + DEBUG((EFI_D_INFO, "Append new microcode\n")); + Status =3D UpdateMicrocode(MicrocodePatchAddress + UsedRegionSize, A= lignedImage, ImageSize, LastAttemptStatus); + } else if (MicrocodePatchRegionSize >=3D ImageSize) { + // + // Ignor all others and just add this one from beginning. + // + DEBUG((EFI_D_INFO, "Add new microcode from beginning\n")); + Status =3D UpdateMicrocode(MicrocodePatchAddress, AlignedImage, Imag= eSize, LastAttemptStatus); + } else { + DEBUG((EFI_D_ERROR, "Microcode too big\n")); + *LastAttemptStatus =3D LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOUR= CES; + Status =3D EFI_OUT_OF_RESOURCES; + } + } else { + // + // Replace + // + DEBUG((EFI_D_INFO, "Replace old microcode\n")); + Status =3D UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, AlignedI= mage, ImageSize, LastAttemptStatus); + } + + FreePool(AlignedImage); + + return Status; +} + + diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h b/UefiCpuPkg/Micr= ocodeUpdate/MicrocodeUpdate.h new file mode 100644 index 0000000..23ec0ba --- /dev/null +++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h @@ -0,0 +1,299 @@ +/** @file + Microcode update header file. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMP= LIED. + +**/ + +#ifndef _MICROCODE_FMP_H_ +#define _MICROCODE_FMP_H_ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + 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 rec= overy or rollback. + + @param[in] This A pointer to the EFI_FIRMWARE_MANAGEM= ENT_PROTOCOL instance. + @param[in, out] ImageInfoSize A pointer to the size, in bytes, of t= he ImageInfo buffer. + On input, this is the size of the buf= fer allocated by the caller. + On output, it is the size of the buff= er returned by the firmware + if the buffer was large enough, or th= e size of the buffer needed + to contain the image(s) information i= f the buffer was too small. + @param[in, out] ImageInfo A pointer to the buffer in which firm= ware places the current image(s) + information. The information is an ar= ray of EFI_FIRMWARE_IMAGE_DESCRIPTORs. + @param[out] DescriptorVersion A pointer to the location in which fi= rmware returns the version number + associated with the EFI_FIRMWARE_IMAG= E_DESCRIPTOR. + @param[out] DescriptorCount A pointer to the location in which fi= rmware returns the number of + descriptors or firmware images within= this device. + @param[out] DescriptorSize A pointer to the location in which fi= rmware returns the size, in bytes, + of an individual EFI_FIRMWARE_IMAGE_D= ESCRIPTOR. + @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 PackageVersi= on is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE ind= icates that package version comparison + is to be performed using PackageVersi= onName. A value of 0xFFFFFFFD indicates + that package version update is in pro= gress. + @param[out] PackageVersionName A pointer to a pointer to a null-term= inated string representing the + package version name. The buffer is a= llocated 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 w= ith the new image. + @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. T= he current buffer size + needed to hold the image(s) informati= on is returned in ImageInfoSize. + @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL. + @retval EFI_DEVICE_ERROR Valid information could not be return= ed. 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 rec= overy 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 DescriptorCou= nt. + @param[in,out] Image Points to the buffer where the current im= age is copied to. + @param[in,out] ImageSize On entry, points to the size of the buffe= r pointed to by Image, in bytes. + On return, points to the length of the im= age, 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 bu= ffer. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATIO 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 updat= able. + If the firmware image is updatable, the function should perform the foll= owing 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 det= ailed information on + why the image is not a supported image. + - Validate the data from VendorCode if not null. Image validation must b= e performed before + VendorCode data validation. VendorCode data is ignored or considered i= nvalid if image + validation failed. The function returns EFI_ABORTED if the data is inv= alid. + + VendorCode enables vendor to implement vendor-specific firmware image up= date policy. Null if + the caller did not specify the policy or use the default policy. As an e= xample, vendor can implement + a policy to allow an option to force a firmware image update when the ab= ort 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 DescriptorCou= nt. + @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-s= pecific 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 t= he progress of the firmware update. + @param[out] AbortReason A pointer to a pointer to a null-terminat= ed string providing more + details for the aborted operation. The bu= ffer 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_VIOLATIO 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 firmwar= e 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 DescriptorCou= nt. + @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 u= pdate. It also provides, + if available, additional information if t= he 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_VIOLATIO 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_MANAG= EMENT_PROTOCOL instance. + @param[out] PackageVersion A version number that represents al= l the firmware images in the device. + The format is vendor specific and n= ew version must have a greater value + than the old version. If PackageVer= sion is not supported, the value is + 0xFFFFFFFF. A value of 0xFFFFFFFE i= ndicates that package version + comparison is to be performed using= PackageVersionName. A value of + 0xFFFFFFFD indicates that package v= ersion update is in progress. + @param[out] PackageVersionName A pointer to a pointer to a null-te= rminated string representing + the package version name. The buffe= r is allocated by this function with + AllocatePool(), and it is the calle= r's responsibility to free it with a + call to FreePool(). + @param[out] PackageVersionNameMaxLen The maximum length of package versi= on name if device supports update of + package version name. A value of 0 = indicates the device does not support + update of package version name. Len= gth is the number of Unicode characters, + including the terminating null char= acter. + @param[out] AttributesSupported Package attributes that are support= ed by this device. See 'Package Attribute + Definitions' for possible returned = values of this parameter. A value of 1 + indicates the attribute is supporte= d and the current setting value is + indicated in AttributesSetting. A v= alue of 0 indicates the attribute is not + supported and the current setting v= alue in AttributesSetting is meaningless. + @param[out] AttributesSetting Package attributes. See 'Package At= tribute Definitions' for possible returned + values of this parameter + + @retval EFI_SUCCESS The package information was success= fully 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 informati= on 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-s= pecific 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 Unic= ode string representing + the package version name. + The string length is equal to or less tha= n 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 t= han the value + returned in PackageVersionNameMaxLen. + @retval EFI_UNSUPPORTED The operation is not supported. + @retval EFI_SECURITY_VIOLATIO 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 + ); + +#endif + diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf b/UefiCpuPkg/Mi= crocodeUpdate/MicrocodeUpdate.inf new file mode 100644 index 0000000..736684c --- /dev/null +++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf @@ -0,0 +1,68 @@ +## @file +# Microcode FMP update driver. +# +# Produce FMP instance to update Microcode. +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may = be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D MicrocodeUpdate + MODULE_UNI_FILE =3D MicrocodeUpdateDxe.uni + FILE_GUID =3D 0565365C-2FE1-4F88-B3BE-624C04623A20 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D MicrocodeFmpMain + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D X64 +# + +[Sources] + MicrocodeFmp.c + MicrocodeUpdate.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + BaseMemoryLib + DebugLib + PcdLib + MemoryAllocationLib + UefiBootServicesTableLib + HobLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + MicrocodeFlashAccessLib + +[Guids] + gMicrocodeFmpImageTypeIdGuid + +[Protocols] + gEfiFirmwareManagementProtocolGuid ## SOMTIMES_PRODUCE + +[Pcd] + gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONS= UMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONS= UMES + +[Depex] + gEfiVariableArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + MicrocodeUpdateDxeExtra.uni + diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni b/UefiCpuPkg= /MicrocodeUpdate/MicrocodeUpdateDxe.uni new file mode 100644 index 0000000..1b0d494 --- /dev/null +++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni @@ -0,0 +1,21 @@ +// /** @file +// Microcode FMP update driver. +// +// Produce FMP instance to update Microcode. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the B= SD License +// which accompanies this distribution. The full text of the license may = be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Microcode FMP upd= ate driver." + +#string STR_MODULE_DESCRIPTION #language en-US "Produce FMP insta= nce to update Microcode." diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni b/UefiC= puPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni new file mode 100644 index 0000000..b667f12 --- /dev/null +++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni @@ -0,0 +1,20 @@ +// /** @file +// MicrocodeUpdateDxe Localized Strings and Content +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the B= SD License +// which accompanies this distribution. The full text of the license may = be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"MicrocodeUpdate DXE Driver" + + --=20 2.7.4.windows.1