]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiCpuPkg/MpInitLib: Implementation of MpInitLibSwitchBSP()
authorJeff Fan <jeff.fan@intel.com>
Thu, 21 Jul 2016 13:20:18 +0000 (21:20 +0800)
committerJeff Fan <jeff.fan@intel.com>
Wed, 17 Aug 2016 12:02:13 +0000 (20:02 +0800)
v4:
  1. Simply the internal function SwitchBSPWorker()'s comment header
     due to it is duplicated with MpInitLibSwitchBSP().

v3:
  1. Rename MpInitLibSwitchBsp to MpInitLibSwitchBSP.

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.c
UefiCpuPkg/Library/MpInitLib/MpLib.h
UefiCpuPkg/Library/MpInitLib/PeiMpLib.c

index 762d76dd7a7f2d774dc004acd1f8bc1ab20ce511..785653be8f6e4708b0f2be2a70609dbac72143cc 100644 (file)
@@ -389,7 +389,31 @@ MpInitLibSwitchBSP (
   IN BOOLEAN                   EnableOldBSP\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  EFI_STATUS            Status;\r
+  BOOLEAN               OldInterruptState;\r
+\r
+  //\r
+  // Before send both BSP and AP to a procedure to exchange their roles,\r
+  // interrupt must be disabled. This is because during the exchange role\r
+  // process, 2 CPU may use 1 stack. If interrupt happens, the stack will\r
+  // be corrupted, since interrupt return address will be pushed to stack\r
+  // by hardware.\r
+  //\r
+  OldInterruptState = SaveAndDisableInterrupts ();\r
+\r
+  //\r
+  // Mask LINT0 & LINT1 for the old BSP\r
+  //\r
+  DisableLvtInterrupts ();\r
+\r
+  Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
+\r
+  //\r
+  // Restore interrupt state.\r
+  //\r
+  SetInterruptState (OldInterruptState);\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
index 5fbcb26ddaf205d397d451afbec5d05db942fb9c..8ae08f4d5d5f050bf89cda7be0fc614e566f62cc 100644 (file)
@@ -183,6 +183,26 @@ ExtractProcessorLocation (
   Location->Package = (InitialApicId >> (ThreadBits + CoreBits));\r
 }\r
 \r
+/**\r
+  Worker function for SwitchBSP().\r
+\r
+  Worker function for SwitchBSP(), assigned to the AP which is intended\r
+  to become BSP.\r
+\r
+  @param[in] Buffer   Pointer to CPU MP Data\r
+**/\r
+VOID\r
+EFIAPI\r
+FutureBSPProc (\r
+  IN  VOID            *Buffer\r
+  )\r
+{\r
+  CPU_MP_DATA         *DataInHob;\r
+\r
+  DataInHob = (CPU_MP_DATA *) Buffer;\r
+  AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);\r
+}\r
+\r
 /**\r
   Get the Application Processors state.\r
 \r
@@ -646,11 +666,20 @@ ApWakeupFunction (
           // Invoke AP function here\r
           //\r
           Procedure (Parameter);\r
-          //\r
-          // Re-get the CPU APICID and Initial APICID\r
-          //\r
-          CpuMpData->CpuData[ProcessorNumber].ApicId        = GetApicId ();\r
-          CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
+          if (CpuMpData->SwitchBspFlag) {\r
+            //\r
+            // Re-get the processor number due to BSP/AP maybe exchange in AP function\r
+            //\r
+            GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
+            CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;\r
+            CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;\r
+          } else {\r
+            //\r
+            // Re-get the CPU APICID and Initial APICID\r
+            //\r
+            CpuMpData->CpuData[ProcessorNumber].ApicId        = GetApicId ();\r
+            CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
+          }\r
         }\r
         SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
       }\r
@@ -941,6 +970,7 @@ MpInitLibInitialize (
   CpuMpData->CpuCount         = 1;\r
   CpuMpData->BspNumber        = 0;\r
   CpuMpData->WaitEvent        = NULL;\r
+  CpuMpData->SwitchBspFlag    = FALSE;\r
   CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);\r
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
   InitializeSpinLock(&CpuMpData->MpLock);\r
@@ -1103,6 +1133,110 @@ MpInitLibGetProcessorInfo (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Worker function to switch the requested AP to be the BSP from that point onward.\r
+\r
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new BSP.\r
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an\r
+                               enabled AP. Otherwise, it will be disabled.\r
+\r
+  @retval EFI_SUCCESS          BSP successfully switched.\r
+  @retval others               Failed to switch BSP. \r
+\r
+**/\r
+EFI_STATUS\r
+SwitchBSPWorker (\r
+  IN UINTN                     ProcessorNumber,\r
+  IN BOOLEAN                   EnableOldBSP\r
+  )\r
+{\r
+  CPU_MP_DATA                  *CpuMpData;\r
+  UINTN                        CallerNumber;\r
+  CPU_STATE                    State;\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+\r
+  CpuMpData = GetCpuMpData ();\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  MpInitLibWhoAmI (&CallerNumber);\r
+  if (CallerNumber != CpuMpData->BspNumber) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (ProcessorNumber >= CpuMpData->CpuCount) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Check whether specified AP is disabled\r
+  //\r
+  State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);\r
+  if (State == CpuStateDisabled) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether ProcessorNumber specifies the current BSP\r
+  //\r
+  if (ProcessorNumber == CpuMpData->BspNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether specified AP is busy\r
+  //\r
+  if (State == CpuStateBusy) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;\r
+  CpuMpData->APInfo.State  = CPU_SWITCH_STATE_IDLE;\r
+  CpuMpData->SwitchBspFlag = TRUE;\r
+\r
+  //\r
+  // Clear the BSP bit of MSR_IA32_APIC_BASE\r
+  //\r
+  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+  ApicBaseMsr.Bits.BSP = 0;\r
+  AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+\r
+  //\r
+  // Need to wakeUp AP (future BSP).\r
+  //\r
+  WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);\r
+\r
+  AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);\r
+\r
+  //\r
+  // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP\r
+  //\r
+  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+  ApicBaseMsr.Bits.BSP = 1;\r
+  AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+\r
+  //\r
+  // Wait for old BSP finished AP task\r
+  //\r
+  while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {\r
+    CpuPause ();\r
+  }\r
+\r
+  CpuMpData->SwitchBspFlag = FALSE;\r
+  //\r
+  // Set old BSP enable state\r
+  //\r
+  if (!EnableOldBSP) {\r
+    SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);\r
+  }\r
+  //\r
+  // Save new BSP number\r
+  //\r
+  CpuMpData->BspNumber = (UINT32) ProcessorNumber;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   This return the handle number for the calling processor.  This service may be\r
index 84e09702b9c6e10b45b8298152d7f9c824cb75e2..bfc7fb72e0124cdee4279d658b661b3d982874c5 100644 (file)
     0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \\r
   }\r
 \r
