On 07/02/18 08:01, Ruiyu Ni wrote:
> Today's MpInitLib PEI implementation directly calls
> PeiServices->GetHobList() from AP which may cause racing issue.
> 
> This patch fixes this issue by duplicating IDT for APs.
> Because CpuMpData structure is stored just after IDT, the CpuMPData
> address equals to IDTR.BASE + IDTR.LIMIT + 1.
> 
> v2:
>   1. Add ALIGN_VALUE() on BufferSize.
>   2. Add ASSERT() to make sure no memory usage outside of the allocated 
> buffer.
>   3. Add more comments in InitConfig path when restoring 
> CpuData[0].VolatileRegisters.
> 
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Ruiyu Ni <ruiyu...@intel.com>
> Cc: Jeff Fan <vanjeff_...@hotmail.com>
> Cc: Eric Dong <eric.d...@intel.com>
> Cc: Jiewen Yao <jiewen....@intel.com>
> Cc: Fish Andrew <af...@apple.com>
> Cc: Laszlo Ersek <ler...@redhat.com>
> ---
>  UefiCpuPkg/Library/MpInitLib/MpLib.c    | 59 
> +++++++++++++++++++++++++++------
>  UefiCpuPkg/Library/MpInitLib/PeiMpLib.c | 18 +++++++---
>  2 files changed, 63 insertions(+), 14 deletions(-)
> 
> diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c 
> b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> index eb2765910c..108eea0a6f 100644
> --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
> @@ -615,7 +615,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);
> @@ -1506,6 +1508,7 @@ MpInitLibInitialize (
>    UINT32                   MaxLogicalProcessorNumber;
>    UINT32                   ApStackSize;
>    MP_ASSEMBLY_ADDRESS_MAP  AddressMap;
> +  CPU_VOLATILE_REGISTERS   VolatileRegisters;
>    UINTN                    BufferSize;
>    UINT32                   MonitorFilterSize;
>    VOID                     *MpBuffer;
> @@ -1516,6 +1519,7 @@ MpInitLibInitialize (
>    UINTN                    Index;
>    UINTN                    ApResetVectorSize;
>    UINTN                    BackupBufferAddr;
> +  UINTN                    ApIdtBase;
>  
>    OldCpuMpData = GetCpuMpDataFromGuidedHob ();
>    if (OldCpuMpData == NULL) {
> @@ -1530,19 +1534,48 @@ 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;
> @@ -1557,10 +1590,20 @@ MpInitLibInitialize (
>    CpuMpData->MicrocodePatchAddress    = PcdGet64 
> (PcdCpuMicrocodePatchAddress);
>    CpuMpData->MicrocodePatchRegionSize = PcdGet64 
> (PcdCpuMicrocodePatchRegionSize);
>    InitializeSpinLock(&CpuMpData->MpLock);
> +
> +  //
> +  // Make sure no memory usage outside of the allocated buffer.
>    //
> -  // Save BSP's Control registers to APs
> +  ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * 
> MaxLogicalProcessorNumber) ==
> +          Buffer + BufferSize);
> +
> +  //
> +  // 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
>    //
> @@ -1618,11 +1661,7 @@ MpInitLibInitialize (
>        }
>        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) {
>        //
> diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c 
> b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
> index 791ae9db6e..92f28681e4 100644
> --- a/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
> +++ b/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
> @@ -27,6 +27,8 @@ EnableDebugAgent (
>  
>  /**
>    Get pointer to CPU MP Data structure.
> +  For BSP, the pointer is retrieved from HOB.
> +  For AP, the structure is just after IDT.
>  
>    @return  The pointer to CPU MP Data structure.
>  **/
> @@ -35,10 +37,18 @@ GetCpuMpData (
>    VOID
>    )
>  {
> -  CPU_MP_DATA      *CpuMpData;
> -
> -  CpuMpData = GetCpuMpDataFromGuidedHob ();
> -  ASSERT (CpuMpData != NULL);
> +  CPU_MP_DATA                  *CpuMpData;
> +  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
> +  IA32_DESCRIPTOR              Idtr;
> +
> +  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
> +  if (ApicBaseMsr.Bits.BSP == 1) {
> +    CpuMpData = GetCpuMpDataFromGuidedHob ();
> +    ASSERT (CpuMpData != NULL);
> +  } else {
> +    AsmReadIdtr (&Idtr);
> +    CpuMpData = (CPU_MP_DATA *) (Idtr.Base + Idtr.Limit + 1);
> +  }
>    return CpuMpData;
>  }
>  
> 

Acked-by: Laszlo Ersek <ler...@redhat.com>
Tested-by: Laszlo Ersek <ler...@redhat.com>

(I performed my usual regression tests, with/without SMM, and S3.)

Thanks!
Laszlo
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to