]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / PeiMpLib.c
index 72791b56173d2eba5eb4a27572be8ca71ee9aadf..e732371ddd2195de7e0eedd6967cadff778adc8f 100644 (file)
@@ -1,32 +1,95 @@
 /** @file\r
   MP initialize support functions for PEI phase.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "MpLib.h"\r
-#include <Ppi/EndOfPeiPhase.h>\r
 #include <Library/PeiServicesLib.h>\r
+#include <Guid/S3SmmInitDone.h>\r
+#include <Ppi/ShadowMicrocode.h>\r
+\r
+STATIC UINT64  mSevEsPeiWakeupBuffer = BASE_1MB;\r
+\r
+/**\r
+  S3 SMM Init Done notification function.\r
+\r
+  @param  PeiServices      Indirect reference to the PEI Services Table.\r
+  @param  NotifyDesc       Address of the notification descriptor data structure.\r
+  @param  InvokePpi        Address of the PPI that was invoked.\r
+\r
+  @retval EFI_SUCCESS      The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnS3SmmInitDonePpi (\r
+  IN  EFI_PEI_SERVICES           **PeiServices,\r
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDesc,\r
+  IN  VOID                       *InvokePpi\r
+  );\r
 \r
 //\r
-// Global PEI notify function descriptor on EndofPei event\r
+// Global function\r
 //\r
-GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMpInitLibNotifyList = {\r
-  (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
-  &gEfiEndOfPeiSignalPpiGuid,\r
-  CpuMpEndOfPeiCallback\r
+EFI_PEI_NOTIFY_DESCRIPTOR  mS3SmmInitDoneNotifyDesc = {\r
+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gEdkiiS3SmmInitDoneGuid,\r
+  NotifyOnS3SmmInitDonePpi\r
 };\r
 \r
+/**\r
+  S3 SMM Init Done notification function.\r
+\r
+  @param  PeiServices      Indirect reference to the PEI Services Table.\r
+  @param  NotifyDesc       Address of the notification descriptor data structure.\r
+  @param  InvokePpi        Address of the PPI that was invoked.\r
+\r
+  @retval EFI_SUCCESS      The function completes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotifyOnS3SmmInitDonePpi (\r
+  IN  EFI_PEI_SERVICES           **PeiServices,\r
+  IN  EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDesc,\r
+  IN  VOID                       *InvokePpi\r
+  )\r
+{\r
+  CPU_MP_DATA  *CpuMpData;\r
+\r
+  CpuMpData = GetCpuMpData ();\r
+\r
+  //\r
+  // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.\r
+  // So in this notify function, code need to check the current loop\r
+  // mode, if it is not HLT mode, code need to change loop mode back\r
+  // to the original mode.\r
+  //\r
+  if (CpuMpData->ApLoopMode != ApInHltLoop) {\r
+    CpuMpData->WakeUpByInitSipiSipi = TRUE;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable Debug Agent to support source debugging on AP function.\r
+\r
+**/\r
+VOID\r
+EnableDebugAgent (\r
+  VOID\r
+  )\r
+{\r
+}\r
+\r
 /**\r
   Get pointer to CPU MP Data structure.\r
+  For BSP, the pointer is retrieved from HOB.\r
+  For AP, the structure is stored in the top of each AP's stack.\r
 \r
   @return  The pointer to CPU MP Data structure.\r
 **/\r
@@ -35,10 +98,21 @@ GetCpuMpData (
   VOID\r
   )\r
 {\r
-  CPU_MP_DATA      *CpuMpData;\r
+  CPU_MP_DATA                  *CpuMpData;\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+  UINTN                        ApTopOfStack;\r
+  AP_STACK_DATA                *ApStackData;\r
+\r
+  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+  if (ApicBaseMsr.Bits.BSP == 1) {\r
+    CpuMpData = GetCpuMpDataFromGuidedHob ();\r
+    ASSERT (CpuMpData != NULL);\r
+  } else {\r
+    ApTopOfStack = ALIGN_VALUE ((UINTN)&ApTopOfStack, (UINTN)PcdGet32 (PcdCpuApStackSize));\r
+    ApStackData  = (AP_STACK_DATA *)((UINTN)ApTopOfStack- sizeof (AP_STACK_DATA));\r
+    CpuMpData    = (CPU_MP_DATA *)ApStackData->MpData;\r
+  }\r
 \r
-  CpuMpData = GetCpuMpDataFromGuidedHob ();\r
-  ASSERT (CpuMpData != NULL);\r
   return CpuMpData;\r
 }\r
 \r
