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....@intel.com>
Cc: Feng Tian <feng.t...@intel.com>
Cc: Star Zeng <star.z...@intel.com>
Cc: Michael D Kinney <michael.d.kin...@intel.com>
Cc: Liming Gao <liming....@intel.com>
Cc: Chao Zhang <chao.b.zh...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen....@intel.com>
---
 UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c              | 641 ++++++++++++++++
 UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c           | 775 
++++++++++++++++++++
 UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h           | 299 ++++++++
 UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf         |  68 ++
 UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni      |  21 +
 UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni |  20 +
 6 files changed, 1824 insertions(+)

diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c 
b/UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c
new file mode 100644
index 0000000..ee94b41
--- /dev/null
+++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeFmp.c
@@ -0,0 +1,641 @@
+/** @file
+  Produce FMP instance for Microcode.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<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"
+
+#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 \
+  )
+
+//
+// MicrocodeFmp driver private data
+//
+MICROCODE_FMP_PRIVATE_DATA *mMicrocodeFmpPrivate = NULL;
+
+EFI_FIRMWARE_MANAGEMENT_PROTOCOL mFirmwareManagementProtocol = {
+  FmpGetImageInfo,
+  FmpGetImage,
+  FmpSetImage,
+  FmpCheckImage,
+  FmpGetPackageInfo,
+  FmpSetPackageInfo
+};
+
+/**
+  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  ImageIndex The index of Microcode image.
+  @param  Image      The Microcode image buffer.
+  @param  ImageSize  The size of Microcode image buffer in bytes.
+
+  @retval EFI_SUCCESS    The Microcode image is read.
+  @retval EFI_NOT_FOUND  The Microcode image is not found.
+**/
+EFI_STATUS
+MicrocodeRead(
+  IN UINTN      ImageIndex,
+  IN OUT VOID   *Image,
+  IN OUT UINTN  *ImageSize
+  );
+
+/**
+  Write Microcode.
+
+  @param  ImageIndex         The index of Microcode image.
+  @param  Image              The Microcode image buffer.
+  @param  ImageSize          The size of Microcode image buffer in bytes.
+  @param  LastAttemptVersion The last attempt version, which will be recorded 
in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param  LastAttemptStatus  The last attempt status, which will be recorded 
in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param  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
+  );
+
+/**
+  Initialize Microcode Descriptor.
+
+  @param MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS Microcode Descriptor is initialized.
+**/
+EFI_STATUS
+InitializeMicrocodeDescriptor(
+  IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+  );
+
+/**
+  Returns information about the current firmware image(s) of the device.
+
+  This function allows a copy of the current firmware image to be created and 
saved.
+  The saved copy could later been used, for example, in firmware image 
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((EFI_D_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((EFI_D_INFO, "SetLastAttemp - %r\n", VarStatus));
+
+  if (!EFI_ERROR(Status)) {
+    InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+  }
+
+  return Status;
+}
+
+/**
+  Checks if the firmware image is valid for the device.
+
+  This function allows firmware update application to validate the 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 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 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((EFI_D_INFO, "GetLastAttemp - %r\n", VarStatus));
+  DEBUG((EFI_D_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  ImageHandle       The firmware allocated handle for the EFI image.
+  @param  SystemTable       A pointer to the EFI System Table.
+
+  @return EFI_SUCCESS Microcode FMP module is initialized.
+**/
+EFI_STATUS
+EFIAPI
+MicrocodeFmpMain (
+  IN EFI_HANDLE                         ImageHandle,
+  IN EFI_SYSTEM_TABLE                   *SystemTable
+  )
+{
+  EFI_STATUS                            Status;
+
+  //
+  // Initialize MicrocodeFmpPrivateData
+  //
+  mMicrocodeFmpPrivate = 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;
+}
diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c 
b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c
new file mode 100644
index 0000000..d19eca9
--- /dev/null
+++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.c
@@ -0,0 +1,775 @@
+/** @file
+  SetImage instance to update Microcode.
+
+  Caution: This module requires additional review when modified.
+  This module will have external input - capsule image.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do 
basic validation.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<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 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((EFI_D_ERROR, "Fail to get Microcode Region\n"));
+    return 0;
+  }
+  DEBUG((EFI_D_ERROR, "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  ImageIndex The index of Microcode image.
+  @param  Image      The Microcode image buffer.
+  @param  ImageSize  The size of Microcode image buffer in bytes.
+
+  @retval EFI_SUCCESS    The Microcode image is read.
+  @retval EFI_NOT_FOUND  The Microcode image is not found.
+**/
+EFI_STATUS
+MicrocodeRead(
+  IN UINTN      ImageIndex,
+  IN OUT VOID   *Image,
+  IN OUT UINTN  *ImageSize
+  )
+{
+  BOOLEAN                                 Result;
+  UINT64                                  MicrocodePatchAddress;
+  UINT64                                  MicrocodePatchRegionSize;
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
+  UINTN                                   MicrocodeEnd;
+  UINTN                                   TotalSize;
+  UINTN                                   Count;
+
+  Result = GetMicrocodeRegion(&MicrocodePatchAddress, 
&MicrocodePatchRegionSize);
+  if (!Result) {
+    DEBUG((EFI_D_ERROR, "Fail to get Microcode Region\n"));
+    return EFI_NOT_FOUND;
+  }
+  DEBUG((EFI_D_ERROR, "Microcode Region - 0x%lx - 0x%lx\n", 
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.
+
+  @param  Image              The Microcode image buffer.
+  @param  ImageSize          The size of Microcode image buffer in bytes.
+  @param  TryLoad            Try to load Microcode or not.
+  @param  LastAttemptStatus  The last attempt status, which will be recorded 
in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param  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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_ERROR, "Fail to get Microcode Region\n"));
+    return NULL;
+  }
+  DEBUG((EFI_D_ERROR, "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((EFI_D_ERROR, "Fail to get Microcode Region\n"));
+    return 0;
+  }
+  DEBUG((EFI_D_ERROR, "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  Address            The flash address of Microcode.
+  @param  Image              The Microcode image buffer.
+  @param  ImageSize          The size of Microcode image buffer in bytes.
+  @param  LastAttemptStatus  The last attempt status, which will be 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((EFI_D_INFO, "PlatformUpdate:"));
+  DEBUG((EFI_D_INFO, "  Address - 0x%lx,", Address));
+  DEBUG((EFI_D_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.
+
+  @param  ImageIndex         The index of Microcode image.
+  @param  Image              The Microcode image buffer.
+  @param  ImageSize          The size of Microcode image buffer in bytes.
+  @param  LastAttemptVersion The last attempt version, which will be recorded 
in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param  LastAttemptStatus  The last attempt status, which will be recorded 
in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param  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((EFI_D_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);
+
+  *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
+  Status = VerifyMicrocode(AlignedImage, ImageSize, TRUE, LastAttemptStatus, 
AbortReason);
+  if (EFI_ERROR(Status)) {
+    DEBUG((EFI_D_ERROR, "Fail to verify Microcode Region\n"));
+    FreePool(AlignedImage);
+    return Status;
+  }
+  DEBUG((EFI_D_INFO, "Pass VerifyMicrocode\n"));
+
+  if (CurrentTotalSize < ImageSize) {
+    UsedRegionSize = GetCurrentMicrocodeUsedRegionSize();
+    if (MicrocodePatchRegionSize - UsedRegionSize >= ImageSize) {
+      //
+      // Append
+      //
+      DEBUG((EFI_D_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((EFI_D_INFO, "Add new microcode from beginning\n"));
+      Status = UpdateMicrocode(MicrocodePatchAddress, AlignedImage, ImageSize, 
LastAttemptStatus);
+    } else {
+      DEBUG((EFI_D_ERROR, "Microcode too big\n"));
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+      Status = EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // Replace
+    //
+    DEBUG((EFI_D_INFO, "Replace old microcode\n"));
+    Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, AlignedImage, 
ImageSize, LastAttemptStatus);
+  }
+
+  FreePool(AlignedImage);
+
+  return Status;
+}
+
+
diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h 
b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h
new file mode 100644
index 0000000..23ec0ba
--- /dev/null
+++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.h
@@ -0,0 +1,299 @@
+/** @file
+  Microcode update header file.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<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>
+
+/**
+  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
+
diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf 
b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf
new file mode 100644
index 0000000..736684c
--- /dev/null
+++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdate.inf
@@ -0,0 +1,68 @@
+## @file
+# Microcode FMP update driver.
+#
+# Produce FMP instance to update Microcode.
+#
+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<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                      = MicrocodeUpdate
+  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
+
diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni 
b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni
new file mode 100644
index 0000000..1b0d494
--- /dev/null
+++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Microcode FMP update driver.
+//
+// Produce FMP instance to update Microcode.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<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."
diff --git a/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni 
b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni
new file mode 100644
index 0000000..b667f12
--- /dev/null
+++ b/UefiCpuPkg/MicrocodeUpdate/MicrocodeUpdateDxeExtra.uni
@@ -0,0 +1,20 @@
+// /** @file
+// MicrocodeUpdateDxe Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<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"
+
+
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to