/** @file
  Implementation of loading microcode on processors.

  Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "MpLib.h"

/**
  Get microcode update signature of currently loaded microcode update.

  @return  Microcode signature.
**/
UINT32
GetCurrentMicrocodeSignature (
  VOID
  )
{
  MSR_IA32_BIOS_SIGN_ID_REGISTER   BiosSignIdMsr;

  AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
  BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
  return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
}

/**
  Detect whether specified processor can find matching microcode patch and load it.

  Microcode Payload as the following format:
  +----------------------------------------+------------------+
  |          CPU_MICROCODE_HEADER          |                  |
  +----------------------------------------+  CheckSum Part1  |
  |            Microcode Binary            |                  |
  +----------------------------------------+------------------+
  |  CPU_MICROCODE_EXTENDED_TABLE_HEADER   |                  |
  +----------------------------------------+  CheckSum Part2  |
  |      CPU_MICROCODE_EXTENDED_TABLE      |                  |
  |                   ...                  |                  |
  +----------------------------------------+------------------+

  There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
  The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
  of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.

  When we are trying to verify the CheckSum32 with extended table.
  We should use the fields of exnteded table to replace the corresponding
  fields in CPU_MICROCODE_HEADER structure, and recalculate the
  CheckSum32 with CPU_MICROCODE_HEADER + Microcode Binary. We named
  it as CheckSum Part3.

  The CheckSum Part2 is used to verify the CPU_MICROCODE_EXTENDED_TABLE_HEADER
  and CPU_MICROCODE_EXTENDED_TABLE parts. We should make sure CheckSum Part2
  is correct before we are going to verify each CPU_MICROCODE_EXTENDED_TABLE.

  Only ProcessorSignature, ProcessorFlag and CheckSum are different between
  CheckSum Part1 and CheckSum Part3. To avoid multiple computing CheckSum Part3.
  Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
  When we are going to calculate CheckSum32, just should use the corresponding part
  of the ProcessorSignature, ProcessorFlag and CheckSum with in-complete CheckSum32.

  Notes: CheckSum32 is not a strong verification.
         It does not guarantee that the data has not been modified.
         CPU has its own mechanism to verify Microcode Binary part.

  @param[in]  CpuMpData        The pointer to CPU MP Data structure.
  @param[in]  ProcessorNumber  The handle number of the processor. The range is
                               from 0 to the total number of logical processors
                               minus 1.
**/
VOID
MicrocodeDetect (
  IN CPU_MP_DATA             *CpuMpData,
  IN UINTN                   ProcessorNumber
  )
{
  UINT32                                  ExtendedTableLength;
  UINT32                                  ExtendedTableCount;
  CPU_MICROCODE_EXTENDED_TABLE            *ExtendedTable;
  CPU_MICROCODE_EXTENDED_TABLE_HEADER     *ExtendedTableHeader;
  CPU_MICROCODE_HEADER                    *MicrocodeEntryPoint;
  UINTN                                   MicrocodeEnd;
  UINTN                                   Index;
  UINT8                                   PlatformId;
  CPUID_VERSION_INFO_EAX                  Eax;
  CPU_AP_DATA                             *CpuData;
  UINT32                                  CurrentRevision;
  UINT32                                  LatestRevision;
  UINTN                                   TotalSize;
  UINT32                                  CheckSum32;
  UINT32                                  InCompleteCheckSum32;
  BOOLEAN                                 CorrectMicrocode;
  VOID                                    *MicrocodeData;
  MSR_IA32_PLATFORM_ID_REGISTER           PlatformIdMsr;
  UINT32                                  ThreadId;
  BOOLEAN                                 IsBspCallIn;

  if (CpuMpData->MicrocodePatchRegionSize == 0) {
    //
    // There is no microcode patches
    //
    return;
  }

  CurrentRevision = GetCurrentMicrocodeSignature ();
  IsBspCallIn     = (ProcessorNumber == (UINTN)CpuMpData->BspNumber) ? TRUE : FALSE;

  GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
  if (ThreadId != 0) {
    //
    // Skip loading microcode if it is not the first thread in one core.
    //
    return;
  }

  ExtendedTableLength = 0;
  //
  // Here data of CPUID leafs have not been collected into context buffer, so
  // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
  //
  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);

  //
  // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
  //
  PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
  PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;


  //
  // Check whether AP has same processor with BSP.
  // If yes, direct use microcode info saved by BSP.
  //
  if (!IsBspCallIn) {
    //
    // Get the CPU data for BSP
    //
    CpuData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
    if ((CpuData->ProcessorSignature == Eax.Uint32) &&
        (CpuData->PlatformId == PlatformId) &&
        (CpuData->MicrocodeEntryAddr != 0)) {
      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *)(UINTN) CpuData->MicrocodeEntryAddr;
      MicrocodeData       = (VOID *) (MicrocodeEntryPoint + 1);
      LatestRevision      = MicrocodeEntryPoint->UpdateRevision;
      goto Done;
    }
  }

  LatestRevision = 0;
  MicrocodeData  = NULL;
  MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
  MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;

  do {
    //
    // Check if the microcode is for the Cpu and the version is newer
    // and the update can be processed on the platform
    //
    CorrectMicrocode = FALSE;

    if (MicrocodeEntryPoint->DataSize == 0) {
      TotalSize = sizeof (CPU_MICROCODE_HEADER) + 2000;
    } else {
      TotalSize = sizeof (CPU_MICROCODE_HEADER) + MicrocodeEntryPoint->DataSize;
    }

    ///
    /// 0x0       MicrocodeBegin  MicrocodeEntry  MicrocodeEnd      0xffffffff
    /// |--------------|---------------|---------------|---------------|
    ///                                 valid TotalSize
    /// TotalSize is only valid between 0 and (MicrocodeEnd - MicrocodeEntry).
    /// And it should be aligned with 4 bytes.
    /// If the TotalSize is invalid, skip 1KB to check next entry.
    ///
    if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
         ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
         (TotalSize & 0x3) != 0
       ) {
      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
      continue;
    }

    //
    // Save an in-complete CheckSum32 from CheckSum Part1 for common parts.
    //
    InCompleteCheckSum32 = CalculateSum32 (
                             (UINT32 *) MicrocodeEntryPoint,
                             TotalSize
                             );
    InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorSignature.Uint32;
    InCompleteCheckSum32 -= MicrocodeEntryPoint->ProcessorFlags;
    InCompleteCheckSum32 -= MicrocodeEntryPoint->Checksum;

    if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
      //
      // It is the microcode header. It is not the padding data between microcode patches
      // because the padding data should not include 0x00000001 and it should be the repeated
      // byte format (like 0xXYXYXYXY....).
      //
      if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
          MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
          (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
          ) {
        //
        // Calculate CheckSum Part1.
        //
        CheckSum32 = InCompleteCheckSum32;
        CheckSum32 += MicrocodeEntryPoint->ProcessorSignature.Uint32;
        CheckSum32 += MicrocodeEntryPoint->ProcessorFlags;
        CheckSum32 += MicrocodeEntryPoint->Checksum;
        if (CheckSum32 == 0) {
          CorrectMicrocode = TRUE;
        }
      } else if ((MicrocodeEntryPoint->DataSize != 0) &&
                 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
        ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
                                sizeof (CPU_MICROCODE_HEADER));
        if (ExtendedTableLength != 0) {
          //
          // Extended Table exist, check if the CPU in support list
          //
          ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
                                  + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
          //
          // Calculate Extended Checksum
          //
          if ((ExtendedTableLength % 4) == 0) {
            //
            // Calculate CheckSum Part2.
            //
            CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
            if (CheckSum32 == 0) {
              //
              // Checksum correct
              //
              ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
              ExtendedTable      = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
              for (Index = 0; Index < ExtendedTableCount; Index ++) {
                //
                // Calculate CheckSum Part3.
                //
                CheckSum32 = InCompleteCheckSum32;
                CheckSum32 += ExtendedTable->ProcessorSignature.Uint32;
                CheckSum32 += ExtendedTable->ProcessorFlag;
                CheckSum32 += ExtendedTable->Checksum;
                if (CheckSum32 == 0) {
                  //
                  // Verify Header
                  //
                  if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
                      (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
                    //
                    // Find one
                    //
                    CorrectMicrocode = TRUE;
                    break;
                  }
                }
                ExtendedTable ++;
              }
            }
          }
        }
      }
    } else {
      //
      // It is the padding data between the microcode patches for microcode patches alignment.
      // Because the microcode patch is the multiple of 1-KByte, the padding data should not
      // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
      // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
      // find the next possible microcode patch header.
      //
      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
      continue;
    }
    //
    // Get the next patch.
    //
    if (MicrocodeEntryPoint->DataSize == 0) {
      TotalSize = 2048;
    } else {
      TotalSize = MicrocodeEntryPoint->TotalSize;
    }

    if (CorrectMicrocode) {
      LatestRevision = MicrocodeEntryPoint->UpdateRevision;
      MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
    }

    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));