@@ -49,48 +123,282 @@ GetCpuMpData (
 **/\r
 VOID\r
 SaveCpuMpData (\r
-  IN CPU_MP_DATA   *CpuMpData\r
+  IN CPU_MP_DATA  *CpuMpData\r
   )\r
 {\r
-  UINT64           Data64;\r
+  UINT64  Data64;\r
+\r
   //\r
   // Build location of CPU MP DATA buffer in HOB\r
   //\r
-  Data64 = (UINT64) (UINTN) CpuMpData;\r
+  Data64 = (UINT64)(UINTN)CpuMpData;\r
   BuildGuidDataHob (\r
     &mCpuInitMpLibHobGuid,\r
-    (VOID *) &Data64,\r
+    (VOID *)&Data64,\r
     sizeof (UINT64)\r
     );\r
 }\r
 \r
+/**\r
+  Check if AP wakeup buffer is overlapped with existing allocated buffer.\r
+\r
+  @param[in]  WakeupBufferStart     AP wakeup buffer start address.\r
+  @param[in]  WakeupBufferEnd       AP wakeup buffer end address.\r
+\r
+  @retval  TRUE       There is overlap.\r
+  @retval  FALSE      There is no overlap.\r
+**/\r
+BOOLEAN\r
+CheckOverlapWithAllocatedBuffer (\r
+  IN UINT64  WakeupBufferStart,\r
+  IN UINT64  WakeupBufferEnd\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS       Hob;\r
+  EFI_HOB_MEMORY_ALLOCATION  *MemoryHob;\r
+  BOOLEAN                    Overlapped;\r
+  UINT64                     MemoryStart;\r
+  UINT64                     MemoryEnd;\r
+\r
+  Overlapped = FALSE;\r
+  //\r
+  // Get the HOB list for processing\r
+  //\r
+  Hob.Raw = GetHobList ();\r
+  //\r
+  // Collect memory ranges\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
+      MemoryHob   = Hob.MemoryAllocation;\r
+      MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
+      MemoryEnd   = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;\r
+      if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {\r
+        Overlapped = TRUE;\r
+        break;\r
+      }\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+\r
+  return Overlapped;\r
+}\r
+\r
+/**\r
+  Get available system memory below 1MB by specified size.\r
+\r
+  @param[in] WakeupBufferSize   Wakeup buffer size required\r
+\r
+  @retval other   Return wakeup buffer address below 1MB.\r
+  @retval -1      Cannot find free memory below 1MB.\r
+**/\r
+UINTN\r
+GetWakeupBuffer (\r
+  IN UINTN  WakeupBufferSize\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+  UINT64                WakeupBufferStart;\r
+  UINT64                WakeupBufferEnd;\r
+\r
+  WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);\r
+\r
+  //\r
+  // Get the HOB list for processing\r
+  //\r
+  Hob.Raw = GetHobList ();\r
+\r
+  //\r
+  // Collect memory ranges\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+      if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&\r
+          (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&\r
+          ((Hob.ResourceDescriptor->ResourceAttribute &\r
+            (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
+             EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
+             EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED\r
+            )) == 0)\r
+          )\r
+      {\r
+        //\r
+        // Need memory under 1MB to be collected here\r
+        //\r
+        WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;\r
+        if (ConfidentialComputingGuestHas (CCAttrAmdSevEs) &&\r
+            (WakeupBufferEnd > mSevEsPeiWakeupBuffer))\r
+        {\r
+          //\r
+          // SEV-ES Wakeup buffer should be under 1MB and under any previous one\r
+          //\r
+          WakeupBufferEnd = mSevEsPeiWakeupBuffer;\r
+        } else if (WakeupBufferEnd > BASE_1MB) {\r
+          //\r
+          // Wakeup buffer should be under 1MB\r
+          //\r
+          WakeupBufferEnd = BASE_1MB;\r
+        }\r
+\r
+        while (WakeupBufferEnd > WakeupBufferSize) {\r
+          //\r
+          // Wakeup buffer should be aligned on 4KB\r
+          //\r
+          WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);\r
+          if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {\r
+            break;\r
+          }\r
+\r
+          if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {\r
+            //\r
+            // If this range is overlapped with existing allocated buffer, skip it\r
+            // and find the next range\r
+            //\r
+            WakeupBufferEnd -= WakeupBufferSize;\r
+            continue;\r
+          }\r
+\r
+          DEBUG ((\r
+            DEBUG_INFO,\r
+            "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
+            WakeupBufferStart,\r
+            WakeupBufferSize\r
+            ));\r
+\r
+          if (ConfidentialComputingGuestHas (CCAttrAmdSevEs)) {\r
+            //\r
+            // Next SEV-ES wakeup buffer allocation must be below this\r
+            // allocation\r
+            //\r
+            mSevEsPeiWakeupBuffer = WakeupBufferStart;\r
+          }\r
+\r
+          return (UINTN)WakeupBufferStart;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Find the next HOB\r
+    //\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+\r
+  return (UINTN)-1;\r
+}\r
+\r
+/**\r
+  Get available EfiBootServicesCode memory below 4GB by specified size.\r
+\r
+  This buffer is required to safely transfer AP from real address mode to\r
+  protected mode or long mode, due to the fact that the buffer returned by\r
+  GetWakeupBuffer() may be marked as non-executable.\r
+\r
+  @param[in] BufferSize   Wakeup transition buffer size.\r
+\r
+  @retval other   Return wakeup transition buffer address below 4GB.\r
+  @retval 0       Cannot find free memory below 4GB.\r
+**/\r
+UINTN\r
+AllocateCodeBuffer (\r
+  IN UINTN  BufferSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+\r
+  Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES (BufferSize), &Address);\r
+  if (EFI_ERROR (Status)) {\r
+    Address = 0;\r
+  }\r
+\r
+  return (UINTN)Address;\r
+}\r
 \r
 /**\r
+  Return the address of the SEV-ES AP jump table.\r
+\r
+  This buffer is required in order for an SEV-ES guest to transition from\r
+  UEFI into an OS.\r
+\r
+  @return         Return SEV-ES AP jump table buffer\r
+**/\r
+UINTN\r
+GetSevEsAPMemory (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // PEI phase doesn't need to do such transition. So simply return 0.\r
+  //\r
+  return 0;\r
+}\r
+\r
 /**\r
-  Notify function on End Of PEI PPI.\r
+  Checks APs status and updates APs status if needed.\r
+\r
+**/\r
+VOID\r
+CheckAndUpdateApsStatus (\r
+  VOID\r
+  )\r
+{\r
+}\r
 \r
