Laszlo, I agree with many of your points.
If you prefer, I can consolidate the UefiCpuPkg updates including 6 items you list below into my UefiCpuPkg series and get that checked in first so you can focus on OVMF SMM. Thanks, Mike >-----Original Message----- >From: edk2-devel [mailto:[email protected]] On Behalf Of >Laszlo Ersek >Sent: Friday, October 16, 2015 11:04 PM >To: Kinney, Michael D; [email protected] >Subject: Re: [edk2] [PATCH v3 04/52] UefiCpuPkg: CpuDxe: broadcast MTRR >changes to APs > >On 10/16/15 23:17, Kinney, Michael D wrote: >> Laszlo, >> >> Here is a proposed fix on top of your v3 patch services to address a >> race condition that was introduced by the v3 patch series call to >> StartupAllAPs() with SingleThread set to TRUE in the MP >> initialization. If the APs have not entered their idle loop before >> StartupAllAPs() is called, then some of the APs will be in an >> unexpected state, and StartupAllAPs() will hang. This is the hang >> condition that is only seen when SingleThread parameter is set to >> TRUE and StartupAllAPs() is called very shortly after >> mAPsAlreadyInitFinished is set to TRUE that releases the APs to >> complete their initialization. >> >> I added an internal function that checks to see if all APs are in the >> sleeping state in the idle loop. On the first call to >> StartupAllAPs(), this internal function is used to make sure the APs >> are in a state that is compatible with StartupAllAPs() being used. I >> put this check in the first call to StartupAllAPs(), so we do not >> take the delay to wait for the APs unconditionally in the MP init >> code. Other work can get done while the APs work their way to their >> idle loop sleeping state. >> >> The one item remaining is to have a timeout with an ASSERT() if >> timeout is triggered in first call to StartupAllAPs() waiting for the >> APs to enter idle loop. >> >> I also reordered some of the actions InitializeMpSupport(), so the MP >> Services Protocol and call to StartupAllAPs() are done as late as >> possible to give APs more time to get to idle loop. >> >> Please merge this into your patch series. > >Many thanks for this! > >I have two comments: > > >First, I don't think that it is my patch "UefiCpuPkg: CpuDxe: broadcast >MTRR changes to APs" that *introduces* the race condition, with the >early call to StartupAllAps(). I believe that the race condition exists >in the current code, and my patch only exposes it. > >Namely, my patch adds the StartupAllAps() call right before the MP >services protocol interface is installed. Considering a case where my >patch is not applied, but another driver registers a protocol notify >callback for MP services, that callback would be invoked on the stack of >InstallMultipleProtocolInterfaces(), while some of the APs might not >have entered their idle loop yet. If the callback in that other driver >located the protocol instance quickly, and called StartupAllAps() with >similar arguments (which would be a valid thing to do), the same issue >could be triggered. So I think the race is already there; the protocol >interface gets installed too early. > >Which leads me to think that the code you add here under >(!mStartupAllAPsCalled) should be executed unconditionally, right after >"mAPsAlreadyInitFinished is set to TRUE that releases the APs to >complete their initialization". We shouldn't install the MP services >protocol interface until initialization is complete, and allows for any >kinds of calls through that interface. > > >Second, I think I'll put aside the SMM series for a short period, and >work on a smaller UefiCpuPkg + OvmfPkg series. I'm thinking about six >patches: > >(1) split out the crux of this patch (without the code rearrangement) >and state that it fixes the existent (although mostly un-triggered) race >condition > >(2) refine the above by introducing the timeout you mention. I'm thinking > > GetTimeInNanoSecond (GetPerformanceCounter ()) > >should be a good way to measure the elapsed time; it seems to be a >pattern used elsewhere in the tree. This will also require a new PCD. >What default would you suggest for the timeout? > >(3) add the rearrangement that gives more time to the APs to enter their >idle loops > >(4) Include my MTRR broadcast patch > >(5) Separately, implement your other suggestion with >gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds, from ><http://thread.gmane.org/gmane.comp.bios.edk2.devel/2415/focus=141501>. > >(6) Xiao Guangrong provided us with the info for wording a commit for >OvmfPkg where the timeout from (5) would be increased. > >Obviously I'll keep your authorship wherever appropriate. > >Once these are in, I'd resume working on the SMM series. > > >... Actually, what do you think about committing your v2 (or maybe v3) >UefiCpuPkg series first? We've been trying to do many things in >parallel, and it's getting a bit chaotic & hard to track. So I'm thinking: > >- your set goes in first >- I'd post the series with the above 6 patches >- once it's in, I'd return to the SMM series. > >What's your opinion? > >Thanks! >Laszlo > >> >> Best regards, >> >> Mike >> >> >> Contributed-under: TianoCore Contribution Agreement 1.0 >> Signed-off-by: Michael Kinney <[email protected]> >> >> >> 24d1f93110e1f73c70ff3705950c119693328deb >> UefiCpuPkg/CpuDxe/CpuMp.c | 93 >++++++++++++++++++++++++++++++++++++++--------- >> 1 file changed, 75 insertions(+), 18 deletions(-) >> >> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c >> index fbe43f5..4af0361 100644 >> --- a/UefiCpuPkg/CpuDxe/CpuMp.c >> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c >> @@ -29,6 +29,7 @@ VOID *mApStackStart = 0; >> >> volatile BOOLEAN mAPsAlreadyInitFinished = FALSE; >> volatile BOOLEAN mStopCheckAllAPsStatus = TRUE; >> +BOOLEAN mStartupAllAPsCalled = FALSE; >> >> EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = { >> GetNumberOfProcessors, >> @@ -313,6 +314,47 @@ CheckAndUpdateAllAPsToIdleState ( >> } >> >> /** >> + Check if all APs are in state CpuStateSleeping. >> + >> + Return TRUE if all APs are in the CpuStateSleeping state. Do not >> + check the state of the BSP or any disabled APs. >> + >> + @retval TRUE All APs are in CpuStateSleeping state. >> + @retval FALSE One or more APs are not in CpuStateSleeping state. >> + >> +**/ >> +BOOLEAN >> +CheckAllAPsSleeping ( >> + VOID >> + ) >> +{ >> + UINTN ProcessorNumber; >> + CPU_DATA_BLOCK *CpuData; >> + >> + for (ProcessorNumber = 0; ProcessorNumber < >mMpSystemData.NumberOfProcessors; ProcessorNumber++) { >> + CpuData = &mMpSystemData.CpuDatas[ProcessorNumber]; >> + if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) { >> + // >> + // Skip BSP >> + // >> + continue; >> + } >> + >> + if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) { >> + // >> + // Skip Disabled processors >> + // >> + continue; >> + } >> + >> + if (GetApState (CpuData) != CpuStateSleeping) { >> + return FALSE; >> + } >> + } >> + return TRUE; >> +} >> + >> +/** >> If the timeout expires before all APs returns from Procedure, >> we should forcibly terminate the executing AP and fill FailedList back >> by StartupAllAPs(). >> @@ -647,6 +689,18 @@ StartupAllAPs ( >> // >> mStopCheckAllAPsStatus = TRUE; >> >> + if (!mStartupAllAPsCalled) { >> + // >> + // If this is first call to StartAllAPs(), then >> + // wait for all APs to enter idle loop. >> + // >> + while (!CheckAllAPsSleeping ()) { >> + CpuPause(); >> + } >> + >> + mStartupAllAPsCalled = TRUE; >> + } >> + >> for (Number = 0; Number < mMpSystemData.NumberOfProcessors; >Number++) { >> CpuData = &mMpSystemData.CpuDatas[Number]; >> if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) { >> @@ -1700,6 +1754,9 @@ InitializeMpSupport ( >> sizeof (CPU_DATA_BLOCK) * >mMpSystemData.NumberOfProcessors, >> mMpSystemData.CpuDatas); >> >> + // >> + // Release all APs to complete initialization and enter idle loop >> + // >> mAPsAlreadyInitFinished = TRUE; >> >> // >> @@ -1707,6 +1764,23 @@ InitializeMpSupport ( >> // >> CollectBistDataFromHob (); >> >> + if (mMpSystemData.NumberOfProcessors > 1 && >mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) { >> + if (mApStackStart != NULL) { >> + FreePages (mApStackStart, EFI_SIZE_TO_PAGES ( >> + (gMaxLogicalProcessorNumber - >mMpSystemData.NumberOfProcessors) * >> + gApStackSize)); >> + } >> + } >> + >> + Status = gBS->CreateEvent ( >> + EVT_SIGNAL_EXIT_BOOT_SERVICES, >> + TPL_CALLBACK, >> + ExitBootServicesCallback, >> + NULL, >> + &mExitBootServicesEvent >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> // >> // Synchronize MTRR settings to APs. >> // >> @@ -1721,28 +1795,11 @@ InitializeMpSupport ( >> NULL // FailedCpuList >> ); >> ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_STARTED); >> - >> + >> Status = gBS->InstallMultipleProtocolInterfaces ( >> &mMpServiceHandle, >> &gEfiMpServiceProtocolGuid, &mMpServicesTemplate, >> NULL >> ); >> ASSERT_EFI_ERROR (Status); >> - >> - if (mMpSystemData.NumberOfProcessors > 1 && >mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) { >> - if (mApStackStart != NULL) { >> - FreePages (mApStackStart, EFI_SIZE_TO_PAGES ( >> - (gMaxLogicalProcessorNumber - >mMpSystemData.NumberOfProcessors) * >> - gApStackSize)); >> - } >> - } >> - >> - Status = gBS->CreateEvent ( >> - EVT_SIGNAL_EXIT_BOOT_SERVICES, >> - TPL_CALLBACK, >> - ExitBootServicesCallback, >> - NULL, >> - &mExitBootServicesEvent >> - ); >> - ASSERT_EFI_ERROR (Status); >> } >> >> >> >> >>> -----Original Message----- >>> From: edk2-devel [mailto:[email protected]] On Behalf Of >>> Laszlo Ersek >>> Sent: Wednesday, October 14, 2015 3:26 PM >>> To: [email protected] >>> Subject: [edk2] [PATCH v3 04/52] UefiCpuPkg: CpuDxe: broadcast MTRR >>> changes to APs >>> >>> The >>> >>> Quark_EDKII_v1.1.0/IA32FamilyCpuBasePkg/CpuArchDxe >>> >>> driver applies any MTRR changes to APs, if the >EFI_MP_SERVICES_PROTOCOL >>> is >>> available. We should do the same. >>> >>> Additionally, the broadcast should occur at MP startup as well, not only >>> when MTRR settings are changed. The inspiration is taken from >>> >>> Quark_EDKII_v1.1.0/IA32FamilyCpuBasePkg/CpuMpDxe/ >>> >>> (see the EarlyMpInit() function and its call sites in >>> "ProcessorConfig.c"). >>> >>> Contributed-under: TianoCore Contribution Agreement 1.0 >>> Signed-off-by: Laszlo Ersek <[email protected]> >>> Reviewed-by: Jeff Fan <[email protected]> >>> --- >>> >>> Notes: >>> v3: >>> - Although Jeff reviewed this, I'm not committing it just yet, because >>> contextually it is on top of Mike's pending patches. Picked up the R-b >>> tag from Jeff though. No code changes. >>> >>> v2: >>> - This patch replaces the following patches from v1: >>> - UefiCpuPkg: CpuDxe: optionally save MTRR settings to AcpiNVS >memory >>> block >>> - UefiCpuPkg: CpuDxe: broadcast MTRR changes to APs >>> - UefiCpuPkg: CpuDxe: sync MTRR settings to APs at MP startup >>> - UefiCpuPkg: CpuDxe: provide EFI_MP_SERVICES_PROTOCOL when >there's >>> no >>> AP >>> >>> The first v1 patch was deemed inappropriate for general use, and Mike >>> suggested a good alternative for OVMF (=> grab MTRR settings in >>> CpuS3DataDxe at EndOfDxe). >>> >>> The second and third v1 patches are now squashed together into this >v2 >>> patch; they are small and belong together logically. >>> >>> The fourth v1 patch is redundant now; the same has been covered by >>> Mike. >>> >>> UefiCpuPkg/CpuDxe/CpuMp.h | 13 ++++++++ >>> UefiCpuPkg/CpuDxe/CpuDxe.c | 26 +++++++++++++++ >>> UefiCpuPkg/CpuDxe/CpuMp.c | 34 +++++++++++++++++++- >>> 3 files changed, 72 insertions(+), 1 deletion(-) >>> >>> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.h b/UefiCpuPkg/CpuDxe/CpuMp.h >>> index d2866e4..503f3ae 100644 >>> --- a/UefiCpuPkg/CpuDxe/CpuMp.h >>> +++ b/UefiCpuPkg/CpuDxe/CpuMp.h >>> @@ -643,5 +643,18 @@ ResetApStackless ( >>> IN UINT32 ProcessorId >>> ); >>> >>> +/** >>> + A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed >to >>> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure. >>> + >>> + @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed >to >>> + MtrrSetAllMtrrs(). >>> +**/ >>> +VOID >>> +EFIAPI >>> +SetMtrrsFromBuffer ( >>> + IN VOID *Buffer >>> + ); >>> + >>> #endif // _CPU_MP_H_ >>> >>> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c >>> index c9df4e1..daf97bd 100644 >>> --- a/UefiCpuPkg/CpuDxe/CpuDxe.c >>> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.c >>> @@ -350,6 +350,9 @@ CpuSetMemoryAttributes ( >>> { >>> RETURN_STATUS Status; >>> MTRR_MEMORY_CACHE_TYPE CacheType; >>> + EFI_STATUS MpStatus; >>> + EFI_MP_SERVICES_PROTOCOL *MpService; >>> + MTRR_SETTINGS MtrrSettings; >>> >>> if (!IsMtrrSupported ()) { >>> return EFI_UNSUPPORTED; >>> @@ -405,6 +408,29 @@ CpuSetMemoryAttributes ( >>> CacheType >>> ); >>> >>> + if (!RETURN_ERROR (Status)) { >>> + MpStatus = gBS->LocateProtocol ( >>> + &gEfiMpServiceProtocolGuid, >>> + NULL, >>> + (VOID **)&MpService >>> + ); >>> + // >>> + // Synchronize the update with all APs >>> + // >>> + if (!EFI_ERROR (MpStatus)) { >>> + MtrrGetAllMtrrs (&MtrrSettings); >>> + MpStatus = MpService->StartupAllAPs ( >>> + MpService, // This >>> + SetMtrrsFromBuffer, // Procedure >>> + TRUE, // SingleThread >>> + NULL, // WaitEvent >>> + 0, // TimeoutInMicrosecsond >>> + &MtrrSettings, // ProcedureArgument >>> + NULL // FailedCpuList >>> + ); >>> + ASSERT (MpStatus == EFI_SUCCESS || MpStatus == >EFI_NOT_STARTED); >>> + } >>> + } >>> return (EFI_STATUS) Status; >>> } >>> >>> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c >>> index da3686e..fbe43f5 100644 >>> --- a/UefiCpuPkg/CpuDxe/CpuMp.c >>> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c >>> @@ -1626,6 +1626,22 @@ ExitBootServicesCallback ( >>> } >>> >>> /** >>> + A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed >to >>> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure. >>> + >>> + @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed >to >>> + MtrrSetAllMtrrs(). >>> +**/ >>> +VOID >>> +EFIAPI >>> +SetMtrrsFromBuffer ( >>> + IN VOID *Buffer >>> + ) >>> +{ >>> + MtrrSetAllMtrrs (Buffer); >>> +} >>> + >>> +/** >>> Initialize Multi-processor support. >>> >>> **/ >>> @@ -1634,7 +1650,8 @@ InitializeMpSupport ( >>> VOID >>> ) >>> { >>> - EFI_STATUS Status; >>> + EFI_STATUS Status; >>> + MTRR_SETTINGS MtrrSettings; >>> >>> gMaxLogicalProcessorNumber = (UINTN) PcdGet32 >>> (PcdCpuMaxLogicalProcessorNumber); >>> if (gMaxLogicalProcessorNumber < 1) { >>> @@ -1690,6 +1707,21 @@ InitializeMpSupport ( >>> // >>> CollectBistDataFromHob (); >>> >>> + // >>> + // Synchronize MTRR settings to APs. >>> + // >>> + MtrrGetAllMtrrs (&MtrrSettings); >>> + Status = mMpServicesTemplate.StartupAllAPs ( >>> + &mMpServicesTemplate, // This >>> + SetMtrrsFromBuffer, // Procedure >>> + TRUE, // SingleThread >>> + NULL, // WaitEvent >>> + 0, // >>> TimeoutInMicrosecsond >>> + &MtrrSettings, // ProcedureArgument >>> + NULL // FailedCpuList >>> + ); >>> + ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_STARTED); >>> + >>> Status = gBS->InstallMultipleProtocolInterfaces ( >>> &mMpServiceHandle, >>> &gEfiMpServiceProtocolGuid, &mMpServicesTemplate, >>> -- >>> 1.8.3.1 >>> >>> >>> _______________________________________________ >>> edk2-devel mailing list >>> [email protected] >>> https://lists.01.org/mailman/listinfo/edk2-devel > >_______________________________________________ >edk2-devel mailing list >[email protected] >https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

