UefiCpuPkg/MicrocodeUpdate: Add MicrocodeUpdate component.
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 <jeff.fan@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Chao Zhang <chao.b.zhang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
		
							
								
								
									
										537
									
								
								UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										537
									
								
								UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,537 @@ | |||||||
|  | /** @file | ||||||
|  |   Produce FMP instance for Microcode. | ||||||
|  |  | ||||||
|  |   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | ||||||
|  |   This program and the accompanying materials | ||||||
|  |   are licensed and made available under the terms and conditions of the BSD 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 IMPLIED. | ||||||
|  |  | ||||||
|  | **/ | ||||||
|  |  | ||||||
|  | #include "MicrocodeUpdate.h" | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // MicrocodeFmp driver private data | ||||||
|  | // | ||||||
|  | MICROCODE_FMP_PRIVATE_DATA *mMicrocodeFmpPrivate = NULL; | ||||||
|  |  | ||||||
|  | EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = { | ||||||
|  |   FmpGetImageInfo, | ||||||
|  |   FmpGetImage, | ||||||
|  |   FmpSetImage, | ||||||
|  |   FmpCheckImage, | ||||||
|  |   FmpGetPackageInfo, | ||||||
|  |   FmpSetPackageInfo | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Initialize Microcode Descriptor. | ||||||
|  |  | ||||||
|  |   @param[in] 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 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 | ||||||
|  |   ) | ||||||
|  | { | ||||||
|  |   MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate; | ||||||
|  |   UINTN                      Index; | ||||||
|  |  | ||||||
|  |   MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This); | ||||||
|  |  | ||||||
|  |   if(ImageInfoSize == NULL) { | ||||||
|  |     return EFI_INVALID_PARAMETER; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (*ImageInfoSize < sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount) { | ||||||
|  |     *ImageInfoSize = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->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) * MicrocodeFmpPrivate->DescriptorCount; | ||||||
|  |   *DescriptorSize     = sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR); | ||||||
|  |   *DescriptorCount    = MicrocodeFmpPrivate->DescriptorCount; | ||||||
|  |   *DescriptorVersion  = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // supports 1 ImageInfo descriptor | ||||||
|  |   // | ||||||
|  |   CopyMem(&ImageInfo[0], MicrocodeFmpPrivate->ImageDescriptor, sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR) * MicrocodeFmpPrivate->DescriptorCount); | ||||||
|  |   for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) { | ||||||
|  |     if ((ImageInfo[Index].AttributesSetting & IMAGE_ATTRIBUTE_IN_USE) != 0) { | ||||||
|  |       ImageInfo[Index].LastAttemptVersion = MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion; | ||||||
|  |       ImageInfo[Index].LastAttemptStatus = MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // package version | ||||||
|  |   // | ||||||
|  |   *PackageVersion = MicrocodeFmpPrivate->PackageVersion; | ||||||
|  |   if (MicrocodeFmpPrivate->PackageVersionName != NULL) { | ||||||
|  |     *PackageVersionName = 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 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_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 == NULL || ImageSize == NULL) { | ||||||
|  |     return EFI_INVALID_PARAMETER; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This); | ||||||
|  |  | ||||||
|  |   if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || ImageSize == NULL || Image == NULL) { | ||||||
|  |     return EFI_INVALID_PARAMETER; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Status = 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 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_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 == NULL || AbortReason == NULL) { | ||||||
|  |     return EFI_INVALID_PARAMETER; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   MicrocodeFmpPrivate = MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(This); | ||||||
|  |   *AbortReason     = NULL; | ||||||
|  |  | ||||||
|  |   if (ImageIndex == 0 || ImageIndex > MicrocodeFmpPrivate->DescriptorCount || Image == NULL) { | ||||||
|  |     return EFI_INVALID_PARAMETER; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Status = MicrocodeWrite(ImageIndex, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason); | ||||||
|  |   DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus)); | ||||||
|  |   VarStatus = gRT->SetVariable( | ||||||
|  |                      MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME, | ||||||
|  |                      &gEfiCallerIdGuid, | ||||||
|  |                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | ||||||
|  |                      sizeof(MicrocodeFmpPrivate->LastAttempt), | ||||||
|  |                      &MicrocodeFmpPrivate->LastAttempt | ||||||
|  |                      ); | ||||||
|  |   DEBUG((DEBUG_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 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_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_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_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[in] 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 = (UINT8)GetMicrocodeInfo(NULL, 0); | ||||||
|  |  | ||||||
|  |   if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) { | ||||||
|  |     if (MicrocodeFmpPrivate->ImageDescriptor != NULL) { | ||||||
|  |       FreePool(MicrocodeFmpPrivate->ImageDescriptor); | ||||||
|  |       MicrocodeFmpPrivate->ImageDescriptor = NULL; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   MicrocodeFmpPrivate->DescriptorCount = CurrentMicrocodeCount; | ||||||
|  |  | ||||||
|  |   if (MicrocodeFmpPrivate->ImageDescriptor == NULL) { | ||||||
|  |     MicrocodeFmpPrivate->ImageDescriptor = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR)); | ||||||
|  |     if (MicrocodeFmpPrivate->ImageDescriptor == NULL) { | ||||||
|  |       return EFI_OUT_OF_RESOURCES; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount); | ||||||
|  |   ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount); | ||||||
|  |  | ||||||
|  |   return EFI_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Initialize MicrocodeFmpDriver private data structure. | ||||||
|  |  | ||||||
|  |   @param[in] 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       = MICROCODE_FMP_PRIVATE_DATA_SIGNATURE; | ||||||
|  |   MicrocodeFmpPrivate->Handle          = NULL; | ||||||
|  |   CopyMem(&MicrocodeFmpPrivate->Fmp, &mFirmwareManagementProtocol, sizeof(EFI_FIRMWARE_MANAGEMENT_PROTOCOL)); | ||||||
|  |  | ||||||
|  |   MicrocodeFmpPrivate->PackageVersion = 0x1; | ||||||
|  |   MicrocodeFmpPrivate->PackageVersionName = L"Microcode"; | ||||||
|  |  | ||||||
|  |   MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion = 0x0; | ||||||
|  |   MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus = 0x0; | ||||||
|  |   VarSize = sizeof(MicrocodeFmpPrivate->LastAttempt); | ||||||
|  |   VarStatus = gRT->GetVariable( | ||||||
|  |                      MICROCODE_FMP_LAST_ATTEMPT_VARIABLE_NAME, | ||||||
|  |                      &gEfiCallerIdGuid, | ||||||
|  |                      NULL, | ||||||
|  |                      &VarSize, | ||||||
|  |                      &MicrocodeFmpPrivate->LastAttempt | ||||||
|  |                      ); | ||||||
|  |   DEBUG((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus)); | ||||||
|  |   DEBUG((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus)); | ||||||
|  |  | ||||||
|  |   Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate); | ||||||
|  |  | ||||||
|  |   return Status; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Microcode FMP module entrypoint | ||||||
|  |  | ||||||
|  |   @param[in]  ImageHandle       The firmware allocated handle for the EFI image. | ||||||
|  |   @param[in]  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 = AllocateZeroPool (sizeof(MICROCODE_FMP_PRIVATE_DATA)); | ||||||
|  |   if (mMicrocodeFmpPrivate == NULL) { | ||||||
|  |     return EFI_OUT_OF_RESOURCES; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Status = InitializePrivateData(mMicrocodeFmpPrivate); | ||||||
|  |   if (EFI_ERROR(Status)) { | ||||||
|  |     FreePool(mMicrocodeFmpPrivate); | ||||||
|  |     mMicrocodeFmpPrivate = NULL; | ||||||
|  |     return Status; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Install FMP protocol. | ||||||
|  |   // | ||||||
|  |   Status = gBS->InstallProtocolInterface ( | ||||||
|  |                   &mMicrocodeFmpPrivate->Handle, | ||||||
|  |                   &gEfiFirmwareManagementProtocolGuid, | ||||||
|  |                   EFI_NATIVE_INTERFACE, | ||||||
|  |                   &mMicrocodeFmpPrivate->Fmp | ||||||
|  |                   ); | ||||||
|  |   if (EFI_ERROR (Status)) { | ||||||
|  |     FreePool(mMicrocodeFmpPrivate); | ||||||
|  |     mMicrocodeFmpPrivate = NULL; | ||||||
|  |     return Status; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return Status; | ||||||
|  | } | ||||||
							
								
								
									
										784
									
								
								UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										784
									
								
								UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,784 @@ | |||||||
|  | /** @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.<BR> | ||||||
|  |   This program and the accompanying materials | ||||||
|  |   are licensed and made available under the terms and conditions of the BSD 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 IMPLIED. | ||||||
|  |  | ||||||
|  | **/ | ||||||
|  |  | ||||||
|  | #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 = PcdGet64(PcdCpuMicrocodePatchAddress); | ||||||
|  |   *MicrocodePatchRegionSize = PcdGet64(PcdCpuMicrocodePatchRegionSize); | ||||||
|  |  | ||||||
|  |   if ((*MicrocodePatchAddress == 0) || (*MicrocodePatchRegionSize == 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 = 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 = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52); | ||||||
|  |   return PlatformId; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Load new Microcode. | ||||||
|  |  | ||||||
|  |   @param[in] 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 allocated. | ||||||
|  |  | ||||||
|  |   @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 = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); | ||||||
|  |   if (!Result) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize)); | ||||||
|  |  | ||||||
|  |   Count = 0; | ||||||
|  |   CurrentRevision = GetCurrentMicrocodeSignature(); | ||||||
|  |  | ||||||
|  |   MicrocodeEnd = (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSize); | ||||||
|  |   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress; | ||||||
|  |   do { | ||||||
|  |     if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) { | ||||||
|  |       // | ||||||
|  |       // It is the microcode header. It is not the padding data between microcode patches | ||||||
|  |       // becasue the padding data should not include 0x00000001 and it should be the repeated | ||||||
|  |       // byte format (like 0xXYXYXYXY....). | ||||||
|  |       // | ||||||
|  |       if (MicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |         TotalSize = 2048; | ||||||
|  |       } else { | ||||||
|  |         TotalSize = MicrocodeEntryPoint->TotalSize; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (ImageDescriptor != NULL && DescriptorCount > Count) { | ||||||
|  |         ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1); | ||||||
|  |         CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid); | ||||||
|  |         ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32; | ||||||
|  |         ImageDescriptor[Count].ImageIdName = NULL; | ||||||
|  |         ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision; | ||||||
|  |         ImageDescriptor[Count].VersionName = NULL; | ||||||
|  |         ImageDescriptor[Count].Size = TotalSize; | ||||||
|  |         ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED; | ||||||
|  |         if (CurrentRevision == MicrocodeEntryPoint->UpdateRevision) { | ||||||
|  |           ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE; | ||||||
|  |         } | ||||||
|  |         ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE; | ||||||
|  |         ImageDescriptor[Count].AttributesSetting = ImageAttributes; | ||||||
|  |         ImageDescriptor[Count].Compatibilities = 0; | ||||||
|  |         ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback | ||||||
|  |         ImageDescriptor[Count].LastAttemptVersion = 0; | ||||||
|  |         ImageDescriptor[Count].LastAttemptStatus = 0; | ||||||
|  |         ImageDescriptor[Count].HardwareInstance = 0; | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       // | ||||||
|  |       // It is the padding data between the microcode patches for microcode patches alignment. | ||||||
|  |       // Because the microcode patch is the multiple of 1-KByte, the padding 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 = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Count++; | ||||||
|  |     ASSERT(Count < 0xFF); | ||||||
|  |  | ||||||
|  |     // | ||||||
|  |     // Get the next patch. | ||||||
|  |     // | ||||||
|  |     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize); | ||||||
|  |   } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); | ||||||
|  |  | ||||||
|  |   return Count; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Read Microcode. | ||||||
|  |  | ||||||
|  |   @param[in]       ImageIndex The index of Microcode image. | ||||||
|  |   @param[in, out]  Image      The Microcode image buffer. | ||||||
|  |   @param[in, out]  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 = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); | ||||||
|  |   if (!Result) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); | ||||||
|  |     return EFI_NOT_FOUND; | ||||||
|  |   } | ||||||
|  |   DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize)); | ||||||
|  |  | ||||||
|  |   Count = 0; | ||||||
|  |  | ||||||
|  |   MicrocodeEnd = (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSize); | ||||||
|  |   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAddress; | ||||||
|  |   do { | ||||||
|  |     if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) { | ||||||
|  |       // | ||||||
|  |       // It is the microcode header. It is not the padding data between microcode patches | ||||||
|  |       // becasue the padding data should not include 0x00000001 and it should be the repeated | ||||||
|  |       // byte format (like 0xXYXYXYXY....). | ||||||
|  |       // | ||||||
|  |       if (MicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |         TotalSize = 2048; | ||||||
|  |       } else { | ||||||
|  |         TotalSize = MicrocodeEntryPoint->TotalSize; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |       // | ||||||
|  |       // It is the padding data between the microcode patches for microcode patches alignment. | ||||||
|  |       // Because the microcode patch is the multiple of 1-KByte, the padding 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 = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Count++; | ||||||
|  |     ASSERT(Count < 0xFF); | ||||||
|  |  | ||||||
|  |     // | ||||||
|  |     // Get the next patch. | ||||||
|  |     // | ||||||
|  |     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + TotalSize); | ||||||
|  |   } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); | ||||||
|  |  | ||||||
|  |   return EFI_NOT_FOUND; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Verify Microcode. | ||||||
|  |  | ||||||
|  |   Caution: This function may receive untrusted input. | ||||||
|  |  | ||||||
|  |   @param[in]  Image              The Microcode image buffer. | ||||||
|  |   @param[in]  ImageSize          The size of Microcode image buffer in bytes. | ||||||
|  |   @param[in]  TryLoad            Try to load Microcode or not. | ||||||
|  |   @param[out] LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR. | ||||||
|  |   @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 Microcode image passes verification. | ||||||
|  |   @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt. | ||||||
|  |   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect. | ||||||
|  |   @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags 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 = Image; | ||||||
|  |   if (MicrocodeEntryPoint->HeaderVersion != 0x1) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion"); | ||||||
|  |     } | ||||||
|  |     return EFI_INCOMPATIBLE_VERSION; | ||||||
|  |   } | ||||||
|  |   // | ||||||
|  |   // Check LoaderRevision | ||||||
|  |   // | ||||||
|  |   if (MicrocodeEntryPoint->LoaderRevision != 0x1) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion"); | ||||||
|  |     } | ||||||
|  |     return EFI_INCOMPATIBLE_VERSION; | ||||||
|  |   } | ||||||
|  |   // | ||||||
|  |   // Check Size | ||||||
|  |   // | ||||||
|  |   if (MicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |     TotalSize = 2048; | ||||||
|  |   } else { | ||||||
|  |     TotalSize = MicrocodeEntryPoint->TotalSize; | ||||||
|  |   } | ||||||
|  |   if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize"); | ||||||
|  |     } | ||||||
|  |     return EFI_VOLUME_CORRUPTED; | ||||||
|  |   } | ||||||
|  |   if (TotalSize != ImageSize) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize"); | ||||||
|  |     } | ||||||
|  |     return EFI_VOLUME_CORRUPTED; | ||||||
|  |   } | ||||||
|  |   // | ||||||
|  |   // Check CheckSum32 | ||||||
|  |   // | ||||||
|  |   if (MicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |     DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER); | ||||||
|  |   } else { | ||||||
|  |     DataSize = MicrocodeEntryPoint->DataSize; | ||||||
|  |   } | ||||||
|  |   if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize"); | ||||||
|  |     } | ||||||
|  |     return EFI_VOLUME_CORRUPTED; | ||||||
|  |   } | ||||||
|  |   if ((DataSize & 0x3) != 0) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize"); | ||||||
|  |     } | ||||||
|  |     return EFI_VOLUME_CORRUPTED; | ||||||
|  |   } | ||||||
|  |   CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER)); | ||||||
|  |   if (CheckSum32 != 0) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum"); | ||||||
|  |     } | ||||||
|  |     return EFI_VOLUME_CORRUPTED; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Check ProcessorSignature/ProcessorFlags | ||||||
|  |   // | ||||||
|  |   CorrectMicrocode = FALSE; | ||||||
|  |   CurrentProcessorSignature = GetCurrentProcessorSignature(); | ||||||
|  |   CurrentPlatformId = GetCurrentPlatformId(); | ||||||
|  |   if ((MicrocodeEntryPoint->ProcessorSignature.Uint32 != CurrentProcessorSignature) || | ||||||
|  |       ((MicrocodeEntryPoint->ProcessorFlags & (1 << CurrentPlatformId)) == 0)) { | ||||||
|  |     ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER)); | ||||||
|  |     if (ExtendedTableLength != 0) { | ||||||
|  |       // | ||||||
|  |       // Extended Table exist, check if the CPU in support list | ||||||
|  |       // | ||||||
|  |       ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER)); | ||||||
|  |       // | ||||||
|  |       // Calculate Extended Checksum | ||||||
|  |       // | ||||||
|  |       if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) { | ||||||
|  |         CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength); | ||||||
|  |         if (CheckSum32 == 0) { | ||||||
|  |           // | ||||||
|  |           // Checksum correct | ||||||
|  |           // | ||||||
|  |           ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; | ||||||
|  |           if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) { | ||||||
|  |             ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1); | ||||||
|  |             for (Index = 0; Index < ExtendedTableCount; Index++) { | ||||||
|  |               CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE)); | ||||||
|  |               if (CheckSum32 == 0) { | ||||||
|  |                 // | ||||||
|  |                 // Verify Header | ||||||
|  |                 // | ||||||
|  |                 if ((ExtendedTable->ProcessorSignature.Uint32 == CurrentProcessorSignature) && | ||||||
|  |                     (ExtendedTable->ProcessorFlag & (1 << CurrentPlatformId))) { | ||||||
|  |                   // | ||||||
|  |                   // Find one | ||||||
|  |                   // | ||||||
|  |                   CorrectMicrocode = TRUE; | ||||||
|  |                   break; | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |               ExtendedTable++; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if (!CorrectMicrocode) { | ||||||
|  |       DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n")); | ||||||
|  |       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; | ||||||
|  |       if (AbortReason != NULL) { | ||||||
|  |         if (MicrocodeEntryPoint->ProcessorSignature.Uint32 != CurrentProcessorSignature) { | ||||||
|  |           *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature"), L"UnsupportedProcessSignature"); | ||||||
|  |         } else { | ||||||
|  |           *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessorFlags"), L"UnsupportedProcessorFlags"); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       return EFI_UNSUPPORTED; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // Check UpdateRevision | ||||||
|  |   // | ||||||
|  |   CurrentRevision = GetCurrentMicrocodeSignature(); | ||||||
|  |   if (MicrocodeEntryPoint->UpdateRevision < CurrentRevision) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION; | ||||||
|  |     if (AbortReason != NULL) { | ||||||
|  |       *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision"); | ||||||
|  |     } | ||||||
|  |     return EFI_INCOMPATIBLE_VERSION; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // try load MCU | ||||||
|  |   // | ||||||
|  |   if (TryLoad) { | ||||||
|  |     CurrentRevision = LoadMicrocode((UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER)); | ||||||
|  |     if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) { | ||||||
|  |       DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n")); | ||||||
|  |       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR; | ||||||
|  |       if (AbortReason != NULL) { | ||||||
|  |         *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData"); | ||||||
|  |       } | ||||||
|  |       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 = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); | ||||||
|  |   if (!Result) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); | ||||||
|  |     return NULL; | ||||||
|  |   } | ||||||
|  |   DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize)); | ||||||
|  |  | ||||||
|  |   Count = 0; | ||||||
|  |  | ||||||
|  |   MicrocodeEnd = (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSize); | ||||||
|  |   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAddress; | ||||||
|  |   do { | ||||||
|  |     if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) { | ||||||
|  |       // | ||||||
|  |       // It is the microcode header. It is not the padding data between microcode patches | ||||||
|  |       // becasue the padding data should not include 0x00000001 and it should be the repeated | ||||||
|  |       // byte format (like 0xXYXYXYXY....). | ||||||
|  |       // | ||||||
|  |       if (MicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |         TotalSize = 2048; | ||||||
|  |       } else { | ||||||
|  |         TotalSize = MicrocodeEntryPoint->TotalSize; | ||||||
|  |       } | ||||||
|  |       Status = VerifyMicrocode(MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL); | ||||||
|  |       if (!EFI_ERROR(Status)) { | ||||||
|  |         return MicrocodeEntryPoint; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |       // | ||||||
|  |       // It is the padding data between the microcode patches for microcode patches alignment. | ||||||
|  |       // Because the microcode patch is the multiple of 1-KByte, the padding 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 = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Count++; | ||||||
|  |     ASSERT(Count < 0xFF); | ||||||
|  |  | ||||||
|  |     // | ||||||
|  |     // Get the next patch. | ||||||
|  |     // | ||||||
|  |     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + 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 = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); | ||||||
|  |   if (!Result) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize)); | ||||||
|  |  | ||||||
|  |   MicrocodeUsedEnd = (UINTN)MicrocodePatchAddress; | ||||||
|  |   Count = 0; | ||||||
|  |  | ||||||
|  |   MicrocodeEnd = (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSize); | ||||||
|  |   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)MicrocodePatchAddress; | ||||||
|  |   do { | ||||||
|  |     if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) { | ||||||
|  |       // | ||||||
|  |       // It is the microcode header. It is not the padding data between microcode patches | ||||||
|  |       // becasue the padding data should not include 0x00000001 and it should be the repeated | ||||||
|  |       // byte format (like 0xXYXYXYXY....). | ||||||
|  |       // | ||||||
|  |       if (MicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |         TotalSize = 2048; | ||||||
|  |       } else { | ||||||
|  |         TotalSize = MicrocodeEntryPoint->TotalSize; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |       // | ||||||
|  |       // It is the padding data between the microcode patches for microcode patches alignment. | ||||||
|  |       // Because the microcode patch is the multiple of 1-KByte, the padding 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 = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Count++; | ||||||
|  |     ASSERT(Count < 0xFF); | ||||||
|  |     MicrocodeUsedEnd = (UINTN)MicrocodeEntryPoint; | ||||||
|  |  | ||||||
|  |     // | ||||||
|  |     // Get the next patch. | ||||||
|  |     // | ||||||
|  |     MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + TotalSize); | ||||||
|  |   } while (((UINTN)MicrocodeEntryPoint < MicrocodeEnd)); | ||||||
|  |  | ||||||
|  |   return MicrocodeUsedEnd - (UINTN)MicrocodePatchAddress; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Update Microcode. | ||||||
|  |  | ||||||
|  |   @param[in]   Address            The flash address of Microcode. | ||||||
|  |   @param[in]   Image              The Microcode image buffer. | ||||||
|  |   @param[in]   ImageSize          The size of Microcode image buffer in bytes. | ||||||
|  |   @param[out]  LastAttemptStatus  The last attempt status, which will be recorded 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((DEBUG_INFO, "PlatformUpdate:")); | ||||||
|  |   DEBUG((DEBUG_INFO, "  Address - 0x%lx,", Address)); | ||||||
|  |   DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ImageSize)); | ||||||
|  |  | ||||||
|  |   Status = MicrocodeFlashWrite ( | ||||||
|  |              Address, | ||||||
|  |              Image, | ||||||
|  |              ImageSize | ||||||
|  |              ); | ||||||
|  |   if (!EFI_ERROR(Status)) { | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS; | ||||||
|  |   } else { | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; | ||||||
|  |   } | ||||||
|  |   return Status; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Write Microcode. | ||||||
|  |  | ||||||
|  |   Caution: This function may receive untrusted input. | ||||||
|  |  | ||||||
|  |   @param[in]   ImageIndex         The index of Microcode image. | ||||||
|  |   @param[in]   Image              The Microcode image buffer. | ||||||
|  |   @param[in]   ImageSize          The size of Microcode image buffer 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[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 Microcode image is written. | ||||||
|  |   @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt. | ||||||
|  |   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect. | ||||||
|  |   @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 = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize); | ||||||
|  |   if (!Result) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n")); | ||||||
|  |     return EFI_NOT_FOUND; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   CurrentTotalSize = 0; | ||||||
|  |   CurrentMicrocodeEntryPoint = GetCurrentMicrocodeInUse(); | ||||||
|  |   if (CurrentMicrocodeEntryPoint != NULL) { | ||||||
|  |     if (CurrentMicrocodeEntryPoint->DataSize == 0) { | ||||||
|  |       CurrentTotalSize = 2048; | ||||||
|  |     } else { | ||||||
|  |       CurrentTotalSize = CurrentMicrocodeEntryPoint->TotalSize; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // MCU must be 16 bytes aligned | ||||||
|  |   // | ||||||
|  |   AlignedImage = AllocateCopyPool(ImageSize, Image); | ||||||
|  |   if (AlignedImage == NULL) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n")); | ||||||
|  |     *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; | ||||||
|  |     return EFI_OUT_OF_RESOURCES; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision; | ||||||
|  |   Status = VerifyMicrocode(AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason); | ||||||
|  |   if (EFI_ERROR(Status)) { | ||||||
|  |     DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n")); | ||||||
|  |     FreePool(AlignedImage); | ||||||
|  |     return Status; | ||||||
|  |   } | ||||||
|  |   DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n")); | ||||||
|  |  | ||||||
|  |   if (CurrentTotalSize < ImageSize) { | ||||||
|  |     UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(); | ||||||
|  |     if (MicrocodePatchRegionSize - UsedRegionSize >= ImageSize) { | ||||||
|  |       // | ||||||
|  |       // Append | ||||||
|  |       // | ||||||
|  |       DEBUG((DEBUG_INFO, "Append new microcode\n")); | ||||||
|  |       Status = UpdateMicrocode(MicrocodePatchAddress + UsedRegionSize, AlignedImage, ImageSize, LastAttemptStatus); | ||||||
|  |     } else if (MicrocodePatchRegionSize >= ImageSize) { | ||||||
|  |       // | ||||||
|  |       // Ignor all others and just add this one from beginning. | ||||||
|  |       // | ||||||
|  |       DEBUG((DEBUG_INFO, "Add new microcode from beginning\n")); | ||||||
|  |       Status = UpdateMicrocode(MicrocodePatchAddress, AlignedImage, ImageSize, LastAttemptStatus); | ||||||
|  |     } else { | ||||||
|  |       DEBUG((DEBUG_ERROR, "Microcode too big\n")); | ||||||
|  |       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES; | ||||||
|  |       Status = EFI_OUT_OF_RESOURCES; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     // | ||||||
|  |     // Replace | ||||||
|  |     // | ||||||
|  |     DEBUG((DEBUG_INFO, "Replace old microcode\n")); | ||||||
|  |     Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, AlignedImage, ImageSize, LastAttemptStatus); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FreePool(AlignedImage); | ||||||
|  |  | ||||||
|  |   return Status; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										403
									
								
								UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,403 @@ | |||||||
|  | /** @file | ||||||
|  |   Microcode update header file. | ||||||
|  |  | ||||||
|  |   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | ||||||
|  |   This program and the accompanying materials | ||||||
|  |   are licensed and made available under the terms and conditions of the BSD 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 IMPLIED. | ||||||
|  |  | ||||||
|  | **/ | ||||||
|  |  | ||||||
|  | #ifndef _MICROCODE_FMP_H_ | ||||||
|  | #define _MICROCODE_FMP_H_ | ||||||
|  |  | ||||||
|  | #include <PiDxe.h> | ||||||
|  |  | ||||||
|  | #include <Guid/SystemResourceTable.h> | ||||||
|  | #include <Guid/MicrocodeFmp.h> | ||||||
|  |  | ||||||
|  | #include <Protocol/FirmwareManagement.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/MicrocodeFlashAccessLib.h> | ||||||
|  |  | ||||||
|  | #include <Register/Cpuid.h> | ||||||
|  | #include <Register/Msr.h> | ||||||
|  | #include <Register/Microcode.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 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 MICROCODE_FMP_PRIVATE_DATA. | ||||||
|  |  | ||||||
|  | **/ | ||||||
|  | #define MICROCODE_FMP_PRIVATE_DATA_FROM_FMP(a) \ | ||||||
|  |   CR ( \ | ||||||
|  |   (a), \ | ||||||
|  |   MICROCODE_FMP_PRIVATE_DATA, \ | ||||||
|  |   Fmp, \ | ||||||
|  |   MICROCODE_FMP_PRIVATE_DATA_SIGNATURE \ | ||||||
|  |   ) | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Get current Microcode information. | ||||||
|  |  | ||||||
|  |   @param[out]  ImageDescriptor  Microcode ImageDescriptor | ||||||
|  |   @param[in]   DescriptorCount  The count of Microcode ImageDescriptor allocated. | ||||||
|  |  | ||||||
|  |   @return Microcode count | ||||||
|  | **/ | ||||||
|  | UINTN | ||||||
|  | GetMicrocodeInfo ( | ||||||
|  |   OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL | ||||||
|  |   IN  UINTN                          DescriptorCount   OPTIONAL | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   Read Microcode. | ||||||
|  |  | ||||||
|  |   @param[in]       ImageIndex The index of Microcode image. | ||||||
|  |   @param[in, out]  Image      The Microcode image buffer. | ||||||
|  |   @param[in, out]  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[in]   ImageIndex         The index of Microcode image. | ||||||
|  |   @param[in]   Image              The Microcode image buffer. | ||||||
|  |   @param[in]   ImageSize          The size of Microcode image buffer 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[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 Microcode image is written. | ||||||
|  |   @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt. | ||||||
|  |   @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect. | ||||||
|  |   @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 | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   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_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 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_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 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_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_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_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 | ||||||
|  |  | ||||||
| @@ -0,0 +1,68 @@ | |||||||
|  | ## @file | ||||||
|  | # Microcode FMP update driver. | ||||||
|  | # | ||||||
|  | # Produce FMP instance to update Microcode. | ||||||
|  | # | ||||||
|  | #  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | ||||||
|  | #  This program and the accompanying materials | ||||||
|  | #  are licensed and made available under the terms and conditions of the BSD 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 IMPLIED. | ||||||
|  | # | ||||||
|  | ## | ||||||
|  |  | ||||||
|  | [Defines] | ||||||
|  |   INF_VERSION                    = 0x00010005 | ||||||
|  |   BASE_NAME                      = MicrocodeUpdateDxe | ||||||
|  |   MODULE_UNI_FILE                = MicrocodeUpdateDxe.uni | ||||||
|  |   FILE_GUID                      = 0565365C-2FE1-4F88-B3BE-624C04623A20 | ||||||
|  |   MODULE_TYPE                    = DXE_DRIVER | ||||||
|  |   VERSION_STRING                 = 1.0 | ||||||
|  |   ENTRY_POINT                    = MicrocodeFmpMain | ||||||
|  |  | ||||||
|  | # | ||||||
|  | # The following information is for reference only and not required by the build tools. | ||||||
|  | # | ||||||
|  | #  VALID_ARCHITECTURES           = 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            ## CONSUMES | ||||||
|  |   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES | ||||||
|  |  | ||||||
|  | [Depex] | ||||||
|  |   gEfiVariableArchProtocolGuid | ||||||
|  |  | ||||||
|  | [UserExtensions.TianoCore."ExtraFiles"] | ||||||
|  |   MicrocodeUpdateDxeExtra.uni | ||||||
|  |  | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | // /** @file | ||||||
|  | // Microcode FMP update driver. | ||||||
|  | // | ||||||
|  | // Produce FMP instance to update Microcode. | ||||||
|  | // | ||||||
|  | // Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | ||||||
|  | // | ||||||
|  | // This program and the accompanying materials | ||||||
|  | // are licensed and made available under the terms and conditions of the BSD 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 IMPLIED. | ||||||
|  | // | ||||||
|  | // **/ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #string STR_MODULE_ABSTRACT             #language en-US "Microcode FMP update driver." | ||||||
|  |  | ||||||
|  | #string STR_MODULE_DESCRIPTION          #language en-US "Produce FMP instance to update Microcode." | ||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | // /** @file | ||||||
|  | // MicrocodeUpdateDxe Localized Strings and Content | ||||||
|  | // | ||||||
|  | // Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | ||||||
|  | // | ||||||
|  | // This program and the accompanying materials | ||||||
|  | // are licensed and made available under the terms and conditions of the BSD 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 IMPLIED. | ||||||
|  | // | ||||||
|  | // **/ | ||||||
|  |  | ||||||
|  | #string STR_PROPERTIES_MODULE_NAME | ||||||
|  | #language en-US | ||||||
|  | "MicrocodeUpdate DXE Driver" | ||||||
|  |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user