Done:
  if (LatestRevision != 0) {
    //
    // Save the detected microcode patch entry address (including the
    // microcode patch header) for each processor.
    // It will be used when building the microcode patch cache HOB.
    //
    CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr =
      (UINTN) MicrocodeData -  sizeof (CPU_MICROCODE_HEADER);
  }

  if (LatestRevision > CurrentRevision) {
    //
    // BIOS only authenticate updates that contain a numerically larger revision
    // than the currently loaded revision, where Current Signature < New Update
    // Revision. A processor with no loaded update is considered to have a
    // revision equal to zero.
    //
    ASSERT (MicrocodeData != NULL);
    AsmWriteMsr64 (
        MSR_IA32_BIOS_UPDT_TRIG,
        (UINT64) (UINTN) MicrocodeData
        );
    //
    // Get and check new microcode signature
    //
    CurrentRevision = GetCurrentMicrocodeSignature ();
    if (CurrentRevision != LatestRevision) {
      AcquireSpinLock(&CpuMpData->MpLock);
      DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
                loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
      ReleaseSpinLock(&CpuMpData->MpLock);
    }
  }
}

/**
  Determine if a microcode patch matchs the specific processor signature and flag.

  @param[in]  CpuMpData             The pointer to CPU MP Data structure.
  @param[in]  ProcessorSignature    The processor signature field value
                                    supported by a microcode patch.
  @param[in]  ProcessorFlags        The prcessor flags field value supported by
                                    a microcode patch.

  @retval TRUE     The specified microcode patch will be loaded.
  @retval FALSE    The specified microcode patch will not be loaded.
**/
BOOLEAN
IsProcessorMatchedMicrocodePatch (
  IN CPU_MP_DATA                 *CpuMpData,
  IN UINT32                      ProcessorSignature,
  IN UINT32                      ProcessorFlags
  )
{
  UINTN          Index;
  CPU_AP_DATA    *CpuData;

  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
    CpuData = &CpuMpData->CpuData[Index];
    if ((ProcessorSignature == CpuData->ProcessorSignature) &&
        (ProcessorFlags & (1 << CpuData->PlatformId)) != 0) {
      return TRUE;
    }
  }

  return FALSE;
}

