]> 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 8f4d4da40c76f5b1beab32af3c47e9389ea22585..f9f070fa8bf230e72b7643b5bd8f96212512905b 100644 (file)
@@ -1,70 +1,16 @@
 /** @file\r
   Implementation of loading microcode on processors.\r
 \r
-  Copyright (c) 2015 - 2020, 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]  ProcessorNumber  The handle number of the processor. The range is\r
                                from 0 to the total number of logical processors\r
@@ -72,29 +18,17 @@ GetCurrentMicrocodeSignature (
 **/\r
 VOID\r
 MicrocodeDetect (\r
-  IN CPU_MP_DATA             *CpuMpData,\r
-  IN UINTN                   ProcessorNumber\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
-  CPU_AP_DATA                             *CpuData;\r
-  UINT32                                  CurrentRevision;\r
-  UINT32                                  LatestRevision;\r
-  UINTN                                   TotalSize;\r
-  UINT32                                  CheckSum32;\r
-  UINT32                                  InCompleteCheckSum32;\r
-  BOOLEAN                                 CorrectMicrocode;\r
-  VOID                                    *MicrocodeData;\r
-  UINT32                                  ThreadId;\r
-  BOOLEAN                                 IsBspCallIn;\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
@@ -103,9 +37,6 @@ MicrocodeDetect (
     return;\r
   }\r
 \r
-  CurrentRevision = GetCurrentMicrocodeSignature ();\r
-  IsBspCallIn     = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;\r
-\r
   GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);\r
   if (ThreadId != 0) {\r
     //\r
@@ -114,146 +45,36 @@ MicrocodeDetect (
     return;\r
   }\r
 \r
-  ExtendedTableLength = 0;\r
-  Eax.Uint32 = CpuMpData->CpuData[ProcessorNumber].ProcessorSignature;\r
-  PlatformId = CpuMpData->CpuData[ProcessorNumber].PlatformId;\r
+  GetProcessorMicrocodeCpuId (&MicrocodeCpuId);\r
 \r
-  //\r
-  // Check whether AP has same processor with BSP.\r
-  // If yes, direct use microcode info saved by BSP.\r
-  //\r
-  if (!IsBspCallIn) {\r
+  if (ProcessorNumber != (UINTN)CpuMpData->BspNumber) {\r
     //\r
-    // Get the CPU data for BSP\r
+    // Direct use microcode of BSP if AP is the same as BSP.\r
+    // Assume BSP calls this routine() before AP.\r
     //\r
-    CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);\r
-    if ((CpuData->ProcessorSignature == Eax.Uint32) &&\r
-        (CpuData->PlatformId == PlatformId) &&\r
-        (CpuData->MicrocodeEntryAddr != 0)) {\r
-      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr;\r
-      MicrocodeData       = (VOID *) (MicrocodeEntryPoint + 1);\r
-      LatestRevision      = MicrocodeEntryPoint->UpdateRevision;\r
-      goto Done;\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
-  LatestRevision = 0;\r
-  MicrocodeData  = NULL;\r
-  MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
-  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
+  //\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
+  LatestRevision  = 0;\r
+  LatestMicrocode = NULL;\r
+  Microcode       = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;\r
+  MicrocodeEnd    = (UINTN)Microcode + (UINTN)CpuMpData->MicrocodePatchRegionSize;\r
 \r
   do {\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
-    //\r
-    CorrectMicrocode = FALSE;\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
-\r
-    ///\r
-    /// 0x0       MicrocodeBegin  MicrocodeEntry  MicrocodeEnd      0xffffffff\r
-    /// |--------------|---------------|---------------|---------------|\r
-    ///                                 valid TotalSize\r
-    /// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).\r
-    /// And it should be aligned with 4 bytes.\r
-    /// If the TotalSize is invalid, skip 1KB to check next entry.\r
-    ///\r
-    if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||\r
-         ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
-         (TotalSize & 0x3) != 0\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
-      //\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
-      //\r
-      if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&\r
-          MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
-          (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
-          ) {\r
-        //\r
-        // Calculate CheckSum Part1.\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
-        }\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
-                    break;\r
-                  }\r
-                }\r
-                ExtendedTable ++;\r
-              }\r
-            }\r
-          }\r
-        }\r
-      }\r
-    } else {\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
@@ -261,97 +82,44 @@ MicrocodeDetect (
       // 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
+      Microcode = (CPU_MICROCODE_HEADER *)((UINTN)Microcode + 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
-    }\r
+    LatestMicrocode = Microcode;\r
+    LatestRevision  = LatestMicrocode->UpdateRevision;\r
 \r
-    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
-  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
+    Microcode = (CPU_MICROCODE_HEADER *)(((UINTN)Microcode) + GetMicrocodeLength (Microcode));\r
+  } while ((UINTN)Microcode < MicrocodeEnd);\r
 \r
-Done:\r
+LoadMicrocode:\r
   if (LatestRevision != 0) {\r
     //\r
-    // Save the detected microcode patch entry address (including the\r
-    // microcode patch header) for each processor.\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 =\r
-      (UINTN) MicrocodeData -  sizeof (CPU_MICROCODE_HEADER);\r
+    CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN)LatestMicrocode;\r
   }\r
 \r
