]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/Microcode.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
index 4763dcfebe35ff4a6ba2c2e0278696e40bc4efab..f9f070fa8bf230e72b7643b5bd8f96212512905b 100644 (file)
 /** @file\r
   Implementation of loading microcode on processors.\r
 \r
-  Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
   SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "MpLib.h"\r
 \r
-/**\r
-  Get microcode update signature of currently loaded microcode update.\r
-\r
-  @return  Microcode signature.\r
-**/\r
-UINT32\r
-GetCurrentMicrocodeSignature (\r
-  VOID\r
-  )\r
-{\r
-  MSR_IA32_BIOS_SIGN_ID_REGISTER   BiosSignIdMsr;\r
-\r
-  AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);\r
-  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
-  BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);\r
-  return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;\r
-}\r
-\r
 /**\r
   Detect whether specified processor can find matching microcode patch and load it.\r
 \r
-  Microcode Payload as the following format:\r
-  +----------------------------------------+------------------+\r
-  |          CPU_MICROCODE_HEADER          |                  |\r
-  +----------------------------------------+  CheckSum Part1  |\r
-  |            Microcode Binary            |                  |\r
-  +----------------------------------------+------------------+\r
-  |  CPU_MICROCODE_EXTENDED_TABLE_HEADER   |                  |\r
-  +----------------------------------------+  CheckSum Part2  |\r
-  |      CPU_MICROCODE_EXTENDED_TABLE      |                  |\r
-  |                   ...                  |                  |\r
-  +----------------------------------------+------------------+\r
-\r
-  There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.\r
-  The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount\r
-  of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.\r
-\r
-  When we are trying to verify the CheckSum32 with extended table.\r
-  We should use the fields of exnteded table to replace the corresponding\r
-  fields in CPU_MICROCODE_HEADER structure, and recalculate the\r
-  CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named\r
-  it as CheckSum Part3.\r
-\r
-  The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER\r
-  and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2\r
-  is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.\r
-\r
-  Only ProcessorSignature, ProcessorFlag and CheckSum are different between\r
-  CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.\r
-  Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
-  When we are going to calculate CheckSum32, just should use the corresponding part\r
-  of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.\r
-\r
-  Notes: CheckSum32 is not a strong verification.\r
-         It does not guarantee that the data has not been modified.\r
-         CPU has its own mechanism to verify Microcode Binary part.\r
-\r
-  @param[in]  CpuMpData    The pointer to CPU MP Data structure.\r
-  @param[in]  IsBspCallIn  Indicate whether the caller is BSP or not.\r
+  @param[in]  CpuMpData        The pointer to CPU MP Data structure.\r
+  @param[in]  ProcessorNumber  The handle number of the processor. The range is\r
+                               from 0 to the total number of logical processors\r
+                               minus 1.\r
 **/\r
 VOID\r
 MicrocodeDetect (\r
-  IN CPU_MP_DATA             *CpuMpData,\r
-  IN BOOLEAN                 IsBspCallIn\r
+  IN CPU_MP_DATA  *CpuMpData,\r
+  IN UINTN        ProcessorNumber\r
   )\r
 {\r
-  UINT32                                  ExtendedTableLength;\r
-  UINT32                                  ExtendedTableCount;\r
-  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;\r
-  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;\r
-  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;\r
-  UINTN                                   MicrocodeEnd;\r
-  UINTN                                   Index;\r
-  UINT8                                   PlatformId;\r
-  CPUID_VERSION_INFO_EAX                  Eax;\r
-  UINT32                                  CurrentRevision;\r
-  UINT32                                  LatestRevision;\r
-  UINTN                                   TotalSize;\r
-  UINT32                                  CheckSum32;\r
-  UINT32                                  InCompleteCheckSum32;\r
-  BOOLEAN                                 CorrectMicrocode;\r
-  VOID                                    *MicrocodeData;\r
-  MSR_IA32_PLATFORM_ID_REGISTER           PlatformIdMsr;\r
-  UINT32                                  ProcessorFlags;\r
-  UINT32                                  ThreadId;\r
-\r
-  //\r
-  // set ProcessorFlags to suppress incorrect compiler/analyzer warnings\r
-  //\r
-  ProcessorFlags = 0;\r
+  CPU_MICROCODE_HEADER        *Microcode;\r
+  UINTN                       MicrocodeEnd;\r
+  CPU_AP_DATA                 *BspData;\r
+  UINT32                      LatestRevision;\r
+  CPU_MICROCODE_HEADER        *LatestMicrocode;\r
+  UINT32                      ThreadId;\r
+  EDKII_PEI_MICROCODE_CPU_ID  MicrocodeCpuId;\r
 \r
   if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
     //\r
@@ -106,222 +37,350 @@ MicrocodeDetect (
     return;\r
   }\r
 \r
-  CurrentRevision = GetCurrentMicrocodeSignature ();\r
-  if (CurrentRevision != 0 && !IsBspCallIn) {\r
+  GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);\r
+  if (ThreadId != 0) {\r
     //\r
-    // Skip loading microcode if it has been loaded successfully\r
+    // Skip loading microcode if it is not the first thread in one core.\r
     //\r
     return;\r
   }\r
 \r
-  GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);\r
-  if (ThreadId != 0) {\r
+  GetProcessorMicrocodeCpuId (&MicrocodeCpuId);\r
+\r
+  if (ProcessorNumber != (UINTN)CpuMpData->BspNumber) {\r
     //\r
-    // Skip loading microcode if it is not the first thread in one core.\r
+    // Direct use microcode of BSP if AP is the same as BSP.\r
+    // Assume BSP calls this routine() before AP.\r
     //\r
-    return;\r
+    BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);\r
+    if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&\r
+        (BspData->PlatformId == MicrocodeCpuId.PlatformId) &&\r
+        (BspData->MicrocodeEntryAddr != 0))\r
+    {\r
+      LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN)BspData->MicrocodeEntryAddr;\r
+      LatestRevision  = LatestMicrocode->UpdateRevision;\r
+      goto LoadMicrocode;\r
+    }\r
   }\r
 \r
