public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH V2 0/2] MicrocodeUpdate enhancement
@ 2016-12-28  6:53 Jiewen Yao
  2016-12-28  6:53 ` [PATCH V2 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic Jiewen Yao
  2016-12-28  6:53 ` [PATCH V2 2/2] UefiCpuPkg/MicrocodeUpdate: Add MP support Jiewen Yao
  0 siblings, 2 replies; 3+ messages in thread
From: Jiewen Yao @ 2016-12-28  6:53 UTC (permalink / raw)
  To: edk2-devel; +Cc: Jeff Fan, Star Zeng

This series patches enhance MicrocodeUpdateDxe driver.
1) It cleanes up the flash write logic, move the Microcode region organization
to a standalone function - UpdateMicrocodeFlashRegion().
2) It fixes a corner case that BSP/AP are using different Microcode.
The original logic only tries to apply Microcode to BSP.
The new logic will try to apply Microcode to all processors.

Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>

Jiewen Yao (2):
  UefiCpuPkg/MicrocodeUpdate: enhance flash write logic
  UefiCpuPkg/MicrocodeUpdate: Add MP support.

 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c         | 225 +++++-
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c      | 789 ++++++++++++--------
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h      | 153 +++-
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf |   4 +-
 4 files changed, 831 insertions(+), 340 deletions(-)

-- 
2.7.4.windows.1



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH V2 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic
  2016-12-28  6:53 [PATCH V2 0/2] MicrocodeUpdate enhancement Jiewen Yao
@ 2016-12-28  6:53 ` Jiewen Yao
  2016-12-28  6:53 ` [PATCH V2 2/2] UefiCpuPkg/MicrocodeUpdate: Add MP support Jiewen Yao
  1 sibling, 0 replies; 3+ messages in thread
From: Jiewen Yao @ 2016-12-28  6:53 UTC (permalink / raw)
  To: edk2-devel; +Cc: Jeff Fan, Star Zeng

The patch updated MicrocodeWrite() to move the Microcode replacement logic
to a standalone function -  UpdateMicrocodeFlashRegion().
More detail description is added in UpdateMicrocodeFlashRegion()
to improve readability.

The Microcode information is collected in InitializeMicrocodeDescriptor(),
so that FmpGetImage() can get the info directly.
MicrocodeRead() is not needed any more.

Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Star Zeng <star.zeng@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>
---
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c    |  40 +-
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c | 684 ++++++++++++--------
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h |  84 ++-
 3 files changed, 492 insertions(+), 316 deletions(-)

diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
index df3563d..97f2f35 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
@@ -174,7 +174,7 @@ FmpGetImage (
   )
 {
   MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate;
-  EFI_STATUS                 Status;
+  MICROCODE_INFO             *MicrocodeInfo;
 
   if (Image == NULL || ImageSize == NULL) {
     return EFI_INVALID_PARAMETER;
@@ -186,8 +186,16 @@ FmpGetImage (
     return EFI_INVALID_PARAMETER;
   }
 
-  Status = MicrocodeRead(ImageIndex, (VOID *)Image, ImageSize);
-  return Status;
+  MicrocodeInfo = &MicrocodeFmpPrivate->MicrocodeInfo[ImageIndex - 1];
+
+  if (*ImageSize < MicrocodeInfo->TotalSize) {
+    *ImageSize = MicrocodeInfo->TotalSize;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  *ImageSize = MicrocodeInfo->TotalSize;
+  CopyMem (Image, MicrocodeInfo->MicrocodeEntryPoint, MicrocodeInfo->TotalSize);
+  return EFI_SUCCESS;
 }
 
 /**
@@ -263,7 +271,7 @@ FmpSetImage (
     return EFI_INVALID_PARAMETER;
   }
 
-  Status = MicrocodeWrite(ImageIndex, (VOID *)Image, ImageSize, &MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, &MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus, AbortReason);
+  Status = MicrocodeWrite(MicrocodeFmpPrivate, (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,
@@ -417,17 +425,22 @@ InitializeMicrocodeDescriptor (
   IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
   )
 {
-  UINT8  CurrentMicrocodeCount;
+  UINT8    CurrentMicrocodeCount;
 
-  CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo(NULL, 0);
+  CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, 0, NULL, NULL);
 
   if (CurrentMicrocodeCount > MicrocodeFmpPrivate->DescriptorCount) {
     if (MicrocodeFmpPrivate->ImageDescriptor != NULL) {
       FreePool(MicrocodeFmpPrivate->ImageDescriptor);
       MicrocodeFmpPrivate->ImageDescriptor = NULL;
     }
+    if (MicrocodeFmpPrivate->MicrocodeInfo != NULL) {
+      FreePool(MicrocodeFmpPrivate->MicrocodeInfo);
+      MicrocodeFmpPrivate->MicrocodeInfo = NULL;
+    }
   } else {
     ZeroMem(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount * sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+    ZeroMem(MicrocodeFmpPrivate->MicrocodeInfo, MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
   }
 
   MicrocodeFmpPrivate->DescriptorCount = CurrentMicrocodeCount;
@@ -438,8 +451,14 @@ InitializeMicrocodeDescriptor (
       return EFI_OUT_OF_RESOURCES;
     }
   }
+  if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
+    MicrocodeFmpPrivate->MicrocodeInfo = AllocateZeroPool(MicrocodeFmpPrivate->DescriptorCount * sizeof(MICROCODE_INFO));
+    if (MicrocodeFmpPrivate->MicrocodeInfo == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
 
-  CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo(MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->DescriptorCount);
+  CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, MicrocodeFmpPrivate->DescriptorCount, MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->MicrocodeInfo);
   ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount);
 
   return EFI_SUCCESS;
@@ -460,6 +479,7 @@ InitializePrivateData (
   EFI_STATUS       Status;
   EFI_STATUS       VarStatus;
   UINTN            VarSize;
+  BOOLEAN          Result;
 
   MicrocodeFmpPrivate->Signature       = MICROCODE_FMP_PRIVATE_DATA_SIGNATURE;
   MicrocodeFmpPrivate->Handle          = NULL;
@@ -481,6 +501,12 @@ InitializePrivateData (
   DEBUG((DEBUG_INFO, "GetLastAttemp - %r\n", VarStatus));
   DEBUG((DEBUG_INFO, "GetLastAttemp Version - 0x%x, State - 0x%x\n", MicrocodeFmpPrivate->LastAttempt.LastAttemptVersion, MicrocodeFmpPrivate->LastAttempt.LastAttemptStatus));
 
+  Result = GetMicrocodeRegion(&MicrocodeFmpPrivate->MicrocodePatchAddress, &MicrocodeFmpPrivate->MicrocodePatchRegionSize);
+  if (!Result) {
+    DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n"));
+    return EFI_NOT_FOUND;
+  }
+
   Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
 
   return Status;
diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
index 2eb4ae4..46739ba 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
@@ -21,6 +21,36 @@
 
 #include "MicrocodeUpdate.h"
 
+
+/**
+  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
+  );
+
 /**
   Get Microcode Region.
 
@@ -32,14 +62,14 @@
 **/
 BOOLEAN
 GetMicrocodeRegion (
-  OUT UINT64   *MicrocodePatchAddress,
-  OUT UINT64   *MicrocodePatchRegionSize
+  OUT VOID     **MicrocodePatchAddress,
+  OUT UINTN    *MicrocodePatchRegionSize
   )
 {
-  *MicrocodePatchAddress = PcdGet64(PcdCpuMicrocodePatchAddress);
-  *MicrocodePatchRegionSize = PcdGet64(PcdCpuMicrocodePatchRegionSize);
+  *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);
+  *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);
 
-  if ((*MicrocodePatchAddress == 0) || (*MicrocodePatchRegionSize == 0)) {
+  if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {
     return FALSE;
   }
 
@@ -114,40 +144,79 @@ LoadMicrocode (
 }
 
 /**
+  If the Microcode is used by current processor.
+
+  @param[in]  MicrocodeEntryPoint  The Microcode buffer
+
+  @retval TRUE  The Microcode is used by current processor.
+  @retval FALSE The Microcode is NOT used by current processor.
+**/
+BOOLEAN
+IsMicrocodeInUse (
+  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
+  )
+{
+  UINT32      AttemptStatus;
+  UINTN       TotalSize;
+  EFI_STATUS  Status;
+
+  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 TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
   Get current Microcode information.
 
-  @param[out]  ImageDescriptor  Microcode ImageDescriptor
-  @param[in]   DescriptorCount  The count of Microcode ImageDescriptor allocated.
+  NOTE: The DescriptorCount/ImageDescriptor/MicrocodeInfo in MicrocodeFmpPrivate
+  are not avaiable in this function.
+
+  @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
+  @param[out]  ImageDescriptor            Microcode ImageDescriptor
+  @param[out]  MicrocodeInfo              Microcode information
 
   @return Microcode count
 **/
 UINTN
 GetMicrocodeInfo (
+  IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,
+  IN  UINTN                          DescriptorCount,  OPTIONAL
   OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
-  IN  UINTN                          DescriptorCount   OPTIONAL
+  OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL
   )
 {
-  BOOLEAN                                 Result;
-  UINT64                                  MicrocodePatchAddress;
-  UINT64                                  MicrocodePatchRegionSize;
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
   CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
   UINTN                                   MicrocodeEnd;
   UINTN                                   TotalSize;
   UINTN                                   Count;
   UINT64                                  ImageAttributes;
-  UINT32                                  CurrentRevision;
+  BOOLEAN                                 IsInUse;
 
-  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));
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
 
   Count = 0;
-  CurrentRevision = GetCurrentMicrocodeSignature();
 
-  MicrocodeEnd = (UINTN)(MicrocodePatchAddress + MicrocodePatchRegionSize);
+  MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;
   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
   do {
     if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {
@@ -162,6 +231,8 @@ GetMicrocodeInfo (
         TotalSize = MicrocodeEntryPoint->TotalSize;
       }
 
+      IsInUse = IsMicrocodeInUse (MicrocodeEntryPoint);
+
       if (ImageDescriptor != NULL && DescriptorCount > Count) {
         ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
         CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);
@@ -171,7 +242,7 @@ GetMicrocodeInfo (
         ImageDescriptor[Count].VersionName = NULL;
         ImageDescriptor[Count].Size = TotalSize;
         ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;
-        if (CurrentRevision == MicrocodeEntryPoint->UpdateRevision) {
+        if (IsInUse) {
           ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;
         }
         ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;
@@ -182,6 +253,11 @@ GetMicrocodeInfo (
         ImageDescriptor[Count].LastAttemptStatus = 0;
         ImageDescriptor[Count].HardwareInstance = 0;
       }
+      if (MicrocodeInfo != NULL && DescriptorCount > Count) {
+        MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;
+        MicrocodeInfo[Count].TotalSize = TotalSize;
+        MicrocodeInfo[Count].InUse = IsInUse;
+      }
     } else {
       //
       // It is the padding data between the microcode patches for microcode patches alignment.
@@ -207,89 +283,6 @@ GetMicrocodeInfo (
 }
 
 /**
-  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;
-      }
-
-      if (ImageIndex == Count + 1) {
-        if (*ImageSize < TotalSize) {
-          *ImageSize = TotalSize;
-          return EFI_BUFFER_TOO_SMALL;
-        }
-        *ImageSize = TotalSize;
-        CopyMem (Image, MicrocodeEntryPoint, TotalSize);
-        return EFI_SUCCESS;
-      }
-
-    } 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.
@@ -461,7 +454,9 @@ VerifyMicrocode (
       }
     }
     if (!CorrectMicrocode) {
-      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
+      if (TryLoad) {
+        DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));
+      }
       *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;
       if (AbortReason != NULL) {
         if (MicrocodeEntryPoint->ProcessorSignature.Uint32 != CurrentProcessorSignature) {
@@ -479,7 +474,9 @@ VerifyMicrocode (
   //
   CurrentRevision = GetCurrentMicrocodeSignature();
   if (MicrocodeEntryPoint->UpdateRevision < CurrentRevision) {
-    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
+    if (TryLoad) {
+      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");
@@ -508,142 +505,79 @@ VerifyMicrocode (
 /**
   Get current Microcode in used.
 
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+
   @return current Microcode in used.
 **/
 VOID *
 GetCurrentMicrocodeInUse (
-  VOID
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate
   )
 {
-  BOOLEAN                                 Result;
-  EFI_STATUS                              Status;
-  UINT64                                  MicrocodePatchAddress;
-  UINT64                                  MicrocodePatchRegionSize;
-  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
-  UINTN                                   MicrocodeEnd;
-  UINTN                                   TotalSize;
-  UINTN                                   Count;
-  UINT32                                  AttemptStatus;
+  UINTN                                   Index;
 
-  Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize);
-  if (!Result) {
-    DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n"));
-    return NULL;
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    if (!MicrocodeFmpPrivate->MicrocodeInfo[Index].InUse) {
+      continue;
+    }
+    if (IsMicrocodeInUse (MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint)) {
+      return MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint;
+    }
   }
-  DEBUG((DEBUG_INFO, "Microcode Region - 0x%lx - 0x%lx\n", MicrocodePatchAddress, MicrocodePatchRegionSize));
+  return NULL;
+}
 
-  Count = 0;
+/**
+  Get next Microcode entrypoint.
 
-  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;
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint
+
+  @return next Microcode entrypoint.
+**/
+CPU_MICROCODE_HEADER *
+GetNextMicrocode (
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
+  )
+{
+  UINTN                                   Index;
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {
+      if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {
+        // it is last one
+        return NULL;
       } else {
-        TotalSize = MicrocodeEntryPoint->TotalSize;
+        // return next one
+        return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;
       }
-      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));
-
+  ASSERT(FALSE);
   return NULL;
 }
 
 /**
   Get current Microcode used region size.
 
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+
   @return current Microcode used region size.
 **/
 UINTN
 GetCurrentMicrocodeUsedRegionSize (
-  VOID
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate
   )
 {
-  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"));
+  if (MicrocodeFmpPrivate->DescriptorCount == 0) {
     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;
+  return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint
+         + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize
+         - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;
 }
 
 /**
@@ -685,62 +619,283 @@ UpdateMicrocode (
 }
 
 /**
-  Write Microcode.
+  Update Microcode flash region.
 
-  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().
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  CurrentMicrocodeEntryPoint Current Microcode entrypoint
+  @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 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.
+  @retval EFI_SUCCESS             The Microcode image is written.
+  @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
+UpdateMicrocodeFlashRegion (
+  IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
+  IN  CPU_MICROCODE_HEADER                    *CurrentMicrocodeEntryPoint,
+  IN  VOID                                    *Image,
+  IN  UINTN                                   ImageSize,
+  OUT UINT32                                  *LastAttemptStatus
   )
 {
-  BOOLEAN                                 Result;
-  EFI_STATUS                              Status;
-  UINT64                                  MicrocodePatchAddress;
-  UINT64                                  MicrocodePatchRegionSize;
-  CPU_MICROCODE_HEADER                    *CurrentMicrocodeEntryPoint;
+  VOID                                    *MicrocodePatchAddress;
+  UINTN                                   MicrocodePatchRegionSize;
   UINTN                                   CurrentTotalSize;
   UINTN                                   UsedRegionSize;
-  VOID                                    *AlignedImage;
+  EFI_STATUS                              Status;
+  VOID                                    *MicrocodePatchScratchBuffer;
+  UINT8                                   *ScratchBufferPtr;
+  UINTN                                   ScratchBufferSize;
+  UINTN                                   RestSize;
+  UINTN                                   AvailableSize;
+  VOID                                    *NextMicrocodeEntryPoint;
+  MICROCODE_INFO                          *MicrocodeInfo;
+  UINTN                                   MicrocodeCount;
+  UINTN                                   Index;
+
+  DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));
 
-  Result = GetMicrocodeRegion(&MicrocodePatchAddress, &MicrocodePatchRegionSize);
-  if (!Result) {
-    DEBUG((DEBUG_ERROR, "Fail to get Microcode Region\n"));
-    return EFI_NOT_FOUND;
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
+
+  MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);
+  if (MicrocodePatchScratchBuffer == NULL) {
+    DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+    return EFI_OUT_OF_RESOURCES;
   }
+  ScratchBufferPtr = MicrocodePatchScratchBuffer;
+  ScratchBufferSize = 0;
 
+  //
+  // Current data collection
+  //
   CurrentTotalSize = 0;
-  CurrentMicrocodeEntryPoint = GetCurrentMicrocodeInUse();
+  AvailableSize = 0;
+  NextMicrocodeEntryPoint = NULL;
   if (CurrentMicrocodeEntryPoint != NULL) {
     if (CurrentMicrocodeEntryPoint->DataSize == 0) {
       CurrentTotalSize = 2048;
     } else {
       CurrentTotalSize = CurrentMicrocodeEntryPoint->TotalSize;
     }
+    DEBUG((DEBUG_INFO, "  CurrentTotalSize - 0x%x\n", CurrentTotalSize));
+    NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, CurrentMicrocodeEntryPoint);
+    DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
+    if (NextMicrocodeEntryPoint != NULL) {
+      ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)CurrentMicrocodeEntryPoint + CurrentTotalSize));
+      AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)CurrentMicrocodeEntryPoint;
+    } else {
+      AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)CurrentMicrocodeEntryPoint;
+    }
+    DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));
+  }
+  ASSERT (AvailableSize >= CurrentTotalSize);
+  UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
+  DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));
+  ASSERT (UsedRegionSize >= CurrentTotalSize);
+  if (CurrentMicrocodeEntryPoint != NULL) {
+    ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)CurrentMicrocodeEntryPoint + CurrentTotalSize));
+  }
+  //
+  // Total Size means the Microcode data size.
+  // Available Size means the Microcode data size plus the pad till next (1) Microcode or (2) the end.
+  //
+  // (1)
+  // +------+-----------+-----+------+===================+
+  // | MCU1 | Microcode | PAD | MCU2 |      Empty        |
+  // +------+-----------+-----+------+===================+
+  //        | TotalSize |
+  //        |<-AvailableSize->|
+  // |<-        UsedRegionSize     ->|
+  //
+  // (2)
+  // +------+-----------+===================+
+  // | MCU  | Microcode |      Empty        |
+  // +------+-----------+===================+
+  //        | TotalSize |
+  //        |<-      AvailableSize        ->|
+  // |<-UsedRegionSize->|
+  //
+
+  //
+  // Update based on policy
+  //
+
+  //
+  // 1. If there is enough space to update old one in situ, replace old microcode in situ.
+  //
+  if (AvailableSize >= ImageSize) {
+    DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));
+    //
+    // +------+------------+------+===================+
+    // |Other1| Old Image  |Other2|      Empty        |
+    // +------+------------+------+===================+
+    //
+    // +------+---------+--+------+===================+
+    // |Other1|New Image|FF|Other2|      Empty        |
+    // +------+---------+--+------+===================+
+    //
+    // 1.1. Copy new image
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+    // 1.2. Pad 0xFF
+    RestSize = AvailableSize - ImageSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    return Status;
   }
 
   //
+  // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
+  //
+  if (MicrocodePatchRegionSize - (UsedRegionSize - CurrentTotalSize) >= ImageSize) {
+    if (CurrentMicrocodeEntryPoint == NULL) {
+      DEBUG((DEBUG_INFO, "Append new microcode\n"));
+      //
+      // +------+------------+------+===================+
+      // |Other1|   Other    |Other2|      Empty        |
+      // +------+------------+------+===================+
+      //
+      // +------+------------+------+-----------+=======+
+      // |Other1|   Other    |Other2| New Image | Empty |
+      // +------+------------+------+-----------+=======+
+      //
+      Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);
+    } else {
+      DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));
+      //
+      // +------+------------+------+===================+
+      // |Other1| Old Image  |Other2|      Empty        |
+      // +------+------------+------+===================+
+      //
+      // +------+---------------+------+================+
+      // |Other1|   New Image   |Other2|      Empty     |
+      // +------+---------------+------+================+
+      //
+      // 2.1. Copy new image
+      CopyMem (MicrocodePatchScratchBuffer, Image, ImageSize);
+      ScratchBufferSize += ImageSize;
+      ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+      // 2.2. Copy rest images after the old image.
+      if (NextMicrocodeEntryPoint != 0) {
+        RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
+        CopyMem (ScratchBufferPtr, (UINT8 *)CurrentMicrocodeEntryPoint + CurrentTotalSize, RestSize);
+        ScratchBufferSize += RestSize;
+        ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+      }
+      Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    }
+    return Status;
+  }
+
+  //
+  // 3. The new image can be put in MCU region, but not all others can be put.
+  //    So all the unused MCU is removed.
+  //
+  if (MicrocodePatchRegionSize >= ImageSize) {
+    //
+    // +------+------------+------+===================+
+    // |Other1| Old Image  |Other2|      Empty        |
+    // +------+------------+------+===================+
+    //
+    // +-------------------------------------+--------+
+    // |        New Image                    | Other  |
+    // +-------------------------------------+--------+
+    //
+    DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));
+
+    MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;
+    MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
+
+    // 3.1. Copy new image
+    CopyMem (MicrocodePatchScratchBuffer, Image, ImageSize);
+    ScratchBufferSize += ImageSize;
+    ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+    // 3.2. Copy some others to rest buffer
+    for (Index = 0; Index < MicrocodeCount; Index++) {
+      if (!MicrocodeInfo[Index].InUse) {
+        continue;
+      }
+      if (MicrocodeInfo[Index].MicrocodeEntryPoint == CurrentMicrocodeEntryPoint) {
+        continue;
+      }
+      if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
+        CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
+        ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
+        ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+      }
+    }
+    // 3.3. Pad 0xFF
+    RestSize = MicrocodePatchRegionSize - ScratchBufferSize;
+    if (RestSize > 0) {
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);
+      ScratchBufferSize += RestSize;
+      ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+    }
+    Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    return Status;
+  }
+
+  //
+  // 4. The new image size is bigger than the whole MCU region.
+  //
+  DEBUG((DEBUG_ERROR, "Microcode too big\n"));
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;
+  Status = EFI_OUT_OF_RESOURCES;
+
+  return Status;
+}
+
+/**
+  Write Microcode.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]   MicrocodeFmpPrivate The Microcode driver private data
+  @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  MICROCODE_FMP_PRIVATE_DATA   *MicrocodeFmpPrivate,
+  IN  VOID                         *Image,
+  IN  UINTN                        ImageSize,
+  OUT UINT32                       *LastAttemptVersion,
+  OUT UINT32                       *LastAttemptStatus,
+  OUT CHAR16                       **AbortReason
+  )
+{
+  EFI_STATUS                              Status;
+  VOID                                    *AlignedImage;
+  CPU_MICROCODE_HEADER                    *CurrentMicrocodeEntryPoint;
+
+  //
+  // We must get Current MicrocodeEntrypoint *before* VerifyMicrocode,
+  // because the MicrocodeSignature might be updated in VerifyMicrocode.
+  //
+  CurrentMicrocodeEntryPoint = GetCurrentMicrocodeInUse(MicrocodeFmpPrivate);
+  DEBUG((DEBUG_INFO, "  CurrentMicrocodeEntryPoint - 0x%x\n", CurrentMicrocodeEntryPoint));
+
+  //
   // MCU must be 16 bytes aligned
   //
   AlignedImage = AllocateCopyPool(ImageSize, Image);
@@ -759,32 +914,13 @@ MicrocodeWrite (
   }
   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);
-  }
+  Status = UpdateMicrocodeFlashRegion(
+             MicrocodeFmpPrivate,
+             CurrentMicrocodeEntryPoint,
+             AlignedImage,
+             ImageSize,
+             LastAttemptStatus
+             );
 
   FreePool(AlignedImage);
 
diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
index 77e8441..b4d1bac 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
@@ -50,12 +50,21 @@ typedef struct {
   UINT32 LastAttemptStatus;
 } MICROCODE_FMP_LAST_ATTEMPT_VARIABLE;
 
+typedef struct {
+  CPU_MICROCODE_HEADER   *MicrocodeEntryPoint;
+  UINTN                  TotalSize;
+  BOOLEAN                InUse;
+} MICROCODE_INFO;
+
 struct _MICROCODE_FMP_PRIVATE_DATA {
   UINT32                               Signature;
   EFI_FIRMWARE_MANAGEMENT_PROTOCOL     Fmp;
   EFI_HANDLE                           Handle;
+  VOID                                 *MicrocodePatchAddress;
+  UINTN                                MicrocodePatchRegionSize;
   UINT8                                DescriptorCount;
   EFI_FIRMWARE_IMAGE_DESCRIPTOR        *ImageDescriptor;
+  MICROCODE_INFO                       *MicrocodeInfo;
   UINT32                               PackageVersion;
   CHAR16                               *PackageVersionName;
   MICROCODE_FMP_LAST_ATTEMPT_VARIABLE  LastAttempt;
@@ -84,63 +93,68 @@ typedef struct _MICROCODE_FMP_PRIVATE_DATA  MICROCODE_FMP_PRIVATE_DATA;
   )
 
 /**
-  Get current Microcode information.
+  Get Microcode Region.
 
-  @param[out]  ImageDescriptor  Microcode ImageDescriptor
-  @param[in]   DescriptorCount  The count of Microcode ImageDescriptor allocated.
+  @param[out] MicrocodePatchAddress      The address of Microcode
+  @param[out] MicrocodePatchRegionSize   The region size of Microcode
 
-  @return Microcode count
+  @retval TRUE   The Microcode region is returned.
+  @retval FALSE  No Microcode region.
 **/
-UINTN
-GetMicrocodeInfo (
-  OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
-  IN  UINTN                          DescriptorCount   OPTIONAL
+BOOLEAN
+GetMicrocodeRegion (
+  OUT VOID     **MicrocodePatchAddress,
+  OUT UINTN    *MicrocodePatchRegionSize
   );
 
 /**
-  Read Microcode.
+  Get current Microcode information.
+
+  NOTE: The DescriptorCount/ImageDescriptor/MicrocodeInfo in MicrocodeFmpPrivate
+  are not avaiable in this function.
 
-  @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.
+  @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
+  @param[out]  ImageDescriptor            Microcode ImageDescriptor
+  @param[out]  MicrocodeInfo              Microcode information
 
-  @retval EFI_SUCCESS    The Microcode image is read.
-  @retval EFI_NOT_FOUND  The Microcode image is not found.
+  @return Microcode count
 **/
-EFI_STATUS
-MicrocodeRead (
-  IN UINTN      ImageIndex,
-  IN OUT VOID   *Image,
-  IN OUT UINTN  *ImageSize
+UINTN
+GetMicrocodeInfo (
+  IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,
+  IN  UINTN                          DescriptorCount,  OPTIONAL
+  OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL
+  OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL
   );
 
 /**
   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().
+  @param[in]   MicrocodeFmpPrivate The Microcode driver private data
+  @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.
+  @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
+  IN MICROCODE_FMP_PRIVATE_DATA    *MicrocodeFmpPrivate,
+  IN VOID                          *Image,
+  IN UINTN                         ImageSize,
+  OUT UINT32                       *LastAttemptVersion,
+  OUT UINT32                       *LastAttemptStatus,
+  OUT CHAR16                       **AbortReason
   );
 
 /**
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH V2 2/2] UefiCpuPkg/MicrocodeUpdate: Add MP support.
  2016-12-28  6:53 [PATCH V2 0/2] MicrocodeUpdate enhancement Jiewen Yao
  2016-12-28  6:53 ` [PATCH V2 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic Jiewen Yao
@ 2016-12-28  6:53 ` Jiewen Yao
  1 sibling, 0 replies; 3+ messages in thread
From: Jiewen Yao @ 2016-12-28  6:53 UTC (permalink / raw)
  To: edk2-devel; +Cc: Jeff Fan, Star Zeng

Support the case that BSP and AP are using different Microcode.
The previous logic validates new MCU on BSP only.
The enhanced logic will validate MCU on every BSP and AP.
As long as one processor loads the MCU successfully, it will be updated.

Cc: Jeff Fan <jeff.fan@intel.com>
Cc: Star Zeng <star.zeng@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>
---
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c         | 185 ++++++++++
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c      | 367 +++++++++++---------
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h      |  81 ++++-
 UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf |   4 +-
 4 files changed, 476 insertions(+), 161 deletions(-)

diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
index 97f2f35..ebde93a 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeFmp.c
@@ -284,6 +284,7 @@ FmpSetImage (
 
   if (!EFI_ERROR(Status)) {
     InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+    DumpPrivateInfo (MicrocodeFmpPrivate);
   }
 
   return Status;
@@ -414,6 +415,47 @@ FmpSetPackageInfo (
 }
 
 /**
+  Initialize Processor Microcode Index.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+**/
+VOID
+InitializedProcessorMicrocodeIndex (
+  IN MICROCODE_FMP_PRIVATE_DATA *MicrocodeFmpPrivate
+  )
+{
+  UINTN       CpuIndex;
+  UINTN       MicrocodeIndex;
+  UINTN       TargetCpuIndex;
+  UINT32      AttemptStatus;
+  EFI_STATUS  Status;
+
+  for (CpuIndex = 0; CpuIndex < MicrocodeFmpPrivate->ProcessorCount; CpuIndex++) {
+    if (MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex != (UINTN)-1) {
+      continue;
+    }
+    for (MicrocodeIndex = 0; MicrocodeIndex < MicrocodeFmpPrivate->DescriptorCount; MicrocodeIndex++) {
+      if (!MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].InUse) {
+        continue;
+      }
+      TargetCpuIndex = CpuIndex;
+      Status = VerifyMicrocode(
+                 MicrocodeFmpPrivate,
+                 MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].MicrocodeEntryPoint,
+                 MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeIndex].TotalSize,
+                 FALSE,
+                 &AttemptStatus,
+                 NULL,
+                 &TargetCpuIndex
+                 );
+      if (!EFI_ERROR(Status)) {
+        MicrocodeFmpPrivate->ProcessorInfo[CpuIndex].MicrocodeIndex = MicrocodeIndex;
+      }
+    }
+  }
+}
+
+/**
   Initialize Microcode Descriptor.
 
   @param[in] MicrocodeFmpPrivate private data structure to be initialized.
@@ -461,10 +503,141 @@ InitializeMicrocodeDescriptor (
   CurrentMicrocodeCount = (UINT8)GetMicrocodeInfo (MicrocodeFmpPrivate, MicrocodeFmpPrivate->DescriptorCount, MicrocodeFmpPrivate->ImageDescriptor, MicrocodeFmpPrivate->MicrocodeInfo);
   ASSERT(CurrentMicrocodeCount == MicrocodeFmpPrivate->DescriptorCount);
 
+  InitializedProcessorMicrocodeIndex (MicrocodeFmpPrivate);
+
   return EFI_SUCCESS;
 }
 
 /**
+  Initialize MicrocodeFmpDriver multiprocessor information.
+
+  @param[in] MicrocodeFmpPrivate private data structure to be initialized.
+
+  @return EFI_SUCCESS private data is initialized.
+**/
+EFI_STATUS
+InitializeProcessorInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_MP_SERVICES_PROTOCOL             *MpService;
+  UINTN                                NumberOfProcessors;
+  UINTN                                NumberOfEnabledProcessors;
+  UINTN                                Index;
+  UINTN                                BspIndex;
+
+  Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
+  ASSERT_EFI_ERROR(Status);
+
+  MicrocodeFmpPrivate->MpService = MpService;
+  MicrocodeFmpPrivate->ProcessorCount = 0;
+  MicrocodeFmpPrivate->ProcessorInfo = NULL;
+
+  Status = MpService->GetNumberOfProcessors (MpService, &NumberOfProcessors, &NumberOfEnabledProcessors);
+  ASSERT_EFI_ERROR(Status);
+  MicrocodeFmpPrivate->ProcessorCount = NumberOfProcessors;
+
+  Status = MpService->WhoAmI (MpService, &BspIndex);
+  ASSERT_EFI_ERROR(Status);
+  MicrocodeFmpPrivate->BspIndex = BspIndex;
+
+  MicrocodeFmpPrivate->ProcessorInfo = AllocateZeroPool (sizeof(PROCESSOR_INFO) * MicrocodeFmpPrivate->ProcessorCount);
+  if (MicrocodeFmpPrivate->ProcessorInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < NumberOfProcessors; Index++) {
+    MicrocodeFmpPrivate->ProcessorInfo[Index].CpuIndex = Index;
+    MicrocodeFmpPrivate->ProcessorInfo[Index].MicrocodeIndex = (UINTN)-1;
+    if (Index == BspIndex) {
+      CollectProcessorInfo (&MicrocodeFmpPrivate->ProcessorInfo[Index]);
+    } else {
+      Status = MpService->StartupThisAP (
+                            MpService,
+                            CollectProcessorInfo,
+                            Index,
+                            NULL,
+                            0,
+                            &MicrocodeFmpPrivate->ProcessorInfo[Index],
+                            NULL
+                            );
+      ASSERT_EFI_ERROR(Status);
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dump private information.
+
+  @param[in] MicrocodeFmpPrivate private data structure.
+**/
+VOID
+DumpPrivateInfo (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate
+  )
+{
+  UINTN                                Index;
+  PROCESSOR_INFO                       *ProcessorInfo;
+  MICROCODE_INFO                       *MicrocodeInfo;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR        *ImageDescriptor;
+
+  DEBUG ((DEBUG_INFO, "ProcessorInfo:\n"));
+  DEBUG ((DEBUG_INFO, "  ProcessorCount - 0x%x\n", MicrocodeFmpPrivate->ProcessorCount));
+  DEBUG ((DEBUG_INFO, "  BspIndex - 0x%x\n", MicrocodeFmpPrivate->BspIndex));
+
+  ProcessorInfo = MicrocodeFmpPrivate->ProcessorInfo;
+  for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
+    DEBUG ((
+      DEBUG_INFO,
+      "  ProcessorInfo[0x%x] - 0x%08x, 0x%02x, 0x%08x, (0x%x)\n",
+      ProcessorInfo[Index].CpuIndex,
+      ProcessorInfo[Index].ProcessorSignature,
+      ProcessorInfo[Index].PlatformId,
+      ProcessorInfo[Index].MicrocodeRevision,
+      ProcessorInfo[Index].MicrocodeIndex
+      ));
+  }
+
+  DEBUG ((DEBUG_INFO, "MicrocodeInfo:\n"));
+  MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
+  DEBUG ((DEBUG_INFO, "  MicrocodeRegion - 0x%x - 0x%x\n", MicrocodeFmpPrivate->MicrocodePatchAddress, MicrocodeFmpPrivate->MicrocodePatchRegionSize));
+  DEBUG ((DEBUG_INFO, "  MicrocodeCount - 0x%x\n", MicrocodeFmpPrivate->DescriptorCount));
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    DEBUG ((
+      DEBUG_INFO,
+      "  MicrocodeInfo[0x%x] - 0x%08x, 0x%08x, (0x%x)\n",
+      Index,
+      MicrocodeInfo[Index].MicrocodeEntryPoint,
+      MicrocodeInfo[Index].TotalSize,
+      MicrocodeInfo[Index].InUse
+      ));
+  }
+
+  ImageDescriptor = MicrocodeFmpPrivate->ImageDescriptor;
+  DEBUG ((DEBUG_VERBOSE, "ImageDescriptor:\n"));
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
+    DEBUG((DEBUG_VERBOSE, "  ImageDescriptor (%d)\n", Index));
+    DEBUG((DEBUG_VERBOSE, "    ImageIndex                  - 0x%x\n", ImageDescriptor[Index].ImageIndex));
+    DEBUG((DEBUG_VERBOSE, "    ImageTypeId                 - %g\n", &ImageDescriptor[Index].ImageTypeId));
+    DEBUG((DEBUG_VERBOSE, "    ImageId                     - 0x%lx\n", ImageDescriptor[Index].ImageId));
+    DEBUG((DEBUG_VERBOSE, "    ImageIdName                 - %s\n", ImageDescriptor[Index].ImageIdName));
+    DEBUG((DEBUG_VERBOSE, "    Version                     - 0x%x\n", ImageDescriptor[Index].Version));
+    DEBUG((DEBUG_VERBOSE, "    VersionName                 - %s\n", ImageDescriptor[Index].VersionName));
+    DEBUG((DEBUG_VERBOSE, "    Size                        - 0x%x\n", ImageDescriptor[Index].Size));
+    DEBUG((DEBUG_VERBOSE, "    AttributesSupported         - 0x%lx\n", ImageDescriptor[Index].AttributesSupported));
+    DEBUG((DEBUG_VERBOSE, "    AttributesSetting           - 0x%lx\n", ImageDescriptor[Index].AttributesSetting));
+    DEBUG((DEBUG_VERBOSE, "    Compatibilities             - 0x%lx\n", ImageDescriptor[Index].Compatibilities));
+    DEBUG((DEBUG_VERBOSE, "    LowestSupportedImageVersion - 0x%x\n", ImageDescriptor[Index].LowestSupportedImageVersion));
+    DEBUG((DEBUG_VERBOSE, "    LastAttemptVersion          - 0x%x\n", ImageDescriptor[Index].LastAttemptVersion));
+    DEBUG((DEBUG_VERBOSE, "    LastAttemptStatus           - 0x%x\n", ImageDescriptor[Index].LastAttemptStatus));
+    DEBUG((DEBUG_VERBOSE, "    HardwareInstance            - 0x%lx\n", ImageDescriptor[Index].HardwareInstance));
+  }
+}
+
+/**
   Initialize MicrocodeFmpDriver private data structure.
 
   @param[in] MicrocodeFmpPrivate private data structure to be initialized.
@@ -507,7 +680,19 @@ InitializePrivateData (
     return EFI_NOT_FOUND;
   }
 
+  Status = InitializeProcessorInfo (MicrocodeFmpPrivate);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "InitializeProcessorInfo - %r\n", Status));
+    return Status;
+  }
+
   Status = InitializeMicrocodeDescriptor(MicrocodeFmpPrivate);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "InitializeMicrocodeDescriptor - %r\n", Status));
+    return Status;
+  }
+
+  DumpPrivateInfo (MicrocodeFmpPrivate);
 
   return Status;
 }
diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
index 46739ba..4e8f1d5 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
@@ -21,36 +21,6 @@
 
 #include "MicrocodeUpdate.h"
 
-
-/**
-  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
-  );
-
 /**
   Get Microcode Region.
 
@@ -144,46 +114,92 @@ LoadMicrocode (
 }
 
 /**
-  If the Microcode is used by current processor.
+  Load Microcode on an Application Processor.
+  The function prototype for invoking a function on an Application Processor.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+MicrocodeLoadAp (
+  IN OUT VOID  *Buffer
+  )
+{
+  MICROCODE_LOAD_BUFFER                *MicrocodeLoadBuffer;
+
+  MicrocodeLoadBuffer = Buffer;
+  MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);
+}
+
+/**
+  Load new Microcode on this processor
 
-  @param[in]  MicrocodeEntryPoint  The Microcode buffer
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  CpuIndex                   The index of the processor.
+  @param[in]  Address                    The address of new Microcode.
+
+  @return  Loaded Microcode signature.
 
-  @retval TRUE  The Microcode is used by current processor.
-  @retval FALSE The Microcode is NOT used by current processor.
 **/
-BOOLEAN
-IsMicrocodeInUse (
-  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint
+UINT32
+LoadMicrocodeOnThis (
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN  UINTN                       CpuIndex,
+  IN  UINT64                      Address
   )
 {
-  UINT32      AttemptStatus;
-  UINTN       TotalSize;
-  EFI_STATUS  Status;
+  EFI_STATUS                           Status;
+  EFI_MP_SERVICES_PROTOCOL             *MpService;
+  MICROCODE_LOAD_BUFFER                MicrocodeLoadBuffer;
 
-  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 TRUE;
-    }
+  if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {
+    return LoadMicrocode (Address);
+  } else {
+    MpService = MicrocodeFmpPrivate->MpService;
+    MicrocodeLoadBuffer.Address = Address;
+    MicrocodeLoadBuffer.Revision = 0;
+    Status = MpService->StartupThisAP (
+                          MpService,
+                          MicrocodeLoadAp,
+                          CpuIndex,
+                          NULL,
+                          0,
+                          &MicrocodeLoadBuffer,
+                          NULL
+                          );
+    ASSERT_EFI_ERROR(Status);
+    return MicrocodeLoadBuffer.Revision;
   }
-  return FALSE;
+}
+
+/**
+  Collect processor information.
+  The function prototype for invoking a function on an Application Processor.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorInfo (
+  IN OUT VOID  *Buffer
+  )
+{
+  PROCESSOR_INFO  *ProcessorInfo;
+
+  ProcessorInfo = Buffer;
+  ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();
+  ProcessorInfo->PlatformId = GetCurrentPlatformId();
+  ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();
 }
 
 /**
   Get current Microcode information.
 
-  NOTE: The DescriptorCount/ImageDescriptor/MicrocodeInfo in MicrocodeFmpPrivate
-  are not avaiable in this function.
+  The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
+  in MicrocodeFmpPrivate must be initialized.
+
+  The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
+  in MicrocodeFmpPrivate may not be avaiable in this function.
 
   @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
   @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
@@ -208,6 +224,9 @@ GetMicrocodeInfo (
   UINTN                                   Count;
   UINT64                                  ImageAttributes;
   BOOLEAN                                 IsInUse;
+  EFI_STATUS                              Status;
+  UINT32                                  AttemptStatus;
+  UINTN                                   TargetCpuIndex;
 
   MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;
   MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;
@@ -231,7 +250,15 @@ GetMicrocodeInfo (
         TotalSize = MicrocodeEntryPoint->TotalSize;
       }
 
-      IsInUse = IsMicrocodeInUse (MicrocodeEntryPoint);
+      TargetCpuIndex = (UINTN)-1;
+      Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);
+      if (!EFI_ERROR(Status)) {
+        IsInUse = TRUE;
+        ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
+        MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;
+      } else {
+        IsInUse = FALSE;
+      }
 
       if (ImageDescriptor != NULL && DescriptorCount > Count) {
         ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);
@@ -283,18 +310,62 @@ GetMicrocodeInfo (
 }
 
 /**
+  Return matched processor information.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @param[in]  ProcessorSignature         The processor signature to be matched
+  @param[in]  ProcessorFlags             The processor flags to be matched
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+                                         On output, the index of target CPU which matches the Microcode.
+
+  @return matched processor information.
+**/
+PROCESSOR_INFO *
+GetMatchedProcessor (
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN UINT32                      ProcessorSignature,
+  IN UINT32                      ProcessorFlags,
+  IN OUT UINTN                   *TargetCpuIndex
+  )
+{
+  UINTN  Index;
+
+  if (*TargetCpuIndex != (UINTN)-1) {
+    Index = *TargetCpuIndex;
+    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
+        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
+      return &MicrocodeFmpPrivate->ProcessorInfo[Index];
+    } else {
+      return NULL;
+    }
+  }
+
+  for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {
+    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&
+        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {
+      *TargetCpuIndex = Index;
+      return &MicrocodeFmpPrivate->ProcessorInfo[Index];
+    }
+  }
+  return NULL;
+}
+
+/**
   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().
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @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().
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+                                         On output, the index of target CPU which matches the Microcode.
 
   @retval EFI_SUCCESS               The Microcode image passes verification.
   @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.
@@ -304,11 +375,13 @@ GetMicrocodeInfo (
 **/
 EFI_STATUS
 VerifyMicrocode (
-  IN VOID    *Image,
-  IN UINTN   ImageSize,
-  IN BOOLEAN TryLoad,
-  OUT UINT32 *LastAttemptStatus,
-  OUT CHAR16 **AbortReason
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN  VOID                        *Image,
+  IN  UINTN                       ImageSize,
+  IN  BOOLEAN                     TryLoad,
+  OUT UINT32                      *LastAttemptStatus,
+  OUT CHAR16                      **AbortReason,   OPTIONAL
+  IN OUT UINTN                    *TargetCpuIndex
   )
 {
   UINTN                                   Index;
@@ -316,8 +389,7 @@ VerifyMicrocode (
   UINTN                                   TotalSize;
   UINTN                                   DataSize;
   UINT32                                  CurrentRevision;
-  UINT32                                  CurrentProcessorSignature;
-  UINT8                                   CurrentPlatformId;
+  PROCESSOR_INFO                          *ProcessorInfo;
   UINT32                                  CheckSum32;
   UINTN                                   ExtendedTableLength;
   UINT32                                  ExtendedTableCount;
@@ -409,11 +481,10 @@ VerifyMicrocode (
   //
   // Check ProcessorSignature/ProcessorFlags
   //
-  CorrectMicrocode = FALSE;
-  CurrentProcessorSignature = GetCurrentProcessorSignature();
-  CurrentPlatformId = GetCurrentPlatformId();
-  if ((MicrocodeEntryPoint->ProcessorSignature.Uint32 != CurrentProcessorSignature) ||
-      ((MicrocodeEntryPoint->ProcessorFlags & (1 << CurrentPlatformId)) == 0)) {
+
+  ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);
+  if (ProcessorInfo == NULL) {
+    CorrectMicrocode = FALSE;
     ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));
     if (ExtendedTableLength != 0) {
       //
@@ -438,8 +509,8 @@ VerifyMicrocode (
                 //
                 // Verify Header
                 //
-                if ((ExtendedTable->ProcessorSignature.Uint32 == CurrentProcessorSignature) &&
-                    (ExtendedTable->ProcessorFlag & (1 << CurrentPlatformId))) {
+                ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);
+                if (ProcessorInfo != NULL) {
                   //
                   // Find one
                   //
@@ -459,11 +530,7 @@ VerifyMicrocode (
       }
       *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");
-        }
+        *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");
       }
       return EFI_UNSUPPORTED;
     }
@@ -472,8 +539,9 @@ VerifyMicrocode (
   //
   // Check UpdateRevision
   //
-  CurrentRevision = GetCurrentMicrocodeSignature();
-  if (MicrocodeEntryPoint->UpdateRevision < CurrentRevision) {
+  CurrentRevision = ProcessorInfo->MicrocodeRevision;
+  if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||
+      (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {
     if (TryLoad) {
       DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));
     }
@@ -488,7 +556,7 @@ VerifyMicrocode (
   // try load MCU
   //
   if (TryLoad) {
-    CurrentRevision = LoadMicrocode((UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));
+    CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (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;
@@ -503,31 +571,6 @@ VerifyMicrocode (
 }
 
 /**
-  Get current Microcode in used.
-
-  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
-
-  @return current Microcode in used.
-**/
-VOID *
-GetCurrentMicrocodeInUse (
-  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate
-  )
-{
-  UINTN                                   Index;
-
-  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {
-    if (!MicrocodeFmpPrivate->MicrocodeInfo[Index].InUse) {
-      continue;
-    }
-    if (IsMicrocodeInUse (MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint)) {
-      return MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint;
-    }
-  }
-  return NULL;
-}
-
-/**
   Get next Microcode entrypoint.
 
   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
@@ -622,7 +665,7 @@ UpdateMicrocode (
   Update Microcode flash region.
 
   @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
-  @param[in]  CurrentMicrocodeEntryPoint Current Microcode entrypoint
+  @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated
   @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.
@@ -633,7 +676,7 @@ UpdateMicrocode (
 EFI_STATUS
 UpdateMicrocodeFlashRegion (
   IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,
-  IN  CPU_MICROCODE_HEADER                    *CurrentMicrocodeEntryPoint,
+  IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,
   IN  VOID                                    *Image,
   IN  UINTN                                   ImageSize,
   OUT UINT32                                  *LastAttemptStatus
@@ -641,7 +684,7 @@ UpdateMicrocodeFlashRegion (
 {
   VOID                                    *MicrocodePatchAddress;
   UINTN                                   MicrocodePatchRegionSize;
-  UINTN                                   CurrentTotalSize;
+  UINTN                                   TargetTotalSize;
   UINTN                                   UsedRegionSize;
   EFI_STATUS                              Status;
   VOID                                    *MicrocodePatchScratchBuffer;
@@ -669,38 +712,38 @@ UpdateMicrocodeFlashRegion (
   ScratchBufferSize = 0;
 
   //
-  // Current data collection
+  // Target data collection
   //
-  CurrentTotalSize = 0;
+  TargetTotalSize = 0;
   AvailableSize = 0;
   NextMicrocodeEntryPoint = NULL;
-  if (CurrentMicrocodeEntryPoint != NULL) {
-    if (CurrentMicrocodeEntryPoint->DataSize == 0) {
-      CurrentTotalSize = 2048;
+  if (TargetMicrocodeEntryPoint != NULL) {
+    if (TargetMicrocodeEntryPoint->DataSize == 0) {
+      TargetTotalSize = 2048;
     } else {
-      CurrentTotalSize = CurrentMicrocodeEntryPoint->TotalSize;
+      TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;
     }
-    DEBUG((DEBUG_INFO, "  CurrentTotalSize - 0x%x\n", CurrentTotalSize));
-    NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, CurrentMicrocodeEntryPoint);
+    DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));
+    NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);
     DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));
     if (NextMicrocodeEntryPoint != NULL) {
-      ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)CurrentMicrocodeEntryPoint + CurrentTotalSize));
-      AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)CurrentMicrocodeEntryPoint;
+      ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
+      AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;
     } else {
-      AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)CurrentMicrocodeEntryPoint;
+      AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;
     }
     DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));
   }
-  ASSERT (AvailableSize >= CurrentTotalSize);
+  ASSERT (AvailableSize >= TargetTotalSize);
   UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);
   DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));
-  ASSERT (UsedRegionSize >= CurrentTotalSize);
-  if (CurrentMicrocodeEntryPoint != NULL) {
-    ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)CurrentMicrocodeEntryPoint + CurrentTotalSize));
+  ASSERT (UsedRegionSize >= TargetTotalSize);
+  if (TargetMicrocodeEntryPoint != NULL) {
+    ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));
   }
   //
   // Total Size means the Microcode data size.
-  // Available Size means the Microcode data size plus the pad till next (1) Microcode or (2) the end.
+  // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.
   //
   // (1)
   // +------+-----------+-----+------+===================+
@@ -740,23 +783,23 @@ UpdateMicrocodeFlashRegion (
     // 1.1. Copy new image
     CopyMem (ScratchBufferPtr, Image, ImageSize);
     ScratchBufferSize += ImageSize;
-    ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
     // 1.2. Pad 0xFF
     RestSize = AvailableSize - ImageSize;
     if (RestSize > 0) {
       SetMem (ScratchBufferPtr, RestSize, 0xFF);
       ScratchBufferSize += RestSize;
-      ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
     }
-    Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+    Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
     return Status;
   }
 
   //
   // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.
   //
-  if (MicrocodePatchRegionSize - (UsedRegionSize - CurrentTotalSize) >= ImageSize) {
-    if (CurrentMicrocodeEntryPoint == NULL) {
+  if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {
+    if (TargetMicrocodeEntryPoint == NULL) {
       DEBUG((DEBUG_INFO, "Append new microcode\n"));
       //
       // +------+------------+------+===================+
@@ -780,17 +823,17 @@ UpdateMicrocodeFlashRegion (
       // +------+---------------+------+================+
       //
       // 2.1. Copy new image
-      CopyMem (MicrocodePatchScratchBuffer, Image, ImageSize);
+      CopyMem (ScratchBufferPtr, Image, ImageSize);
       ScratchBufferSize += ImageSize;
-      ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
       // 2.2. Copy rest images after the old image.
       if (NextMicrocodeEntryPoint != 0) {
         RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);
-        CopyMem (ScratchBufferPtr, (UINT8 *)CurrentMicrocodeEntryPoint + CurrentTotalSize, RestSize);
+        CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);
         ScratchBufferSize += RestSize;
-        ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
       }
-      Status = UpdateMicrocode((UINTN)CurrentMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
+      Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
     }
     return Status;
   }
@@ -815,21 +858,21 @@ UpdateMicrocodeFlashRegion (
     MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;
 
     // 3.1. Copy new image
-    CopyMem (MicrocodePatchScratchBuffer, Image, ImageSize);
+    CopyMem (ScratchBufferPtr, Image, ImageSize);
     ScratchBufferSize += ImageSize;
-    ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
     // 3.2. Copy some others to rest buffer
     for (Index = 0; Index < MicrocodeCount; Index++) {
       if (!MicrocodeInfo[Index].InUse) {
         continue;
       }
-      if (MicrocodeInfo[Index].MicrocodeEntryPoint == CurrentMicrocodeEntryPoint) {
+      if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {
         continue;
       }
       if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {
         CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);
         ScratchBufferSize += MicrocodeInfo[Index].TotalSize;
-        ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
       }
     }
     // 3.3. Pad 0xFF
@@ -837,7 +880,7 @@ UpdateMicrocodeFlashRegion (
     if (RestSize > 0) {
       SetMem (ScratchBufferPtr, RestSize, 0xFF);
       ScratchBufferSize += RestSize;
-      ScratchBufferPtr = (UINT8 *)ScratchBufferPtr + ScratchBufferSize;
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;
     }
     Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);
     return Status;
@@ -886,14 +929,9 @@ MicrocodeWrite (
 {
   EFI_STATUS                              Status;
   VOID                                    *AlignedImage;
-  CPU_MICROCODE_HEADER                    *CurrentMicrocodeEntryPoint;
-
-  //
-  // We must get Current MicrocodeEntrypoint *before* VerifyMicrocode,
-  // because the MicrocodeSignature might be updated in VerifyMicrocode.
-  //
-  CurrentMicrocodeEntryPoint = GetCurrentMicrocodeInUse(MicrocodeFmpPrivate);
-  DEBUG((DEBUG_INFO, "  CurrentMicrocodeEntryPoint - 0x%x\n", CurrentMicrocodeEntryPoint));
+  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint;
+  UINTN                                   TargetCpuIndex;
+  UINTN                                   TargetMicrcodeIndex;
 
   //
   // MCU must be 16 bytes aligned
@@ -906,7 +944,8 @@ MicrocodeWrite (
   }
 
   *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;
-  Status = VerifyMicrocode(AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason);
+  TargetCpuIndex = (UINTN)-1;
+  Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);
   if (EFI_ERROR(Status)) {
     DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));
     FreePool(AlignedImage);
@@ -914,9 +953,21 @@ MicrocodeWrite (
   }
   DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));
 
+  DEBUG((DEBUG_INFO, "  TargetCpuIndex - 0x%x\n", TargetCpuIndex));
+  ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);
+  TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;
+  DEBUG((DEBUG_INFO, "  TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));
+  if (TargetMicrcodeIndex != (UINTN)-1) {
+    ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);
+    TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;
+  } else {
+    TargetMicrocodeEntryPoint = NULL;
+  }
+  DEBUG((DEBUG_INFO, "  TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));
+
   Status = UpdateMicrocodeFlashRegion(
              MicrocodeFmpPrivate,
-             CurrentMicrocodeEntryPoint,
+             TargetMicrocodeEntryPoint,
              AlignedImage,
              ImageSize,
              LastAttemptStatus
diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
index b4d1bac..9dc3063 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.h
@@ -21,6 +21,7 @@
 #include <Guid/MicrocodeFmp.h>
 
 #include <Protocol/FirmwareManagement.h>
+#include <Protocol/MpService.h>
 
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
@@ -56,6 +57,19 @@ typedef struct {
   BOOLEAN                InUse;
 } MICROCODE_INFO;
 
+typedef struct {
+  UINTN                  CpuIndex;
+  UINT32                 ProcessorSignature;
+  UINT8                  PlatformId;
+  UINT32                 MicrocodeRevision;
+  UINTN                  MicrocodeIndex;
+} PROCESSOR_INFO;
+
+typedef struct {
+  UINT64                 Address;
+  UINT32                 Revision;
+} MICROCODE_LOAD_BUFFER;
+
 struct _MICROCODE_FMP_PRIVATE_DATA {
   UINT32                               Signature;
   EFI_FIRMWARE_MANAGEMENT_PROTOCOL     Fmp;
@@ -68,6 +82,10 @@ struct _MICROCODE_FMP_PRIVATE_DATA {
   UINT32                               PackageVersion;
   CHAR16                               *PackageVersionName;
   MICROCODE_FMP_LAST_ATTEMPT_VARIABLE  LastAttempt;
+  EFI_MP_SERVICES_PROTOCOL             *MpService;
+  UINTN                                BspIndex;
+  UINTN                                ProcessorCount;
+  PROCESSOR_INFO                       *ProcessorInfo;
 };
 
 typedef struct _MICROCODE_FMP_PRIVATE_DATA  MICROCODE_FMP_PRIVATE_DATA;
@@ -108,10 +126,25 @@ GetMicrocodeRegion (
   );
 
 /**
+  Collect processor information.
+  The function prototype for invoking a function on an Application Processor.
+
+  @param[in,out] Buffer  The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorInfo (
+  IN OUT VOID  *Buffer
+  );
+
+/**
   Get current Microcode information.
 
-  NOTE: The DescriptorCount/ImageDescriptor/MicrocodeInfo in MicrocodeFmpPrivate
-  are not avaiable in this function.
+  The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)
+  in MicrocodeFmpPrivate must be initialized.
+
+  The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)
+  in MicrocodeFmpPrivate may not be avaiable in this function.
 
   @param[in]   MicrocodeFmpPrivate        The Microcode driver private data
   @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.
@@ -129,6 +162,40 @@ GetMicrocodeInfo (
   );
 
 /**
+  Verify Microcode.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data
+  @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().
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.
+                                         On output, the index of target CPU which matches the Microcode.
+
+  @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  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,
+  IN  VOID                        *Image,
+  IN  UINTN                       ImageSize,
+  IN  BOOLEAN                     TryLoad,
+  OUT UINT32                      *LastAttemptStatus,
+  OUT CHAR16                      **AbortReason,   OPTIONAL
+  IN OUT UINTN                    *TargetCpuIndex  OPTIONAL
+  );
+
+/**
   Write Microcode.
 
   @param[in]   MicrocodeFmpPrivate The Microcode driver private data
@@ -158,6 +225,16 @@ MicrocodeWrite (
   );
 
 /**
+  Dump private information.
+
+  @param[in] MicrocodeFmpPrivate private data structure.
+**/
+VOID
+DumpPrivateInfo (
+  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.
diff --git a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
index 7aae348..55797cf 100644
--- a/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
+++ b/UefiCpuPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdateDxe.inf
@@ -56,13 +56,15 @@
 
 [Protocols]
   gEfiFirmwareManagementProtocolGuid            ## PRODUCES
+  gEfiMpServiceProtocolGuid                     ## CONSUMES
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress            ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize         ## CONSUMES
 
 [Depex]
-  gEfiVariableArchProtocolGuid
+  gEfiVariableArchProtocolGuid AND
+  gEfiMpServiceProtocolGuid
 
 [UserExtensions.TianoCore."ExtraFiles"]
   MicrocodeUpdateDxeExtra.uni
-- 
2.7.4.windows.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-12-28  6:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-12-28  6:53 [PATCH V2 0/2] MicrocodeUpdate enhancement Jiewen Yao
2016-12-28  6:53 ` [PATCH V2 1/2] UefiCpuPkg/MicrocodeUpdate: enhance flash write logic Jiewen Yao
2016-12-28  6:53 ` [PATCH V2 2/2] UefiCpuPkg/MicrocodeUpdate: Add MP support Jiewen Yao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox