On 10/17/15 18:15, Kinney, Michael D wrote:
> 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.

That's greatly appreciated; I can see them in your v4.

Thank you!
Laszlo

> 
> 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

Reply via email to