/**
  Check the 'ProcessorSignature' and 'ProcessorFlags' of the microcode
  patch header with the CPUID and PlatformID of the processors within
  system to decide if it will be copied into memory.

  @param[in]  CpuMpData             The pointer to CPU MP Data structure.
  @param[in]  MicrocodeEntryPoint   The pointer to the microcode patch header.

  @retval TRUE     The specified microcode patch need to be loaded.
  @retval FALSE    The specified microcode patch dosen't need to be loaded.
**/
BOOLEAN
IsMicrocodePatchNeedLoad (
  IN CPU_MP_DATA                 *CpuMpData,
  CPU_MICROCODE_HEADER           *MicrocodeEntryPoint
  )
{
  BOOLEAN                                NeedLoad;
  UINTN                                  DataSize;
  UINTN                                  TotalSize;
  CPU_MICROCODE_EXTENDED_TABLE_HEADER    *ExtendedTableHeader;
  UINT32                                 ExtendedTableCount;
  CPU_MICROCODE_EXTENDED_TABLE           *ExtendedTable;
  UINTN                                  Index;

  //
  // Check the 'ProcessorSignature' and 'ProcessorFlags' in microcode patch header.
  //
  NeedLoad = IsProcessorMatchedMicrocodePatch (
               CpuMpData,
               MicrocodeEntryPoint->ProcessorSignature.Uint32,
               MicrocodeEntryPoint->ProcessorFlags
               );

  //
  // If the Extended Signature Table exists, check if the processor is in the
  // support list
  //
  DataSize  = MicrocodeEntryPoint->DataSize;
  TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
  if ((!NeedLoad) && (DataSize != 0) &&
      (TotalSize - DataSize > sizeof (CPU_MICROCODE_HEADER) +
                              sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))) {
    ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
                            + DataSize + sizeof (CPU_MICROCODE_HEADER));
    ExtendedTableCount  = ExtendedTableHeader->ExtendedSignatureCount;
    ExtendedTable       = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);

    for (Index = 0; Index < ExtendedTableCount; Index ++) {
      //
      // Check the 'ProcessorSignature' and 'ProcessorFlag' of the Extended
      // Signature Table entry with the CPUID and PlatformID of the processors
      // within system to decide if it will be copied into memory
      //
      NeedLoad = IsProcessorMatchedMicrocodePatch (
                   CpuMpData,
                   ExtendedTable->ProcessorSignature.Uint32,
                   ExtendedTable->ProcessorFlag
                   );
      if (NeedLoad) {
        break;
      }
      ExtendedTable ++;
    }
  }

  return NeedLoad;
}