-  On S3 boot, this function will restore wakeup buffer data.\r
-  On normal boot, this function will flag wakeup buffer to be un-used type.\r
+/**\r
+  Build the microcode patch HOB that contains the base address and size of the\r
+  microcode patch stored in the memory.\r
 \r
-  @param[in]  PeiServices        The pointer to the PEI Services Table.\r
-  @param[in]  NotifyDescriptor   Address of the notification descriptor data structure.\r
-  @param[in]  Ppi                Address of the PPI that was installed.\r
+  @param[in]  CpuMpData    Pointer to the CPU_MP_DATA structure.\r
 \r
-  @retval EFI_SUCCESS        When everything is OK.\r
 **/\r
-EFI_STATUS\r
-EFIAPI\r
-CpuMpEndOfPeiCallback (\r
-  IN EFI_PEI_SERVICES             **PeiServices,\r
-  IN EFI_PEI_NOTIFY_DESCRIPTOR    *NotifyDescriptor,\r
-  IN VOID                         *Ppi\r
+VOID\r
+BuildMicrocodeCacheHob (\r
+  IN CPU_MP_DATA  *CpuMpData\r
   )\r
 {\r
+  EDKII_MICROCODE_PATCH_HOB  *MicrocodeHob;\r
+  UINTN                      HobDataLength;\r
+  UINT32                     Index;\r
 \r
-  DEBUG ((DEBUG_INFO, "PeiMpInitLib: CpuMpEndOfPeiCallback () invoked\n"));\r
+  HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +\r
+                  sizeof (UINT64) * CpuMpData->CpuCount;\r
 \r
-  return EFI_SUCCESS;\r
+  MicrocodeHob = AllocatePool (HobDataLength);\r
+  if (MicrocodeHob == NULL) {\r
+    ASSERT (FALSE);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Store the information of the memory region that holds the microcode patches.\r
+  //\r
+  MicrocodeHob->MicrocodePatchAddress    = CpuMpData->MicrocodePatchAddress;\r
+  MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;\r
+\r
+  //\r
+  // Store the detected microcode patch for each processor as well.\r
+  //\r
+  MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;\r
+  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+    if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {\r
+      MicrocodeHob->ProcessorSpecificPatchOffset[Index] =\r
+        CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;\r
+    } else {\r
+      MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;\r
+    }\r
+  }\r
+\r
+  BuildGuidDataHob (\r
+    &gEdkiiMicrocodePatchHobGuid,\r
+    MicrocodeHob,\r
+    HobDataLength\r
+    );\r
+\r
+  return;\r
 }\r
+\r
 /**\r
   Initialize global data for MP support.\r
 \r
@@ -98,16 +406,18 @@ CpuMpEndOfPeiCallback (
 **/\r
 VOID\r
 InitMpGlobalData (\r
-  IN CPU_MP_DATA               *CpuMpData\r
+  IN CPU_MP_DATA  *CpuMpData\r
   )\r
 {\r
-  EFI_STATUS      Status;\r
+  EFI_STATUS  Status;\r
 \r
+  BuildMicrocodeCacheHob (CpuMpData);\r
   SaveCpuMpData (CpuMpData);\r
-  //\r
-  // Register an event for EndOfPei\r
-  //\r
-  Status  = PeiServicesNotifyPpi (&mMpInitLibNotifyList);\r
+\r
+  ///\r
+  /// Install Notify\r
+  ///\r
+  Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);\r
   ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
@@ -138,7 +448,7 @@ InitMpGlobalData (
                                       EFI_EVENT is defined in CreateEvent() in\r
                                       the Unified Extensible Firmware Interface\r
                                       Specification.\r
-  @param[in]  TimeoutInMicrosecsond   Indicates the time limit in microseconds for\r
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for\r
                                       APs to return from Procedure, either for\r
                                       blocking or non-blocking mode. Zero means\r
                                       infinity.  If the timeout expires before\r
@@ -189,15 +499,27 @@ InitMpGlobalData (
 EFI_STATUS\r
 EFIAPI\r
 MpInitLibStartupAllAPs (\r
-  IN  EFI_AP_PROCEDURE          Procedure,\r
-  IN  BOOLEAN                   SingleThread,\r
-  IN  EFI_EVENT                 WaitEvent               OPTIONAL,\r
-  IN  UINTN                     TimeoutInMicroseconds,\r
-  IN  VOID                      *ProcedureArgument      OPTIONAL,\r
-  OUT UINTN                     **FailedCpuList         OPTIONAL\r
+  IN  EFI_AP_PROCEDURE  Procedure,\r
+  IN  BOOLEAN           SingleThread,\r
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,\r
+  IN  UINTN             TimeoutInMicroseconds,\r
+  IN  VOID              *ProcedureArgument      OPTIONAL,\r
+  OUT UINTN             **FailedCpuList         OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  if (WaitEvent != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return StartupAllCPUsWorker (\r
+           Procedure,\r
+           SingleThread,\r
+           TRUE,\r
+           NULL,\r
+           TimeoutInMicroseconds,\r
+           ProcedureArgument,\r
+           FailedCpuList\r
+           );\r
 }\r
 \r
 /**\r
@@ -227,7 +549,7 @@ MpInitLibStartupAllAPs (
                                       EFI_EVENT is defined in CreateEvent() in\r
                                       the Unified Extensible Firmware Interface\r
                                       Specification.\r
-  @param[in]  TimeoutInMicrosecsond   Indicates the time limit in microseconds for\r
+  @param[in]  TimeoutInMicroseconds   Indicates the time limit in microseconds for\r
                                       this AP to finish this Procedure, either for\r
                                       blocking or non-blocking mode. Zero means\r
                                       infinity.  If the timeout expires before\r
@@ -274,15 +596,26 @@ MpInitLibStartupAllAPs (
 EFI_STATUS\r
 EFIAPI\r
 MpInitLibStartupThisAP (\r
-  IN  EFI_AP_PROCEDURE          Procedure,\r
-  IN  UINTN                     ProcessorNumber,\r
-  IN  EFI_EVENT                 WaitEvent               OPTIONAL,\r
-  IN  UINTN                     TimeoutInMicroseconds,\r
-  IN  VOID                      *ProcedureArgument      OPTIONAL,\r
-  OUT BOOLEAN                   *Finished               OPTIONAL\r
+  IN  EFI_AP_PROCEDURE  Procedure,\r
+  IN  UINTN             ProcessorNumber,\r
+  IN  EFI_EVENT         WaitEvent               OPTIONAL,\r
+  IN  UINTN             TimeoutInMicroseconds,\r
+  IN  VOID              *ProcedureArgument      OPTIONAL,\r
+  OUT BOOLEAN           *Finished               OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  if (WaitEvent != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return StartupThisAPWorker (\r
+           Procedure,\r
+           ProcessorNumber,\r
+           NULL,\r
+           TimeoutInMicroseconds,\r
+           ProcedureArgument,\r
+           Finished\r
+           );\r
 }\r
 \r
 /**\r
@@ -314,11 +647,11 @@ MpInitLibStartupThisAP (
 EFI_STATUS\r
 EFIAPI\r
 MpInitLibSwitchBSP (\r
-  IN UINTN                     ProcessorNumber,\r
-  IN  BOOLEAN                  EnableOldBSP\r
+  IN UINTN     ProcessorNumber,\r
+  IN  BOOLEAN  EnableOldBSP\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
 }\r
 \r
 /**\r
@@ -354,12 +687,81 @@ MpInitLibSwitchBSP (
 EFI_STATUS\r
 EFIAPI\r
 MpInitLibEnableDisableAP (\r
-  IN  UINTN                     ProcessorNumber,\r
-  IN  BOOLEAN                   EnableAP,\r
-  IN  UINT32                    *HealthFlag OPTIONAL\r
+  IN  UINTN    ProcessorNumber,\r
+  IN  BOOLEAN  EnableAP,\r
+  IN  UINT32   *HealthFlag OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
 }\r
 \r
+/**\r
+  This funtion will try to invoke platform specific microcode shadow logic to\r
+  relocate microcode update patches into memory.\r
+\r
+  @param[in, out] CpuMpData  The pointer to CPU MP Data structure.\r
 \r
+  @retval EFI_SUCCESS              Shadow microcode success.\r
+  @retval EFI_OUT_OF_RESOURCES     No enough resource to complete the operation.\r
+  @retval EFI_UNSUPPORTED          Can't find platform specific microcode shadow\r
+                                   PPI/Protocol.\r
+**/\r
+EFI_STATUS\r
+PlatformShadowMicrocode (\r
+  IN OUT CPU_MP_DATA  *CpuMpData\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EDKII_PEI_SHADOW_MICROCODE_PPI  *ShadowMicrocodePpi;\r
+  UINTN                           CpuCount;\r
+  EDKII_PEI_MICROCODE_CPU_ID      *MicrocodeCpuId;\r
+  UINTN                           Index;\r
+  UINTN                           BufferSize;\r
+  VOID                            *Buffer;\r
+\r
+  Status = PeiServicesLocatePpi (\r
+             &gEdkiiPeiShadowMicrocodePpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **)&ShadowMicrocodePpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  CpuCount       = CpuMpData->CpuCount;\r
+  MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *)AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);\r
+  if (MicrocodeCpuId == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+    MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;\r
+    MicrocodeCpuId[Index].PlatformId         = CpuMpData->CpuData[Index].PlatformId;\r
+  }\r
+\r
+  Status = ShadowMicrocodePpi->ShadowMicrocode (\r
+                                 ShadowMicrocodePpi,\r
+                                 CpuCount,\r
+                                 MicrocodeCpuId,\r
+                                 &BufferSize,\r
+                                 &Buffer\r
+                                 );\r
+  FreePool (MicrocodeCpuId);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  CpuMpData->MicrocodePatchAddress    = (UINTN)Buffer;\r
+  CpuMpData->MicrocodePatchRegionSize = BufferSize;\r
+\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 EFI_SUCCESS;\r
+}\r