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
//\r
// Load microcode on AP\r
//\r
- MicrocodeDetect (CpuMpData);\r
+ MicrocodeDetect (CpuMpData, FALSE);\r
//\r
// Sync BSP's MTRR table to AP\r
//\r
//\r
ApInitializeSync (CpuMpData);\r
//\r
- // Sync BSP's Control registers to APs\r
+ // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,\r
+ // to initialize AP in InitConfig path.\r
+ // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.\r
//\r
RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);\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
SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
//\r
// Enable source debugging on AP function\r
- // \r
+ //\r
EnableDebugAgent ();\r
//\r
// Invoke AP function here\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 (ExchangeInfo->ModeTransitionMemory != 0) {\r
+ if (CpuMpData->WakeupBufferHigh != 0) {\r
Size = CpuMpData->AddressMap.RendezvousFunnelSize -\r
CpuMpData->AddressMap.ModeTransitionOffset;\r
CopyMem (\r
- (VOID *)(UINTN)ExchangeInfo->ModeTransitionMemory,\r
+ (VOID *)CpuMpData->WakeupBufferHigh,\r
CpuMpData->AddressMap.RendezvousFunnelAddress +\r
CpuMpData->AddressMap.ModeTransitionOffset,\r
Size\r
);\r
\r
- ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory;\r
- ExchangeInfo->ModeHighMemory += (UINT32)ExchangeInfo->ModeOffset -\r
- (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
- ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\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->MpCpuExchangeInfo->ModeTransitionMemory = (UINT32)\r
- GetModeTransitionBuffer (\r
- CpuMpData->AddressMap.RendezvousFunnelSize -\r
- CpuMpData->AddressMap.ModeTransitionOffset\r
- );\r
+ CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (\r
+ CpuMpData->AddressMap.RendezvousFunnelSize -\r
+ CpuMpData->AddressMap.ModeTransitionOffset\r
+ );\r
}\r
BackupAndPrepareWakeupBuffer (CpuMpData);\r
}\r
\r
//\r
// GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
- // in Hz. \r
+ // in Hz.\r
//\r
TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);\r
\r
UINT32 MaxLogicalProcessorNumber;\r
UINT32 ApStackSize;\r
MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
+ CPU_VOLATILE_REGISTERS VolatileRegisters;\r
UINTN BufferSize;\r
UINT32 MonitorFilterSize;\r
VOID *MpBuffer;\r
UINTN Index;\r
UINTN ApResetVectorSize;\r
UINTN BackupBufferAddr;\r
+ UINTN ApIdtBase;\r
+ VOID *MicrocodePatchInRam;\r
\r
OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
if (OldCpuMpData == NULL) {\r
ApStackSize = PcdGet32(PcdCpuApStackSize);\r
ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
\r
+ //\r
+ // Save BSP's Control registers for APs\r
+ //\r
+ SaveVolatileRegisters (&VolatileRegisters);\r
+\r
BufferSize = ApStackSize * MaxLogicalProcessorNumber;\r
BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
- BufferSize += sizeof (CPU_MP_DATA);\r
BufferSize += ApResetVectorSize;\r
+ BufferSize = ALIGN_VALUE (BufferSize, 8);\r
+ BufferSize += VolatileRegisters.Idtr.Limit + 1;\r
+ BufferSize += sizeof (CPU_MP_DATA);\r
BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
ASSERT (MpBuffer != NULL);\r
ZeroMem (MpBuffer, BufferSize);\r
Buffer = (UINTN) MpBuffer;\r
\r
+ //\r
+ // The layout of the Buffer is as below:\r
+ //\r
+ // +--------------------+ <-- Buffer\r
+ // AP Stacks (N)\r
+ // +--------------------+ <-- MonitorBuffer\r
+ // AP Monitor Filters (N)\r
+ // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)\r
+ // Backup Buffer\r
+ // +--------------------+\r
+ // Padding\r
+ // +--------------------+ <-- ApIdtBase (8-byte boundary)\r
+ // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.\r
+ // +--------------------+ <-- CpuMpData\r
+ // CPU_MP_DATA\r
+ // +--------------------+ <-- CpuMpData->CpuData\r
+ // CPU_AP_DATA (N)\r
+ // +--------------------+ <-- CpuMpData->CpuInfoInHob\r
+ // CPU_INFO_IN_HOB (N)\r
+ // +--------------------+\r
+ //\r
MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
- CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
+ ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);\r
+ CpuMpData = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1);\r
CpuMpData->Buffer = Buffer;\r
CpuMpData->CpuApStackSize = ApStackSize;\r
CpuMpData->BackupBuffer = BackupBufferAddr;\r
CpuMpData->SwitchBspFlag = FALSE;\r
CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
- CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+ //\r
+ // If platform has more than one CPU, relocate microcode to memory to reduce\r
+ // loading microcode time.\r
+ //\r
+ MicrocodePatchInRam = NULL;\r
+ if (MaxLogicalProcessorNumber > 1) {\r
+ MicrocodePatchInRam = AllocatePages (\r
+ EFI_SIZE_TO_PAGES (\r
+ (UINTN)CpuMpData->MicrocodePatchRegionSize\r
+ )\r
+ );\r
+ }\r
+ if (MicrocodePatchInRam == NULL) {\r
+ //\r
+ // there is only one processor, or no microcode patch is available, or\r
+ // memory allocation failed\r
+ //\r
+ CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+ } else {\r
+ //\r
+ // there are multiple processors, and a microcode patch is available, and\r
+ // memory allocation succeeded\r
+ //\r
+ CopyMem (\r
+ MicrocodePatchInRam,\r
+ (VOID *)(UINTN)PcdGet64 (PcdCpuMicrocodePatchAddress),\r
+ (UINTN)CpuMpData->MicrocodePatchRegionSize\r
+ );\r
+ CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;\r
+ }\r
+\r
InitializeSpinLock(&CpuMpData->MpLock);\r
+\r
//\r
- // Save BSP's Control registers to APs\r
+ // Make sure no memory usage outside of the allocated buffer.\r
//\r
- SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
+ ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==\r
+ Buffer + BufferSize);\r
+\r
+ //\r
+ // Duplicate BSP's IDT to APs.\r
+ // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1\r
+ //\r
+ CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);\r
+ VolatileRegisters.Idtr.Base = ApIdtBase;\r
+ CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));\r
//\r
// Set BSP basic information\r
//\r
//\r
// Load Microcode on BSP\r
//\r
- MicrocodeDetect (CpuMpData);\r
+ MicrocodeDetect (CpuMpData, TRUE);\r
//\r
// Store BSP's MTRR setting\r
//\r
}\r
CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;\r
CpuMpData->CpuData[Index].ApFunction = 0;\r
- CopyMem (\r
- &CpuMpData->CpuData[Index].VolatileRegisters,\r
- &CpuMpData->CpuData[0].VolatileRegisters,\r
- sizeof (CPU_VOLATILE_REGISTERS)\r
- );\r
+ CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS));\r
}\r
if (MaxLogicalProcessorNumber > 1) {\r
//\r
enabled AP. Otherwise, it will be disabled.\r
\r
@retval EFI_SUCCESS BSP successfully switched.\r
- @retval others Failed to switch BSP. \r
+ @retval others Failed to switch BSP.\r
\r
**/\r
EFI_STATUS\r