X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=UefiCpuPkg%2FLibrary%2FMpInitLib%2FDxeMpLib.c;h=e832c16ecacec771b7a5be37a77520a9942b17c6;hp=7f3900b4c10d8fb577da5714cddf43e6bae5601e;hb=523152618d20a58c9ad55203fa6e5b8bebe938f0;hpb=8677a56af68ea7fc93938c710be2ec53752ae961 diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c index 7f3900b4c1..e832c16eca 100644 --- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c @@ -16,8 +16,13 @@ #include #include +#include +#include + +#include #define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100)) +#define AP_SAFE_STACK_SIZE 128 CPU_MP_DATA *mCpuMpData = NULL; EFI_EVENT mCheckAllApsEvent = NULL; @@ -25,6 +30,23 @@ EFI_EVENT mMpInitExitBootServicesEvent = NULL; EFI_EVENT mLegacyBootEvent = NULL; volatile BOOLEAN mStopCheckAllApsStatus = TRUE; VOID *mReservedApLoopFunc = NULL; +UINTN mReservedTopOfApStack; +volatile UINT32 mNumberToFinish = 0; + +/** + Enable Debug Agent to support source debugging on AP function. + +**/ +VOID +EnableDebugAgent ( + VOID + ) +{ + // + // Initialize Debug Agent to support source level debug in DXE phase + // + InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL); +} /** Get the pointer to CPU MP Data structure. @@ -54,72 +76,41 @@ SaveCpuMpData ( } /** - Allocate reset vector buffer. - - @param[in, out] CpuMpData The pointer to CPU MP Data structure. -**/ -VOID -AllocateResetVector ( - IN OUT CPU_MP_DATA *CpuMpData - ) -{ - EFI_STATUS Status; - UINTN ApResetVectorSize; - EFI_PHYSICAL_ADDRESS StartAddress; - - if (CpuMpData->SaveRestoreFlag) { - BackupAndPrepareWakeupBuffer (CpuMpData); - } else { - ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + - sizeof (MP_CPU_EXCHANGE_INFO); - - StartAddress = BASE_1MB; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (ApResetVectorSize), - &StartAddress - ); - ASSERT_EFI_ERROR (Status); - - CpuMpData->WakeupBuffer = (UINTN) StartAddress; - CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) - (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize); - // - // copy AP reset code in it - // - CopyMem ( - (VOID *) CpuMpData->WakeupBuffer, - (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress, - CpuMpData->AddressMap.RendezvousFunnelSize - ); - } -} + Get available system memory below 1MB by specified size. -/** - Free AP reset vector buffer. + @param[in] WakeupBufferSize Wakeup buffer size required - @param[in] CpuMpData The pointer to CPU MP Data structure. + @retval other Return wakeup buffer address below 1MB. + @retval -1 Cannot find free memory below 1MB. **/ -VOID -FreeResetVector ( - IN CPU_MP_DATA *CpuMpData +UINTN +GetWakeupBuffer ( + IN UINTN WakeupBufferSize ) { - EFI_STATUS Status; - UINTN ApResetVectorSize; - - if (CpuMpData->SaveRestoreFlag) { - RestoreWakeupBuffer (CpuMpData); - } else { - ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize + - sizeof (MP_CPU_EXCHANGE_INFO); + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS StartAddress; + + StartAddress = BASE_1MB; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (WakeupBufferSize), + &StartAddress + ); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { Status = gBS->FreePages( - (EFI_PHYSICAL_ADDRESS)CpuMpData->WakeupBuffer, - EFI_SIZE_TO_PAGES (ApResetVectorSize) + StartAddress, + EFI_SIZE_TO_PAGES (WakeupBufferSize) ); ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n", + (UINTN) StartAddress, WakeupBufferSize)); + } else { + StartAddress = (EFI_PHYSICAL_ADDRESS) -1; } + return (UINTN) StartAddress; } /** @@ -241,11 +232,19 @@ RelocateApLoop ( CPU_MP_DATA *CpuMpData; BOOLEAN MwaitSupport; ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc; + UINTN ProcessorNumber; + MpInitLibWhoAmI (&ProcessorNumber); CpuMpData = GetCpuMpData (); MwaitSupport = IsMwaitSupport (); - AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) Buffer; - AsmRelocateApLoopFunc (MwaitSupport, CpuMpData->ApTargetCState, CpuMpData->PmCodeSegment); + AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc; + AsmRelocateApLoopFunc ( + MwaitSupport, + CpuMpData->ApTargetCState, + CpuMpData->PmCodeSegment, + mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE, + (UINTN) &mNumberToFinish + ); // // It should never reach here // @@ -270,10 +269,13 @@ MpInitChangeApLoopCallback ( CPU_MP_DATA *CpuMpData; CpuMpData = GetCpuMpData (); - CpuMpData->SaveRestoreFlag = TRUE; CpuMpData->PmCodeSegment = GetProtectedModeCS (); CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode); - WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, mReservedApLoopFunc); + mNumberToFinish = CpuMpData->CpuCount - 1; + WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL); + while (mNumberToFinish > 0) { + CpuPause (); + } DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__)); } @@ -287,8 +289,13 @@ InitMpGlobalData ( IN CPU_MP_DATA *CpuMpData ) { - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS Address; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + UINTN ApSafeBufferSize; + UINTN Index; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc; + UINTN StackBase; + CPU_INFO_IN_HOB *CpuInfoInHob; SaveCpuMpData (CpuMpData); @@ -299,6 +306,46 @@ InitMpGlobalData ( return; } + if (PcdGetBool (PcdCpuStackGuard)) { + // + // One extra page at the bottom of the stack is needed for Guard page. + // + if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) { + DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n")); + ASSERT (FALSE); + } + + // + // DXE will reuse stack allocated for APs at PEI phase if it's available. + // Let's check it here. + // + // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of + // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be + // set here. + // + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + for (Index = 0; Index < CpuMpData->CpuCount; ++Index) { + if (CpuInfoInHob != NULL && CpuInfoInHob[Index].ApTopOfStack != 0) { + StackBase = CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize; + } else { + StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize; + } + + Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc); + ASSERT_EFI_ERROR (Status); + + Status = gDS->SetMemorySpaceAttributes ( + StackBase, + EFI_PAGES_TO_SIZE (1), + MemDesc.Attributes | EFI_MEMORY_RP + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n", + (UINT64)StackBase, (UINT64)Index)); + } + } + // // Avoid APs access invalid buffer data which allocated by BootServices, // so we will allocate reserved data for AP loop code. We also need to @@ -307,16 +354,21 @@ InitMpGlobalData ( // Allocating it in advance since memory services are not available in // Exit Boot Services callback function. // + ApSafeBufferSize = CpuMpData->AddressMap.RelocateApLoopFuncSize; + ApSafeBufferSize += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE; + Address = BASE_4GB - 1; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, - EFI_SIZE_TO_PAGES (sizeof (CpuMpData->AddressMap.RelocateApLoopFuncSize)), + EFI_SIZE_TO_PAGES (ApSafeBufferSize), &Address ); ASSERT_EFI_ERROR (Status); mReservedApLoopFunc = (VOID *) (UINTN) Address; ASSERT (mReservedApLoopFunc != NULL); + mReservedTopOfApStack = (UINTN) Address + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize)); + ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0); CopyMem ( mReservedApLoopFunc, CpuMpData->AddressMap.RelocateApLoopFuncAddress, @@ -389,7 +441,7 @@ InitMpGlobalData ( EFI_EVENT is defined in CreateEvent() in the Unified Extensible Firmware Interface Specification. - @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for APs to return from Procedure, either for blocking or non-blocking mode. Zero means infinity. If the timeout expires before @@ -499,7 +551,7 @@ MpInitLibStartupAllAPs ( EFI_EVENT is defined in CreateEvent() in the Unified Extensible Firmware Interface Specification. - @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for + @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for this AP to finish this Procedure, either for blocking or non-blocking mode. Zero means infinity. If the timeout expires before @@ -608,29 +660,38 @@ MpInitLibSwitchBSP ( IN BOOLEAN EnableOldBSP ) { - EFI_STATUS Status; - BOOLEAN OldInterruptState; + EFI_STATUS Status; + EFI_TIMER_ARCH_PROTOCOL *Timer; + UINT64 TimerPeriod; + TimerPeriod = 0; // - // Before send both BSP and AP to a procedure to exchange their roles, - // interrupt must be disabled. This is because during the exchange role - // process, 2 CPU may use 1 stack. If interrupt happens, the stack will - // be corrupted, since interrupt return address will be pushed to stack - // by hardware. + // Locate Timer Arch Protocol // - OldInterruptState = SaveAndDisableInterrupts (); + Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer); + if (EFI_ERROR (Status)) { + Timer = NULL; + } - // - // Mask LINT0 & LINT1 for the old BSP - // - DisableLvtInterrupts (); + if (Timer != NULL) { + // + // Save current rate of DXE Timer + // + Timer->GetTimerPeriod (Timer, &TimerPeriod); + // + // Disable DXE Timer and drain pending interrupts + // + Timer->SetTimerPeriod (Timer, 0); + } Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP); - // - // Restore interrupt state. - // - SetInterruptState (OldInterruptState); + if (Timer != NULL) { + // + // Enable and restore rate of DXE Timer + // + Timer->SetTimerPeriod (Timer, TimerPeriod); + } return Status; }