/**
  Actual worker function that shadows the required microcode patches into memory.

  @param[in, out]  CpuMpData        The pointer to CPU MP Data structure.
  @param[in]       Patches          The pointer to an array of information on
                                    the microcode patches that will be loaded
                                    into memory.
  @param[in]       PatchCount       The number of microcode patches that will
                                    be loaded into memory.
  @param[in]       TotalLoadSize    The total size of all the microcode patches
                                    to be loaded.
**/
VOID
ShadowMicrocodePatchWorker (
  IN OUT CPU_MP_DATA             *CpuMpData,
  IN     MICROCODE_PATCH_INFO    *Patches,
  IN     UINTN                   PatchCount,
  IN     UINTN                   TotalLoadSize
  )
{
  UINTN    Index;
  VOID     *MicrocodePatchInRam;
  UINT8    *Walker;

  ASSERT ((Patches != NULL) && (PatchCount != 0));

  MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
  if (MicrocodePatchInRam == NULL) {
    return;
  }

  //
  // Load all the required microcode patches into memory
  //
  for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
    CopyMem (
      Walker,
      (VOID *) Patches[Index].Address,
      Patches[Index].Size
      );
    Walker += Patches[Index].Size;
  }

  //
  // Update the microcode patch related fields in CpuMpData
  //
  CpuMpData->MicrocodePatchAddress    = (UINTN) MicrocodePatchInRam;
  CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;

  DEBUG ((
    DEBUG_INFO,
    "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
    __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
    ));

  return;
}