-  ExtendedTableLength = 0;\r
   //\r
-  // Here data of CPUID leafs have not been collected into context buffer, so\r
-  // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
+  // BSP or AP which is different from BSP runs here\r
+  // Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs\r
+  // the latest microcode location even it's loaded to the processor.\r
   //\r
-  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);\r
+  LatestRevision  = 0;\r
+  LatestMicrocode = NULL;\r
+  Microcode       = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;\r
+  MicrocodeEnd    = (UINTN)Microcode + (UINTN)CpuMpData->MicrocodePatchRegionSize;\r
+\r
+  do {\r
+    if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN)Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {\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
+      Microcode = (CPU_MICROCODE_HEADER *)((UINTN)Microcode + SIZE_1KB);\r
+      continue;\r
+    }\r
+\r
+    LatestMicrocode = Microcode;\r
+    LatestRevision  = LatestMicrocode->UpdateRevision;\r
+\r
+    Microcode = (CPU_MICROCODE_HEADER *)(((UINTN)Microcode) + GetMicrocodeLength (Microcode));\r
+  } while ((UINTN)Microcode < MicrocodeEnd);\r
+\r
+LoadMicrocode:\r
+  if (LatestRevision != 0) {\r
+    //\r
+    // Save the detected microcode patch entry address (including the microcode\r
+    // patch header) for each processor even it's the same as the loaded one.\r
+    // It will be used when building the microcode patch cache HOB.\r
+    //\r
+    CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN)LatestMicrocode;\r
+  }\r
+\r
+  if (LatestRevision > GetProcessorMicrocodeSignature ()) {\r
+    //\r
+    // BIOS only authenticate updates that contain a numerically larger revision\r
+    // than the currently loaded revision, where Current Signature < New Update\r
+    // Revision. A processor with no loaded update is considered to have a\r
+    // revision equal to zero.\r
+    //\r
+    LoadMicrocode (LatestMicrocode);\r
+  }\r
 \r
   //\r
-  // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
+  // It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.\r
   //\r
