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
// 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
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
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
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
\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
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
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