X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=UefiCpuPkg%2FLibrary%2FMpInitLib%2FMpLib.c;h=c82b9859439c6481f39702e910b5699aaacb9a70;hp=03d6c2d89e007de6bd13b7bdf5819b11fae86b77;hb=e52838d358d5062c4b1ed8e87bdc3d0f527095d3;hpb=cb811673c765b1bdb2e88ed4f8210f784a88fd6c diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 03d6c2d89e..c82b985943 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -1,7 +1,7 @@ /** @file CPU MP Initialize Library common functions. - Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -195,6 +195,10 @@ SaveVolatileRegisters ( VolatileRegisters->Dr6 = AsmReadDr6 (); VolatileRegisters->Dr7 = AsmReadDr7 (); } + + AsmReadGdtr (&VolatileRegisters->Gdtr); + AsmReadIdtr (&VolatileRegisters->Idtr); + VolatileRegisters->Tr = AsmReadTr (); } /** @@ -211,6 +215,7 @@ RestoreVolatileRegisters ( ) { CPUID_VERSION_INFO_EDX VersionInfoEdx; + IA32_TSS_DESCRIPTOR *Tss; AsmWriteCr0 (VolatileRegisters->Cr0); AsmWriteCr3 (VolatileRegisters->Cr3); @@ -231,6 +236,18 @@ RestoreVolatileRegisters ( AsmWriteDr7 (VolatileRegisters->Dr7); } } + + AsmWriteGdtr (&VolatileRegisters->Gdtr); + AsmWriteIdtr (&VolatileRegisters->Idtr); + if (VolatileRegisters->Tr != 0 && + VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit) { + Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base + + VolatileRegisters->Tr); + if (Tss->Bits.P == 1) { + Tss->Bits.Type &= 0xD; // 1101 - Clear busy bit just in case + AsmWriteTr (VolatileRegisters->Tr); + } + } } /** @@ -313,6 +330,7 @@ SortApicId ( CPU_INFO_IN_HOB CpuInfo; UINT32 ApCount; CPU_INFO_IN_HOB *CpuInfoInHob; + volatile UINT32 *StartupApSignal; ApCount = CpuMpData->CpuCount - 1; CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; @@ -337,6 +355,14 @@ SortApicId ( sizeof (CPU_INFO_IN_HOB) ); CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB)); + + // + // Also exchange the StartupApSignal. + // + StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal; + CpuMpData->CpuData[Index3].StartupApSignal = + CpuMpData->CpuData[Index1].StartupApSignal; + CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal; } } @@ -384,7 +410,7 @@ ApInitializeSync ( // // Load microcode on AP // - MicrocodeDetect (CpuMpData); + MicrocodeDetect (CpuMpData, FALSE); // // Sync BSP's MTRR table to AP // @@ -409,16 +435,19 @@ GetProcessorNumber ( UINTN TotalProcessorNumber; UINTN Index; CPU_INFO_IN_HOB *CpuInfoInHob; + UINT32 CurrentApicId; CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; TotalProcessorNumber = CpuMpData->CpuCount; + CurrentApicId = GetApicId (); for (Index = 0; Index < TotalProcessorNumber; Index ++) { - if (CpuInfoInHob[Index].ApicId == GetApicId ()) { + if (CpuInfoInHob[Index].ApicId == CurrentApicId) { *ProcessorNumber = Index; return EFI_SUCCESS; } } + return EFI_NOT_FOUND; } @@ -434,6 +463,8 @@ CollectProcessorCount ( IN CPU_MP_DATA *CpuMpData ) { + UINTN Index; + // // Send 1st broadcast IPI to APs to wakeup APs // @@ -449,6 +480,12 @@ CollectProcessorCount ( CpuPause (); } + if (CpuMpData->CpuCount > 255) { + // + // If there are more than 255 processor found, force to enable X2APIC + // + CpuMpData->X2ApicEnable = TRUE; + } if (CpuMpData->X2ApicEnable) { DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n")); // @@ -465,6 +502,12 @@ CollectProcessorCount ( // Enable x2APIC on BSP // SetApicMode (LOCAL_APIC_MODE_X2APIC); + // + // Set BSP/Aps state to IDLE + // + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); + } } DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ())); // @@ -522,13 +565,13 @@ InitializeApData ( This function will be called from AP reset code if BSP uses WakeUpAP. @param[in] ExchangeInfo Pointer to the MP exchange info buffer - @param[in] NumApsExecuting Number of current executing AP + @param[in] ApIndex Number of current executing AP **/ VOID EFIAPI ApWakeupFunction ( IN MP_CPU_EXCHANGE_INFO *ExchangeInfo, - IN UINTN NumApsExecuting + IN UINTN ApIndex ) { CPU_MP_DATA *CpuMpData; @@ -539,6 +582,7 @@ ApWakeupFunction ( volatile UINT32 *ApStartupSignalBuffer; CPU_INFO_IN_HOB *CpuInfoInHob; UINT64 ApTopOfStack; + UINTN CurrentApicMode; // // AP finished assembly code and begin to execute C code @@ -550,15 +594,20 @@ ApWakeupFunction ( // We need to re-initialize them at here // ProgramVirtualWireMode (); + // + // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler. + // + DisableLvtInterrupts (); SyncLocalApicTimerSetting (CpuMpData); + CurrentApicMode = GetApicMode (); while (TRUE) { if (CpuMpData->InitFlag == ApInitConfig) { // // Add CPU number // InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount); - ProcessorNumber = NumApsExecuting; + ProcessorNumber = ApIndex; // // This is first time AP wakeup, get BIST information from AP stack // @@ -569,7 +618,9 @@ ApWakeupFunction ( // ApInitializeSync (CpuMpData); // - // Sync BSP's Control registers to APs + // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment, + // to initialize AP in InitConfig path. + // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs. // RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE); InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack); @@ -593,6 +644,13 @@ ApWakeupFunction ( // Restore AP's volatile registers saved // RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE); + } else { + // + // The CPU driver might not flush TLB for APs on spot after updating + // page attributes. AP in mwait loop mode needs to take care of it when + // woken up. + // + CpuFlushTlb (); } if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) { @@ -602,7 +660,7 @@ ApWakeupFunction ( SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy); // // Enable source debugging on AP function - // + // EnableDebugAgent (); // // Invoke AP function here @@ -619,11 +677,23 @@ ApWakeupFunction ( ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal; CpuInfoInHob[ProcessorNumber].ApTopOfStack = CpuInfoInHob[CpuMpData->NewBspNumber].ApTopOfStack; } else { - // - // Re-get the CPU APICID and Initial APICID - // - CpuInfoInHob[ProcessorNumber].ApicId = GetApicId (); - CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId (); + if (CpuInfoInHob[ProcessorNumber].ApicId != GetApicId () || + CpuInfoInHob[ProcessorNumber].InitialApicId != GetInitialApicId ()) { + if (CurrentApicMode != GetApicMode ()) { + // + // If APIC mode change happened during AP function execution, + // we do not support APIC ID value changed. + // + ASSERT (FALSE); + CpuDeadLoop (); + } else { + // + // Re-get the CPU APICID and Initial APICID if they are changed + // + CpuInfoInHob[ProcessorNumber].ApicId = GetApicId (); + CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId (); + } + } } } SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished); @@ -634,6 +704,7 @@ ApWakeupFunction ( // AP finished executing C code // InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount); + InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting); // // Place AP is specified loop mode @@ -722,6 +793,8 @@ FillExchangeInfoData ( ) { volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; + UINTN Size; + IA32_SEGMENT_DESCRIPTOR *Selector; ExchangeInfo = CpuMpData->MpCpuExchangeInfo; ExchangeInfo->Lock = 0; @@ -736,6 +809,7 @@ FillExchangeInfoData ( ExchangeInfo->Cr3 = AsmReadCr3 (); ExchangeInfo->CFunction = (UINTN) ApWakeupFunction; + ExchangeInfo->ApIndex = 0; ExchangeInfo->NumApsExecuting = 0; ExchangeInfo->InitFlag = (UINTN) CpuMpData->InitFlag; ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; @@ -743,11 +817,53 @@ FillExchangeInfoData ( ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled (); + ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits; + // // Get the BSP's data of GDT and IDT // AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile); AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile); + + // + // Find a 32-bit code segment + // + Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base; + Size = ExchangeInfo->GdtrProfile.Limit + 1; + while (Size > 0) { + if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) { + ExchangeInfo->ModeTransitionSegment = + (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base); + break; + } + Selector += 1; + Size -= sizeof (IA32_SEGMENT_DESCRIPTOR); + } + + // + // Copy all 32-bit code and 64-bit code into memory with type of + // EfiBootServicesCode to avoid page fault if NX memory protection is enabled. + // + if (CpuMpData->WakeupBufferHigh != 0) { + Size = CpuMpData->AddressMap.RendezvousFunnelSize - + CpuMpData->AddressMap.ModeTransitionOffset; + CopyMem ( + (VOID *)CpuMpData->WakeupBufferHigh, + CpuMpData->AddressMap.RendezvousFunnelAddress + + CpuMpData->AddressMap.ModeTransitionOffset, + Size + ); + + ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh; + } else { + ExchangeInfo->ModeTransitionMemory = (UINT32) + (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset); + } + + ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory + + (UINT32)ExchangeInfo->ModeOffset - + (UINT32)CpuMpData->AddressMap.ModeTransitionOffset; + ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment; } /** @@ -765,6 +881,85 @@ TimedWaitForApFinish ( IN UINT32 TimeLimit ); +/** + Get available system memory below 1MB by specified size. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +BackupAndPrepareWakeupBuffer( + IN CPU_MP_DATA *CpuMpData + ) +{ + CopyMem ( + (VOID *) CpuMpData->BackupBuffer, + (VOID *) CpuMpData->WakeupBuffer, + CpuMpData->BackupBufferSize + ); + CopyMem ( + (VOID *) CpuMpData->WakeupBuffer, + (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress, + CpuMpData->AddressMap.RendezvousFunnelSize + ); +} + +/** + Restore wakeup buffer data. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +RestoreWakeupBuffer( + IN CPU_MP_DATA *CpuMpData + ) +{ + CopyMem ( + (VOID *) CpuMpData->WakeupBuffer, + (VOID *) CpuMpData->BackupBuffer, + CpuMpData->BackupBufferSize + ); +} + +/** + Allocate reset vector buffer. + + @param[in, out] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +AllocateResetVector ( + IN OUT CPU_MP_DATA *CpuMpData + ) +{ + UINTN ApResetVectorSize; + + if (CpuMpData->WakeupBuffer == (UINTN) -1) { + ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + + sizeof (MP_CPU_EXCHANGE_INFO); + + CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize); + CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) + (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize); + CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer ( + CpuMpData->AddressMap.RendezvousFunnelSize - + CpuMpData->AddressMap.ModeTransitionOffset + ); + } + BackupAndPrepareWakeupBuffer (CpuMpData); +} + +/** + Free AP reset vector buffer. + + @param[in] CpuMpData The pointer to CPU MP Data structure. +**/ +VOID +FreeResetVector ( + IN CPU_MP_DATA *CpuMpData + ) +{ + RestoreWakeupBuffer (CpuMpData); +} + /** This function will be called by BSP to wakeup AP. @@ -793,13 +988,15 @@ WakeUpAP ( CpuMpData->FinishedCount = 0; ResetVectorRequired = FALSE; - if (CpuMpData->ApLoopMode == ApInHltLoop || + if (CpuMpData->WakeUpByInitSipiSipi || CpuMpData->InitFlag != ApInitDone) { ResetVectorRequired = TRUE; AllocateResetVector (CpuMpData); FillExchangeInfoData (CpuMpData); SaveLocalApicTimerSetting (CpuMpData); - } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) { + } + + if (CpuMpData->ApLoopMode == ApInMwaitLoop) { // // Get AP target C-state each time when waking up AP, // for it maybe updated by platform again @@ -829,13 +1026,24 @@ WakeUpAP ( } if (CpuMpData->InitFlag == ApInitConfig) { // - // Wait for all potential APs waken up in one specified period + // Here support two methods to collect AP count through adjust + // PcdCpuApInitTimeOutInMicroSeconds values. + // + // one way is set a value to just let the first AP to start the + // initialization, then through the later while loop to wait all Aps + // finsh the initialization. + // The other way is set a value to let all APs finished the initialzation. + // In this case, the later while loop is useless. // TimedWaitForApFinish ( CpuMpData, PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1, PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds) ); + + while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) { + CpuPause(); + } } else { // // Wait all APs waken up if this is not the 1st broadcast of SIPI @@ -873,6 +1081,13 @@ WakeUpAP ( if (ResetVectorRequired) { FreeResetVector (CpuMpData); } + + // + // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with + // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by + // S3SmmInitDone Ppi. + // + CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop); } /** @@ -896,6 +1111,9 @@ CalculateTimeout ( OUT UINT64 *CurrentTime ) { + UINT64 TimeoutInSeconds; + UINT64 TimestampCounterFreq; + // // Read the current value of the performance counter // @@ -911,16 +1129,36 @@ CalculateTimeout ( // // GetPerformanceCounterProperties () returns the timestamp counter's frequency - // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide - // it by 1,000,000, to get the number of ticks for the timeout value. - // - return DivU64x32 ( - MultU64x64 ( - GetPerformanceCounterProperties (NULL, NULL), - TimeoutInMicroseconds - ), - 1000000 - ); + // in Hz. + // + TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL); + + // + // Check the potential overflow before calculate the number of ticks for the timeout value. + // + if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) { + // + // Convert microseconds into seconds if direct multiplication overflows + // + TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000); + // + // Assertion if the final tick count exceeds MAX_UINT64 + // + ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq); + return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds); + } else { + // + // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide + // it by 1,000,000, to get the number of ticks for the timeout value. + // + return DivU64x32 ( + MultU64x64 ( + TimestampCounterFreq, + TimeoutInMicroseconds + ), + 1000000 + ); + } } /** @@ -1282,6 +1520,7 @@ MpInitLibInitialize ( UINT32 MaxLogicalProcessorNumber; UINT32 ApStackSize; MP_ASSEMBLY_ADDRESS_MAP AddressMap; + CPU_VOLATILE_REGISTERS VolatileRegisters; UINTN BufferSize; UINT32 MonitorFilterSize; VOID *MpBuffer; @@ -1292,6 +1531,8 @@ MpInitLibInitialize ( UINTN Index; UINTN ApResetVectorSize; UINTN BackupBufferAddr; + UINTN ApIdtBase; + VOID *MicrocodePatchInRam; OldCpuMpData = GetCpuMpDataFromGuidedHob (); if (OldCpuMpData == NULL) { @@ -1306,24 +1547,52 @@ MpInitLibInitialize ( ApStackSize = PcdGet32(PcdCpuApStackSize); ApLoopMode = GetApLoopMode (&MonitorFilterSize); + // + // Save BSP's Control registers for APs + // + SaveVolatileRegisters (&VolatileRegisters); + BufferSize = ApStackSize * MaxLogicalProcessorNumber; BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber; - BufferSize += sizeof (CPU_MP_DATA); BufferSize += ApResetVectorSize; + BufferSize = ALIGN_VALUE (BufferSize, 8); + BufferSize += VolatileRegisters.Idtr.Limit + 1; + BufferSize += sizeof (CPU_MP_DATA); BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber; MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize)); ASSERT (MpBuffer != NULL); ZeroMem (MpBuffer, BufferSize); Buffer = (UINTN) MpBuffer; + // + // The layout of the Buffer is as below: + // + // +--------------------+ <-- Buffer + // AP Stacks (N) + // +--------------------+ <-- MonitorBuffer + // AP Monitor Filters (N) + // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer) + // Backup Buffer + // +--------------------+ + // Padding + // +--------------------+ <-- ApIdtBase (8-byte boundary) + // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base. + // +--------------------+ <-- CpuMpData + // CPU_MP_DATA + // +--------------------+ <-- CpuMpData->CpuData + // CPU_AP_DATA (N) + // +--------------------+ <-- CpuMpData->CpuInfoInHob + // CPU_INFO_IN_HOB (N) + // +--------------------+ + // MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber); BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber; - CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize); + ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8); + CpuMpData = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1); CpuMpData->Buffer = Buffer; CpuMpData->CpuApStackSize = ApStackSize; CpuMpData->BackupBuffer = BackupBufferAddr; CpuMpData->BackupBufferSize = ApResetVectorSize; - CpuMpData->SaveRestoreFlag = FALSE; CpuMpData->WakeupBuffer = (UINTN) -1; CpuMpData->CpuCount = 1; CpuMpData->BspNumber = 0; @@ -1331,15 +1600,57 @@ MpInitLibInitialize ( CpuMpData->SwitchBspFlag = FALSE; CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1); CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber); + CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize); + // + // If platform has more than one CPU, relocate microcode to memory to reduce + // loading microcode time. + // + MicrocodePatchInRam = NULL; + if (MaxLogicalProcessorNumber > 1) { + MicrocodePatchInRam = AllocatePages ( + EFI_SIZE_TO_PAGES ( + (UINTN)CpuMpData->MicrocodePatchRegionSize + ) + ); + } + if (MicrocodePatchInRam == NULL) { + // + // there is only one processor, or no microcode patch is available, or + // memory allocation failed + // + CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress); + } else { + // + // there are multiple processors, and a microcode patch is available, and + // memory allocation succeeded + // + CopyMem ( + MicrocodePatchInRam, + (VOID *)(UINTN)PcdGet64 (PcdCpuMicrocodePatchAddress), + (UINTN)CpuMpData->MicrocodePatchRegionSize + ); + CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam; + } + InitializeSpinLock(&CpuMpData->MpLock); + + // + // Make sure no memory usage outside of the allocated buffer. + // + ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) == + Buffer + BufferSize); + // - // Save BSP's Control registers to APs + // Duplicate BSP's IDT to APs. + // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1 // - SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters); + CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1); + VolatileRegisters.Idtr.Base = ApIdtBase; + CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters)); // // Set BSP basic information // - InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer); + InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize); // // Save assembly code information // @@ -1349,6 +1660,9 @@ MpInitLibInitialize ( // CpuMpData->ApLoopMode = ApLoopMode; DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode)); + + CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop); + // // Set up APs wakeup signal buffer // @@ -1359,11 +1673,15 @@ MpInitLibInitialize ( // // Load Microcode on BSP // - MicrocodeDetect (CpuMpData); + MicrocodeDetect (CpuMpData, TRUE); // // Store BSP's MTRR setting // MtrrGetAllMtrrs (&CpuMpData->MtrrTable); + // + // Enable the local APIC for Virtual Wire Mode. + // + ProgramVirtualWireMode (); if (OldCpuMpData == NULL) { if (MaxLogicalProcessorNumber > 1) { @@ -1384,16 +1702,12 @@ MpInitLibInitialize ( CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob; for (Index = 0; Index < CpuMpData->CpuCount; Index++) { InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock); - if (CpuInfoInHob[Index].InitialApicId >= 255) { + if (CpuInfoInHob[Index].InitialApicId >= 255 || Index > 254) { CpuMpData->X2ApicEnable = TRUE; } CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE; CpuMpData->CpuData[Index].ApFunction = 0; - CopyMem ( - &CpuMpData->CpuData[Index].VolatileRegisters, - &CpuMpData->CpuData[0].VolatileRegisters, - sizeof (CPU_VOLATILE_REGISTERS) - ); + CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS)); } if (MaxLogicalProcessorNumber > 1) { // @@ -1508,7 +1822,7 @@ MpInitLibGetProcessorInfo ( enabled AP. Otherwise, it will be disabled. @retval EFI_SUCCESS BSP successfully switched. - @retval others Failed to switch BSP. + @retval others Failed to switch BSP. **/ EFI_STATUS @@ -1550,7 +1864,7 @@ SwitchBSPWorker ( // MpInitLibWhoAmI (&CallerNumber); if (CallerNumber != CpuMpData->BspNumber) { - return EFI_SUCCESS; + return EFI_DEVICE_ERROR; } if (ProcessorNumber >= CpuMpData->CpuCount) { @@ -1604,6 +1918,7 @@ SwitchBSPWorker ( ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE); ApicBaseMsr.Bits.BSP = 1; AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64); + ProgramVirtualWireMode (); // // Wait for old BSP finished AP task @@ -1683,7 +1998,7 @@ EnableDisableApWorker ( if (!EnableAP) { SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled); } else { - SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle); + ResetProcessorToIdleState (ProcessorNumber); } if (HealthFlag != NULL) { @@ -2086,41 +2401,3 @@ GetCpuMpDataFromGuidedHob ( return CpuMpData; } -/** - Get available system memory below 1MB by specified size. - - @param[in] CpuMpData The pointer to CPU MP Data structure. -**/ -VOID -BackupAndPrepareWakeupBuffer( - IN CPU_MP_DATA *CpuMpData - ) -{ - CopyMem ( - (VOID *) CpuMpData->BackupBuffer, - (VOID *) CpuMpData->WakeupBuffer, - CpuMpData->BackupBufferSize - ); - CopyMem ( - (VOID *) CpuMpData->WakeupBuffer, - (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress, - CpuMpData->AddressMap.RendezvousFunnelSize - ); -} - -/** - Restore wakeup buffer data. - - @param[in] CpuMpData The pointer to CPU MP Data structure. -**/ -VOID -RestoreWakeupBuffer( - IN CPU_MP_DATA *CpuMpData - ) -{ - CopyMem ( - (VOID *) CpuMpData->WakeupBuffer, - (VOID *) CpuMpData->BackupBuffer, - CpuMpData->BackupBufferSize - ); -}