-  PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
-  PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
+  CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();\r
+}\r
+\r
+/**\r
+  Actual worker function that shadows the required microcode patches into memory.\r
+\r
+  @param[in, out]  CpuMpData        The pointer to CPU MP Data structure.\r
+  @param[in]       Patches          The pointer to an array of information on\r
+                                    the microcode patches that will be loaded\r
+                                    into memory.\r
+  @param[in]       PatchCount       The number of microcode patches that will\r
+                                    be loaded into memory.\r
+  @param[in]       TotalLoadSize    The total size of all the microcode patches\r
+                                    to be loaded.\r
+**/\r
+VOID\r
+ShadowMicrocodePatchWorker (\r
+  IN OUT CPU_MP_DATA           *CpuMpData,\r
+  IN     MICROCODE_PATCH_INFO  *Patches,\r
+  IN     UINTN                 PatchCount,\r
+  IN     UINTN                 TotalLoadSize\r
+  )\r
+{\r
+  UINTN  Index;\r
+  VOID   *MicrocodePatchInRam;\r
+  UINT8  *Walker;\r
+\r
+  ASSERT ((Patches != NULL) && (PatchCount != 0));\r
+\r
+  MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));\r
+  if (MicrocodePatchInRam == NULL) {\r
+    return;\r
+  }\r
 \r
   //\r
-  // Check whether AP has same processor with BSP.\r
-  // If yes, direct use microcode info saved by BSP.\r
+  // Load all the required microcode patches into memory\r
   //\r
-  if (!IsBspCallIn) {\r
-    if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&\r
-        (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {\r
-        MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;\r
-        LatestRevision = CpuMpData->MicrocodeRevision;\r
-        goto Done;\r
-    }\r
+  for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {\r
+    CopyMem (\r
+      Walker,\r
+      (VOID *)Patches[Index].Address,\r
+      Patches[Index].Size\r
+      );\r
+    Walker += Patches[Index].Size;\r
   }\r
 \r
-  LatestRevision = 0;\r
-  MicrocodeData  = NULL;\r
-  MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
-  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+  //\r
+  // Update the microcode patch related fields in CpuMpData\r
+  //\r
+  CpuMpData->MicrocodePatchAddress    = (UINTN)MicrocodePatchInRam;\r
+  CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;\r
 \r
-  do {\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
+    __FUNCTION__,\r
+    CpuMpData->MicrocodePatchAddress,\r
+    CpuMpData->MicrocodePatchRegionSize\r
+    ));\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Shadow the required microcode patches data into memory according to PCD\r
+  PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.\r
+\r
+  @param[in, out]  CpuMpData    The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+ShadowMicrocodePatchByPcd (\r
+  IN OUT CPU_MP_DATA  *CpuMpData\r
+  )\r
+{\r
+  UINTN                       Index;\r
+  CPU_MICROCODE_HEADER        *MicrocodeEntryPoint;\r
+  UINTN                       MicrocodeEnd;\r
+  UINTN                       TotalSize;\r
+  MICROCODE_PATCH_INFO        *PatchInfoBuffer;\r
+  UINTN                       MaxPatchNumber;\r
+  UINTN                       PatchCount;\r
+  UINTN                       TotalLoadSize;\r
+  EDKII_PEI_MICROCODE_CPU_ID  *MicrocodeCpuIds;\r
+  BOOLEAN                     Valid;\r
+\r
+  //\r
+  // Initialize the microcode patch related fields in CpuMpData as the values\r
+  // specified by the PCD pair. If the microcode patches are loaded into memory,\r
+  // these fields will be updated.\r
+  //\r
+  CpuMpData->MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+  CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+\r
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;\r
+  MicrocodeEnd        = (UINTN)MicrocodeEntryPoint +\r
+                        (UINTN)CpuMpData->MicrocodePatchRegionSize;\r
+  if ((MicrocodeEntryPoint == NULL) || ((UINTN)MicrocodeEntryPoint == MicrocodeEnd)) {\r
     //\r
-    // Check if the microcode is for the Cpu and the version is newer\r
-    // and the update can be processed on the platform\r
+    // There is no microcode patches\r
     //\r
-    CorrectMicrocode = FALSE;\r
+    return;\r
+  }\r
 \r
-    if (MicrocodeEntryPoint->DataSize == 0) {\r
-      TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;\r
-    } else {\r
-      TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;\r
-    }\r
+  PatchCount      = 0;\r
+  MaxPatchNumber  = DEFAULT_MAX_MICROCODE_PATCH_NUM;\r
+  TotalLoadSize   = 0;\r
+  PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));\r
+  if (PatchInfoBuffer == NULL) {\r
+    return;\r
+  }\r
 \r
