]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
IntelSiliconPkg: Move MicrocodeUpdate from UefiCpuPkg
[mirror_edk2.git] / IntelSiliconPkg / Feature / Capsule / MicrocodeUpdateDxe / MicrocodeUpdate.c
diff --git a/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c b/IntelSiliconPkg/Feature/Capsule/MicrocodeUpdateDxe/MicrocodeUpdate.c
new file mode 100644 (file)
index 0000000..4e8f1d5
--- /dev/null
@@ -0,0 +1,981 @@
+/** @file\r
+  SetImage instance to update Microcode.\r
+\r
+  Caution: This module requires additional review when modified.\r
+  This module will have external input - capsule image.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  MicrocodeWrite() and VerifyMicrocode() will receive untrusted input and do basic validation.\r
+\r
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "MicrocodeUpdate.h"\r
+\r
+/**\r
+  Get Microcode Region.\r
+\r
+  @param[out] MicrocodePatchAddress      The address of Microcode\r
+  @param[out] MicrocodePatchRegionSize   The region size of Microcode\r
+\r
+  @retval TRUE   The Microcode region is returned.\r
+  @retval FALSE  No Microcode region.\r
+**/\r
+BOOLEAN\r
+GetMicrocodeRegion (\r
+  OUT VOID     **MicrocodePatchAddress,\r
+  OUT UINTN    *MicrocodePatchRegionSize\r
+  )\r
+{\r
+  *MicrocodePatchAddress = (VOID *)(UINTN)PcdGet64(PcdCpuMicrocodePatchAddress);\r
+  *MicrocodePatchRegionSize = (UINTN)PcdGet64(PcdCpuMicrocodePatchRegionSize);\r
+\r
+  if ((*MicrocodePatchAddress == NULL) || (*MicrocodePatchRegionSize == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Get Microcode update signature of currently loaded Microcode update.\r
+\r
+  @return  Microcode signature.\r
+\r
+**/\r
+UINT32\r
+GetCurrentMicrocodeSignature (\r
+  VOID\r
+  )\r
+{\r
+  UINT64 Signature;\r
+\r
+  AsmWriteMsr64(MSR_IA32_BIOS_SIGN_ID, 0);\r
+  AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
+  Signature = AsmReadMsr64(MSR_IA32_BIOS_SIGN_ID);\r
+  return (UINT32)RShiftU64(Signature, 32);\r
+}\r
+\r
+/**\r
+  Get current processor signature.\r
+\r
+  @return current processor signature.\r
+**/\r
+UINT32\r
+GetCurrentProcessorSignature (\r
+  VOID\r
+  )\r
+{\r
+  UINT32                                  RegEax;\r
+  AsmCpuid(CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
+  return RegEax;\r
+}\r
+\r
+/**\r
+  Get current platform ID.\r
+\r
+  @return current platform ID.\r
+**/\r
+UINT8\r
+GetCurrentPlatformId (\r
+  VOID\r
+  )\r
+{\r
+  UINT8                                   PlatformId;\r
+\r
+  PlatformId = (UINT8)AsmMsrBitFieldRead64(MSR_IA32_PLATFORM_ID, 50, 52);\r
+  return PlatformId;\r
+}\r
+\r
+/**\r
+  Load new Microcode.\r
+\r
+  @param[in] Address  The address of new Microcode.\r
+\r
+  @return  Loaded Microcode signature.\r
+\r
+**/\r
+UINT32\r
+LoadMicrocode (\r
+  IN UINT64  Address\r
+  )\r
+{\r
+  AsmWriteMsr64(MSR_IA32_BIOS_UPDT_TRIG, Address);\r
+  return GetCurrentMicrocodeSignature();\r
+}\r
+\r
+/**\r
+  Load Microcode on an Application Processor.\r
+  The function prototype for invoking a function on an Application Processor.\r
+\r
+  @param[in,out] Buffer  The pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+MicrocodeLoadAp (\r
+  IN OUT VOID  *Buffer\r
+  )\r
+{\r
+  MICROCODE_LOAD_BUFFER                *MicrocodeLoadBuffer;\r
+\r
+  MicrocodeLoadBuffer = Buffer;\r
+  MicrocodeLoadBuffer->Revision = LoadMicrocode (MicrocodeLoadBuffer->Address);\r
+}\r
+\r
+/**\r
+  Load new Microcode on this processor\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  CpuIndex                   The index of the processor.\r
+  @param[in]  Address                    The address of new Microcode.\r
+\r
+  @return  Loaded Microcode signature.\r
+\r
+**/\r
+UINT32\r
+LoadMicrocodeOnThis (\r
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,\r
+  IN  UINTN                       CpuIndex,\r
+  IN  UINT64                      Address\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_MP_SERVICES_PROTOCOL             *MpService;\r
+  MICROCODE_LOAD_BUFFER                MicrocodeLoadBuffer;\r
+\r
+  if (CpuIndex == MicrocodeFmpPrivate->BspIndex) {\r
+    return LoadMicrocode (Address);\r
+  } else {\r
+    MpService = MicrocodeFmpPrivate->MpService;\r
+    MicrocodeLoadBuffer.Address = Address;\r
+    MicrocodeLoadBuffer.Revision = 0;\r
+    Status = MpService->StartupThisAP (\r
+                          MpService,\r
+                          MicrocodeLoadAp,\r
+                          CpuIndex,\r
+                          NULL,\r
+                          0,\r
+                          &MicrocodeLoadBuffer,\r
+                          NULL\r
+                          );\r
+    ASSERT_EFI_ERROR(Status);\r
+    return MicrocodeLoadBuffer.Revision;\r
+  }\r
+}\r
+\r
+/**\r
+  Collect processor information.\r
+  The function prototype for invoking a function on an Application Processor.\r
+\r
+  @param[in,out] Buffer  The pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+CollectProcessorInfo (\r
+  IN OUT VOID  *Buffer\r
+  )\r
+{\r
+  PROCESSOR_INFO  *ProcessorInfo;\r
+\r
+  ProcessorInfo = Buffer;\r
+  ProcessorInfo->ProcessorSignature = GetCurrentProcessorSignature();\r
+  ProcessorInfo->PlatformId = GetCurrentPlatformId();\r
+  ProcessorInfo->MicrocodeRevision = GetCurrentMicrocodeSignature();\r
+}\r
+\r
+/**\r
+  Get current Microcode information.\r
+\r
+  The ProcessorInformation (BspIndex/ProcessorCount/ProcessorInfo)\r
+  in MicrocodeFmpPrivate must be initialized.\r
+\r
+  The MicrocodeInformation (DescriptorCount/ImageDescriptor/MicrocodeInfo)\r
+  in MicrocodeFmpPrivate may not be avaiable in this function.\r
+\r
+  @param[in]   MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]   DescriptorCount            The count of Microcode ImageDescriptor allocated.\r
+  @param[out]  ImageDescriptor            Microcode ImageDescriptor\r
+  @param[out]  MicrocodeInfo              Microcode information\r
+\r
+  @return Microcode count\r
+**/\r
+UINTN\r
+GetMicrocodeInfo (\r
+  IN  MICROCODE_FMP_PRIVATE_DATA     *MicrocodeFmpPrivate,\r
+  IN  UINTN                          DescriptorCount,  OPTIONAL\r
+  OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR  *ImageDescriptor, OPTIONAL\r
+  OUT MICROCODE_INFO                 *MicrocodeInfo    OPTIONAL\r
+  )\r
+{\r
+  VOID                                    *MicrocodePatchAddress;\r
+  UINTN                                   MicrocodePatchRegionSize;\r
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;\r
+  UINTN                                   MicrocodeEnd;\r
+  UINTN                                   TotalSize;\r
+  UINTN                                   Count;\r
+  UINT64                                  ImageAttributes;\r
+  BOOLEAN                                 IsInUse;\r
+  EFI_STATUS                              Status;\r
+  UINT32                                  AttemptStatus;\r
+  UINTN                                   TargetCpuIndex;\r
+\r
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+  DEBUG((DEBUG_INFO, "Microcode Region - 0x%x - 0x%x\n", MicrocodePatchAddress, MicrocodePatchRegionSize));\r
+\r
+  Count = 0;\r
+\r
+  MicrocodeEnd = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize;\r
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
+  do {\r
+    if (MicrocodeEntryPoint->HeaderVersion == 0x1 && MicrocodeEntryPoint->LoaderRevision == 0x1) {\r
+      //\r
+      // It is the microcode header. It is not the padding data between microcode patches\r
+      // becasue the padding data should not include 0x00000001 and it should be the repeated\r
+      // byte format (like 0xXYXYXYXY....).\r
+      //\r
+      if (MicrocodeEntryPoint->DataSize == 0) {\r
+        TotalSize = 2048;\r
+      } else {\r
+        TotalSize = MicrocodeEntryPoint->TotalSize;\r
+      }\r
+\r
+      TargetCpuIndex = (UINTN)-1;\r
+      Status = VerifyMicrocode(MicrocodeFmpPrivate, MicrocodeEntryPoint, TotalSize, FALSE, &AttemptStatus, NULL, &TargetCpuIndex);\r
+      if (!EFI_ERROR(Status)) {\r
+        IsInUse = TRUE;\r
+        ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
+        MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex = Count;\r
+      } else {\r
+        IsInUse = FALSE;\r
+      }\r
+\r
+      if (ImageDescriptor != NULL && DescriptorCount > Count) {\r
+        ImageDescriptor[Count].ImageIndex = (UINT8)(Count + 1);\r
+        CopyGuid (&ImageDescriptor[Count].ImageTypeId, &gMicrocodeFmpImageTypeIdGuid);\r
+        ImageDescriptor[Count].ImageId = LShiftU64(MicrocodeEntryPoint->ProcessorFlags, 32) + MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
+        ImageDescriptor[Count].ImageIdName = NULL;\r
+        ImageDescriptor[Count].Version = MicrocodeEntryPoint->UpdateRevision;\r
+        ImageDescriptor[Count].VersionName = NULL;\r
+        ImageDescriptor[Count].Size = TotalSize;\r
+        ImageAttributes = IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | IMAGE_ATTRIBUTE_RESET_REQUIRED;\r
+        if (IsInUse) {\r
+          ImageAttributes |= IMAGE_ATTRIBUTE_IN_USE;\r
+        }\r
+        ImageDescriptor[Count].AttributesSupported = ImageAttributes | IMAGE_ATTRIBUTE_IN_USE;\r
+        ImageDescriptor[Count].AttributesSetting = ImageAttributes;\r
+        ImageDescriptor[Count].Compatibilities = 0;\r
+        ImageDescriptor[Count].LowestSupportedImageVersion = MicrocodeEntryPoint->UpdateRevision; // do not support rollback\r
+        ImageDescriptor[Count].LastAttemptVersion = 0;\r
+        ImageDescriptor[Count].LastAttemptStatus = 0;\r
+        ImageDescriptor[Count].HardwareInstance = 0;\r
+      }\r
+      if (MicrocodeInfo != NULL && DescriptorCount > Count) {\r
+        MicrocodeInfo[Count].MicrocodeEntryPoint = MicrocodeEntryPoint;\r
+        MicrocodeInfo[Count].TotalSize = TotalSize;\r
+        MicrocodeInfo[Count].InUse = IsInUse;\r
+      }\r
+    } else {\r
+      //\r
+      // It is the padding data between the microcode patches for microcode patches alignment.\r
+      // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
+      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
+      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
+      // find the next possible microcode patch header.\r
+      //\r
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+      continue;\r
+    }\r
+\r
+    Count++;\r
+    ASSERT(Count < 0xFF);\r
+\r
+    //\r
+    // Get the next patch.\r
+    //\r
+    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
+  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
+\r
+  return Count;\r
+}\r
+\r
+/**\r
+  Return matched processor information.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  ProcessorSignature         The processor signature to be matched\r
+  @param[in]  ProcessorFlags             The processor flags to be matched\r
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
+                                         On output, the index of target CPU which matches the Microcode.\r
+\r
+  @return matched processor information.\r
+**/\r
+PROCESSOR_INFO *\r
+GetMatchedProcessor (\r
+  IN MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,\r
+  IN UINT32                      ProcessorSignature,\r
+  IN UINT32                      ProcessorFlags,\r
+  IN OUT UINTN                   *TargetCpuIndex\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  if (*TargetCpuIndex != (UINTN)-1) {\r
+    Index = *TargetCpuIndex;\r
+    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
+        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
+      return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
+    } else {\r
+      return NULL;\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < MicrocodeFmpPrivate->ProcessorCount; Index++) {\r
+    if ((ProcessorSignature == MicrocodeFmpPrivate->ProcessorInfo[Index].ProcessorSignature) &&\r
+        ((ProcessorFlags & (1 << MicrocodeFmpPrivate->ProcessorInfo[Index].PlatformId)) != 0)) {\r
+      *TargetCpuIndex = Index;\r
+      return &MicrocodeFmpPrivate->ProcessorInfo[Index];\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Verify Microcode.\r
+\r
+  Caution: This function may receive untrusted input.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  Image                      The Microcode image buffer.\r
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.\r
+  @param[in]  TryLoad                    Try to load Microcode or not.\r
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[out] AbortReason                A pointer to a pointer to a null-terminated string providing more\r
+                                         details for the aborted operation. The buffer is allocated by this function\r
+                                         with AllocatePool(), and it is the caller's responsibility to free it with a\r
+                                         call to FreePool().\r
+  @param[in, out] TargetCpuIndex         On input, the index of target CPU which tries to match the Microcode. (UINTN)-1 means to try all.\r
+                                         On output, the index of target CPU which matches the Microcode.\r
+\r
+  @retval EFI_SUCCESS               The Microcode image passes verification.\r
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.\r
+  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.\r
+  @retval EFI_UNSUPPORTED           The Microcode ProcessorSignature or ProcessorFlags is incorrect.\r
+  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.\r
+**/\r
+EFI_STATUS\r
+VerifyMicrocode (\r
+  IN  MICROCODE_FMP_PRIVATE_DATA  *MicrocodeFmpPrivate,\r
+  IN  VOID                        *Image,\r
+  IN  UINTN                       ImageSize,\r
+  IN  BOOLEAN                     TryLoad,\r
+  OUT UINT32                      *LastAttemptStatus,\r
+  OUT CHAR16                      **AbortReason,   OPTIONAL\r
+  IN OUT UINTN                    *TargetCpuIndex\r
+  )\r
+{\r
+  UINTN                                   Index;\r
+  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;\r
+  UINTN                                   TotalSize;\r
+  UINTN                                   DataSize;\r
+  UINT32                                  CurrentRevision;\r
+  PROCESSOR_INFO                          *ProcessorInfo;\r
+  UINT32                                  CheckSum32;\r
+  UINTN                                   ExtendedTableLength;\r
+  UINT32                                  ExtendedTableCount;\r
+  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;\r
+  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;\r
+  BOOLEAN                                 CorrectMicrocode;\r
+\r
+  //\r
+  // Check HeaderVersion\r
+  //\r
+  MicrocodeEntryPoint = Image;\r
+  if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on HeaderVersion\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidHeaderVersion"), L"InvalidHeaderVersion");\r
+    }\r
+    return EFI_INCOMPATIBLE_VERSION;\r
+  }\r
+  //\r
+  // Check LoaderRevision\r
+  //\r
+  if (MicrocodeEntryPoint->LoaderRevision != 0x1) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoaderRevision\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidLoaderVersion"), L"InvalidLoaderVersion");\r
+    }\r
+    return EFI_INCOMPATIBLE_VERSION;\r
+  }\r
+  //\r
+  // Check Size\r
+  //\r
+  if (MicrocodeEntryPoint->DataSize == 0) {\r
+    TotalSize = 2048;\r
+  } else {\r
+    TotalSize = MicrocodeEntryPoint->TotalSize;\r
+  }\r
+  if (TotalSize <= sizeof(CPU_MICROCODE_HEADER)) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - TotalSize too small\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
+    }\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  if (TotalSize != ImageSize) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on TotalSize\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidTotalSize"), L"InvalidTotalSize");\r
+    }\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  //\r
+  // Check CheckSum32\r
+  //\r
+  if (MicrocodeEntryPoint->DataSize == 0) {\r
+    DataSize = 2048 - sizeof(CPU_MICROCODE_HEADER);\r
+  } else {\r
+    DataSize = MicrocodeEntryPoint->DataSize;\r
+  }\r
+  if (DataSize > TotalSize - sizeof(CPU_MICROCODE_HEADER)) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize too big\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
+    }\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  if ((DataSize & 0x3) != 0) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - DataSize not aligned\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidDataSize"), L"InvalidDataSize");\r
+    }\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+  CheckSum32 = CalculateSum32((UINT32 *)MicrocodeEntryPoint, DataSize + sizeof(CPU_MICROCODE_HEADER));\r
+  if (CheckSum32 != 0) {\r
+    DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CheckSum32\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"InvalidChecksum"), L"InvalidChecksum");\r
+    }\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  //\r
+  // Check ProcessorSignature/ProcessorFlags\r
+  //\r
+\r
+  ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, MicrocodeEntryPoint->ProcessorSignature.Uint32, MicrocodeEntryPoint->ProcessorFlags, TargetCpuIndex);\r
+  if (ProcessorInfo == NULL) {\r
+    CorrectMicrocode = FALSE;\r
+    ExtendedTableLength = TotalSize - (DataSize + sizeof(CPU_MICROCODE_HEADER));\r
+    if (ExtendedTableLength != 0) {\r
+      //\r
+      // Extended Table exist, check if the CPU in support list\r
+      //\r
+      ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + DataSize + sizeof(CPU_MICROCODE_HEADER));\r
+      //\r
+      // Calculate Extended Checksum\r
+      //\r
+      if ((ExtendedTableLength > sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) && ((ExtendedTableLength & 0x3) != 0)) {\r
+        CheckSum32 = CalculateSum32((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
+        if (CheckSum32 == 0) {\r
+          //\r
+          // Checksum correct\r
+          //\r
+          ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
+          if (ExtendedTableCount <= (ExtendedTableLength - sizeof(CPU_MICROCODE_EXTENDED_TABLE_HEADER)) / sizeof(CPU_MICROCODE_EXTENDED_TABLE)) {\r
+            ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
+            for (Index = 0; Index < ExtendedTableCount; Index++) {\r
+              CheckSum32 = CalculateSum32((UINT32 *)ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
+              if (CheckSum32 == 0) {\r
+                //\r
+                // Verify Header\r
+                //\r
+                ProcessorInfo = GetMatchedProcessor (MicrocodeFmpPrivate, ExtendedTable->ProcessorSignature.Uint32, ExtendedTable->ProcessorFlag, TargetCpuIndex);\r
+                if (ProcessorInfo != NULL) {\r
+                  //\r
+                  // Find one\r
+                  //\r
+                  CorrectMicrocode = TRUE;\r
+                  break;\r
+                }\r
+              }\r
+              ExtendedTable++;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    if (!CorrectMicrocode) {\r
+      if (TryLoad) {\r
+        DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on CurrentProcessorSignature/ProcessorFlags\n"));\r
+      }\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
+      if (AbortReason != NULL) {\r
+        *AbortReason = AllocateCopyPool(sizeof(L"UnsupportedProcessSignature/ProcessorFlags"), L"UnsupportedProcessSignature/ProcessorFlags");\r
+      }\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check UpdateRevision\r
+  //\r
+  CurrentRevision = ProcessorInfo->MicrocodeRevision;\r
+  if ((MicrocodeEntryPoint->UpdateRevision < CurrentRevision) ||\r
+      (TryLoad && (MicrocodeEntryPoint->UpdateRevision == CurrentRevision))) {\r
+    if (TryLoad) {\r
+      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on UpdateRevision\n"));\r
+    }\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INCORRECT_VERSION;\r
+    if (AbortReason != NULL) {\r
+      *AbortReason = AllocateCopyPool(sizeof(L"IncorrectRevision"), L"IncorrectRevision");\r
+    }\r
+    return EFI_INCOMPATIBLE_VERSION;\r
+  }\r
+\r
+  //\r
+  // try load MCU\r
+  //\r
+  if (TryLoad) {\r
+    CurrentRevision = LoadMicrocodeOnThis(MicrocodeFmpPrivate, ProcessorInfo->CpuIndex, (UINTN)MicrocodeEntryPoint + sizeof(CPU_MICROCODE_HEADER));\r
+    if (MicrocodeEntryPoint->UpdateRevision != CurrentRevision) {\r
+      DEBUG((DEBUG_ERROR, "VerifyMicrocode - fail on LoadMicrocode\n"));\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;\r
+      if (AbortReason != NULL) {\r
+        *AbortReason = AllocateCopyPool(sizeof(L"InvalidData"), L"InvalidData");\r
+      }\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get next Microcode entrypoint.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  MicrocodeEntryPoint        Current Microcode entrypoint\r
+\r
+  @return next Microcode entrypoint.\r
+**/\r
+CPU_MICROCODE_HEADER *\r
+GetNextMicrocode (\r
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,\r
+  IN CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint\r
+  )\r
+{\r
+  UINTN                                   Index;\r
+\r
+  for (Index = 0; Index < MicrocodeFmpPrivate->DescriptorCount; Index++) {\r
+    if (MicrocodeEntryPoint == MicrocodeFmpPrivate->MicrocodeInfo[Index].MicrocodeEntryPoint) {\r
+      if (Index == (UINTN)MicrocodeFmpPrivate->DescriptorCount - 1) {\r
+        // it is last one\r
+        return NULL;\r
+      } else {\r
+        // return next one\r
+        return MicrocodeFmpPrivate->MicrocodeInfo[Index + 1].MicrocodeEntryPoint;\r
+      }\r
+    }\r
+  }\r
+\r
+  ASSERT(FALSE);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Get current Microcode used region size.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+\r
+  @return current Microcode used region size.\r
+**/\r
+UINTN\r
+GetCurrentMicrocodeUsedRegionSize (\r
+  IN MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate\r
+  )\r
+{\r
+  if (MicrocodeFmpPrivate->DescriptorCount == 0) {\r
+    return 0;\r
+  }\r
+\r
+  return (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].MicrocodeEntryPoint\r
+         + (UINTN)MicrocodeFmpPrivate->MicrocodeInfo[MicrocodeFmpPrivate->DescriptorCount - 1].TotalSize\r
+         - (UINTN)MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+}\r
+\r
+/**\r
+  Update Microcode.\r
+\r
+  @param[in]   Address            The flash address of Microcode.\r
+  @param[in]   Image              The Microcode image buffer.\r
+  @param[in]   ImageSize          The size of Microcode image buffer in bytes.\r
+  @param[out]  LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS           The Microcode image is updated.\r
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+UpdateMicrocode (\r
+  IN UINT64   Address,\r
+  IN VOID     *Image,\r
+  IN UINTN    ImageSize,\r
+  OUT UINT32  *LastAttemptStatus\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
+  DEBUG((DEBUG_INFO, "  Address - 0x%lx,", Address));\r
+  DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ImageSize));\r
+\r
+  Status = MicrocodeFlashWrite (\r
+             Address,\r
+             Image,\r
+             ImageSize\r
+             );\r
+  if (!EFI_ERROR(Status)) {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+  } else {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Update Microcode flash region.\r
+\r
+  @param[in]  MicrocodeFmpPrivate        The Microcode driver private data\r
+  @param[in]  TargetMicrocodeEntryPoint  Target Microcode entrypoint to be updated\r
+  @param[in]  Image                      The Microcode image buffer.\r
+  @param[in]  ImageSize                  The size of Microcode image buffer in bytes.\r
+  @param[out] LastAttemptStatus          The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS             The Microcode image is written.\r
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+UpdateMicrocodeFlashRegion (\r
+  IN  MICROCODE_FMP_PRIVATE_DATA              *MicrocodeFmpPrivate,\r
+  IN  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint,\r
+  IN  VOID                                    *Image,\r
+  IN  UINTN                                   ImageSize,\r
+  OUT UINT32                                  *LastAttemptStatus\r
+  )\r
+{\r
+  VOID                                    *MicrocodePatchAddress;\r
+  UINTN                                   MicrocodePatchRegionSize;\r
+  UINTN                                   TargetTotalSize;\r
+  UINTN                                   UsedRegionSize;\r
+  EFI_STATUS                              Status;\r
+  VOID                                    *MicrocodePatchScratchBuffer;\r
+  UINT8                                   *ScratchBufferPtr;\r
+  UINTN                                   ScratchBufferSize;\r
+  UINTN                                   RestSize;\r
+  UINTN                                   AvailableSize;\r
+  VOID                                    *NextMicrocodeEntryPoint;\r
+  MICROCODE_INFO                          *MicrocodeInfo;\r
+  UINTN                                   MicrocodeCount;\r
+  UINTN                                   Index;\r
+\r
+  DEBUG((DEBUG_INFO, "UpdateMicrocodeFlashRegion: Image - 0x%x, size - 0x%x\n", Image, ImageSize));\r
+\r
+  MicrocodePatchAddress = MicrocodeFmpPrivate->MicrocodePatchAddress;\r
+  MicrocodePatchRegionSize = MicrocodeFmpPrivate->MicrocodePatchRegionSize;\r
+\r
+  MicrocodePatchScratchBuffer = AllocateZeroPool (MicrocodePatchRegionSize);\r
+  if (MicrocodePatchScratchBuffer == NULL) {\r
+    DEBUG((DEBUG_ERROR, "Fail to allocate Microcode Scratch buffer\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ScratchBufferPtr = MicrocodePatchScratchBuffer;\r
+  ScratchBufferSize = 0;\r
+\r
+  //\r
+  // Target data collection\r
+  //\r
+  TargetTotalSize = 0;\r
+  AvailableSize = 0;\r
+  NextMicrocodeEntryPoint = NULL;\r
+  if (TargetMicrocodeEntryPoint != NULL) {\r
+    if (TargetMicrocodeEntryPoint->DataSize == 0) {\r
+      TargetTotalSize = 2048;\r
+    } else {\r
+      TargetTotalSize = TargetMicrocodeEntryPoint->TotalSize;\r
+    }\r
+    DEBUG((DEBUG_INFO, "  TargetTotalSize - 0x%x\n", TargetTotalSize));\r
+    NextMicrocodeEntryPoint = GetNextMicrocode(MicrocodeFmpPrivate, TargetMicrocodeEntryPoint);\r
+    DEBUG((DEBUG_INFO, "  NextMicrocodeEntryPoint - 0x%x\n", NextMicrocodeEntryPoint));\r
+    if (NextMicrocodeEntryPoint != NULL) {\r
+      ASSERT ((UINTN)NextMicrocodeEntryPoint >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
+      AvailableSize = (UINTN)NextMicrocodeEntryPoint - (UINTN)TargetMicrocodeEntryPoint;\r
+    } else {\r
+      AvailableSize = (UINTN)MicrocodePatchAddress + MicrocodePatchRegionSize - (UINTN)TargetMicrocodeEntryPoint;\r
+    }\r
+    DEBUG((DEBUG_INFO, "  AvailableSize - 0x%x\n", AvailableSize));\r
+  }\r
+  ASSERT (AvailableSize >= TargetTotalSize);\r
+  UsedRegionSize = GetCurrentMicrocodeUsedRegionSize(MicrocodeFmpPrivate);\r
+  DEBUG((DEBUG_INFO, "  UsedRegionSize - 0x%x\n", UsedRegionSize));\r
+  ASSERT (UsedRegionSize >= TargetTotalSize);\r
+  if (TargetMicrocodeEntryPoint != NULL) {\r
+    ASSERT ((UINTN)MicrocodePatchAddress + UsedRegionSize >= ((UINTN)TargetMicrocodeEntryPoint + TargetTotalSize));\r
+  }\r
+  //\r
+  // Total Size means the Microcode data size.\r
+  // Available Size means the Microcode data size plus the pad till (1) next Microcode or (2) the end.\r
+  //\r
+  // (1)\r
+  // +------+-----------+-----+------+===================+\r
+  // | MCU1 | Microcode | PAD | MCU2 |      Empty        |\r
+  // +------+-----------+-----+------+===================+\r
+  //        | TotalSize |\r
+  //        |<-AvailableSize->|\r
+  // |<-        UsedRegionSize     ->|\r
+  //\r
+  // (2)\r
+  // +------+-----------+===================+\r
+  // | MCU  | Microcode |      Empty        |\r
+  // +------+-----------+===================+\r
+  //        | TotalSize |\r
+  //        |<-      AvailableSize        ->|\r
+  // |<-UsedRegionSize->|\r
+  //\r
+\r
+  //\r
+  // Update based on policy\r
+  //\r
+\r
+  //\r
+  // 1. If there is enough space to update old one in situ, replace old microcode in situ.\r
+  //\r
+  if (AvailableSize >= ImageSize) {\r
+    DEBUG((DEBUG_INFO, "Replace old microcode in situ\n"));\r
+    //\r
+    // +------+------------+------+===================+\r
+    // |Other1| Old Image  |Other2|      Empty        |\r
+    // +------+------------+------+===================+\r
+    //\r
+    // +------+---------+--+------+===================+\r
+    // |Other1|New Image|FF|Other2|      Empty        |\r
+    // +------+---------+--+------+===================+\r
+    //\r
+    // 1.1. Copy new image\r
+    CopyMem (ScratchBufferPtr, Image, ImageSize);\r
+    ScratchBufferSize += ImageSize;\r
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    // 1.2. Pad 0xFF\r
+    RestSize = AvailableSize - ImageSize;\r
+    if (RestSize > 0) {\r
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
+      ScratchBufferSize += RestSize;\r
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    }\r
+    Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 2. If there is enough space to remove old one and add new one, reorg and replace old microcode.\r
+  //\r
+  if (MicrocodePatchRegionSize - (UsedRegionSize - TargetTotalSize) >= ImageSize) {\r
+    if (TargetMicrocodeEntryPoint == NULL) {\r
+      DEBUG((DEBUG_INFO, "Append new microcode\n"));\r
+      //\r
+      // +------+------------+------+===================+\r
+      // |Other1|   Other    |Other2|      Empty        |\r
+      // +------+------------+------+===================+\r
+      //\r
+      // +------+------------+------+-----------+=======+\r
+      // |Other1|   Other    |Other2| New Image | Empty |\r
+      // +------+------------+------+-----------+=======+\r
+      //\r
+      Status = UpdateMicrocode((UINTN)MicrocodePatchAddress + UsedRegionSize, Image, ImageSize, LastAttemptStatus);\r
+    } else {\r
+      DEBUG((DEBUG_INFO, "Reorg and replace old microcode\n"));\r
+      //\r
+      // +------+------------+------+===================+\r
+      // |Other1| Old Image  |Other2|      Empty        |\r
+      // +------+------------+------+===================+\r
+      //\r
+      // +------+---------------+------+================+\r
+      // |Other1|   New Image   |Other2|      Empty     |\r
+      // +------+---------------+------+================+\r
+      //\r
+      // 2.1. Copy new image\r
+      CopyMem (ScratchBufferPtr, Image, ImageSize);\r
+      ScratchBufferSize += ImageSize;\r
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+      // 2.2. Copy rest images after the old image.\r
+      if (NextMicrocodeEntryPoint != 0) {\r
+        RestSize = (UINTN)MicrocodePatchAddress + UsedRegionSize - ((UINTN)NextMicrocodeEntryPoint);\r
+        CopyMem (ScratchBufferPtr, (UINT8 *)TargetMicrocodeEntryPoint + TargetTotalSize, RestSize);\r
+        ScratchBufferSize += RestSize;\r
+        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+      }\r
+      Status = UpdateMicrocode((UINTN)TargetMicrocodeEntryPoint, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 3. The new image can be put in MCU region, but not all others can be put.\r
+  //    So all the unused MCU is removed.\r
+  //\r
+  if (MicrocodePatchRegionSize >= ImageSize) {\r
+    //\r
+    // +------+------------+------+===================+\r
+    // |Other1| Old Image  |Other2|      Empty        |\r
+    // +------+------------+------+===================+\r
+    //\r
+    // +-------------------------------------+--------+\r
+    // |        New Image                    | Other  |\r
+    // +-------------------------------------+--------+\r
+    //\r
+    DEBUG((DEBUG_INFO, "Add new microcode from beginning\n"));\r
+\r
+    MicrocodeCount = MicrocodeFmpPrivate->DescriptorCount;\r
+    MicrocodeInfo = MicrocodeFmpPrivate->MicrocodeInfo;\r
+\r
+    // 3.1. Copy new image\r
+    CopyMem (ScratchBufferPtr, Image, ImageSize);\r
+    ScratchBufferSize += ImageSize;\r
+    ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    // 3.2. Copy some others to rest buffer\r
+    for (Index = 0; Index < MicrocodeCount; Index++) {\r
+      if (!MicrocodeInfo[Index].InUse) {\r
+        continue;\r
+      }\r
+      if (MicrocodeInfo[Index].MicrocodeEntryPoint == TargetMicrocodeEntryPoint) {\r
+        continue;\r
+      }\r
+      if (MicrocodeInfo[Index].TotalSize <= MicrocodePatchRegionSize - ScratchBufferSize) {\r
+        CopyMem (ScratchBufferPtr, MicrocodeInfo[Index].MicrocodeEntryPoint, MicrocodeInfo[Index].TotalSize);\r
+        ScratchBufferSize += MicrocodeInfo[Index].TotalSize;\r
+        ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+      }\r
+    }\r
+    // 3.3. Pad 0xFF\r
+    RestSize = MicrocodePatchRegionSize - ScratchBufferSize;\r
+    if (RestSize > 0) {\r
+      SetMem (ScratchBufferPtr, RestSize, 0xFF);\r
+      ScratchBufferSize += RestSize;\r
+      ScratchBufferPtr = (UINT8 *)MicrocodePatchScratchBuffer + ScratchBufferSize;\r
+    }\r
+    Status = UpdateMicrocode((UINTN)MicrocodePatchAddress, MicrocodePatchScratchBuffer, ScratchBufferSize, LastAttemptStatus);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // 4. The new image size is bigger than the whole MCU region.\r
+  //\r
+  DEBUG((DEBUG_ERROR, "Microcode too big\n"));\r
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Write Microcode.\r
+\r
+  Caution: This function may receive untrusted input.\r
+\r
+  @param[in]   MicrocodeFmpPrivate The Microcode driver private data\r
+  @param[in]   Image               The Microcode image buffer.\r
+  @param[in]   ImageSize           The size of Microcode image buffer in bytes.\r
+  @param[out]  LastAttemptVersion  The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[out]  LastAttemptStatus   The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[out]  AbortReason         A pointer to a pointer to a null-terminated string providing more\r
+                                   details for the aborted operation. The buffer is allocated by this function\r
+                                   with AllocatePool(), and it is the caller's responsibility to free it with a\r
+                                   call to FreePool().\r
+\r
+  @retval EFI_SUCCESS               The Microcode image is written.\r
+  @retval EFI_VOLUME_CORRUPTED      The Microcode image is corrupt.\r
+  @retval EFI_INCOMPATIBLE_VERSION  The Microcode image version is incorrect.\r
+  @retval EFI_SECURITY_VIOLATION    The Microcode image fails to load.\r
+  @retval EFI_WRITE_PROTECTED       The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+MicrocodeWrite (\r
+  IN  MICROCODE_FMP_PRIVATE_DATA   *MicrocodeFmpPrivate,\r
+  IN  VOID                         *Image,\r
+  IN  UINTN                        ImageSize,\r
+  OUT UINT32                       *LastAttemptVersion,\r
+  OUT UINT32                       *LastAttemptStatus,\r
+  OUT CHAR16                       **AbortReason\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  VOID                                    *AlignedImage;\r
+  CPU_MICROCODE_HEADER                    *TargetMicrocodeEntryPoint;\r
+  UINTN                                   TargetCpuIndex;\r
+  UINTN                                   TargetMicrcodeIndex;\r
+\r
+  //\r
+  // MCU must be 16 bytes aligned\r
+  //\r
+  AlignedImage = AllocateCopyPool(ImageSize, Image);\r
+  if (AlignedImage == NULL) {\r
+    DEBUG((DEBUG_ERROR, "Fail to allocate aligned image\n"));\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *LastAttemptVersion = ((CPU_MICROCODE_HEADER *)Image)->UpdateRevision;\r
+  TargetCpuIndex = (UINTN)-1;\r
+  Status = VerifyMicrocode(MicrocodeFmpPrivate, AlignedImage, ImageSize, TRUE, LastAttemptStatus, AbortReason, &TargetCpuIndex);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG((DEBUG_ERROR, "Fail to verify Microcode Region\n"));\r
+    FreePool(AlignedImage);\r
+    return Status;\r
+  }\r
+  DEBUG((DEBUG_INFO, "Pass VerifyMicrocode\n"));\r
+\r
+  DEBUG((DEBUG_INFO, "  TargetCpuIndex - 0x%x\n", TargetCpuIndex));\r
+  ASSERT (TargetCpuIndex < MicrocodeFmpPrivate->ProcessorCount);\r
+  TargetMicrcodeIndex = MicrocodeFmpPrivate->ProcessorInfo[TargetCpuIndex].MicrocodeIndex;\r
+  DEBUG((DEBUG_INFO, "  TargetMicrcodeIndex - 0x%x\n", TargetMicrcodeIndex));\r
+  if (TargetMicrcodeIndex != (UINTN)-1) {\r
+    ASSERT (TargetMicrcodeIndex < MicrocodeFmpPrivate->DescriptorCount);\r
+    TargetMicrocodeEntryPoint = MicrocodeFmpPrivate->MicrocodeInfo[TargetMicrcodeIndex].MicrocodeEntryPoint;\r
+  } else {\r
+    TargetMicrocodeEntryPoint = NULL;\r
+  }\r
+  DEBUG((DEBUG_INFO, "  TargetMicrocodeEntryPoint - 0x%x\n", TargetMicrocodeEntryPoint));\r
+\r
+  Status = UpdateMicrocodeFlashRegion(\r
+             MicrocodeFmpPrivate,\r
+             TargetMicrocodeEntryPoint,\r
+             AlignedImage,\r
+             ImageSize,\r
+             LastAttemptStatus\r
+             );\r
+\r
+  FreePool(AlignedImage);\r
+\r
+  return Status;\r
+}\r
+\r
+\r