]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/Microcode.c
UefiCpuPkg/MpInitLib: Remove redundant microcode fields in CPU_MP_DATA
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
index efda143e67198c19b14ad0d28591da3e392e9371..3da5bfb9cf2f9a4a4293a0967b80323e6480474c 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   Implementation of loading microcode on processors.\r
 \r
-  Copyright (c) 2015 - 2018, 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
+  Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -35,13 +29,51 @@ GetCurrentMicrocodeSignature (
 /**\r
   Detect whether specified processor can find matching microcode patch and load it.\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
+  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
+                               minus 1.\r
 **/\r
 VOID\r
 MicrocodeDetect (\r
   IN CPU_MP_DATA             *CpuMpData,\r
-  IN BOOLEAN                 IsBspCallIn\r
+  IN UINTN                   ProcessorNumber\r
   )\r
 {\r
   UINT32                                  ExtendedTableLength;\r
@@ -53,15 +85,16 @@ MicrocodeDetect (
   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
-  MSR_IA32_PLATFORM_ID_REGISTER           PlatformIdMsr;\r
-  UINT32                                  ProcessorFlags;\r
   UINT32                                  ThreadId;\r
+  BOOLEAN                                 IsBspCallIn;\r
 \r
   if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
     //\r
@@ -71,6 +104,7 @@ MicrocodeDetect (
   }\r
 \r
   CurrentRevision = GetCurrentMicrocodeSignature ();\r
+  IsBspCallIn     = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;\r
   if (CurrentRevision != 0 && !IsBspCallIn) {\r
     //\r
     // Skip loading microcode if it has been loaded successfully\r
@@ -87,28 +121,25 @@ MicrocodeDetect (
   }\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
-  //\r
-  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);\r
-\r
-  //\r
-  // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
-  //\r
-  PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
-  PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
+  Eax.Uint32 = CpuMpData->CpuData[ProcessorNumber].ProcessorSignature;\r
+  PlatformId = CpuMpData->CpuData[ProcessorNumber].PlatformId;\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 ((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
+    // Get the CPU data for BSP\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
     }\r
   }\r
 \r
@@ -116,12 +147,47 @@ MicrocodeDetect (
   MicrocodeData  = NULL;\r
   MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
   MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\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
@@ -132,17 +198,15 @@ MicrocodeDetect (
           MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
           (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
           ) {\r
-        if (MicrocodeEntryPoint->DataSize == 0) {\r
-          CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);\r
-        } else {\r
-          CheckSum32 = CalculateSum32 (\r
-                         (UINT32 *) MicrocodeEntryPoint,\r
-                         MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)\r
-                         );\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
-          ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;\r
         }\r
       } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
                  (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
@@ -158,6 +222,9 @@ MicrocodeDetect (
           // 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
@@ -166,7 +233,13 @@ MicrocodeDetect (
               ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\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
+                //\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
@@ -177,7 +250,6 @@ MicrocodeDetect (
                     // Find one\r
                     //\r
                     CorrectMicrocode = TRUE;\r
-                    ProcessorFlags = ExtendedTable->ProcessorFlag;\r
                     break;\r
                   }\r
                 }\r
@@ -216,6 +288,16 @@ MicrocodeDetect (
   } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
 \r
 Done:\r
+  if (LatestRevision != 0) {\r
+    //\r
+    // Save the detected microcode patch entry address (including the\r
+    // microcode patch header) for each processor.\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
+  }\r
+\r
   if (LatestRevision > CurrentRevision) {\r
     //\r
     // BIOS only authenticate updates that contain a numerically larger revision\r
@@ -239,16 +321,292 @@ Done:
       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
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Actual worker function that loads 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
+LoadMicrocodePatchWorker (\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
+  // Load all the required microcode patches into memory\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
+\r
+    //\r
+    // Zero-fill the padding area\r
+    // Please note that AlignedSize will be no less than Size\r
+    //\r
+    ZeroMem (\r
+      Walker + Patches[Index].Size,\r
+      Patches[Index].AlignedSize - Patches[Index].Size\r
+      );\r
+\r
+    Walker += Patches[Index].AlignedSize;\r
+  }\r
+\r
+  //\r
+  // Update the microcode patch related fields in CpuMpData\r
+  //\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
+    ));\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Load the required microcode patches data into memory.\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
+  )\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
+\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
+    // There is no microcode patches\r
+    //\r
+    return;\r
+  }\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
+  // 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
+  //\r
+  do {\r
+    if (MicrocodeEntryPoint->HeaderVersion != 0x1) {\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
+    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
+      //\r
+      // Not a valid microcode header, skip 1KB to check next entry.\r
+      //\r
+      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
+      continue;\r
+    }\r
 \r
-  if (IsBspCallIn && (LatestRevision != 0)) {\r
     //\r
-    // Save BSP processor info and microcode info for later AP use.\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
-    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
+    // 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
+        //\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
+        //\r
+        NeedLoad = IsMicrocodePatchNeedLoad (\r
+                     CpuMpData,\r
+                     ExtendedTable->ProcessorSignature.Uint32,\r
+                     ExtendedTable->ProcessorFlag\r
+                     );\r
+        if (NeedLoad) {\r
+          break;\r
+        }\r
+        ExtendedTable ++;\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
+      }\r
+\r
+      //\r
+      // Store the information of this microcode patch\r
+      //\r
+      if (TotalSize > ALIGN_VALUE (TotalSize, SIZE_1KB) ||\r
+          ALIGN_VALUE (TotalSize, SIZE_1KB) > MAX_UINTN - TotalLoadSize) {\r
+        goto OnExit;\r
+      }\r
+      PatchInfoBuffer[PatchCount - 1].Address     = (UINTN) MicrocodeEntryPoint;\r
+      PatchInfoBuffer[PatchCount - 1].Size        = TotalSize;\r
+      PatchInfoBuffer[PatchCount - 1].AlignedSize = ALIGN_VALUE (TotalSize, SIZE_1KB);\r
+      TotalLoadSize += PatchInfoBuffer[PatchCount - 1].AlignedSize;\r
+    }\r
+\r
+    //\r
+    // Process the next microcode patch\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__, PatchCount, TotalLoadSize\r
+      ));\r
+\r
+    LoadMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);\r
+  }\r
+\r
+OnExit:\r
+  if (PatchInfoBuffer != NULL) {\r
+    FreePool (PatchInfoBuffer);\r
   }\r
+  return;\r
 }\r