-    ///\r
-    /// Check overflow and whether TotalSize is aligned with 4 bytes.\r
-    ///\r
-    if ( ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
-         (TotalSize & 0x3) != 0\r
-       ) {\r
-      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+  MicrocodeCpuIds = AllocatePages (\r
+                      EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID))\r
+                      );\r
+  if (MicrocodeCpuIds == NULL) {\r
+    FreePool (PatchInfoBuffer);\r
+    return;\r
+  }\r
+\r
+  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+    MicrocodeCpuIds[Index].PlatformId         = CpuMpData->CpuData[Index].PlatformId;\r
+    MicrocodeCpuIds[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;\r
+  }\r
+\r
+  //\r
+  // Process the header of each microcode patch within the region.\r
+  // The purpose is to decide which microcode patch(es) will be loaded into memory.\r
+  // Microcode checksum is not verified because it's slow when performing on flash.\r
+  //\r
+  do {\r
+    Valid = IsValidMicrocode (\r
+              MicrocodeEntryPoint,\r
+              MicrocodeEnd - (UINTN)MicrocodeEntryPoint,\r
+              0,\r
+              MicrocodeCpuIds,\r
+              CpuMpData->CpuCount,\r
+              FALSE\r
+              );\r
+    if (!Valid) {\r
+      //\r
+      // Padding data between the microcode patches, skip 1KB to check next entry.\r
+      //\r
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB);\r
       continue;\r
     }\r
 \r
-    //\r
-    // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.\r
-    //\r
-    InCompleteCheckSum32 = CalculateSum32 (\r
-                             (UINT32 *) MicrocodeEntryPoint,\r
-                             TotalSize\r
-                             );\r
-    InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
-    InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;\r
-    InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;\r
-\r
-    if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
+    PatchCount++;\r
+    if (PatchCount > MaxPatchNumber) {\r
       //\r
-      // It is the microcode header. It is not the padding data between microcode patches\r
-      // because the padding data should not include 0x00000001 and it should be the repeated\r
-      // byte format (like 0xXYXYXYXY....).\r
+      // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
+      // and allocate a new buffer.\r
       //\r
-      if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&\r
-          MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
-          (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
-          ) {\r
+      if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
         //\r
-        // Calculate CheckSum Part1.\r
+        // Overflow check for MaxPatchNumber\r
         //\r
-        CheckSum32 = InCompleteCheckSum32;\r
-        CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;\r
-        CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;\r
-        CheckSum32 += MicrocodeEntryPoint->Checksum;\r
-        if (CheckSum32 == 0) {\r
-          CorrectMicrocode = TRUE;\r
-          ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;\r
-        }\r
-      } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
-                 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
-        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +\r
-                                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)\r
-                                  + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));\r
-          //\r
-          // Calculate Extended Checksum\r
-          //\r
-          if ((ExtendedTableLength % 4) == 0) {\r
-            //\r
-            // Calculate CheckSum Part2.\r
-            //\r
-            CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);\r
-            if (CheckSum32 == 0) {\r
-              //\r
-              // Checksum correct\r
-              //\r
-              ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
-              ExtendedTable      = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
-              for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
-                //\r
-                // Calculate CheckSum Part3.\r
-                //\r
-                CheckSum32 = InCompleteCheckSum32;\r
-                CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;\r
-                CheckSum32 += ExtendedTable->ProcessorFlag;\r
-                CheckSum32 += ExtendedTable->Checksum;\r
-                if (CheckSum32 == 0) {\r
-                  //\r
-                  // Verify Header\r
-                  //\r
-                  if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&\r
-                      (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {\r
-                    //\r
-                    // Find one\r
-                    //\r
-                    CorrectMicrocode = TRUE;\r
-                    ProcessorFlags = ExtendedTable->ProcessorFlag;\r
-                    break;\r
-                  }\r
-                }\r
-                ExtendedTable ++;\r
-              }\r
-            }\r
-          }\r
-        }\r
+        goto OnExit;\r
+      }\r
+\r
+      PatchInfoBuffer = ReallocatePool (\r
+                          MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
+                          2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),\r
+                          PatchInfoBuffer\r
+                          );\r
+      if (PatchInfoBuffer == NULL) {\r
+        goto OnExit;\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
-    // Get the next patch.\r
-    //\r
-    if (MicrocodeEntryPoint->DataSize == 0) {\r
-      TotalSize = 2048;\r
-    } else {\r
-      TotalSize = MicrocodeEntryPoint->TotalSize;\r
-    }\r
 \r
-    if (CorrectMicrocode) {\r
-      LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
-      MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));\r
+      MaxPatchNumber = MaxPatchNumber * 2;\r
     }\r
 \r
-    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
-  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
+    TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);\r
 \r
-Done:\r
-  if (LatestRevision > CurrentRevision) {\r
     //\r
-    // BIOS only authenticate updates that contain a numerically larger revision\r
-    // than the currently loaded revision, where Current Signature < New Update\r
-    // Revision. A processor with no loaded update is considered to have a\r
-    // revision equal to zero.\r
+    // Store the information of this microcode patch\r
     //\r
-    ASSERT (MicrocodeData != NULL);\r
-    AsmWriteMsr64 (\r
-        MSR_IA32_BIOS_UPDT_TRIG,\r
-        (UINT64) (UINTN) MicrocodeData\r
-        );\r
+    PatchInfoBuffer[PatchCount - 1].Address = (UINTN)MicrocodeEntryPoint;\r
+    PatchInfoBuffer[PatchCount - 1].Size    = TotalSize;\r
+    TotalLoadSize                          += TotalSize;\r
+\r
     //\r
-    // Get and check new microcode signature\r
+    // Process the next microcode patch\r
     //\r
-    CurrentRevision = GetCurrentMicrocodeSignature ();\r
-    if (CurrentRevision != LatestRevision) {\r
-      AcquireSpinLock(&CpuMpData->MpLock);\r
-      DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \\r
-                loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));\r
-      ReleaseSpinLock(&CpuMpData->MpLock);\r
-    }\r
+    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)((UINTN)MicrocodeEntryPoint + TotalSize);\r
+  } while ((UINTN)MicrocodeEntryPoint < MicrocodeEnd);\r
+\r
+  if (PatchCount != 0) {\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",\r
+      __FUNCTION__,\r
+      PatchCount,\r
+      TotalLoadSize\r
+      ));\r
+\r
+    ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
   }\r
 \r
-  if (IsBspCallIn && (LatestRevision != 0)) {\r
-    //\r
-    // Save BSP processor info and microcode info for later AP use.\r
-    //\r
-    CpuMpData->ProcessorSignature   = Eax.Uint32;\r
-    CpuMpData->ProcessorFlags       = ProcessorFlags;\r
-    CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;\r
-    CpuMpData->MicrocodeRevision    = LatestRevision;\r
-    DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \\r
-       MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));\r
+OnExit:\r
+  if (PatchInfoBuffer != NULL) {\r
+    FreePool (PatchInfoBuffer);\r
   }\r
+\r
+  FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));\r
+}\r
+\r
+/**\r
+  Shadow the required microcode patches data into memory.\r
+\r
+  @param[in, out]  CpuMpData    The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+ShadowMicrocodeUpdatePatch (\r
+  IN OUT CPU_MP_DATA  *CpuMpData\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = PlatformShadowMicrocode (CpuMpData);\r
+  if (EFI_ERROR (Status)) {\r
+    ShadowMicrocodePatchByPcd (CpuMpData);\r
+  }\r
+}\r
+\r
+/**\r
+  Get the cached microcode patch base address and size from the microcode patch\r
+  information cache HOB.\r
+\r
+  @param[out] Address       Base address of the microcode patches data.\r
+                            It will be updated if the microcode patch\r
+                            information cache HOB is found.\r
+  @param[out] RegionSize    Size of the microcode patches data.\r
+                            It will be updated if the microcode patch\r
+                            information cache HOB is found.\r
+\r
+  @retval  TRUE     The microcode patch information cache HOB is found.\r
+  @retval  FALSE    The microcode patch information cache HOB is not found.\r
+\r
+**/\r
+BOOLEAN\r
+GetMicrocodePatchInfoFromHob (\r
+  UINT64  *Address,\r
+  UINT64  *RegionSize\r
+  )\r
+{\r
+  EFI_HOB_GUID_TYPE          *GuidHob;\r
+  EDKII_MICROCODE_PATCH_HOB  *MicrocodePathHob;\r
+\r
+  GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);\r
+  if (GuidHob == NULL) {\r
+    DEBUG ((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));\r
+    return FALSE;\r
+  }\r
+\r
+  MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);\r
+\r
+  *Address    = MicrocodePathHob->MicrocodePatchAddress;\r
+  *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",\r
+    __FUNCTION__,\r
+    *Address,\r
+    *RegionSize\r
+    ));\r
+\r
+  return TRUE;\r
 }\r