/** @file\r
CPU MP Initialize Library common functions.\r
\r
- Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2016 - 2017, 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
\r
/**\r
The function will check if BSP Execute Disable is enabled.\r
- DxeIpl may have enabled Execute Disable for BSP,\r
- APs need to get the status and sync up the settings.\r
+\r
+ DxeIpl may have enabled Execute Disable for BSP, APs need to\r
+ get the status and sync up the settings.\r
+ If BSP's CR0.Paging is not set, BSP execute Disble feature is\r
+ not working actually.\r
\r
@retval TRUE BSP Execute Disable is enabled.\r
@retval FALSE BSP Execute Disable is not enabled.\r
CPUID_EXTENDED_CPU_SIG_EDX Edx;\r
MSR_IA32_EFER_REGISTER EferMsr;\r
BOOLEAN Enabled;\r
+ IA32_CR0 Cr0;\r
\r
Enabled = FALSE;\r
- AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);\r
- if (Eax >= CPUID_EXTENDED_CPU_SIG) {\r
- AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);\r
+ Cr0.UintN = AsmReadCr0 ();\r
+ if (Cr0.Bits.PG != 0) {\r
//\r
- // CPUID 0x80000001\r
- // Bit 20: Execute Disable Bit available.\r
+ // If CR0 Paging bit is set\r
//\r
- if (Edx.Bits.NX != 0) {\r
- EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);\r
+ if (Eax >= CPUID_EXTENDED_CPU_SIG) {\r
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);\r
//\r
- // MSR 0xC0000080\r
- // Bit 11: Execute Disable Bit enable.\r
+ // CPUID 0x80000001\r
+ // Bit 20: Execute Disable Bit available.\r
//\r
- if (EferMsr.Bits.NXE != 0) {\r
- Enabled = TRUE;\r
+ if (Edx.Bits.NX != 0) {\r
+ EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
+ //\r
+ // MSR 0xC0000080\r
+ // Bit 11: Execute Disable Bit enable.\r
+ //\r
+ if (EferMsr.Bits.NXE != 0) {\r
+ Enabled = TRUE;\r
+ }\r
}\r
}\r
}\r
ReleaseSpinLock (&CpuData->ApLock);\r
}\r
\r
+/**\r
+ Save BSP's local APIC timer setting.\r
+\r
+ @param[in] CpuMpData Pointer to CPU MP Data\r
+**/\r
+VOID\r
+SaveLocalApicTimerSetting (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ //\r
+ // Record the current local APIC timer setting of BSP\r
+ //\r
+ GetApicTimerState (\r
+ &CpuMpData->DivideValue,\r
+ &CpuMpData->PeriodicMode,\r
+ &CpuMpData->Vector\r
+ );\r
+ CpuMpData->CurrentTimerCount = GetApicTimerCurrentCount ();\r
+ CpuMpData->TimerInterruptState = GetApicTimerInterruptState ();\r
+}\r
+\r
+/**\r
+ Sync local APIC timer setting from BSP to AP.\r
+\r
+ @param[in] CpuMpData Pointer to CPU MP Data\r
+**/\r
+VOID\r
+SyncLocalApicTimerSetting (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ //\r
+ // Sync local APIC timer setting from BSP to AP\r
+ //\r
+ InitializeApicTimer (\r
+ CpuMpData->DivideValue,\r
+ CpuMpData->CurrentTimerCount,\r
+ CpuMpData->PeriodicMode,\r
+ CpuMpData->Vector\r
+ );\r
+ //\r
+ // Disable AP's local APIC timer interrupt\r
+ //\r
+ DisableApicTimerInterrupt ();\r
+}\r
+\r
/**\r
Save the volatile registers required to be restored following INIT IPI.\r
\r
\r
CpuMpData = (CPU_MP_DATA *) Buffer;\r
//\r
- // Sync BSP's MTRR table to AP\r
- //\r
- MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
- //\r
// Load microcode on AP\r
//\r
MicrocodeDetect (CpuMpData);\r
+ //\r
+ // Sync BSP's MTRR table to AP\r
+ //\r
+ MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
}\r
\r
/**\r
Find the current Processor number by APIC ID.\r
\r
- @param[in] CpuMpData Pointer to PEI CPU MP Data\r
- @param[in] ProcessorNumber Return the pocessor number found\r
+ @param[in] CpuMpData Pointer to PEI CPU MP Data\r
+ @param[out] ProcessorNumber Return the pocessor number found\r
\r
@retval EFI_SUCCESS ProcessorNumber is found and returned.\r
@retval EFI_NOT_FOUND ProcessorNumber is not found.\r
IN CPU_MP_DATA *CpuMpData\r
)\r
{\r
+ UINTN Index;\r
+\r
//\r
// Send 1st broadcast IPI to APs to wakeup APs\r
//\r
// Enable x2APIC on BSP\r
//\r
SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
+ //\r
+ // Set BSP/Aps state to IDLE\r
+ //\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
+ }\r
}\r
DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
//\r
return CpuMpData->CpuCount;\r
}\r
\r
-/*\r
+/**\r
Initialize CPU AP Data when AP is wakeup at the first time.\r
\r
@param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
@param[in] ProcessorNumber The handle number of processor\r
@param[in] BistData Processor BIST data\r
+ @param[in] ApTopOfStack Top of AP stack\r
\r
**/\r
VOID\r
//\r
CpuMpData = ExchangeInfo->CpuMpData;\r
\r
- ProgramVirtualWireMode (); \r
+ //\r
+ // AP's local APIC settings will be lost after received INIT IPI\r
+ // We need to re-initialize them at here\r
+ //\r
+ ProgramVirtualWireMode ();\r
+ SyncLocalApicTimerSetting (CpuMpData);\r
\r
while (TRUE) {\r
if (CpuMpData->InitFlag == ApInitConfig) {\r
if (Procedure != NULL) {\r
SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
//\r
+ // Enable source debugging on AP function\r
+ // \r
+ EnableDebugAgent ();\r
+ //\r
// Invoke AP function here\r
//\r
Procedure (Parameter);\r
\r
ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
\r
+ ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;\r
+\r
//\r
// Get the BSP's data of GDT and IDT\r
//\r
ResetVectorRequired = TRUE;\r
AllocateResetVector (CpuMpData);\r
FillExchangeInfoData (CpuMpData);\r
+ SaveLocalApicTimerSetting (CpuMpData);\r
} else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
//\r
// Get AP target C-state each time when waking up AP,\r
// Store BSP's MTRR setting\r
//\r
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
+ //\r
+ // Enable the local APIC for Virtual Wire Mode.\r
+ //\r
+ ProgramVirtualWireMode ();\r
\r
if (OldCpuMpData == NULL) {\r
if (MaxLogicalProcessorNumber > 1) {\r
UINTN CallerNumber;\r
CPU_STATE State;\r
MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
+ BOOLEAN OldInterruptState;\r
+ BOOLEAN OldTimerInterruptState;\r
+\r
+ //\r
+ // Save and Disable Local APIC timer interrupt\r
+ //\r
+ OldTimerInterruptState = GetApicTimerInterruptState ();\r
+ DisableApicTimerInterrupt ();\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
CpuMpData = GetCpuMpData ();\r
\r
//\r
if (!EnableOldBSP) {\r
SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);\r
+ } else {\r
+ SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);\r
}\r
//\r
// Save new BSP number\r
//\r
CpuMpData->BspNumber = (UINT32) ProcessorNumber;\r
\r
+ //\r
+ // Restore interrupt state.\r
+ //\r
+ SetInterruptState (OldInterruptState);\r
+\r
+ if (OldTimerInterruptState) {\r
+ EnableApicTimerInterrupt ();\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
simultaneously.\r
@param[in] WaitEvent The event created by the caller with CreateEvent()\r
service.\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.\r
@param[in] ProcedureArgument The parameter passed into Procedure for\r
@param[in] ProcessorNumber The handle number of the AP.\r
@param[in] WaitEvent The event created by the caller with CreateEvent()\r
service.\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.\r
@param[in] ProcedureArgument The parameter passed into Procedure for\r