/**
  Shadow the required microcode patches data into memory according to PCD
  PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.

  @param[in, out]  CpuMpData    The pointer to CPU MP Data structure.
**/
VOID
ShadowMicrocodePatchByPcd (
  IN OUT CPU_MP_DATA             *CpuMpData
  )
{
  CPU_MICROCODE_HEADER                   *MicrocodeEntryPoint;
  UINTN                                  MicrocodeEnd;
  UINTN                                  DataSize;
  UINTN                                  TotalSize;
  MICROCODE_PATCH_INFO                   *PatchInfoBuffer;
  UINTN                                  MaxPatchNumber;
  UINTN                                  PatchCount;
  UINTN                                  TotalLoadSize;

  //
  // Initialize the microcode patch related fields in CpuMpData as the values
  // specified by the PCD pair. If the microcode patches are loaded into memory,
  // these fields will be updated.
  //
  CpuMpData->MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);
  CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);

  MicrocodeEntryPoint    = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
  MicrocodeEnd           = (UINTN) MicrocodeEntryPoint +
                           (UINTN) CpuMpData->MicrocodePatchRegionSize;
  if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {
    //
    // There is no microcode patches
    //
    return;
  }

  PatchCount      = 0;
  MaxPatchNumber  = DEFAULT_MAX_MICROCODE_PATCH_NUM;
  TotalLoadSize   = 0;
  PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
  if (PatchInfoBuffer == NULL) {
    return;
  }

  //
  // Process the header of each microcode patch within the region.
  // The purpose is to decide which microcode patch(es) will be loaded into memory.
  //
  do {
    if (MicrocodeEntryPoint->HeaderVersion != 0x1) {
      //
      // Padding data between the microcode patches, skip 1KB to check next entry.
      //
      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
      continue;
    }

    DataSize  = MicrocodeEntryPoint->DataSize;
    TotalSize = (DataSize == 0) ? 2048 : MicrocodeEntryPoint->TotalSize;
    if ( (UINTN)MicrocodeEntryPoint > (MAX_ADDRESS - TotalSize) ||
         ((UINTN)MicrocodeEntryPoint + TotalSize) > MicrocodeEnd ||
         (DataSize & 0x3) != 0 ||
         (TotalSize & (SIZE_1KB - 1)) != 0 ||
         TotalSize < DataSize
       ) {
      //
      // Not a valid microcode header, skip 1KB to check next entry.
      //
      MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
      continue;
    }

    if (IsMicrocodePatchNeedLoad (CpuMpData, MicrocodeEntryPoint)) {
      PatchCount++;
      if (PatchCount > MaxPatchNumber) {
        //
        // Current 'PatchInfoBuffer' cannot hold the information, double the size
        // and allocate a new buffer.
        //
        if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
          //
          // Overflow check for MaxPatchNumber
          //
          goto OnExit;
        }

        PatchInfoBuffer = ReallocatePool (
                            MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
                            2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
                            PatchInfoBuffer
                            );
        if (PatchInfoBuffer == NULL) {
          goto OnExit;
        }
        MaxPatchNumber = MaxPatchNumber * 2;
      }

      //
      // Store the information of this microcode patch
      //
      PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
      PatchInfoBuffer[PatchCount - 1].Size    = TotalSize;
      TotalLoadSize += TotalSize;
    }

    //
    // Process the next microcode patch
    //
    MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
  } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));

  if (PatchCount != 0) {
    DEBUG ((
      DEBUG_INFO,
      "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
      __FUNCTION__, PatchCount, TotalLoadSize
      ));

    ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
  }

OnExit:
  if (PatchInfoBuffer != NULL) {
    FreePool (PatchInfoBuffer);
  }
  return;
}

/**
  Shadow the required microcode patches data into memory.

  @param[in, out]  CpuMpData    The pointer to CPU MP Data structure.
**/
VOID
ShadowMicrocodeUpdatePatch (
  IN OUT CPU_MP_DATA             *CpuMpData
  )
{
  EFI_STATUS     Status;

  Status = PlatformShadowMicrocode (CpuMpData);
  if (EFI_ERROR (Status)) {
    ShadowMicrocodePatchByPcd (CpuMpData);
  }
}

/**
  Get the cached microcode patch base address and size from the microcode patch
  information cache HOB.

  @param[out] Address       Base address of the microcode patches data.
                            It will be updated if the microcode patch
                            information cache HOB is found.
  @param[out] RegionSize    Size of the microcode patches data.
                            It will be updated if the microcode patch
                            information cache HOB is found.

  @retval  TRUE     The microcode patch information cache HOB is found.
  @retval  FALSE    The microcode patch information cache HOB is not found.

**/
BOOLEAN
GetMicrocodePatchInfoFromHob (
  UINT64                         *Address,
  UINT64                         *RegionSize
  )
{
  EFI_HOB_GUID_TYPE            *GuidHob;
  EDKII_MICROCODE_PATCH_HOB    *MicrocodePathHob;

  GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);
  if (GuidHob == NULL) {
    DEBUG((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));
    return FALSE;
  }

  MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);

  *Address    = MicrocodePathHob->MicrocodePatchAddress;
  *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;

  DEBUG((
    DEBUG_INFO, "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",
    __FUNCTION__, *Address, *RegionSize
    ));

  return TRUE;
}