+//\r
+//  The MP data for switch BSP\r
+//\r
+#define CPU_SWITCH_STATE_IDLE   0\r
+#define CPU_SWITCH_STATE_STORED 1\r
+#define CPU_SWITCH_STATE_LOADED 2\r
+\r
+//\r
+// CPU exchange information for switch BSP\r
+//\r
+typedef struct {\r
+  UINT8             State;        // offset 0\r
+  UINTN             StackPointer; // offset 4 / 8\r
+  IA32_DESCRIPTOR   Gdtr;         // offset 8 / 16\r
+  IA32_DESCRIPTOR   Idtr;         // offset 14 / 26\r
+} CPU_EXCHANGE_ROLE_INFO;\r
+\r
 //\r
 // AP loop state when APs are in idle state\r
 // It's value is the same with PcdCpuApLoopMode\r
@@ -198,6 +215,9 @@ struct _CPU_MP_DATA {
 \r
   AP_INIT_STATE                  InitFlag;\r
   BOOLEAN                        X2ApicEnable;\r
+  BOOLEAN                        SwitchBspFlag;\r
+  CPU_EXCHANGE_ROLE_INFO         BSPInfo;\r
+  CPU_EXCHANGE_ROLE_INFO         APInfo;\r
   MTRR_SETTINGS                  MtrrTable;\r
   UINT8                          ApLoopMode;\r
   UINT8                          ApTargetCState;\r
@@ -242,6 +262,22 @@ AsmGetAddressMap (
   OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap\r
   );\r
 \r
+/**\r
+  This function is called by both the BSP and the AP which is to become the BSP to\r
+  Exchange execution context including stack between them. After return from this\r
+  function, the BSP becomes AP and the AP becomes the BSP.\r
+\r
+  @param[in] MyInfo      Pointer to buffer holding the exchanging information for the executing processor.\r
+  @param[in] OthersInfo  Pointer to buffer holding the exchanging information for the peer.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsmExchangeRole (\r
+  IN CPU_EXCHANGE_ROLE_INFO    *MyInfo,\r
+  IN CPU_EXCHANGE_ROLE_INFO    *OthersInfo\r
+  );\r
+\r
 /**\r
   Get the pointer to CPU MP Data structure.\r
 \r
@@ -311,6 +347,23 @@ InitMpGlobalData (
   IN CPU_MP_DATA               *CpuMpData\r
   );\r
 \r
+/**\r
+  Worker function to switch the requested AP to be the BSP from that point onward.\r
+\r
+  @param[in] ProcessorNumber   The handle number of AP that is to become the new BSP.\r
+  @param[in] EnableOldBSP      If TRUE, then the old BSP will be listed as an\r
+                               enabled AP. Otherwise, it will be disabled.\r
+\r
+  @retval EFI_SUCCESS          BSP successfully switched.\r
+  @retval others               Failed to switch BSP. \r
+\r
+**/\r
+EFI_STATUS\r
+SwitchBSPWorker (\r
+  IN UINTN                     ProcessorNumber,\r
+  IN BOOLEAN                   EnableOldBSP\r
+  );\r
+\r
 /**\r
   Get pointer to CPU MP Data structure from GUIDed HOB.\r
 \r
index a7e1cdeac11ec4d3649663a0115e9c0aecd4d87f..cdec0108c54b06482d1990496bd0bbb49c3a9a74 100644 (file)
@@ -563,7 +563,7 @@ MpInitLibSwitchBSP (
   IN  BOOLEAN                  EnableOldBSP\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
 }\r
 \r
 /**\r