-  if (LatestRevision > CurrentRevision) {\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
-    ASSERT (MicrocodeData != NULL);\r
-    AsmWriteMsr64 (\r
-        MSR_IA32_BIOS_UPDT_TRIG,\r
-        (UINT64) (UINTN) MicrocodeData\r
-        );\r
-    //\r
-    // Get and check new microcode signature\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
-  }\r
-}\r
-\r
-/**\r
-  Determine if a microcode patch will be loaded into memory.\r
-\r
-  @param[in]  CpuMpData             The pointer to CPU MP Data structure.\r
-  @param[in]  ProcessorSignature    The processor signature field value\r
-                                    supported by a microcode patch.\r
-  @param[in]  ProcessorFlags        The prcessor flags field value supported by\r
-                                    a microcode patch.\r
-\r
-  @retval TRUE     The specified microcode patch will be loaded.\r
-  @retval FALSE    The specified microcode patch will not be loaded.\r
-**/\r
-BOOLEAN\r
-IsMicrocodePatchNeedLoad (\r
-  IN CPU_MP_DATA                 *CpuMpData,\r
-  IN UINT32                      ProcessorSignature,\r
-  IN UINT32                      ProcessorFlags\r
-  )\r
-{\r
-  UINTN          Index;\r
-  CPU_AP_DATA    *CpuData;\r
-\r
-  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
-    CpuData = &CpuMpData->CpuData[Index];\r
-    if ((ProcessorSignature == CpuData->ProcessorSignature) &&\r
-        (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {\r
-      return TRUE;\r
-    }\r
+    LoadMicrocode (LatestMicrocode);\r
   }\r
 \r
-  return FALSE;\r
+  //\r
+  // It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.\r
+  //\r
+  CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();\r
 }\r
 \r
 /**\r
-  Actual worker function that loads the required microcode patches into memory.\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
@@ -363,16 +131,16 @@ IsMicrocodePatchNeedLoad (
                                     to be loaded.\r
 **/\r
 VOID\r
-LoadMicrocodePatchWorker (\r
-  IN OUT CPU_MP_DATA             *CpuMpData,\r
-  IN     MICROCODE_PATCH_INFO    *Patches,\r
-  IN     UINTN                   PatchCount,\r
-  IN     UINTN                   TotalLoadSize\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
+  UINTN  Index;\r
+  VOID   *MicrocodePatchInRam;\r
+  UINT8  *Walker;\r
 \r
   ASSERT ((Patches != NULL) && (PatchCount != 0));\r
 \r
@@ -387,51 +155,50 @@ LoadMicrocodePatchWorker (
   for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {\r
     CopyMem (\r
       Walker,\r
-      (VOID *) Patches[Index].Address,\r
+      (VOID *)Patches[Index].Address,\r
       Patches[Index].Size\r
       );\r
-\r
     Walker += Patches[Index].Size;\r
   }\r
 \r
   //\r
   // Update the microcode patch related fields in CpuMpData\r
   //\r
-  CpuMpData->MicrocodePatchAddress    = (UINTN) MicrocodePatchInRam;\r
+  CpuMpData->MicrocodePatchAddress    = (UINTN)MicrocodePatchInRam;\r
   CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;\r
 \r
   DEBUG ((\r
     DEBUG_INFO,\r
     "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",\r
-    __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize\r
+    __FUNCTION__,\r
+    CpuMpData->MicrocodePatchAddress,\r
+    CpuMpData->MicrocodePatchRegionSize\r
     ));\r
 \r
   return;\r
 }\r
 \r
 /**\r
-  Load the required microcode patches data into memory.\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
-LoadMicrocodePatch (\r
-  IN OUT CPU_MP_DATA             *CpuMpData\r
+ShadowMicrocodePatchByPcd (\r
+  IN OUT CPU_MP_DATA  *CpuMpData\r
   )\r
 {\r
-  CPU_MICROCODE_HEADER                   *MicrocodeEntryPoint;\r
-  UINTN                                  MicrocodeEnd;\r
-  UINTN                                  DataSize;\r
-  UINTN                                  TotalSize;\r
-  CPU_MICROCODE_EXTENDED_TABLE_HEADER    *ExtendedTableHeader;\r
-  UINT32                                 ExtendedTableCount;\r
-  CPU_MICROCODE_EXTENDED_TABLE           *ExtendedTable;\r
-  MICROCODE_PATCH_INFO                   *PatchInfoBuffer;\r
-  UINTN                                  MaxPatchNumber;\r
-  UINTN                                  PatchCount;\r
-  UINTN                                  TotalLoadSize;\r
-  UINTN                                  Index;\r
-  BOOLEAN                                NeedLoad;\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
@@ -441,10 +208,10 @@ LoadMicrocodePatch (
   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
+  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->MicrocodePatchAddress;\r
+  MicrocodeEnd        = (UINTN)MicrocodeEntryPoint +\r
+                        (UINTN)CpuMpData->MicrocodePatchRegionSize;\r
+  if ((MicrocodeEntryPoint == NULL) || ((UINTN)MicrocodeEntryPoint == MicrocodeEnd)) {\r
     //\r
     // There is no microcode patches\r
     //\r
@@ -459,134 +226,161 @@ LoadMicrocodePatch (
     return;\r
   }\r
 \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
-    if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\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
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(((UINTN)MicrocodeEntryPoint) + SIZE_1KB);\r
       continue;\r
     }\r
 \r
-    DataSize  = MicrocodeEntryPoint->DataSize;\r
-    TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;\r
-    if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||\r
-         ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||\r
-         (DataSize & 0x3) != 0 ||\r
-         (TotalSize & (SIZE_1KB - 1)) != 0 ||\r
-         TotalSize < DataSize\r
-       ) {\r
+    PatchCount++;\r
+    if (PatchCount > MaxPatchNumber) {\r
       //\r
-      // Not a valid microcode header, skip 1KB to check next entry.\r
+      // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
+      // and allocate a new buffer.\r
       //\r
-      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
-      continue;\r
-    }\r
-\r
-    //\r
-    // Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode\r
-    // patch header with the CPUID and PlatformID of the processors within\r
-    // system to decide if it will be copied into memory\r
-    //\r
-    NeedLoad = IsMicrocodePatchNeedLoad (\r
-                 CpuMpData,\r
-                 MicrocodeEntryPoint->ProcessorSignature.Uint32,\r
-                 MicrocodeEntryPoint->ProcessorFlags\r
-                 );\r
-\r
-    //\r
-    // If the Extended Signature Table exists, check if the processor is in the\r
-    // support list\r
-    //\r
-    if ((!NeedLoad) && (DataSize != 0) &&\r
-        (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +\r
-                                sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {\r
-      ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)\r
-                              + DataSize + sizeof (CPU_MICROCODE_HEADER));\r
-      ExtendedTableCount  = ExtendedTableHeader->ExtendedSignatureCount;\r
-      ExtendedTable       = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
-\r
-      for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
-        //\r
-        // Avoid access content beyond MicrocodeEnd\r
-        //\r
-        if ((UINTN) ExtendedTable > MicrocodeEnd - sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {\r
-          break;\r
-        }\r
-\r
+      if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
         //\r
-        // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended\r
-        // Signature Table entry with the CPUID and PlatformID of the processors\r
-        // within system to decide if it will be copied into memory\r
+        // Overflow check for MaxPatchNumber\r
         //\r
-        NeedLoad = IsMicrocodePatchNeedLoad (\r
-                     CpuMpData,\r
-                     ExtendedTable->ProcessorSignature.Uint32,\r
-                     ExtendedTable->ProcessorFlag\r
-                     );\r
-        if (NeedLoad) {\r
-          break;\r
-        }\r
-        ExtendedTable ++;\r
+        goto OnExit;\r
       }\r
-    }\r
 \r
-    if (NeedLoad) {\r
-      PatchCount++;\r
-      if (PatchCount > MaxPatchNumber) {\r
-        //\r
-        // Current 'PatchInfoBuffer' cannot hold the information, double the size\r
-        // and allocate a new buffer.\r
-        //\r
-        if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {\r
-          //\r
-          // Overflow check for MaxPatchNumber\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
-        MaxPatchNumber = MaxPatchNumber * 2;\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
 \r
-      //\r
-      // Store the information of this microcode patch\r
-      //\r
-      PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;\r
-      PatchInfoBuffer[PatchCount - 1].Size    = TotalSize;\r
-      TotalLoadSize += TotalSize;\r
+      MaxPatchNumber = MaxPatchNumber * 2;\r
     }\r
 \r
+    TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);\r
+\r
+    //\r
+    // Store the information of this microcode patch\r
+    //\r
+    PatchInfoBuffer[PatchCount - 1].Address = (UINTN)MicrocodeEntryPoint;\r
+    PatchInfoBuffer[PatchCount - 1].Size    = TotalSize;\r
+    TotalLoadSize                          += TotalSize;\r
+\r
     //\r
     // Process the next microcode patch\r
     //\r
-    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
-  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\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__, PatchCount, TotalLoadSize\r
+      __FUNCTION__,\r
+      PatchCount,\r
+      TotalLoadSize\r
       ));\r
 \r
-    LoadMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
+    ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
   }\r
 \r
 OnExit:\r
   if (PatchInfoBuffer != NULL) {\r
     FreePool (PatchInfoBuffer);\r
   }\r
-  return;\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