]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/MpInitLib: Place APs in safe loop before hand-off to OS
authorJeff Fan <jeff.fan@intel.com>
Sun, 24 Jul 2016 15:03:12 +0000 (23:03 +0800)
committerJeff Fan <jeff.fan@intel.com>
Wed, 17 Aug 2016 12:02:39 +0000 (20:02 +0800)
Register Exit Boot Service callback function MpInitExitBootServicesCallback() to
place AP one safe loop before hand-off to OS.

Allocated one reserved memory and copy the AsmRellocateApLoop() code into it. It
could avoid the CPU Dxe driver (located in Boot Service data range) crashed
after Exit Boot Service event.
Place AP into the target Cx-State (specified by PcdCpuApTargetCstate) could save
power if Monitor-mwait feature supported.
In long mode, switch AP into protected mode could let AP not require page table
when executing this safe loop. Page Table (located in Boot Service data range)
may crashed after Exit Boot Service event.

v3:
  1. Rename *RellocateAp* to *RelocateAp*

Cc: Michael Kinney <michael.d.kinney@intel.com>
Cc: Feng Tian <feng.tian@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
UefiCpuPkg/Library/MpInitLib/MpLib.h

index 1043becf4c2e37b9837fb0aa19b41b57ecc4d583..42d320ff8a6efc59256aef03e38ec4613f312ef5 100644 (file)
@@ -21,6 +21,7 @@
 \r
 CPU_MP_DATA      *mCpuMpData = NULL;\r
 EFI_EVENT        mCheckAllApsEvent = NULL;\r
+EFI_EVENT        mMpInitExitBootServicesEvent = NULL;\r
 volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
 \r
 \r
@@ -185,6 +186,94 @@ CheckApsStatus (
   }\r
 }\r
 \r
+/**\r
+  Get Protected mode code segment from current GDT table.\r
+\r
+  @returen  Protected mode code segment value.\r
+**/\r
+UINT16\r
+GetProtectedModeCS (\r
+  VOID\r
+  )\r
+{\r
+  IA32_DESCRIPTOR          GdtrDesc;\r
+  IA32_SEGMENT_DESCRIPTOR  *GdtEntry;\r
+  UINTN                    GdtEntryCount;\r
+  UINT16                   Index;\r
+\r
+  Index = (UINT16) -1;\r
+  AsmReadGdtr (&GdtrDesc);\r
+  GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+  GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
+  for (Index = 0; Index < GdtEntryCount; Index++) {\r
+    if (GdtEntry->Bits.L == 0) {\r
+      if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {\r
+        break;\r
+      }\r
+    }\r
+    GdtEntry++;\r
+  }\r
+  ASSERT (Index != -1);\r
+  return Index * 8;\r
+}\r
+\r
+/**\r
+  Do sync on APs.\r
+\r
+  @param[in, out] Buffer  Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+RelocateApLoop (\r
+  IN OUT VOID  *Buffer\r
+  )\r
+{\r
+  CPU_MP_DATA            *CpuMpData;\r
+  BOOLEAN                MwaitSupport;\r
+  ASM_RELOCATE_AP_LOOP   AsmRelocateApLoopFunc;\r
+\r
+  CpuMpData    = GetCpuMpData ();\r
+  MwaitSupport = IsMwaitSupport ();\r
+  AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) Buffer;\r
+  AsmRelocateApLoopFunc (MwaitSupport, CpuMpData->ApTargetCState, CpuMpData->PmCodeSegment);\r
+  //\r
+  // It should never reach here\r
+  //\r
+  ASSERT (FALSE);\r
+}\r
+\r
+/**\r
+  Callback function for ExitBootServices.\r
+\r
+  @param[in]  Event             Event whose notification function is being invoked.\r
+  @param[in]  Context           The pointer to the notification function's context,\r
+                                which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+MpInitExitBootServicesCallback (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  CPU_MP_DATA               *CpuMpData;\r
+  VOID                      *ReservedApLoopFunc;\r
+  //\r
+  // Avoid APs access invalid buff data which allocated by BootServices,\r
+  // so we will allocate reserved data for AP loop code.\r
+  //\r
+  CpuMpData = GetCpuMpData ();\r
+  CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
+  CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
+  ReservedApLoopFunc = AllocateReservedCopyPool (\r
+                         CpuMpData->AddressMap.RelocateApLoopFuncSize,\r
+                         CpuMpData->AddressMap.RelocateApLoopFuncAddress\r
+                         );\r
+  WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, ReservedApLoopFunc);\r
+  DEBUG ((DEBUG_INFO, "MpInitExitBootServicesCallback() done!\n"));\r
+}\r
+\r
 /**\r
   Initialize global data for MP support.\r
 \r
@@ -217,6 +306,14 @@ InitMpGlobalData (
                   AP_CHECK_INTERVAL\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+                  TPL_CALLBACK,\r
+                  MpInitExitBootServicesCallback,\r
+                  NULL,\r
+                  &mMpInitExitBootServicesEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
 /**\r
index 06af7cc15b40164d5d9c759a182fec287ba41417..e53deb449d977be7ef81a6ae1ad72eb56961dd77 100644 (file)
@@ -519,6 +519,17 @@ MicrocodeDetect (
   IN CPU_MP_DATA             *CpuMpData\r
   );\r
 \r
+/**\r
+  Detect whether Mwait-monitor feature is supported.\r
+\r
+  @retval TRUE    Mwait-monitor feature is supported.\r
+  @retval FALSE   Mwait-monitor feature is not supported.\r
+**/\r
+BOOLEAN\r
+IsMwaitSupport (\r
+  VOID\r
+  );\r
+\r
 /**\r
   Notify function on End Of PEI PPI.\r
 \r