/** @file\r
CPU MP Initialize Library common functions.\r
\r
- Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2016 - 2018, 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
VolatileRegisters->Dr6 = AsmReadDr6 ();\r
VolatileRegisters->Dr7 = AsmReadDr7 ();\r
}\r
+\r
+ AsmReadGdtr (&VolatileRegisters->Gdtr);\r
+ AsmReadIdtr (&VolatileRegisters->Idtr);\r
+ VolatileRegisters->Tr = AsmReadTr ();\r
}\r
\r
/**\r
)\r
{\r
CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
+ IA32_TSS_DESCRIPTOR *Tss;\r
\r
AsmWriteCr0 (VolatileRegisters->Cr0);\r
AsmWriteCr3 (VolatileRegisters->Cr3);\r
AsmWriteDr7 (VolatileRegisters->Dr7);\r
}\r
}\r
+\r
+ AsmWriteGdtr (&VolatileRegisters->Gdtr);\r
+ AsmWriteIdtr (&VolatileRegisters->Idtr);\r
+ if (VolatileRegisters->Tr != 0 &&\r
+ VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit) {\r
+ Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +\r
+ VolatileRegisters->Tr);\r
+ if (Tss->Bits.P == 1) {\r
+ Tss->Bits.Type &= 0xD; // 1101 - Clear busy bit just in case\r
+ AsmWriteTr (VolatileRegisters->Tr);\r
+ }\r
+ }\r
}\r
\r
/**\r
CPU_INFO_IN_HOB CpuInfo;\r
UINT32 ApCount;\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
+ volatile UINT32 *StartupApSignal;\r
\r
ApCount = CpuMpData->CpuCount - 1;\r
CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
sizeof (CPU_INFO_IN_HOB)\r
);\r
CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));\r
+\r
+ //\r
+ // Also exchange the StartupApSignal.\r
+ //\r
+ StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;\r
+ CpuMpData->CpuData[Index3].StartupApSignal =\r
+ CpuMpData->CpuData[Index1].StartupApSignal;\r
+ CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;\r
}\r
}\r
\r
This function will be called from AP reset code if BSP uses WakeUpAP.\r
\r
@param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
- @param[in] NumApsExecuting Number of current executing AP\r
+ @param[in] ApIndex Number of current executing AP\r
**/\r
VOID\r
EFIAPI\r
ApWakeupFunction (\r
IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
- IN UINTN NumApsExecuting\r
+ IN UINTN ApIndex\r
)\r
{\r
CPU_MP_DATA *CpuMpData;\r
// We need to re-initialize them at here\r
//\r
ProgramVirtualWireMode ();\r
+ //\r
+ // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.\r
+ //\r
+ DisableLvtInterrupts ();\r
SyncLocalApicTimerSetting (CpuMpData);\r
\r
CurrentApicMode = GetApicMode ();\r
// Add CPU number\r
//\r
InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
- ProcessorNumber = NumApsExecuting;\r
+ ProcessorNumber = ApIndex;\r
//\r
// This is first time AP wakeup, get BIST information from AP stack\r
//\r
// Restore AP's volatile registers saved\r
//\r
RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
+ } else {\r
+ //\r
+ // The CPU driver might not flush TLB for APs on spot after updating\r
+ // page attributes. AP in mwait loop mode needs to take care of it when\r
+ // woken up.\r
+ //\r
+ CpuFlushTlb ();\r
}\r
\r
if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
// AP finished executing C code\r
//\r
InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
+ InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r
\r
//\r
// Place AP is specified loop mode\r
)\r
{\r
volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
+ UINTN Size;\r
+ IA32_SEGMENT_DESCRIPTOR *Selector;\r
\r
ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
ExchangeInfo->Lock = 0;\r
ExchangeInfo->Cr3 = AsmReadCr3 ();\r
\r
ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
+ ExchangeInfo->ApIndex = 0;\r
ExchangeInfo->NumApsExecuting = 0;\r
ExchangeInfo->InitFlag = (UINTN) CpuMpData->InitFlag;\r
ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
//\r
AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
+\r
+ //\r
+ // Find a 32-bit code segment\r
+ //\r
+ Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;\r
+ Size = ExchangeInfo->GdtrProfile.Limit + 1;\r
+ while (Size > 0) {\r
+ if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {\r
+ ExchangeInfo->ModeTransitionSegment =\r
+ (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);\r
+ break;\r
+ }\r
+ Selector += 1;\r
+ Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+ }\r
+\r
+ //\r
+ // Copy all 32-bit code and 64-bit code into memory with type of\r
+ // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.\r
+ //\r
+ if (CpuMpData->WakeupBufferHigh != 0) {\r
+ Size = CpuMpData->AddressMap.RendezvousFunnelSize -\r
+ CpuMpData->AddressMap.ModeTransitionOffset;\r
+ CopyMem (\r
+ (VOID *)CpuMpData->WakeupBufferHigh,\r
+ CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+ CpuMpData->AddressMap.ModeTransitionOffset,\r
+ Size\r
+ );\r
+\r
+ ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;\r
+ } else {\r
+ ExchangeInfo->ModeTransitionMemory = (UINT32)\r
+ (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);\r
+ }\r
+\r
+ ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +\r
+ (UINT32)ExchangeInfo->ModeOffset -\r
+ (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
+ ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\r
}\r
\r
/**\r
CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);\r
CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
(CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
+ CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (\r
+ CpuMpData->AddressMap.RendezvousFunnelSize -\r
+ CpuMpData->AddressMap.ModeTransitionOffset\r
+ );\r
}\r
BackupAndPrepareWakeupBuffer (CpuMpData);\r
}\r
}\r
if (CpuMpData->InitFlag == ApInitConfig) {\r
//\r
- // Wait for all potential APs waken up in one specified period\r
+ // Here support two methods to collect AP count through adjust\r
+ // PcdCpuApInitTimeOutInMicroSeconds values.\r
+ //\r
+ // one way is set a value to just let the first AP to start the\r
+ // initialization, then through the later while loop to wait all Aps\r
+ // finsh the initialization.\r
+ // The other way is set a value to let all APs finished the initialzation.\r
+ // In this case, the later while loop is useless.\r
//\r
TimedWaitForApFinish (\r
CpuMpData,\r
PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,\r
PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)\r
);\r
+\r
+ while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {\r
+ CpuPause();\r
+ }\r
} else {\r
//\r
// Wait all APs waken up if this is not the 1st broadcast of SIPI\r
//\r
// Set BSP basic information\r
//\r
- InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer);\r
+ InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);\r
//\r
// Save assembly code information\r
//\r
ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
ApicBaseMsr.Bits.BSP = 1;\r
AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+ ProgramVirtualWireMode ();\r
\r
//\r
// Wait for old BSP finished AP task\r