On 2/15/24 10:31, Gerd Hoffmann wrote:
> Loop over all MP_HAND_OFF HOBs instead of expecting a single HOB
> covering all CPUs in the system.
> 
> Add a new HaveMpHandOff variable to track whenever MP_HAND_OFF HOBs are
> present, using the MpHandOff pointer for that does not work because the
> variable will be NULL after looping over all HOBs.
> 
> Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.c | 54 +++++++++++++++++++---------
>  1 file changed, 37 insertions(+), 17 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c 
> b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index 35f47d3b1289..1547b7e74a1a 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -2023,6 +2023,7 @@ MpInitLibInitialize (
>    )
>  {
>    MP_HAND_OFF              *MpHandOff;
> +  BOOLEAN                  HaveMpHandOff;
>    CPU_INFO_IN_HOB          *CpuInfoInHob;
>    UINT32                   MaxLogicalProcessorNumber;
>    UINT32                   ApStackSize;
> @@ -2035,17 +2036,29 @@ MpInitLibInitialize (
>    CPU_MP_DATA              *CpuMpData;
>    UINT8                    ApLoopMode;
>    UINT8                    *MonitorBuffer;
> -  UINTN                    Index;
> +  UINTN                    Index, HobIndex;
>    UINTN                    ApResetVectorSizeBelow1Mb;
>    UINTN                    ApResetVectorSizeAbove1Mb;
>    UINTN                    BackupBufferAddr;
>    UINTN                    ApIdtBase;
>  
> -  MpHandOff = GetMpHandOffHob (0);
> -  if (MpHandOff == NULL) {
> +  MaxLogicalProcessorNumber = 0;
> +  HaveMpHandOff             = FALSE;
> +
> +  while ((MpHandOff = GetMpHandOffHob (MaxLogicalProcessorNumber)) != 0) {
> +    DEBUG ((
> +      DEBUG_INFO,
> +      "%a: ProcessorIndex=%u CpuCount=%u\n",
> +      __func__,
> +      MpHandOff->ProcessorIndex,
> +      MpHandOff->CpuCount
> +      ));
> +    MaxLogicalProcessorNumber += MpHandOff->CpuCount;
> +    HaveMpHandOff              = TRUE;
> +  }
> +
> +  if (!HaveMpHandOff) {
>      MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
> -  } else {
> -    MaxLogicalProcessorNumber = MpHandOff->CpuCount;
>    }
>  
>    ASSERT (MaxLogicalProcessorNumber != 0);

How about:

- just looping over the GUID HOBs, summing their CpuCount fields,

- replacing the HaveMpHandOff variable with the sum being nonzero, after
the loop

(One extra assertion, on top, could be: while iterating over the GUID
HOB list, also perform a maximum search for (MpHandOff->ProcessorIndex +
MpHandOff->CpuCount), and after the loop, check that the maximum found
like this equals the sum of CpuCount fields. But this is really an extra.)

In other words -- again, I don't see any need for going through the HOBs
in a particular order, just for summing their CpuCount fields.


> @@ -2189,7 +2202,7 @@ MpInitLibInitialize (
>    //
>    ProgramVirtualWireMode ();
>  
> -  if (MpHandOff == NULL) {
> +  if (!HaveMpHandOff) {
>      if (MaxLogicalProcessorNumber > 1) {
>        //
>        // Wakeup all APs and calculate the processor count in system
> @@ -2205,19 +2218,26 @@ MpInitLibInitialize (
>        AmdSevUpdateCpuMpData (CpuMpData);
>      }

Hm, okay, considering this code, I do agree we need the "HaveMpHandOff"
variable. Because, at this point, MaxLogicalProcessorNumber will be
nonzero, regardless of how we calculated it it.

>  
> -    CpuMpData->CpuCount  = MpHandOff->CpuCount;
> +    CpuMpData->CpuCount  = MaxLogicalProcessorNumber;
>      CpuMpData->BspNumber = GetBspNumber ();
>      CpuInfoInHob         = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
> -    for (Index = 0; Index < CpuMpData->CpuCount; Index++) {

This original code here is a bit confused. Namely, after briefly
auditing MpInitLibInitialize(), it seems like "Index" should always have
been UINT32; making it UINTN is a confusing and unneeded generality.
(But, if you disagree with my claim, please say so.)

And the new variable HobIndex should be UINT32 too.

> -      InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
> -      CpuMpData->CpuData[Index].CpuHealthy = (MpHandOff->Info[Index].Health 
> == 0) ? TRUE : FALSE;

Comment on the pre-patch code:

  Predicate ? TRUE : FALSE

is poor style.

> -      CpuMpData->CpuData[Index].ApFunction = 0;
> -      CpuInfoInHob[Index].InitialApicId    = MpHandOff->Info[Index].ApicId;
> -      CpuInfoInHob[Index].ApTopOfStack     = CpuMpData->Buffer + (Index + 1) 
> * CpuMpData->CpuApStackSize;
> -      CpuInfoInHob[Index].ApicId           = MpHandOff->Info[Index].ApicId;
> -      CpuInfoInHob[Index].Health           = MpHandOff->Info[Index].Health;
> +    for (MpHandOff = GetMpHandOffHob (0);
> +         MpHandOff != NULL;
> +         MpHandOff = GetMpHandOffHob (MpHandOff->ProcessorIndex + 
> MpHandOff->CpuCount))
> +    {
> +      for (HobIndex = 0; HobIndex < MpHandOff->CpuCount; HobIndex++) {
> +        Index = MpHandOff->ProcessorIndex + HobIndex;
> +        InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock);
> +        CpuMpData->CpuData[Index].CpuHealthy = 
> (MpHandOff->Info[HobIndex].Health == 0) ? TRUE : FALSE;
> +        CpuMpData->CpuData[Index].ApFunction = 0;
> +        CpuInfoInHob[Index].InitialApicId    = 
> MpHandOff->Info[HobIndex].ApicId;
> +        CpuInfoInHob[Index].ApTopOfStack     = CpuMpData->Buffer + (Index + 
> 1) * CpuMpData->CpuApStackSize;
> +        CpuInfoInHob[Index].ApicId           = 
> MpHandOff->Info[HobIndex].ApicId;
> +        CpuInfoInHob[Index].Health           = 
> MpHandOff->Info[HobIndex].Health;
> +      }
>      }

Same observation as before: we don't need to *dicate* the HOB order for
these nested loops, we can (and should) just process the HOBs in
whatever order they appear. That makes the outer loop linear, rather
than quadratic.

>  
> +    MpHandOff = GetMpHandOffHob (0);
>      DEBUG ((DEBUG_INFO, "MpHandOff->WaitLoopExecutionMode: %04d, sizeof 
> (VOID *): %04d\n", MpHandOff->WaitLoopExecutionMode, sizeof (VOID *)));
>      if (MpHandOff->WaitLoopExecutionMode == sizeof (VOID *)) {
>        ASSERT (CpuMpData->ApLoopMode != ApInHltLoop);

This indicates that a refactoring -- "normalization" -- of the
MP_HAND_OFF structure is necessary.

Namely, each MP_HAND_OFF HOB contains a WaitLoopExecutionMode field, but
their values are expected to be identical. And here you have to use one
of the HOBs (doesn't matter which one) for getting that value.

The WaitLoopExecutionMode field should be a singleton, regardless of how
many MP_HAND_OFF HOBs exist. It could be a separate GUID HOB, or perhaps
(for simplicity?) a dynamic UINT32 PCD.

... In fact, the same seems to apply to the StartupSignalValue field.
That field is only ever set to MP_HAND_OFF_SIGNAL, and that setting only
depends on "CpuMpData->ApLoopMode". Therefore both WaitLoopExecutionMode
and StartupSignalValue are singletons, and should not be duplicated;
they should be "normalized out" to dynamic PCDs or a separate (unique)
GUID HOB.

> @@ -2284,7 +2304,7 @@ MpInitLibInitialize (
>    // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
>    //
>    if (CpuMpData->CpuCount > 1) {
> -    if (MpHandOff != NULL) {
> +    if (HaveMpHandOff) {
>        //
>        // Only needs to use this flag for DXE phase to update the wake up
>        // buffer. Wakeup buffer allocated in PEI phase is no longer valid
> @@ -2301,7 +2321,7 @@ MpInitLibInitialize (
>        CpuPause ();
>      }
>  
> -    if (MpHandOff != NULL) {
> +    if (HaveMpHandOff) {
>        CpuMpData->InitFlag = ApInitDone;
>      }
>  

Laszlo



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#115594): https://edk2.groups.io/g/devel/message/115594
Mute This Topic: https://groups.io/mt/104369843/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to