* [PATCH v2 0/2] ArmPkg,ArmVirtPkg: Add support EFI_MP_SERVICES_PROTOCOL on AARCH64 @ 2021-12-15 17:46 Rebecca Cran 2021-12-15 17:46 ` [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct Rebecca Cran 2021-12-15 17:46 ` [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL Rebecca Cran 0 siblings, 2 replies; 9+ messages in thread From: Rebecca Cran @ 2021-12-15 17:46 UTC (permalink / raw) To: devel, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar Cc: Rebecca Cran ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL Changes from v1 to v2: Mask off the non-affinity bits of the MPIDR, and since cluster 0/core 0 is 0x0 set the end of list value to MAX_UINT32. Other changes based on Sami's feedback. Rebecca Cran (2): ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL ArmPkg/ArmPkg.dec | 4 + ArmPkg/ArmPkg.dsc | 4 + ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 21 + ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 21 + ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 + ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 + ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 + ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 608 ++++++++ ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +- ArmPkg/Include/Library/ArmLib.h | 10 +- ArmPkg/Include/Library/MpInitLib.h | 366 +++++ ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 65 + ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 + ArmPkg/Library/MpInitLib/DxeMpLib.c | 1477 ++++++++++++++++++++ ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 359 +++++ ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 +- ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +- ArmPlatformPkg/PrePi/MainMPCore.c | 2 +- ArmVirtPkg/ArmVirt.dsc.inc | 3 + 19 files changed, 3013 insertions(+), 11 deletions(-) create mode 100644 ArmPkg/Drivers/CpuDxe/AArch64/Arch.c create mode 100644 ArmPkg/Drivers/CpuDxe/Arm/Arch.c create mode 100644 ArmPkg/Drivers/CpuDxe/CpuMpInit.c create mode 100644 ArmPkg/Include/Library/MpInitLib.h create mode 100644 ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S create mode 100644 ArmPkg/Library/MpInitLib/DxeMpInitLib.inf create mode 100644 ArmPkg/Library/MpInitLib/DxeMpLib.c create mode 100644 ArmPkg/Library/MpInitLib/InternalMpInitLib.h -- 2.31.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct 2021-12-15 17:46 [PATCH v2 0/2] ArmPkg,ArmVirtPkg: Add support EFI_MP_SERVICES_PROTOCOL on AARCH64 Rebecca Cran @ 2021-12-15 17:46 ` Rebecca Cran 2021-12-15 17:53 ` Ard Biesheuvel 2021-12-15 17:46 ` [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL Rebecca Cran 1 sibling, 1 reply; 9+ messages in thread From: Rebecca Cran @ 2021-12-15 17:46 UTC (permalink / raw) To: devel, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar Cc: Rebecca Cran Remove the ClusterId and CoreId fields in the ARM_CORE_INFO structure in favor of a new Mpidr field. Update code in ArmPlatformPkg/PrePeiCore/MainMPCore and ArmPlatformPkg/PrePi/MainMPCore.c to use the new field and call new macros GET_MPIDR_AFF0 and GET_MPIDR_AFF1 instead. Signed-off-by: Rebecca Cran <rebecca@nuviainc.com> --- ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +-- ArmPkg/Include/Library/ArmLib.h | 10 +++++++--- ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 ++++---- ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +- ArmPlatformPkg/PrePi/MainMPCore.c | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ArmPkg/Include/Guid/ArmMpCoreInfo.h b/ArmPkg/Include/Guid/ArmMpCoreInfo.h index 06f9326ca021..43f0848e78b8 100644 --- a/ArmPkg/Include/Guid/ArmMpCoreInfo.h +++ b/ArmPkg/Include/Guid/ArmMpCoreInfo.h @@ -14,8 +14,7 @@ #define MPIDR_U_BIT_MASK 0x40000000 typedef struct { - UINT32 ClusterId; - UINT32 CoreId; + UINT64 Mpidr; // MP Core Mailbox EFI_PHYSICAL_ADDRESS MailboxSetAddress; diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index e4d0476090c7..5287bdfc8684 100644 --- a/ArmPkg/Include/Library/ArmLib.h +++ b/ArmPkg/Include/Library/ArmLib.h @@ -108,10 +108,14 @@ typedef enum { #define ARM_CORE_MASK ARM_CORE_AFF0 #define ARM_CLUSTER_MASK ARM_CORE_AFF1 -#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK) -#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8) +#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK) +#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8) #define GET_MPID(ClusterId, CoreId) (((ClusterId) << 8) | (CoreId)) -#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK) +#define GET_MPIDR_AFF0(MpId) ((MpId) & ARM_CORE_AFF0) +#define GET_MPIDR_AFF1(MpId) (((MpId) & ARM_CORE_AFF1) >> 8) +#define GET_MPIDR_AFF2(MpId) (((MpId) & ARM_CORE_AFF2) >> 16) +#define GET_MPIDR_AFF3(MpId) (((MpId) & ARM_CORE_AFF3) >> 32) +#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK) /** Reads the CCSIDR register for the specified cache. diff --git a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c index eeab58805e67..852275f44fc3 100644 --- a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c +++ b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c @@ -14,7 +14,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { { // Cluster 0, Core 0 - 0x0, 0x0, + 0x0, // MP Core MailBox Set/Get/Clear Addresses and Clear Value (EFI_PHYSICAL_ADDRESS)0, @@ -24,7 +24,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { }, { // Cluster 0, Core 1 - 0x0, 0x1, + 0x1, // MP Core MailBox Set/Get/Clear Addresses and Clear Value (EFI_PHYSICAL_ADDRESS)0, @@ -34,7 +34,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { }, { // Cluster 0, Core 2 - 0x0, 0x2, + 0x2, // MP Core MailBox Set/Get/Clear Addresses and Clear Value (EFI_PHYSICAL_ADDRESS)0, @@ -44,7 +44,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { }, { // Cluster 0, Core 3 - 0x0, 0x3, + 0x3, // MP Core MailBox Set/Get/Clear Addresses and Clear Value (EFI_PHYSICAL_ADDRESS)0, diff --git a/ArmPlatformPkg/PrePeiCore/MainMPCore.c b/ArmPlatformPkg/PrePeiCore/MainMPCore.c index 0b8e5dfb3f30..e6cb75157053 100644 --- a/ArmPlatformPkg/PrePeiCore/MainMPCore.c +++ b/ArmPlatformPkg/PrePeiCore/MainMPCore.c @@ -68,7 +68,7 @@ SecondaryMain ( // Find the core in the ArmCoreTable for (Index = 0; Index < ArmCoreCount; Index++) { - if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) { + if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) { break; } } diff --git a/ArmPlatformPkg/PrePi/MainMPCore.c b/ArmPlatformPkg/PrePi/MainMPCore.c index ce53cea6367c..0433fd0f2e75 100644 --- a/ArmPlatformPkg/PrePi/MainMPCore.c +++ b/ArmPlatformPkg/PrePi/MainMPCore.c @@ -67,7 +67,7 @@ SecondaryMain ( // Find the core in the ArmCoreTable for (Index = 0; Index < ArmCoreCount; Index++) { - if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) { + if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) { break; } } -- 2.31.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct 2021-12-15 17:46 ` [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct Rebecca Cran @ 2021-12-15 17:53 ` Ard Biesheuvel 2021-12-15 20:33 ` Rebecca Cran 0 siblings, 1 reply; 9+ messages in thread From: Ard Biesheuvel @ 2021-12-15 17:53 UTC (permalink / raw) To: Rebecca Cran Cc: edk2-devel-groups-io, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar Hi Rebecca, Some nits below. On Wed, 15 Dec 2021 at 18:46, Rebecca Cran <rebecca@nuviainc.com> wrote: > > Remove the ClusterId and CoreId fields in the ARM_CORE_INFO structure in > favor of a new Mpidr field. Update code in > ArmPlatformPkg/PrePeiCore/MainMPCore and ArmPlatformPkg/PrePi/MainMPCore.c > to use the new field and call new macros GET_MPIDR_AFF0 and GET_MPIDR_AFF1 > instead. > > Signed-off-by: Rebecca Cran <rebecca@nuviainc.com> > --- > ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +-- > ArmPkg/Include/Library/ArmLib.h | 10 +++++++--- > ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 ++++---- > ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +- > ArmPlatformPkg/PrePi/MainMPCore.c | 2 +- > 5 files changed, 14 insertions(+), 11 deletions(-) > > diff --git a/ArmPkg/Include/Guid/ArmMpCoreInfo.h b/ArmPkg/Include/Guid/ArmMpCoreInfo.h > index 06f9326ca021..43f0848e78b8 100644 > --- a/ArmPkg/Include/Guid/ArmMpCoreInfo.h > +++ b/ArmPkg/Include/Guid/ArmMpCoreInfo.h > @@ -14,8 +14,7 @@ > #define MPIDR_U_BIT_MASK 0x40000000 > > typedef struct { > - UINT32 ClusterId; > - UINT32 CoreId; > + UINT64 Mpidr; > > // MP Core Mailbox > EFI_PHYSICAL_ADDRESS MailboxSetAddress; > diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h > index e4d0476090c7..5287bdfc8684 100644 > --- a/ArmPkg/Include/Library/ArmLib.h > +++ b/ArmPkg/Include/Library/ArmLib.h > @@ -108,10 +108,14 @@ typedef enum { > > #define ARM_CORE_MASK ARM_CORE_AFF0 > #define ARM_CLUSTER_MASK ARM_CORE_AFF1 > -#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK) > -#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8) > +#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK) > +#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8) > #define GET_MPID(ClusterId, CoreId) (((ClusterId) << 8) | (CoreId)) > -#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK) > +#define GET_MPIDR_AFF0(MpId) ((MpId) & ARM_CORE_AFF0) > +#define GET_MPIDR_AFF1(MpId) (((MpId) & ARM_CORE_AFF1) >> 8) > +#define GET_MPIDR_AFF2(MpId) (((MpId) & ARM_CORE_AFF2) >> 16) > +#define GET_MPIDR_AFF3(MpId) (((MpId) & ARM_CORE_AFF3) >> 32) > +#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK) > Any reason in particular for these whitespace changes? If not, please omit them - reviewing changes in unfamiliar code is challenging enough without having to figure out which hunks actually matter and which ones don't. > /** Reads the CCSIDR register for the specified cache. > > diff --git a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c > index eeab58805e67..852275f44fc3 100644 > --- a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c > +++ b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c > @@ -14,7 +14,7 @@ > ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { > { > // Cluster 0, Core 0 > - 0x0, 0x0, > + 0x0, > > // MP Core MailBox Set/Get/Clear Addresses and Clear Value > (EFI_PHYSICAL_ADDRESS)0, > @@ -24,7 +24,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { > }, > { > // Cluster 0, Core 1 > - 0x0, 0x1, > + 0x1, > > // MP Core MailBox Set/Get/Clear Addresses and Clear Value > (EFI_PHYSICAL_ADDRESS)0, > @@ -34,7 +34,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { > }, > { > // Cluster 0, Core 2 > - 0x0, 0x2, > + 0x2, > > // MP Core MailBox Set/Get/Clear Addresses and Clear Value > (EFI_PHYSICAL_ADDRESS)0, > @@ -44,7 +44,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = { > }, > { > // Cluster 0, Core 3 > - 0x0, 0x3, > + 0x3, > > // MP Core MailBox Set/Get/Clear Addresses and Clear Value > (EFI_PHYSICAL_ADDRESS)0, > diff --git a/ArmPlatformPkg/PrePeiCore/MainMPCore.c b/ArmPlatformPkg/PrePeiCore/MainMPCore.c > index 0b8e5dfb3f30..e6cb75157053 100644 > --- a/ArmPlatformPkg/PrePeiCore/MainMPCore.c > +++ b/ArmPlatformPkg/PrePeiCore/MainMPCore.c > @@ -68,7 +68,7 @@ SecondaryMain ( > > // Find the core in the ArmCoreTable > for (Index = 0; Index < ArmCoreCount; Index++) { > - if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) { > + if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) { Please rewrap overly long lines. > break; > } > } > diff --git a/ArmPlatformPkg/PrePi/MainMPCore.c b/ArmPlatformPkg/PrePi/MainMPCore.c > index ce53cea6367c..0433fd0f2e75 100644 > --- a/ArmPlatformPkg/PrePi/MainMPCore.c > +++ b/ArmPlatformPkg/PrePi/MainMPCore.c > @@ -67,7 +67,7 @@ SecondaryMain ( > > // Find the core in the ArmCoreTable > for (Index = 0; Index < ArmCoreCount; Index++) { > - if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) { > + if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) { > break; > } > } > -- > 2.31.1 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct 2021-12-15 17:53 ` Ard Biesheuvel @ 2021-12-15 20:33 ` Rebecca Cran 0 siblings, 0 replies; 9+ messages in thread From: Rebecca Cran @ 2021-12-15 20:33 UTC (permalink / raw) To: Ard Biesheuvel Cc: edk2-devel-groups-io, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar On 12/15/21 10:53 AM, Ard Biesheuvel wrote: > On Wed, 15 Dec 2021 at 18:46, Rebecca Cran <rebecca@nuviainc.com> wrote: >> #define ARM_CORE_MASK ARM_CORE_AFF0 >> #define ARM_CLUSTER_MASK ARM_CORE_AFF1 >> -#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK) >> -#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8) >> +#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK) >> +#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8) >> #define GET_MPID(ClusterId, CoreId) (((ClusterId) << 8) | (CoreId)) >> -#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK) >> +#define GET_MPIDR_AFF0(MpId) ((MpId) & ARM_CORE_AFF0) >> +#define GET_MPIDR_AFF1(MpId) (((MpId) & ARM_CORE_AFF1) >> 8) >> +#define GET_MPIDR_AFF2(MpId) (((MpId) & ARM_CORE_AFF2) >> 16) >> +#define GET_MPIDR_AFF3(MpId) (((MpId) & ARM_CORE_AFF3) >> 32) >> +#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK) >> > Any reason in particular for these whitespace changes? If not, please > omit them - reviewing changes in unfamiliar code is challenging enough > without having to figure out which hunks actually matter and which > ones don't. Nope, that was a mistake I made when trying to integrate my changes following the Uncrustify work. > // Find the core in the ArmCoreTable > for (Index = 0; Index < ArmCoreCount; Index++) { > - if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) { > + if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) { > Please rewrap overly long lines. Will do. -- Rebecca Cran ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL 2021-12-15 17:46 [PATCH v2 0/2] ArmPkg,ArmVirtPkg: Add support EFI_MP_SERVICES_PROTOCOL on AARCH64 Rebecca Cran 2021-12-15 17:46 ` [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct Rebecca Cran @ 2021-12-15 17:46 ` Rebecca Cran 2021-12-15 17:55 ` Ard Biesheuvel ` (2 more replies) 1 sibling, 3 replies; 9+ messages in thread From: Rebecca Cran @ 2021-12-15 17:46 UTC (permalink / raw) To: devel, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar Cc: Rebecca Cran Add support for EFI_MP_SERVICES_PROTOCOL during the DXE phase under AArch64. PSCI_CPU_ON is called to power on the core, the supplied procedure is executed and PSCI_CPU_OFF is called to power off the core. Minimal setup is done before calling the supplied procedure: for example the MMU and caches are not enabled. Signed-off-by: Rebecca Cran <rebecca@nuviainc.com> --- ArmPkg/ArmPkg.dec | 4 + ArmPkg/ArmPkg.dsc | 4 + ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 21 + ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 21 + ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 + ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 + ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 + ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 608 ++++++++ ArmPkg/Include/Library/MpInitLib.h | 366 +++++ ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 65 + ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 + ArmPkg/Library/MpInitLib/DxeMpLib.c | 1477 ++++++++++++++++++++ ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 359 +++++ ArmVirtPkg/ArmVirt.dsc.inc | 3 + 14 files changed, 2999 insertions(+) diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 9da1bbc9f216..363eddc57393 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -75,6 +75,10 @@ # DefaultExceptionHandlerLib|Include/Library/DefaultExceptionHandlerLib.h + ## @libraryclass Provides a MP Services interface. + # + MpInitLib|Include/Library/MpInitLib.h + ## @libraryclass Provides an interface to query miscellaneous OEM # information. # diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 59fd8f295d4f..6e053d6ee31d 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -100,6 +100,9 @@ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf +[LibraryClasses.AARCH64] + MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf + [LibraryClasses.ARM, LibraryClasses.AARCH64] NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf @@ -163,6 +166,7 @@ [Components.AARCH64] ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf + ArmPkg/Library/MpInitLib/DxeMpInitLib.inf [Components.AARCH64, Components.ARM] ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c new file mode 100644 index 000000000000..cb7cb747bc15 --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c @@ -0,0 +1,21 @@ +/** @file + Architecture specific functions. + + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <CpuDxe.h> + +/** Initializes multi-processor support. + * +**/ +VOID +ArchInitializeMpSupport ( + VOID + ) +{ + InitializeMpSupport (); +} diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Arch.c b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c new file mode 100644 index 000000000000..f8d57b41225a --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c @@ -0,0 +1,21 @@ +/** @file + Architecture specific functions. + + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <CpuDxe.h> + +/** Initializes multi-processor support. + * +**/ +VOID +ArchInitializeMpSupport ( + VOID + ) +{ + /* Nothing to do - ARM doesn't support EFI_MP_SERVICES_PROTOCOL */ +} diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c index 62a6e2d620a6..6c076982a1bd 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c @@ -275,5 +275,7 @@ CpuDxeInitialize ( ); ASSERT_EFI_ERROR (Status); + ArchInitializeMpSupport (); + return Status; } diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h index 58ee1444c1b3..3f04b89d7ad0 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h @@ -141,4 +141,14 @@ SetGcdMemorySpaceAttributes ( IN UINT64 Attributes ); +VOID +InitializeMpSupport ( + VOID + ); + +VOID +ArchInitializeMpSupport ( + VOID + ); + #endif // CPU_DXE_H_ diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf index e5549fc71df7..f4cdb8ab5613 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf @@ -26,10 +26,13 @@ Exception.c [Sources.ARM] + Arm/Arch.c Arm/Mmu.c [Sources.AARCH64] + AArch64/Arch.c AArch64/Mmu.c + CpuMpInit.c [Packages] ArmPkg/ArmPkg.dec @@ -37,6 +40,9 @@ MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec +[LibraryClasses.AARCH64] + MpInitLib + [LibraryClasses] ArmLib ArmMmuLib diff --git a/ArmPkg/Drivers/CpuDxe/CpuMpInit.c b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c new file mode 100644 index 000000000000..876a29e09b1b --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c @@ -0,0 +1,608 @@ +/** @file + Construct MP Services Protocol. + + The MP Services Protocol provides a generalized way of performing following tasks: + - Retrieving information of multi-processor environment and MP-related status of + specific processors. + - Dispatching user-provided function to APs. + - Maintain MP-related processor status. + + The MP Services Protocol must be produced on any system with more than one logical + processor. + + The Protocol is available only during boot time. + + MP Services Protocol is hardware-independent. Most of the logic of this protocol + is architecturally neutral. It abstracts the multi-processor environment and + status of processors, and provides interfaces to retrieve information, maintain, + and dispatch. + + MP Services Protocol may be consumed by ACPI module. The ACPI module may use this + protocol to retrieve data that are needed for an MP platform and report them to OS. + MP Services Protocol may also be used to program and configure processors, such + as MTRR synchronization for memory space attributes setting in DXE Services. + MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot + by taking advantage of the processing capabilities of the APs, for example, using + APs to help test system memory in parallel with other device initialization. + Diagnostics applications may also use this protocol for multi-processor. + + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/MpInitLib.h> +#include <Library/UefiBootServicesTableLib.h> + +/** + This service retrieves the number of logical processor in the platform + and the number of those logical processors that are enabled on this boot. + This service may only be called from the BSP. + + This function is used to retrieve the following information: + - The number of logical processors that are present in the system. + - The number of enabled logical processors in the system at the instant + this call is made. + + Because MP Service Protocol provides services to enable and disable processors + dynamically, the number of enabled logical processors may vary during the + course of a boot session. + + If this service is called from an AP, then EFI_DEVICE_ERROR is returned. + If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then + EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors + is returned in NumberOfProcessors, the number of currently enabled processor + is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the + EFI_MP_SERVICES_PROTOCOL instance. + @param[out] NumberOfProcessors Pointer to the total number of logical + processors in the system, including + the BSP and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled + logical processors that exist in the + system, including the BSP. + + @retval EFI_SUCCESS The number of logical processors and enabled + logical processors was retrieved. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. + +**/ +STATIC +EFI_STATUS +EFIAPI +GetNumberOfProcessors ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + return MpInitLibGetNumberOfProcessors ( + This, + NumberOfProcessors, + NumberOfEnabledProcessors + ); +} + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. This service may only be called from the BSP. + + This service retrieves detailed MP-related information about any processor + on the platform. Note the following: + - The processor information may change during the course of a boot session. + - The information presented here is entirely MP related. + + Information regarding the number of caches and their sizes, frequency of + operation, slot numbers is all considered platform-related information and is + not provided by this service. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] ProcessorNumber The index of the processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where information + for the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist in the platform. + +**/ +STATIC +EFI_STATUS +EFIAPI +GetProcessorInfo ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + return MpInitLibGetProcessorInfo ( + This, + ProcessorNumber, + ProcessorInfoBuffer + ); +} + +/** + This service executes a caller provided function on all enabled APs. APs can + run either simultaneously or one at a time in sequence. This service supports + both blocking and non-blocking requests. The non-blocking requests use EFI + events so the BSP can detect when the APs have finished. This service may only + be called from the BSP. + + This function is used to dispatch all the enabled APs to the function + specified by Procedure. If any enabled AP is busy, then EFI_NOT_READY is + returned immediately and Procedure is not started on any AP. + + If SingleThread is TRUE, all the enabled APs execute the function specified by + Procedure one by one, in ascending order of processor handle number. + Otherwise, all the enabled APs execute the function specified by Procedure + simultaneously. + + If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all + APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in + non-blocking mode, and the BSP returns from this service without waiting for + APs. If a non-blocking mode is requested after the UEFI Event + EFI_EVENT_GROUP_READY_TO_BOOT is signaled, then EFI_UNSUPPORTED must be + returned. + + If the timeout specified by TimeoutInMicroseconds expires before all APs + return from Procedure, then Procedure on the failed APs is terminated. + All enabled APs are always available for further calls to + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and + EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its + content points to the list of processor handle numbers in which Procedure was + terminated. + + Note: It is the responsibility of the consumer of the + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() to make sure that the nature of the + code that is executed on the BSP and the dispatched APs is well controlled. + The MP Services Protocol does not guarantee that the Procedure function is + MP-safe. Hence, the tasks that can be run in parallel are limited to certain + independent tasks and well-controlled exclusive code. EFI services and + protocols may not be called by APs unless otherwise specified. + + In blocking execution mode, BSP waits until all APs finish or + TimeoutInMicroseconds expires. + + In non-blocking execution mode, BSP is freed to return to the caller and then + proceed to the next task without having to wait for APs. The following + sequence needs to occur in a non-blocking execution mode: + + -# The caller that intends to use this MP Services Protocol in non-blocking + mode creates WaitEvent by calling the EFI CreateEvent() service. The + caller invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter + WaitEvent is not NULL, then StartupAllAPs() executes in non-blocking + mode. It requests the function specified by Procedure to be started on + all the enabled APs, and releases the BSP to continue with other tasks. + -# The caller can use the CheckEvent() and WaitForEvent() services to check + the state of the WaitEvent created in step 1. + -# When the APs complete their task or TimeoutInMicroSecondss expires, the + MP Service signals WaitEvent by calling the EFI SignalEvent() function. + If FailedCpuList is not NULL, its content is available when WaitEvent is + signaled. If all APs returned from Procedure prior to the timeout, then + FailedCpuList is set to NULL. If not all APs return from Procedure before + the timeout, then FailedCpuList is filled in with the list of the failed + APs. The buffer is allocated by MP Service Protocol using AllocatePool(). + It is the caller's responsibility to free the buffer with FreePool() + service. + -# This invocation of SignalEvent() function informs the caller that invoked + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs + completed the specified task or a timeout occurred. The contents of + FailedCpuList can be examined to determine which APs did not complete the + specified task prior to the timeout. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] Procedure A pointer to the function to be run on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] SingleThread If TRUE, then all the enabled APs execute + the function specified by Procedure one by + one, in ascending order of processor + handle number. If FALSE, then all the + enabled APs execute the function specified + by Procedure simultaneously. + @param[in] WaitEvent The event created by the caller with + CreateEvent() service. If it is NULL, + then execute in blocking mode. BSP waits + until all APs finish or + TimeoutInMicroseconds expires. If it's + not NULL, then execute in non-blocking + mode. BSP requests the function specified + by Procedure to be started on all the + enabled APs, and go on executing + immediately. If all return from Procedure, + or TimeoutInMicroseconds expires, this + event is signaled. The BSP can use the + CheckEvent() or WaitForEvent() + services to check the state of event. Type + EFI_EVENT is defined in CreateEvent() in + the Unified Extensible Firmware Interface + Specification. + @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 all APs return from Procedure, then + Procedure on the failed APs is terminated. + All enabled APs are available for next + function assigned by + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + If the timeout expires in blocking mode, + BSP returns EFI_TIMEOUT. If the timeout + expires in non-blocking mode, WaitEvent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] FailedCpuList If NULL, this parameter is ignored. + Otherwise, if all APs finish successfully, + then its content is set to NULL. If not + all APs finish before timeout expires, + then its content is set to address of the + buffer holding handle numbers of the + failed APs. + The buffer is allocated by MP Service + Protocol, and it's the caller's + responsibility to free the buffer with + FreePool() service. + In blocking mode, it is ready for + consumption when the call returns. In + non-blocking mode, it is ready when + WaitEvent is signaled. The list of failed + CPU is terminated by END_OF_CPU_LIST. + + @retval EFI_SUCCESS In blocking mode, all APs have finished before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been + dispatched to all enabled APs. + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was + signaled. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_STARTED No enabled APs exist in the system. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_TIMEOUT In blocking mode, the timeout expired before + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +STATIC +EFI_STATUS +EFIAPI +StartupAllAPs ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + return MpInitLibStartupAllAPs ( + This, + Procedure, + SingleThread, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); +} + +/** + This service lets the caller get one enabled AP to execute a caller-provided + function. The caller can request the BSP to either wait for the completion + of the AP or just proceed with the next task by using the EFI event mechanism. + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking + execution support. This service may only be called from the BSP. + + This function is used to dispatch one enabled AP to the function specified by + Procedure passing in the argument specified by ProcedureArgument. If WaitEvent + is NULL, execution is in blocking mode. The BSP waits until the AP finishes or + TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode. + BSP proceeds to the next task without waiting for the AP. If a non-blocking mode + is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, + then EFI_UNSUPPORTED must be returned. + + If the timeout specified by TimeoutInMicroseconds expires before the AP returns + from Procedure, then execution of Procedure by the AP is terminated. The AP is + available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and + EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] Procedure A pointer to the function to be run on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The range is + from 0 to the total number of logical + processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] WaitEvent The event created by the caller with CreateEvent() + service. If it is NULL, then execute in + blocking mode. BSP waits until all APs finish + or TimeoutInMicroseconds expires. If it's + not NULL, then execute in non-blocking mode. + BSP requests the function specified by + Procedure to be started on all the enabled + APs, and go on executing immediately. If + all return from Procedure or TimeoutInMicroseconds + expires, this event is signaled. The BSP + can use the CheckEvent() or WaitForEvent() + services to check the state of event. Type + EFI_EVENT is defined in CreateEvent() in + the Unified Extensible Firmware Interface + Specification. + @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 + all APs return from Procedure, then Procedure + on the failed APs is terminated. All enabled + APs are available for next function assigned + by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + If the timeout expires in blocking mode, + BSP returns EFI_TIMEOUT. If the timeout + expires in non-blocking mode, WaitEvent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] Finished If NULL, this parameter is ignored. In + blocking mode, this parameter is ignored. + In non-blocking mode, if AP returns from + Procedure before the timeout expires, its + content is set to TRUE. Otherwise, the + value is set to FALSE. The caller can + determine if the AP returned from Procedure + by evaluating this value. + + @retval EFI_SUCCESS In blocking mode, specified AP finished before + the timeout expires. + @retval EFI_SUCCESS In non-blocking mode, the function has been + dispatched to specified AP. + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was + signaled. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_TIMEOUT In blocking mode, the timeout expired before + the specified AP has finished. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +STATIC +EFI_STATUS +EFIAPI +StartupThisAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ) +{ + return MpInitLibStartupThisAP ( + This, + Procedure, + ProcessorNumber, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + Finished + ); +} + +/** + This service switches the requested AP to be the BSP from that point onward. + This service changes the BSP for all purposes. This call can only be + performed by the current BSP. + + This service switches the requested AP to be the BSP from that point onward. + This service changes the BSP for all purposes. The new BSP can take over the + execution of the old BSP and continue seamlessly from where the old one left + off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT + is signaled. + + If the BSP cannot be switched prior to the return from this service, then + EFI_UNSUPPORTED must be returned. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an + enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_SUCCESS The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + +**/ +STATIC +EFI_STATUS +EFIAPI +SwitchBSP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + return MpInitLibSwitchBSP (This, ProcessorNumber, EnableOldBSP); +} + +/** + This service lets the caller enable or disable an AP from this point onward. + This service may only be called from the BSP. + + This service allows the caller enable or disable an AP from this point onward. + The caller can optionally specify the health status of the AP by Health. If + an AP is being disabled, then the state of the disabled AP is implementation + dependent. If an AP is enabled, then the implementation must guarantee that a + complete initialization sequence is performed on the AP, so the AP is in a state + that is compatible with an MP operating system. This service may not be supported + after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled. + + If the enable or disable AP operation cannot be completed prior to the return + from this service, then EFI_UNSUPPORTED must be returned. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] EnableAP Specifies the new state for the processor for + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that specifies + the new health status of the AP. This flag + corresponds to StatusFlag defined in + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only + the PROCESSOR_HEALTH_STATUS_BIT is used. All other + bits are ignored. If it is NULL, this parameter + is ignored. + + @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed + prior to this service returning. + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber + does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. + +**/ +STATIC +EFI_STATUS +EFIAPI +EnableDisableAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ) +{ + return MpInitLibEnableDisableAP (This, ProcessorNumber, EnableAP, HealthFlag); +} + +/** + This return the handle number for the calling processor. This service may be + called from the BSP and APs. + + This service returns the processor handle number for the calling processor. + The returned value is in the range from 0 to the total number of logical + processors minus 1. The total number of logical processors can be retrieved + with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be + called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER + is returned. Otherwise, the current processors handle number is returned in + ProcessorNumber, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[out] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + + @retval EFI_SUCCESS The current processor handle number was returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +STATIC +EFI_STATUS +EFIAPI +WhoAmI ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ) +{ + return MpInitLibWhoAmI (This, ProcessorNumber); +} + +EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = { + GetNumberOfProcessors, + GetProcessorInfo, + StartupAllAPs, + StartupThisAP, + SwitchBSP, + EnableDisableAP, + WhoAmI +}; + +/** Initialize multi-processor support. + +**/ +VOID +InitializeMpSupport ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + UINTN MaxCpus; + EFI_HOB_GENERIC_HEADER *Hob; + VOID *HobData; + UINTN HobDataSize; + ARM_PROCESSOR_TABLE CpuInfo; + + MaxCpus = 1; + ZeroMem (&CpuInfo, sizeof (ARM_PROCESSOR_TABLE)); + + DEBUG ((DEBUG_INFO, "Starting MP services")); + + Hob = GetFirstGuidHob (&gArmMpCoreInfoGuid); + if (Hob != NULL) { + HobData = GET_GUID_HOB_DATA (Hob); + HobDataSize = GET_GUID_HOB_DATA_SIZE (Hob); + CpuInfo.ArmCpus = (ARM_CORE_INFO *)HobData; + CpuInfo.NumberOfEntries = HobDataSize / sizeof (ARM_CORE_INFO); + MaxCpus = CpuInfo.NumberOfEntries; + } + + if (MaxCpus == 1) { + DEBUG ((DEBUG_WARN, "Trying to use EFI_MP_SERVICES_PROTOCOL on a UP system")); + // We are not MP so nothing to do + return; + } + + MpInitLibInitialize (MaxCpus, &CpuInfo); + + // + // Now install the MP services protocol. + // + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiMpServiceProtocolGuid, + &mMpServicesTemplate, + NULL + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/ArmPkg/Include/Library/MpInitLib.h b/ArmPkg/Include/Library/MpInitLib.h new file mode 100644 index 000000000000..a4b80c18a9e8 --- /dev/null +++ b/ArmPkg/Include/Library/MpInitLib.h @@ -0,0 +1,366 @@ +/** @file + +Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2011, Apple Inc. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef MP_INITLIB_H_ +#define MP_INITLIB_H_ + +#include <Protocol/Cpu.h> +#include <Protocol/MpService.h> +#include <Library/BaseLib.h> +#include <Library/UefiLib.h> +#include <Guid/ArmMpCoreInfo.h> + + +/** + This service retrieves the number of logical processor in the platform + and the number of those logical processors that are enabled on this boot. + This service may only be called from the BSP. + + @param[in] This A pointer to the + EFI_MP_SERVICES_PROTOCOL instance. + @param[out] NumberOfProcessors Pointer to the total number of logical + processors in the system, including + the BSP and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled + logical processors that exist in the + system, including the BSP. + + @retval EFI_SUCCESS The number of logical processors and enabled + logical processors was retrieved. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibGetNumberOfProcessors ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ); + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] ProcessorIndex The index of the processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where information + for the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist in the platform. + +**/ +EFI_STATUS +EFIAPI +MpInitLibGetProcessorInfo ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorIndex, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ); + + +/** + This service executes a caller provided function on all enabled APs. APs can + run either simultaneously or one at a time in sequence. This service supports + both blocking and non-blocking requests. The non-blocking requests use EFI + events so the BSP can detect when the APs have finished. This service may only + be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] Procedure A pointer to the function to be run on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] SingleThread If TRUE, then all the enabled APs execute + the function specified by Procedure one by + one, in ascending order of processor + handle number. If FALSE, then all the + enabled APs execute the function specified + by Procedure simultaneously. + @param[in] WaitEvent The event created by the caller with + CreateEvent() service. If it is NULL, + then execute in blocking mode. BSP waits + until all APs finish or + TimeoutInMicroseconds expires. If it's + not NULL, then execute in non-blocking + mode. BSP requests the function specified + by Procedure to be started on all the + enabled APs, and go on executing + immediately. If all return from Procedure, + or TimeoutInMicroseconds expires, this + event is signaled. The BSP can use the + CheckEvent() or WaitForEvent() + services to check the state of event. Type + EFI_EVENT is defined in CreateEvent() in + the Unified Extensible Firmware Interface + Specification. + @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 all APs return from Procedure, then + Procedure on the failed APs is terminated. + All enabled APs are available for next + function assigned by + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + If the timeout expires in blocking mode, + BSP returns EFI_TIMEOUT. If the timeout + expires in non-blocking mode, WaitEvent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] FailedCpuList If NULL, this parameter is ignored. + Otherwise, if all APs finish successfully, + then its content is set to NULL. If not + all APs finish before timeout expires, + then its content is set to address of the + buffer holding handle numbers of the + failed APs. + The buffer is allocated by MP Service + Protocol, and it's the caller's + responsibility to free the buffer with + FreePool() service. + In blocking mode, it is ready for + consumption when the call returns. In + non-blocking mode, it is ready when + WaitEvent is signaled. The list of failed + CPU is terminated by END_OF_CPU_LIST. + + @retval EFI_SUCCESS In blocking mode, all APs have finished before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been + dispatched to all enabled APs. + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was + signaled. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_STARTED No enabled APs exist in the system. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_TIMEOUT In blocking mode, the timeout expired before + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupAllAPs ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ); + +/** + This service lets the caller get one enabled AP to execute a caller-provided + function. The caller can request the BSP to either wait for the completion + of the AP or just proceed with the next task by using the EFI event mechanism. + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking + execution support. This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] Procedure A pointer to the function to be run on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The range is + from 0 to the total number of logical + processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] WaitEvent The event created by the caller with CreateEvent() + service. If it is NULL, then execute in + blocking mode. BSP waits until all APs finish + or TimeoutInMicroseconds expires. If it's + not NULL, then execute in non-blocking mode. + BSP requests the function specified by + Procedure to be started on all the enabled + APs, and go on executing immediately. If + all return from Procedure or TimeoutInMicroseconds + expires, this event is signaled. The BSP + can use the CheckEvent() or WaitForEvent() + services to check the state of event. Type + EFI_EVENT is defined in CreateEvent() in + the Unified Extensible Firmware Interface + Specification. + @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 + all APs return from Procedure, then Procedure + on the failed APs is terminated. All enabled + APs are available for next function assigned + by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + If the timeout expires in blocking mode, + BSP returns EFI_TIMEOUT. If the timeout + expires in non-blocking mode, WaitEvent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] Finished If NULL, this parameter is ignored. In + blocking mode, this parameter is ignored. + In non-blocking mode, if AP returns from + Procedure before the timeout expires, its + content is set to TRUE. Otherwise, the + value is set to FALSE. The caller can + determine if the AP returned from Procedure + by evaluating this value. + + @retval EFI_SUCCESS In blocking mode, specified AP finished before + the timeout expires. + @retval EFI_SUCCESS In non-blocking mode, the function has been + dispatched to specified AP. + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was + signaled. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_TIMEOUT In blocking mode, the timeout expired before + the specified AP has finished. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupThisAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ); + +/** + This service switches the requested AP to be the BSP from that point onward. + This service changes the BSP for all purposes. This call can only be + performed by the current BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an + enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_SUCCESS The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + +**/ +EFI_STATUS +EFIAPI +MpInitLibSwitchBSP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ); + +/** + This service lets the caller enable or disable an AP from this point onward. + This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] EnableAP Specifies the new state for the processor for + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that specifies + the new health status of the AP. This flag + corresponds to StatusFlag defined in + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only + the PROCESSOR_HEALTH_STATUS_BIT is used. All other + bits are ignored. If it is NULL, this parameter + is ignored. + + @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed + prior to this service returning. + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber + does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. + +**/ +EFI_STATUS +EFIAPI +MpInitLibEnableDisableAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ); + +/** + This return the handle number for the calling processor. This service may be + called from the BSP and APs. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[out] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + + @retval EFI_SUCCESS The current processor handle number was returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibWhoAmI ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ); + +/** Initializes the MP Services system data + + @param NumberOfProcessors The number of processors, both BSP and AP. + @param CpuInfo CPU information gathered earlier during boot. + +**/ +VOID +MpInitLibInitialize ( + IN UINTN NumberOfProcessors, + IN ARM_PROCESSOR_TABLE *CpuInfo + ); + + + +#endif /* MP_INITLIB_H_ */ diff --git a/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S new file mode 100644 index 000000000000..8f7019a1c62c --- /dev/null +++ b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S @@ -0,0 +1,65 @@ +#=============================================================================== +# Copyright (c) 2021 NUVIA Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +#=============================================================================== + +.text +.align 3 + +#include <AsmMacroIoLibV8.h> +#include <IndustryStandard/ArmStdSmc.h> + +#include "InternalMpInitLib.h" + +GCC_ASM_IMPORT (gApStacksBase) +GCC_ASM_IMPORT (gProcessorIDs) +GCC_ASM_IMPORT (ApProcedure) +GCC_ASM_IMPORT (gApStackSize) + +GCC_ASM_EXPORT (ApEntryPoint) + +StartupAddr: .8byte ASM_PFX(ApProcedure) + +// Entry-point for the AP +// VOID +// ApEntryPoint ( +// VOID +// ); +ASM_PFX(ApEntryPoint): + mrs x0, mpidr_el1 + // Mask the non-affinity bits + ldr x1, =0xff00ffffff + and x0, x0, x1 + ldr x1, gProcessorIDs + mov x2, 0 // x2 = processor index + mov x3, 0 // x3 = address offset + +// Find index in gProcessorIDs for current processor +1: + ldr x4, [x1, x3] // x4 = gProcessorIDs + x3 + ldr x5, =0xffffffffff + cmp x4, x5 // check if we've reached the end of gProcessorIDs + beq ProcessorNotFound + add x3, x3, 8 // x3 += sizeof (*gProcessorIDs) + add x2, x2, 1 // x2++ + cmp x0, x4 // if mpidr_el1 != *(gProcessorIDs + x3) then loop + bne 1b + sub x2, x2, 1 + +// Calculate stack address + // x2 contains the index for the current processor + ldr x0, gApStacksBase + ldr x1, gApStackSize + mul x3, x2, x1 // x3 = ProcessorIndex * gApStackSize + add x4, x0, x3 // x4 = gApStacksBase + x3 + add sp, x4, x1 // sp = x4 + gApStackSize + + ldr x0, StartupAddr // ASM_PFX(ApProcedure) + blr x0 // doesn't return + +ProcessorNotFound: +// Turn off the processor + MOV32 (w0, ARM_SMC_ID_PSCI_CPU_OFF) + smc #0 + b . diff --git a/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf new file mode 100644 index 000000000000..2275b6cca33a --- /dev/null +++ b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf @@ -0,0 +1,53 @@ +#/** @file +# +# Component description file for the DxeMpInitLib module. +# +# Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = DxeMpInitLib + FILE_GUID = c9ca773c-8ae4-4b74-82fd-f7345503294e + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = MpInitLib|DXE_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources.AARCH64] + AArch64/MpFuncs.S + +[Sources] + DxeMpLib.c + InternalMpInitLib.h + +[Packages] + ArmPkg/ArmPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmLib + ArmSmcLib + BaseLib + BaseMemoryLib + DebugLib + HobLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiMpServiceProtocolGuid + +[Guids] + gArmMpCoreInfoGuid diff --git a/ArmPkg/Library/MpInitLib/DxeMpLib.c b/ArmPkg/Library/MpInitLib/DxeMpLib.c new file mode 100644 index 000000000000..e8d8808a3225 --- /dev/null +++ b/ArmPkg/Library/MpInitLib/DxeMpLib.c @@ -0,0 +1,1477 @@ +/** @file + Construct MP Services Protocol. + + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> + Portions Copyright (c) 2011, Apple Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Ppi/ArmMpCoreInfo.h> +#include <Library/ArmLib.h> +#include <Library/ArmSmcLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/MpInitLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <IndustryStandard/ArmStdSmc.h> + +#include "InternalMpInitLib.h" + +#define POLL_INTERVAL_US 50000 + +#define GET_MPIDR_AFFINITY_BITS(x) ((x) & 0xFF00FFFFFF) + +#define MPIDR_MT_BIT BIT24 + +STATIC CPU_MP_DATA mCpuMpData; +STATIC BOOLEAN mNonBlockingModeAllowed; +UINT64 *gApStacksBase; +UINT64 *gProcessorIDs; +CONST UINT64 gApStackSize = AP_STACK_SIZE; + +/** C entry-point for the AP. + This function gets called from the assembly function ApEntryPoint. + +**/ +VOID +ApProcedure ( + VOID + ) +{ + ARM_SMC_ARGS Args; + EFI_AP_PROCEDURE UserApProcedure; + VOID *UserApParameter; + UINTN ProcessorIndex; + + MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex); + + /* Fetch the user-supplied procedure and parameter to execute */ + UserApProcedure = mCpuMpData.CpuData[ProcessorIndex].Procedure; + UserApParameter = mCpuMpData.CpuData[ProcessorIndex].Parameter; + + UserApProcedure (UserApParameter); + + mCpuMpData.CpuData[ProcessorIndex].State = CpuStateFinished; + + /* Since we're finished with this AP, turn it off */ + Args.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF; + ArmCallSmc (&Args); + + /* Should never be reached */ + ASSERT (FALSE); + CpuDeadLoop (); +} + +/** Turns on the specified core using PSCI and executes the user-supplied + function that's been configured via a previous call to SetApProcedure. + + @param ProcessorIndex The index of the core to turn on. + + @retval EFI_SUCCESS Success. + @retval EFI_DEVICE_ERROR The processor could not be turned on. + +**/ +STATIC +EFI_STATUS +EFIAPI +DispatchCpu ( + IN UINTN ProcessorIndex + ) +{ + ARM_SMC_ARGS Args; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + mCpuMpData.CpuData[ProcessorIndex].State = CpuStateBusy; + + /* Turn the AP on */ + if (sizeof (Args.Arg0) == sizeof (UINT32)) { + Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH32; + } else { + Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH64; + } + + Args.Arg1 = gProcessorIDs[ProcessorIndex]; + Args.Arg2 = (UINTN)ApEntryPoint; + + ArmCallSmc (&Args); + + if (Args.Arg0 != ARM_SMC_PSCI_RET_SUCCESS) { + DEBUG ((DEBUG_ERROR, "PSCI_CPU_ON call failed: %d", Args.Arg0)); + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** Returns whether the specified processor is the BSP. + + @param[in] ProcessorIndex The index the processor to check. + + @return TRUE if the processor is the BSP, FALSE otherwise. +**/ +STATIC +BOOLEAN +IsProcessorBSP ( + UINTN ProcessorIndex + ) +{ + EFI_PROCESSOR_INFORMATION *CpuInfo; + + CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info; + + return (CpuInfo->StatusFlag & PROCESSOR_AS_BSP_BIT) != 0; +} + +/** Returns whether the processor executing this function is the BSP. + + @return Whether the current processor is the BSP. +**/ +STATIC +BOOLEAN +IsCurrentProcessorBSP ( + VOID + ) +{ + EFI_STATUS Status; + UINTN ProcessorIndex; + + Status = MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex); + if (EFI_ERROR (Status)) { + ASSERT (0); + return FALSE; + } + + return IsProcessorBSP (ProcessorIndex); +} + +/** Get the Application Processors state. + + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP. + + @return The AP status. +**/ +CPU_STATE +GetApState ( + IN CPU_AP_DATA *CpuData + ) +{ + return CpuData->State; +} + +/** Configures the processor context with the user-supplied procedure and + argument. + + @param CpuData The processor context. + @param Procedure The user-supplied procedure. + @param ProcedureArgument The user-supplied procedure argument. + +**/ +STATIC +VOID +SetApProcedure ( + IN CPU_AP_DATA *CpuData, + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument + ) +{ + ASSERT (CpuData != NULL); + ASSERT (Procedure != NULL); + + CpuData->Parameter = ProcedureArgument; + CpuData->Procedure = Procedure; +} + +/** Returns the index of the next processor that is blocked. + + @param[out] NextNumber The index of the next blocked processor. + + @retval EFI_SUCCESS Successfully found the next blocked processor. + @retval EFI_NOT_FOUND There are no blocked processors. + +**/ +STATIC +EFI_STATUS +GetNextBlockedNumber ( + OUT UINTN *NextNumber + ) +{ + UINTN Index; + CPU_STATE State; + CPU_AP_DATA *CpuData; + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + if (IsProcessorBSP (Index)) { + // Skip BSP + continue; + } + + State = CpuData->State; + + if (State == CpuStateBlocked) { + *NextNumber = Index; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** Stalls the BSP for the minimum of POLL_INTERVAL_US and Timeout. + + @param[in] Timeout The time limit in microseconds remaining for + APs to return from Procedure. + + @retval StallTime Time of execution stall. +**/ +STATIC +UINTN +CalculateAndStallInterval ( + IN UINTN Timeout + ) +{ + UINTN StallTime; + + if ((Timeout < POLL_INTERVAL_US) && (Timeout != 0)) { + StallTime = Timeout; + } else { + StallTime = POLL_INTERVAL_US; + } + + gBS->Stall (StallTime); + + return StallTime; +} + +/** + This service retrieves the number of logical processor in the platform + and the number of those logical processors that are enabled on this boot. + This service may only be called from the BSP. + + @param[in] This A pointer to the + EFI_MP_SERVICES_PROTOCOL instance. + @param[out] NumberOfProcessors Pointer to the total number of logical + processors in the system, including + the BSP and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled + logical processors that exist in the + system, including the BSP. + + @retval EFI_SUCCESS The number of logical processors and enabled + logical processors was retrieved. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibGetNumberOfProcessors ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!IsCurrentProcessorBSP ()) { + return EFI_DEVICE_ERROR; + } + + *NumberOfProcessors = mCpuMpData.NumberOfProcessors; + *NumberOfEnabledProcessors = mCpuMpData.NumberOfEnabledProcessors; + return EFI_SUCCESS; +} + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] ProcessorIndex The index of the processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where information + for the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist in the platform. + +**/ +EFI_STATUS +EFIAPI +MpInitLibGetProcessorInfo ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorIndex, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + if (ProcessorInfoBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!IsCurrentProcessorBSP ()) { + return EFI_DEVICE_ERROR; + } + + ProcessorIndex &= ~CPU_V2_EXTENDED_TOPOLOGY; + + if (ProcessorIndex >= mCpuMpData.NumberOfProcessors) { + return EFI_NOT_FOUND; + } + + CopyMem ( + ProcessorInfoBuffer, + &mCpuMpData.CpuData[ProcessorIndex], + sizeof (EFI_PROCESSOR_INFORMATION) + ); + return EFI_SUCCESS; +} + +/** Returns whether the specified processor is enabled. + + @param[in] ProcessorIndex The index of the processor to check. + + @return TRUE if the processor is enabled, FALSE otherwise. +**/ +STATIC +BOOLEAN +IsProcessorEnabled ( + UINTN ProcessorIndex + ) +{ + EFI_PROCESSOR_INFORMATION *CpuInfo; + + CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info; + + return (CpuInfo->StatusFlag & PROCESSOR_ENABLED_BIT) != 0; +} + +/** Returns whether all processors are in the idle state. + + @return Whether all the processors are idle. + +**/ +STATIC +BOOLEAN +CheckAllCpusReady ( + VOID + ) +{ + UINTN Index; + CPU_AP_DATA *CpuData; + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + if (IsProcessorBSP (Index)) { + // Skip BSP + continue; + } + + if (!IsProcessorEnabled (Index)) { + // Skip Disabled processors + continue; + } + + if (GetApState (CpuData) != CpuStateIdle) { + return FALSE; + } + } + + return TRUE; +} + +/** Sets up the state for the StartupAllAPs function. + + @param SingleThread Whether the APs will execute sequentially. + +**/ +STATIC +VOID +StartupAllAPsPrepareState ( + IN BOOLEAN SingleThread + ) +{ + UINTN Index; + CPU_STATE APInitialState; + CPU_AP_DATA *CpuData; + + mCpuMpData.FinishCount = 0; + mCpuMpData.StartCount = 0; + mCpuMpData.SingleThread = SingleThread; + + APInitialState = CpuStateReady; + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + + // + // Get APs prepared, and put failing APs into FailedCpuList. + // If "SingleThread", only 1 AP will put into ready state, other AP will be + // put into ready state 1 by 1, until the previous 1 finished its task. + // If not "SingleThread", all APs are put into ready state from the + // beginning + // + + if (IsProcessorBSP (Index)) { + // Skip BSP + continue; + } + + if (!IsProcessorEnabled (Index)) { + // Skip Disabled processors + if (mCpuMpData.FailedList != NULL) { + mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index; + } + + continue; + } + + ASSERT (GetApState (CpuData) == CpuStateIdle); + CpuData->State = APInitialState; + + mCpuMpData.StartCount++; + if (SingleThread) { + APInitialState = CpuStateBlocked; + } + } +} + +/** Handles execution of StartupAllAPs when a WaitEvent has been specified. + + @param Procedure The user-supplied procedure. + @param ProcedureArgument The user-supplied procedure argument. + @param WaitEvent The wait event to be signaled when the work is + complete or a timeout has occurred. + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero + indicates an infinite timeout. + + @return EFI_SUCCESS on success. +**/ +STATIC +EFI_STATUS +StartupAllAPsWithWaitEvent ( + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument, + IN EFI_EVENT WaitEvent, + IN UINTN TimeoutInMicroseconds + ) +{ + EFI_STATUS Status; + UINTN Index; + CPU_AP_DATA *CpuData; + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + if (IsProcessorBSP (Index)) { + // Skip BSP + continue; + } + + if (!IsProcessorEnabled (Index)) { + // Skip Disabled processors + continue; + } + + if (GetApState (CpuData) == CpuStateReady) { + SetApProcedure (CpuData, Procedure, ProcedureArgument); + } + } + + // + // Save data into private data structure, and create timer to poll AP state + // before exiting + // + mCpuMpData.Procedure = Procedure; + mCpuMpData.ProcedureArgument = ProcedureArgument; + mCpuMpData.WaitEvent = WaitEvent; + mCpuMpData.Timeout = TimeoutInMicroseconds; + mCpuMpData.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0); + Status = gBS->SetTimer ( + mCpuMpData.CheckAllAPsEvent, + TimerPeriodic, + POLL_INTERVAL_US + ); + return Status; +} + +/** Handles execution of StartupAllAPs when no wait event has been specified. + + @param Procedure The user-supplied procedure. + @param ProcedureArgument The user-supplied procedure argument. + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero + indicates an infinite timeout. + @param SingleThread Whether the APs will execute sequentially. + @param FailedCpuList User-supplied pointer for list of failed CPUs. + + @return EFI_SUCCESS on success. +**/ +STATIC +EFI_STATUS +StartupAllAPsNoWaitEvent ( + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument, + IN UINTN TimeoutInMicroseconds, + IN BOOLEAN SingleThread, + IN UINTN **FailedCpuList + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN NextIndex; + UINTN Timeout; + CPU_AP_DATA *CpuData; + + Timeout = TimeoutInMicroseconds; + + while (TRUE) { + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + if (IsProcessorBSP (Index)) { + // Skip BSP + continue; + } + + if (!IsProcessorEnabled (Index)) { + // Skip Disabled processors + continue; + } + + switch (GetApState (CpuData)) { + case CpuStateReady: + SetApProcedure (CpuData, Procedure, ProcedureArgument); + Status = DispatchCpu (Index); + if (EFI_ERROR (Status)) { + CpuData->State = CpuStateIdle; + Status = EFI_NOT_READY; + goto Done; + } + + break; + + case CpuStateFinished: + mCpuMpData.FinishCount++; + if (SingleThread) { + Status = GetNextBlockedNumber (&NextIndex); + if (!EFI_ERROR (Status)) { + mCpuMpData.CpuData[NextIndex].State = CpuStateReady; + } + } + + CpuData->State = CpuStateIdle; + break; + + default: + break; + } + } + + if (mCpuMpData.FinishCount == mCpuMpData.StartCount) { + Status = EFI_SUCCESS; + goto Done; + } + + if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) { + Status = EFI_TIMEOUT; + goto Done; + } + + Timeout -= CalculateAndStallInterval (Timeout); + } + +Done: + if (FailedCpuList != NULL) { + if (mCpuMpData.FailedListIndex == 0) { + FreePool (*FailedCpuList); + *FailedCpuList = NULL; + } + } + + return Status; +} + +/** + This service executes a caller provided function on all enabled APs. APs can + run either simultaneously or one at a time in sequence. This service supports + both blocking and non-blocking requests. The non-blocking requests use EFI + events so the BSP can detect when the APs have finished. This service may only + be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] Procedure A pointer to the function to be run on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] SingleThread If TRUE, then all the enabled APs execute + the function specified by Procedure one by + one, in ascending order of processor + handle number. If FALSE, then all the + enabled APs execute the function specified + by Procedure simultaneously. + @param[in] WaitEvent The event created by the caller with + CreateEvent() service. If it is NULL, + then execute in blocking mode. BSP waits + until all APs finish or + TimeoutInMicroseconds expires. If it's + not NULL, then execute in non-blocking + mode. BSP requests the function specified + by Procedure to be started on all the + enabled APs, and go on executing + immediately. If all return from Procedure, + or TimeoutInMicroseconds expires, this + event is signaled. The BSP can use the + CheckEvent() or WaitForEvent() + services to check the state of event. Type + EFI_EVENT is defined in CreateEvent() in + the Unified Extensible Firmware Interface + Specification. + @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 all APs return from Procedure, then + Procedure on the failed APs is terminated. + All enabled APs are available for next + function assigned by + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + If the timeout expires in blocking mode, + BSP returns EFI_TIMEOUT. If the timeout + expires in non-blocking mode, WaitEvent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] FailedCpuList If NULL, this parameter is ignored. + Otherwise, if all APs finish successfully, + then its content is set to NULL. If not + all APs finish before timeout expires, + then its content is set to address of the + buffer holding handle numbers of the + failed APs. + The buffer is allocated by MP Service + Protocol, and it's the caller's + responsibility to free the buffer with + FreePool() service. + In blocking mode, it is ready for + consumption when the call returns. In + non-blocking mode, it is ready when + WaitEvent is signaled. The list of failed + CPU is terminated by END_OF_CPU_LIST. + + @retval EFI_SUCCESS In blocking mode, all APs have finished before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been + dispatched to all enabled APs. + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was + signaled. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_STARTED No enabled APs exist in the system. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_TIMEOUT In blocking mode, the timeout expired before + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupAllAPs ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + EFI_STATUS Status; + + if (!IsCurrentProcessorBSP ()) { + return EFI_DEVICE_ERROR; + } + + if (mCpuMpData.NumberOfProcessors == 1) { + return EFI_NOT_STARTED; + } + + if (Procedure == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) { + return EFI_UNSUPPORTED; + } + + if (!CheckAllCpusReady ()) { + return EFI_NOT_READY; + } + + if (FailedCpuList != NULL) { + mCpuMpData.FailedList = AllocatePool ( + (mCpuMpData.NumberOfProcessors + 1) * + sizeof (UINTN) + ); + if (mCpuMpData.FailedList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SetMemN ( + mCpuMpData.FailedList, + (mCpuMpData.NumberOfProcessors + 1) * + sizeof (UINTN), + END_OF_CPU_LIST + ); + mCpuMpData.FailedListIndex = 0; + *FailedCpuList = mCpuMpData.FailedList; + } + + StartupAllAPsPrepareState (SingleThread); + + if (WaitEvent != NULL) { + Status = StartupAllAPsWithWaitEvent ( + Procedure, + ProcedureArgument, + WaitEvent, + TimeoutInMicroseconds + ); + } else { + Status = StartupAllAPsNoWaitEvent ( + Procedure, + ProcedureArgument, + TimeoutInMicroseconds, + SingleThread, + FailedCpuList + ); + } + + return Status; +} + +/** + This service lets the caller get one enabled AP to execute a caller-provided + function. The caller can request the BSP to either wait for the completion + of the AP or just proceed with the next task by using the EFI event mechanism. + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking + execution support. This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL + instance. + @param[in] Procedure A pointer to the function to be run on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The range is + from 0 to the total number of logical + processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] WaitEvent The event created by the caller with CreateEvent() + service. If it is NULL, then execute in + blocking mode. BSP waits until all APs finish + or TimeoutInMicroseconds expires. If it's + not NULL, then execute in non-blocking mode. + BSP requests the function specified by + Procedure to be started on all the enabled + APs, and go on executing immediately. If + all return from Procedure or TimeoutInMicroseconds + expires, this event is signaled. The BSP + can use the CheckEvent() or WaitForEvent() + services to check the state of event. Type + EFI_EVENT is defined in CreateEvent() in + the Unified Extensible Firmware Interface + Specification. + @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 + all APs return from Procedure, then Procedure + on the failed APs is terminated. All enabled + APs are available for next function assigned + by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + If the timeout expires in blocking mode, + BSP returns EFI_TIMEOUT. If the timeout + expires in non-blocking mode, WaitEvent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure for + all APs. + @param[out] Finished If NULL, this parameter is ignored. In + blocking mode, this parameter is ignored. + In non-blocking mode, if AP returns from + Procedure before the timeout expires, its + content is set to TRUE. Otherwise, the + value is set to FALSE. The caller can + determine if the AP returned from Procedure + by evaluating this value. + + @retval EFI_SUCCESS In blocking mode, specified AP finished before + the timeout expires. + @retval EFI_SUCCESS In non-blocking mode, the function has been + dispatched to specified AP. + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was + signaled. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_TIMEOUT In blocking mode, the timeout expired before + the specified AP has finished. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibStartupThisAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN Timeout; + CPU_AP_DATA *CpuData; + + if (!IsCurrentProcessorBSP ()) { + return EFI_DEVICE_ERROR; + } + + if (Procedure == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) { + return EFI_NOT_FOUND; + } + + CpuData = &mCpuMpData.CpuData[ProcessorNumber]; + + if (IsProcessorBSP (ProcessorNumber)) { + return EFI_INVALID_PARAMETER; + } + + if (!IsProcessorEnabled (ProcessorNumber)) { + return EFI_INVALID_PARAMETER; + } + + if (GetApState (CpuData) != CpuStateIdle) { + return EFI_NOT_READY; + } + + if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) { + return EFI_UNSUPPORTED; + } + + Timeout = TimeoutInMicroseconds; + + mCpuMpData.StartCount = 1; + mCpuMpData.FinishCount = 0; + + SetApProcedure ( + CpuData, + Procedure, + ProcedureArgument + ); + + Status = DispatchCpu (ProcessorNumber); + if (EFI_ERROR (Status)) { + CpuData->State = CpuStateIdle; + return EFI_NOT_READY; + } + + if (WaitEvent != NULL) { + // Non Blocking + mCpuMpData.WaitEvent = WaitEvent; + gBS->SetTimer ( + CpuData->CheckThisAPEvent, + TimerPeriodic, + POLL_INTERVAL_US + ); + return EFI_SUCCESS; + } + + // Blocking + while (TRUE) { + if (GetApState (CpuData) == CpuStateFinished) { + CpuData->State = CpuStateIdle; + break; + } + + if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) { + return EFI_TIMEOUT; + } + + Timeout -= CalculateAndStallInterval (Timeout); + } + + return EFI_SUCCESS; +} + +/** + This service switches the requested AP to be the BSP from that point onward. + This service changes the BSP for all purposes. This call can only be + performed by the current BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an + enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_SUCCESS The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + +**/ +EFI_STATUS +EFIAPI +MpInitLibSwitchBSP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + // Skip for now as we need switch a bunch of stack stuff around and it's + // complex. May not be worth it? + return EFI_UNSUPPORTED; +} + +/** + This service lets the caller enable or disable an AP from this point onward. + This service may only be called from the BSP. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[in] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + @param[in] EnableAP Specifies the new state for the processor for + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that specifies + the new health status of the AP. This flag + corresponds to StatusFlag defined in + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only + the PROCESSOR_HEALTH_STATUS_BIT is used. All other + bits are ignored. If it is NULL, this parameter + is ignored. + + @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed + prior to this service returning. + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber + does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. + +**/ +EFI_STATUS +EFIAPI +MpInitLibEnableDisableAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ) +{ + UINTN StatusFlag; + CPU_AP_DATA *CpuData; + + StatusFlag = mCpuMpData.CpuData[ProcessorNumber].Info.StatusFlag; + CpuData = &mCpuMpData.CpuData[ProcessorNumber]; + + if (!IsCurrentProcessorBSP ()) { + return EFI_DEVICE_ERROR; + } + + if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) { + return EFI_NOT_FOUND; + } + + if (IsProcessorBSP (ProcessorNumber)) { + return EFI_INVALID_PARAMETER; + } + + if (GetApState (CpuData) != CpuStateIdle) { + return EFI_UNSUPPORTED; + } + + if (EnableAP) { + if (!IsProcessorEnabled (ProcessorNumber)) { + mCpuMpData.NumberOfEnabledProcessors++; + } + + StatusFlag |= PROCESSOR_ENABLED_BIT; + } else { + if (IsProcessorEnabled (ProcessorNumber)) { + mCpuMpData.NumberOfEnabledProcessors--; + } + + StatusFlag &= ~PROCESSOR_ENABLED_BIT; + } + + if (HealthFlag != NULL) { + StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT; + StatusFlag |= (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT); + } + + return EFI_SUCCESS; +} + +/** + This return the handle number for the calling processor. This service may be + called from the BSP and APs. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. + @param[out] ProcessorNumber The handle number of AP that is to become the new + BSP. The range is from 0 to the total number of + logical processors minus 1. The total number of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). + + @retval EFI_SUCCESS The current processor handle number was returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +EFI_STATUS +EFIAPI +MpInitLibWhoAmI ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ) +{ + UINTN Index; + UINT64 ProcessorId; + CPU_AP_DATA *CpuData; + + if (ProcessorNumber == NULL) { + return EFI_INVALID_PARAMETER; + } + + ProcessorId = GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ()); + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + if (CpuData->Info.ProcessorId == ProcessorId) { + break; + } + } + + *ProcessorNumber = Index; + return EFI_SUCCESS; +} + +/** Adds the specified processor the list of failed processors. + + @param ProcessorIndex The processor index to add. + @param ApState Processor state. + +**/ +STATIC +VOID +AddProcessorToFailedList ( + UINTN ProcessorIndex, + CPU_STATE ApState + ) +{ + UINTN Index; + BOOLEAN Found; + + Found = FALSE; + + if (ApState == CpuStateIdle) { + return; + } + + // If we are retrying make sure we don't double count + for (Index = 0; Index < mCpuMpData.FailedListIndex; Index++) { + if (mCpuMpData.FailedList[Index] == ProcessorIndex) { + Found = TRUE; + break; + } + } + + /* If the CPU isn't already in the FailedList, add it */ + if (!Found) { + mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index; + } +} + +/** Handles the StartupAllAPs case where the timeout has occurred. + +**/ +STATIC +VOID +ProcessStartupAllAPsTimeout ( + VOID + ) +{ + CPU_AP_DATA *CpuData; + UINTN Index; + + if (mCpuMpData.FailedList == NULL) { + return; + } + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + CpuData = &mCpuMpData.CpuData[Index]; + if (IsProcessorBSP (Index)) { + // Skip BSP + continue; + } + + if (!IsProcessorEnabled (Index)) { + // Skip Disabled processors + continue; + } + + CpuData = &mCpuMpData.CpuData[Index]; + AddProcessorToFailedList (Index, GetApState (CpuData)); + } +} + +/** Updates the status of the APs. + + @param[in] ProcessorIndex The index of the AP to update. +**/ +STATIC +VOID +UpdateApStatus ( + IN UINTN ProcessorIndex + ) +{ + EFI_STATUS Status; + CPU_AP_DATA *CpuData; + CPU_AP_DATA *NextCpuData; + CPU_STATE State; + UINTN NextNumber; + + CpuData = &mCpuMpData.CpuData[ProcessorIndex]; + + if (IsProcessorBSP (ProcessorIndex)) { + // Skip BSP + return; + } + + if (!IsProcessorEnabled (ProcessorIndex)) { + // Skip Disabled processors + return; + } + + State = GetApState (CpuData); + + switch (State) { + case CpuStateFinished: + if (mCpuMpData.SingleThread) { + Status = GetNextBlockedNumber (&NextNumber); + if (!EFI_ERROR (Status)) { + NextCpuData = &mCpuMpData.CpuData[NextNumber]; + + NextCpuData->State = CpuStateReady; + + SetApProcedure ( + NextCpuData, + mCpuMpData.Procedure, + mCpuMpData.ProcedureArgument + ); + } + } + + CpuData->State = CpuStateIdle; + mCpuMpData.FinishCount++; + break; + + default: + break; + } +} + +/** + If a timeout is specified in StartupAllAps(), a timer is set, which invokes + this procedure periodically to check whether all APs have finished. + + @param[in] Event The WaitEvent the user supplied. + @param[in] Context The event context. +**/ +STATIC +VOID +EFIAPI +CheckAllAPsStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + + if (mCpuMpData.TimeoutActive) { + mCpuMpData.Timeout -= CalculateAndStallInterval (mCpuMpData.Timeout); + } + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + UpdateApStatus (Index); + } + + if (mCpuMpData.TimeoutActive && (mCpuMpData.Timeout == 0)) { + ProcessStartupAllAPsTimeout (); + + // Force terminal exit + mCpuMpData.FinishCount = mCpuMpData.StartCount; + } + + if (mCpuMpData.FinishCount != mCpuMpData.StartCount) { + return; + } + + gBS->SetTimer ( + mCpuMpData.CheckAllAPsEvent, + TimerCancel, + 0 + ); + + if (mCpuMpData.FailedListIndex == 0) { + if (mCpuMpData.FailedList != NULL) { + FreePool (mCpuMpData.FailedList); + mCpuMpData.FailedList = NULL; + } + } + + gBS->SignalEvent (mCpuMpData.WaitEvent); +} + +/** Invoked periodically via a timer to check the state of the processor. + + @param Event The event supplied by the timer expiration. + @param Context The processor context. + +**/ +STATIC +VOID +EFIAPI +CheckThisAPStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + CPU_AP_DATA *CpuData; + CPU_STATE State; + + CpuData = Context; + CpuData->TimeTaken += POLL_INTERVAL_US; + + State = GetApState (CpuData); + + if (State == CpuStateFinished) { + Status = gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0); + ASSERT_EFI_ERROR (Status); + + if (mCpuMpData.WaitEvent != NULL) { + Status = gBS->SignalEvent (mCpuMpData.WaitEvent); + ASSERT_EFI_ERROR (Status); + } + + CpuData->State = CpuStateIdle; + } + + if (CpuData->TimeTaken > CpuData->Timeout) { + if (mCpuMpData.WaitEvent != NULL) { + Status = gBS->SignalEvent (mCpuMpData.WaitEvent); + ASSERT_EFI_ERROR (Status); + } + } +} + +/** + This function is called by all processors (both BSP and AP) once and collects + MP related data. + + @param BSP TRUE if the processor is the BSP. + @param Mpidr The MPIDR for the specified processor. This should be + the full MPIDR and not only the affinity bits. + @param ProcessorIndex The index of the processor. + + @return EFI_SUCCESS if the data for the processor collected and filled in. + +**/ +STATIC +EFI_STATUS +FillInProcessorInformation ( + IN BOOLEAN BSP, + IN UINTN Mpidr, + IN UINTN ProcessorIndex + ) +{ + EFI_PROCESSOR_INFORMATION *CpuInfo; + + CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info; + + CpuInfo->ProcessorId = GET_MPIDR_AFFINITY_BITS (Mpidr); + CpuInfo->StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT; + + if (BSP) { + CpuInfo->StatusFlag |= PROCESSOR_AS_BSP_BIT; + } + + if (Mpidr & MPIDR_MT_BIT) { + CpuInfo->Location.Package = GET_MPIDR_AFF2 (Mpidr); + CpuInfo->Location.Core = GET_MPIDR_AFF1 (Mpidr); + CpuInfo->Location.Thread = GET_MPIDR_AFF0 (Mpidr); + + CpuInfo->ExtendedInformation.Location2.Package = GET_MPIDR_AFF3 (Mpidr); + CpuInfo->ExtendedInformation.Location2.Die = GET_MPIDR_AFF2 (Mpidr); + CpuInfo->ExtendedInformation.Location2.Core = GET_MPIDR_AFF1 (Mpidr); + CpuInfo->ExtendedInformation.Location2.Thread = GET_MPIDR_AFF0 (Mpidr); + } else { + CpuInfo->Location.Package = GET_MPIDR_AFF1 (Mpidr); + CpuInfo->Location.Core = GET_MPIDR_AFF0 (Mpidr); + CpuInfo->Location.Thread = 0; + + CpuInfo->ExtendedInformation.Location2.Package = GET_MPIDR_AFF2 (Mpidr); + CpuInfo->ExtendedInformation.Location2.Die = GET_MPIDR_AFF1 (Mpidr); + CpuInfo->ExtendedInformation.Location2.Core = GET_MPIDR_AFF0 (Mpidr); + CpuInfo->ExtendedInformation.Location2.Thread = 0; + } + + CpuInfo->ExtendedInformation.Location2.Package = 0; + CpuInfo->ExtendedInformation.Location2.Module = 0; + CpuInfo->ExtendedInformation.Location2.Tile = 0; + + mCpuMpData.CpuData[ProcessorIndex].State = BSP ? CpuStateBusy : CpuStateIdle; + + mCpuMpData.CpuData[ProcessorIndex].Procedure = NULL; + mCpuMpData.CpuData[ProcessorIndex].Parameter = NULL; + + return EFI_SUCCESS; +} + +/** Initializes the MP Services system data + + @param NumberOfProcessors The number of processors, both BSP and AP. + @param CpuInfo CPU information gathered earlier during boot. + +**/ +VOID +MpInitLibInitialize ( + IN UINTN NumberOfProcessors, + IN ARM_PROCESSOR_TABLE *CpuInfo + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_EVENT ReadyToBootEvent; + + // + // Clear the data structure area first. + // + ZeroMem (&mCpuMpData, sizeof (CPU_MP_DATA)); + // + // First BSP fills and inits all known values, including its own records. + // + mCpuMpData.NumberOfProcessors = NumberOfProcessors; + mCpuMpData.NumberOfEnabledProcessors = NumberOfProcessors; + + mCpuMpData.CpuData = AllocateZeroPool ( + mCpuMpData.NumberOfProcessors * + sizeof (CPU_AP_DATA) + ); + ASSERT (mCpuMpData.CpuData != NULL); + + /* Allocate one extra for the NULL entry at the end */ + gProcessorIDs = AllocatePool ((mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64)); + ASSERT (gProcessorIDs != NULL); + + FillInProcessorInformation (TRUE, CpuInfo->ArmCpus[0].Mpidr, 0); + gProcessorIDs[0] = mCpuMpData.CpuData[0].Info.ProcessorId; + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + CheckAllAPsStatus, + NULL, + &mCpuMpData.CheckAllAPsEvent + ); + ASSERT_EFI_ERROR (Status); + + gApStacksBase = AllocatePool ( + mCpuMpData.NumberOfProcessors * + gApStackSize + ); + ASSERT (gApStacksBase != NULL); + + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { + if (IsProcessorBSP (Index)) { + /* Skip BSP */ + continue; + } + + FillInProcessorInformation (FALSE, CpuInfo->ArmCpus[Index].Mpidr, Index); + + gProcessorIDs[Index] = mCpuMpData.CpuData[Index].Info.ProcessorId; + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + CheckThisAPStatus, + (VOID *)&mCpuMpData.CpuData[Index], + &mCpuMpData.CpuData[Index].CheckThisAPEvent + ); + ASSERT (Status == EFI_SUCCESS); + } + + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + ReadyToBootSignaled, + NULL, + &ReadyToBootEvent + ); + ASSERT_EFI_ERROR (Status); + + gProcessorIDs[Index] = MAX_UINT32; +} + +/** + Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is + signaled. After this point, non-blocking mode is no longer allowed. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +STATIC +VOID +EFIAPI +ReadyToBootSignaled ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mNonBlockingModeAllowed = FALSE; +} diff --git a/ArmPkg/Library/MpInitLib/InternalMpInitLib.h b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h new file mode 100644 index 000000000000..461d85ffd28f --- /dev/null +++ b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h @@ -0,0 +1,359 @@ +/** @file + +Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2011, Apple Inc. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef MP_INTERNAL_INIT_LIB_H_ +#define MP_INTERNAL_INIT_LIB_H_ + +#include <Protocol/Cpu.h> +#include <Protocol/MpService.h> + +#include <Library/BaseLib.h> +#include <Library/UefiLib.h> + + +#define AP_STACK_SIZE 0x1000 + +// +// Internal Data Structures +// + +// +// AP state +// +// The state transitions for an AP when it process a procedure are: +// Idle ----> Ready ----> Busy ----> Idle +// [BSP] [AP] [AP] +// +typedef enum { + CpuStateIdle, + CpuStateReady, + CpuStateBlocked, + CpuStateBusy, + CpuStateFinished, + CpuStateDisabled +} CPU_STATE; + +// +// Define Individual Processor Data block. +// +typedef struct { + EFI_PROCESSOR_INFORMATION Info; + EFI_AP_PROCEDURE Procedure; + VOID *Parameter; + CPU_STATE State; + EFI_EVENT CheckThisAPEvent; + UINTN Timeout; + UINTN TimeTaken; +} CPU_AP_DATA; + +// +// Define MP data block which consumes individual processor block. +// +typedef struct { + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + EFI_EVENT CheckAllAPsEvent; + EFI_EVENT WaitEvent; + UINTN FinishCount; + UINTN StartCount; + EFI_AP_PROCEDURE Procedure; + VOID *ProcedureArgument; + BOOLEAN SingleThread; + UINTN StartedNumber; + CPU_AP_DATA *CpuData; + UINTN Timeout; + UINTN *FailedList; + UINTN FailedListIndex; + BOOLEAN TimeoutActive; +} CPU_MP_DATA; + +EFI_STATUS +EFIAPI +CpuMpServicesInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +extern EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate; + +/** Secondary core entry point. + +**/ +VOID ApEntryPoint ( + VOID + ); + +/** C entry-point for the AP. + This function gets called from the assembly function ApEntryPoint. +**/ +VOID +ApProcedure ( + VOID + ); + +/** Turns on the specified core using PSCI and executes the user-supplied + function that's been configured via a previous call to SetApProcedure. + + @param ProcessorIndex The index of the core to turn on. + + @retval EFI_SUCCESS The processor was successfully turned on. + @retval EFI_DEVICE_ERROR An error occurred turning the processor on. + +**/ +STATIC +EFI_STATUS +EFIAPI +DispatchCpu ( + IN UINTN ProcessorIndex + ); + +/** Returns whether the specified processor is the BSP. + + @param[in] ProcessorIndex The index the processor to check. + + @return TRUE if the processor is the BSP, FALSE otherwise. +**/ +STATIC +BOOLEAN +IsProcessorBSP ( + UINTN ProcessorIndex + ); + +/** Returns whether the processor executing this function is the BSP. + + @return Whether the current processor is the BSP. +**/ +STATIC +BOOLEAN +IsCurrentProcessorBSP ( + VOID + ); + +/** Returns whether the specified processor is enabled. + + @param[in] ProcessorIndex The index of the processor to check. + + @return TRUE if the processor is enabled, FALSE otherwise. +**/ +STATIC +BOOLEAN +IsProcessorEnabled ( + UINTN ProcessorIndex + ); + +/** Configures the processor context with the user-supplied procedure and + argument. + + @param CpuData The processor context. + @param Procedure The user-supplied procedure. + @param ProcedureArgument The user-supplied procedure argument. + +**/ +STATIC +VOID +SetApProcedure ( + IN CPU_AP_DATA *CpuData, + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument + ); + +/** + Get the Application Processors state. + + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP + + @return The AP status +**/ +CPU_STATE +GetApState ( + IN CPU_AP_DATA *CpuData + ); + +/** Returns the index of the next processor that is blocked. + + @param[out] NextNumber The index of the next blocked processor. + + @retval EFI_SUCCESS Successfully found the next blocked processor. + @retval EFI_NOT_FOUND There are no blocked processors. + +**/ +STATIC +EFI_STATUS +GetNextBlockedNumber ( + OUT UINTN *NextNumber + ); + +/** Stalls the BSP for the minimum of gPollInterval and Timeout. + + @param[in] Timeout The time limit in microseconds remaining for + APs to return from Procedure. + + @retval StallTime Time of execution stall. +**/ +STATIC +UINTN +CalculateAndStallInterval ( + IN UINTN Timeout + ); + +/** Returns whether all processors are in the idle state. + + @return Whether all the processors are idle. + +**/ +STATIC +BOOLEAN +CheckAllCpusReady ( + VOID + ); + +/** Sets up the state for the StartupAllAPs function. + + @param SingleThread Whether the APs will execute sequentially. + +**/ +STATIC +VOID +StartupAllAPsPrepareState ( + IN BOOLEAN SingleThread + ); + +/** Handles execution of StartupAllAPs when a WaitEvent has been specified. + + @param Procedure The user-supplied procedure. + @param ProcedureArgument The user-supplied procedure argument. + @param WaitEvent The wait event to be signaled when the work is + complete or a timeout has occurred. + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero + indicates an infinite timeout. + + @return EFI_SUCCESS on success. +**/ +STATIC +EFI_STATUS +StartupAllAPsWithWaitEvent ( + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument, + IN EFI_EVENT WaitEvent, + IN UINTN TimeoutInMicroseconds + ); + +/** Handles execution of StartupAllAPs when no wait event has been specified. + + @param Procedure The user-supplied procedure. + @param ProcedureArgument The user-supplied procedure argument. + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero + indicates an infinite timeout. + @param SingleThread Whether the APs will execute sequentially. + @param FailedCpuList User-supplied pointer for list of failed CPUs. + + @return EFI_SUCCESS on success. +**/ +STATIC +EFI_STATUS +StartupAllAPsNoWaitEvent ( + IN EFI_AP_PROCEDURE Procedure, + IN VOID *ProcedureArgument, + IN UINTN TimeoutInMicroseconds, + IN BOOLEAN SingleThread, + IN UINTN **FailedCpuList + ); + + +/** Adds the specified processor the list of failed processors. + + @param ProcessorIndex The processor index to add. + @param ApState Processor state. + +**/ +STATIC +VOID +AddProcessorToFailedList ( + UINTN ProcessorIndex, + CPU_STATE ApState + ); + +/** Handles the StartupAllAPs case where the timeout has occurred. + +**/ +STATIC +VOID +ProcessStartupAllAPsTimeout ( + VOID + ); + +/** + If a timeout is specified in StartupAllAps(), a timer is set, which invokes + this procedure periodically to check whether all APs have finished. + + @param[in] Event The WaitEvent the user supplied. + @param[in] Context The event context. +**/ +STATIC +VOID +EFIAPI +CheckAllAPsStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** Invoked periodically via a timer to check the state of the processor. + + @param Event The event supplied by the timer expiration. + @param Context The processor context. + +**/ +STATIC +VOID +EFIAPI +CheckThisAPStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + This function is called by all processors (both BSP and AP) once and collects + MP related data. + + @param BSP TRUE if the processor is the BSP. + @param Mpidr The MPIDR for the specified processor. This should be + the full MPIDR and not only the affinity bits. + @param ProcessorIndex The index of the processor. + + @return EFI_SUCCESS if the data for the processor collected and filled in. + +**/ +STATIC +EFI_STATUS +FillInProcessorInformation ( + IN BOOLEAN BSP, + IN UINTN Mpidr, + IN UINTN ProcessorIndex + ); + +/** + Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is + signaled. After this point, non-blocking mode is no longer allowed. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +STATIC +VOID +EFIAPI +ReadyToBootSignaled ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +#endif /* MP_INTERNAL_INIT_LIB_H_ */ diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc index 5a1598d90ca7..af6e48fd6cfc 100644 --- a/ArmVirtPkg/ArmVirt.dsc.inc +++ b/ArmVirtPkg/ArmVirt.dsc.inc @@ -261,6 +261,9 @@ [LibraryClasses.ARM] ArmSoftFloatLib|ArmPkg/Library/ArmSoftFloatLib/ArmSoftFloatLib.inf +[LibraryClasses.AARCH64] + MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf + [BuildOptions] RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG -- 2.31.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL 2021-12-15 17:46 ` [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL Rebecca Cran @ 2021-12-15 17:55 ` Ard Biesheuvel 2021-12-15 18:15 ` Rebecca Cran 2021-12-15 21:26 ` Rebecca Cran [not found] ` <16C10ACB9CD70BF0.6360@groups.io> 2 siblings, 1 reply; 9+ messages in thread From: Ard Biesheuvel @ 2021-12-15 17:55 UTC (permalink / raw) To: Rebecca Cran Cc: edk2-devel-groups-io, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar Hi Rebecca, On Wed, 15 Dec 2021 at 18:47, Rebecca Cran <rebecca@nuviainc.com> wrote: > > Add support for EFI_MP_SERVICES_PROTOCOL during the DXE phase under > AArch64. > > PSCI_CPU_ON is called to power on the core, the supplied procedure is > executed and PSCI_CPU_OFF is called to power off the core. > > Minimal setup is done before calling the supplied procedure: for example > the MMU and caches are not enabled. > > Signed-off-by: Rebecca Cran <rebecca@nuviainc.com> > --- > ArmPkg/ArmPkg.dec | 4 + > ArmPkg/ArmPkg.dsc | 4 + > ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 21 + > ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 21 + > ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 + > ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 + > ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 + > ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 608 ++++++++ > ArmPkg/Include/Library/MpInitLib.h | 366 +++++ > ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 65 + > ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 + > ArmPkg/Library/MpInitLib/DxeMpLib.c | 1477 ++++++++++++++++++++ > ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 359 +++++ Perhaps I misunderstood your question about splitting up this patch, as surely, adding a completely new library can be broken out into a separate one? > ArmVirtPkg/ArmVirt.dsc.inc | 3 + > 14 files changed, 2999 insertions(+) > > diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec > index 9da1bbc9f216..363eddc57393 100644 > --- a/ArmPkg/ArmPkg.dec > +++ b/ArmPkg/ArmPkg.dec > @@ -75,6 +75,10 @@ > # > DefaultExceptionHandlerLib|Include/Library/DefaultExceptionHandlerLib.h > > + ## @libraryclass Provides a MP Services interface. > + # > + MpInitLib|Include/Library/MpInitLib.h > + > ## @libraryclass Provides an interface to query miscellaneous OEM > # information. > # > diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc > index 59fd8f295d4f..6e053d6ee31d 100644 > --- a/ArmPkg/ArmPkg.dsc > +++ b/ArmPkg/ArmPkg.dsc > @@ -100,6 +100,9 @@ > PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf > PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf > > +[LibraryClasses.AARCH64] > + MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > + > [LibraryClasses.ARM, LibraryClasses.AARCH64] > NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf > > @@ -163,6 +166,7 @@ > [Components.AARCH64] > ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf > ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf > + ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > > [Components.AARCH64, Components.ARM] > ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf > diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c > new file mode 100644 > index 000000000000..cb7cb747bc15 > --- /dev/null > +++ b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c > @@ -0,0 +1,21 @@ > +/** @file > + Architecture specific functions. > + > + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include <CpuDxe.h> > + > +/** Initializes multi-processor support. > + * > +**/ > +VOID > +ArchInitializeMpSupport ( > + VOID > + ) > +{ > + InitializeMpSupport (); > +} > diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Arch.c b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c > new file mode 100644 > index 000000000000..f8d57b41225a > --- /dev/null > +++ b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c > @@ -0,0 +1,21 @@ > +/** @file > + Architecture specific functions. > + > + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include <CpuDxe.h> > + > +/** Initializes multi-processor support. > + * > +**/ > +VOID > +ArchInitializeMpSupport ( > + VOID > + ) > +{ > + /* Nothing to do - ARM doesn't support EFI_MP_SERVICES_PROTOCOL */ > +} > diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c > index 62a6e2d620a6..6c076982a1bd 100644 > --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c > +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c > @@ -275,5 +275,7 @@ CpuDxeInitialize ( > ); > ASSERT_EFI_ERROR (Status); > > + ArchInitializeMpSupport (); > + > return Status; > } > diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h > index 58ee1444c1b3..3f04b89d7ad0 100644 > --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h > +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h > @@ -141,4 +141,14 @@ SetGcdMemorySpaceAttributes ( > IN UINT64 Attributes > ); > > +VOID > +InitializeMpSupport ( > + VOID > + ); > + > +VOID > +ArchInitializeMpSupport ( > + VOID > + ); > + > #endif // CPU_DXE_H_ > diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf > index e5549fc71df7..f4cdb8ab5613 100644 > --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf > +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf > @@ -26,10 +26,13 @@ > Exception.c > > [Sources.ARM] > + Arm/Arch.c > Arm/Mmu.c > > [Sources.AARCH64] > + AArch64/Arch.c > AArch64/Mmu.c > + CpuMpInit.c > > [Packages] > ArmPkg/ArmPkg.dec > @@ -37,6 +40,9 @@ > MdePkg/MdePkg.dec > MdeModulePkg/MdeModulePkg.dec > > +[LibraryClasses.AARCH64] > + MpInitLib > + > [LibraryClasses] > ArmLib > ArmMmuLib > diff --git a/ArmPkg/Drivers/CpuDxe/CpuMpInit.c b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c > new file mode 100644 > index 000000000000..876a29e09b1b > --- /dev/null > +++ b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c > @@ -0,0 +1,608 @@ > +/** @file > + Construct MP Services Protocol. > + > + The MP Services Protocol provides a generalized way of performing following tasks: > + - Retrieving information of multi-processor environment and MP-related status of > + specific processors. > + - Dispatching user-provided function to APs. > + - Maintain MP-related processor status. > + > + The MP Services Protocol must be produced on any system with more than one logical > + processor. > + > + The Protocol is available only during boot time. > + > + MP Services Protocol is hardware-independent. Most of the logic of this protocol > + is architecturally neutral. It abstracts the multi-processor environment and > + status of processors, and provides interfaces to retrieve information, maintain, > + and dispatch. > + > + MP Services Protocol may be consumed by ACPI module. The ACPI module may use this > + protocol to retrieve data that are needed for an MP platform and report them to OS. > + MP Services Protocol may also be used to program and configure processors, such > + as MTRR synchronization for memory space attributes setting in DXE Services. > + MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot > + by taking advantage of the processing capabilities of the APs, for example, using > + APs to help test system memory in parallel with other device initialization. > + Diagnostics applications may also use this protocol for multi-processor. > + > + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > +#include <Library/HobLib.h> > +#include <Library/MpInitLib.h> > +#include <Library/UefiBootServicesTableLib.h> > + > +/** > + This service retrieves the number of logical processor in the platform > + and the number of those logical processors that are enabled on this boot. > + This service may only be called from the BSP. > + > + This function is used to retrieve the following information: > + - The number of logical processors that are present in the system. > + - The number of enabled logical processors in the system at the instant > + this call is made. > + > + Because MP Service Protocol provides services to enable and disable processors > + dynamically, the number of enabled logical processors may vary during the > + course of a boot session. > + > + If this service is called from an AP, then EFI_DEVICE_ERROR is returned. > + If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then > + EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors > + is returned in NumberOfProcessors, the number of currently enabled processor > + is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned. > + > + @param[in] This A pointer to the > + EFI_MP_SERVICES_PROTOCOL instance. > + @param[out] NumberOfProcessors Pointer to the total number of logical > + processors in the system, including > + the BSP and disabled APs. > + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled > + logical processors that exist in the > + system, including the BSP. > + > + @retval EFI_SUCCESS The number of logical processors and enabled > + logical processors was retrieved. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. > + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GetNumberOfProcessors ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + OUT UINTN *NumberOfProcessors, > + OUT UINTN *NumberOfEnabledProcessors > + ) > +{ > + return MpInitLibGetNumberOfProcessors ( > + This, > + NumberOfProcessors, > + NumberOfEnabledProcessors > + ); > +} > + > +/** > + Gets detailed MP-related information on the requested processor at the > + instant this call is made. This service may only be called from the BSP. > + > + This service retrieves detailed MP-related information about any processor > + on the platform. Note the following: > + - The processor information may change during the course of a boot session. > + - The information presented here is entirely MP related. > + > + Information regarding the number of caches and their sizes, frequency of > + operation, slot numbers is all considered platform-related information and is > + not provided by this service. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] ProcessorNumber The index of the processor. > + @param[out] ProcessorInfoBuffer A pointer to the buffer where information > + for the requested processor is deposited. > + > + @retval EFI_SUCCESS Processor information was returned. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist in the platform. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +GetProcessorInfo ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer > + ) > +{ > + return MpInitLibGetProcessorInfo ( > + This, > + ProcessorNumber, > + ProcessorInfoBuffer > + ); > +} > + > +/** > + This service executes a caller provided function on all enabled APs. APs can > + run either simultaneously or one at a time in sequence. This service supports > + both blocking and non-blocking requests. The non-blocking requests use EFI > + events so the BSP can detect when the APs have finished. This service may only > + be called from the BSP. > + > + This function is used to dispatch all the enabled APs to the function > + specified by Procedure. If any enabled AP is busy, then EFI_NOT_READY is > + returned immediately and Procedure is not started on any AP. > + > + If SingleThread is TRUE, all the enabled APs execute the function specified by > + Procedure one by one, in ascending order of processor handle number. > + Otherwise, all the enabled APs execute the function specified by Procedure > + simultaneously. > + > + If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all > + APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in > + non-blocking mode, and the BSP returns from this service without waiting for > + APs. If a non-blocking mode is requested after the UEFI Event > + EFI_EVENT_GROUP_READY_TO_BOOT is signaled, then EFI_UNSUPPORTED must be > + returned. > + > + If the timeout specified by TimeoutInMicroseconds expires before all APs > + return from Procedure, then Procedure on the failed APs is terminated. > + All enabled APs are always available for further calls to > + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and > + EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its > + content points to the list of processor handle numbers in which Procedure was > + terminated. > + > + Note: It is the responsibility of the consumer of the > + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() to make sure that the nature of the > + code that is executed on the BSP and the dispatched APs is well controlled. > + The MP Services Protocol does not guarantee that the Procedure function is > + MP-safe. Hence, the tasks that can be run in parallel are limited to certain > + independent tasks and well-controlled exclusive code. EFI services and > + protocols may not be called by APs unless otherwise specified. > + > + In blocking execution mode, BSP waits until all APs finish or > + TimeoutInMicroseconds expires. > + > + In non-blocking execution mode, BSP is freed to return to the caller and then > + proceed to the next task without having to wait for APs. The following > + sequence needs to occur in a non-blocking execution mode: > + > + -# The caller that intends to use this MP Services Protocol in non-blocking > + mode creates WaitEvent by calling the EFI CreateEvent() service. The > + caller invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter > + WaitEvent is not NULL, then StartupAllAPs() executes in non-blocking > + mode. It requests the function specified by Procedure to be started on > + all the enabled APs, and releases the BSP to continue with other tasks. > + -# The caller can use the CheckEvent() and WaitForEvent() services to check > + the state of the WaitEvent created in step 1. > + -# When the APs complete their task or TimeoutInMicroSecondss expires, the > + MP Service signals WaitEvent by calling the EFI SignalEvent() function. > + If FailedCpuList is not NULL, its content is available when WaitEvent is > + signaled. If all APs returned from Procedure prior to the timeout, then > + FailedCpuList is set to NULL. If not all APs return from Procedure before > + the timeout, then FailedCpuList is filled in with the list of the failed > + APs. The buffer is allocated by MP Service Protocol using AllocatePool(). > + It is the caller's responsibility to free the buffer with FreePool() > + service. > + -# This invocation of SignalEvent() function informs the caller that invoked > + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs > + completed the specified task or a timeout occurred. The contents of > + FailedCpuList can be examined to determine which APs did not complete the > + specified task prior to the timeout. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs execute > + the function specified by Procedure one by > + one, in ascending order of processor > + handle number. If FALSE, then all the > + enabled APs execute the function specified > + by Procedure simultaneously. > + @param[in] WaitEvent The event created by the caller with > + CreateEvent() service. If it is NULL, > + then execute in blocking mode. BSP waits > + until all APs finish or > + TimeoutInMicroseconds expires. If it's > + not NULL, then execute in non-blocking > + mode. BSP requests the function specified > + by Procedure to be started on all the > + enabled APs, and go on executing > + immediately. If all return from Procedure, > + or TimeoutInMicroseconds expires, this > + event is signaled. The BSP can use the > + CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @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 all APs return from Procedure, then > + Procedure on the failed APs is terminated. > + All enabled APs are available for next > + function assigned by > + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() > + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored. > + Otherwise, if all APs finish successfully, > + then its content is set to NULL. If not > + all APs finish before timeout expires, > + then its content is set to address of the > + buffer holding handle numbers of the > + failed APs. > + The buffer is allocated by MP Service > + Protocol, and it's the caller's > + responsibility to free the buffer with > + FreePool() service. > + In blocking mode, it is ready for > + consumption when the call returns. In > + non-blocking mode, it is ready when > + WaitEvent is signaled. The list of failed > + CPU is terminated by END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finished before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has been > + dispatched to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_DEVICE_ERROR Caller processor is AP. > + @retval EFI_NOT_STARTED No enabled APs exist in the system. > + @retval EFI_NOT_READY Any enabled APs are busy. > + @retval EFI_TIMEOUT In blocking mode, the timeout expired before > + all enabled APs have finished. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +StartupAllAPs ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ) > +{ > + return MpInitLibStartupAllAPs ( > + This, > + Procedure, > + SingleThread, > + WaitEvent, > + TimeoutInMicroseconds, > + ProcedureArgument, > + FailedCpuList > + ); > +} > + > +/** > + This service lets the caller get one enabled AP to execute a caller-provided > + function. The caller can request the BSP to either wait for the completion > + of the AP or just proceed with the next task by using the EFI event mechanism. > + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking > + execution support. This service may only be called from the BSP. > + > + This function is used to dispatch one enabled AP to the function specified by > + Procedure passing in the argument specified by ProcedureArgument. If WaitEvent > + is NULL, execution is in blocking mode. The BSP waits until the AP finishes or > + TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode. > + BSP proceeds to the next task without waiting for the AP. If a non-blocking mode > + is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled, > + then EFI_UNSUPPORTED must be returned. > + > + If the timeout specified by TimeoutInMicroseconds expires before the AP returns > + from Procedure, then execution of Procedure by the AP is terminated. The AP is > + available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and > + EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The range is > + from 0 to the total number of logical > + processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until all APs finish > + or TimeoutInMicroseconds expires. If it's > + not NULL, then execute in non-blocking mode. > + BSP requests the function specified by > + Procedure to be started on all the enabled > + APs, and go on executing immediately. If > + all return from Procedure or TimeoutInMicroseconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @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 > + all APs return from Procedure, then Procedure > + on the failed APs is terminated. All enabled > + APs are available for next function assigned > + by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() > + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] Finished If NULL, this parameter is ignored. In > + blocking mode, this parameter is ignored. > + In non-blocking mode, if AP returns from > + Procedure before the timeout expires, its > + content is set to TRUE. Otherwise, the > + value is set to FALSE. The caller can > + determine if the AP returned from Procedure > + by evaluating this value. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finished before > + the timeout expires. > + @retval EFI_SUCCESS In non-blocking mode, the function has been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_TIMEOUT In blocking mode, the timeout expired before > + the specified AP has finished. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +StartupThisAP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + return MpInitLibStartupThisAP ( > + This, > + Procedure, > + ProcessorNumber, > + WaitEvent, > + TimeoutInMicroseconds, > + ProcedureArgument, > + Finished > + ); > +} > + > +/** > + This service switches the requested AP to be the BSP from that point onward. > + This service changes the BSP for all purposes. This call can only be > + performed by the current BSP. > + > + This service switches the requested AP to be the BSP from that point onward. > + This service changes the BSP for all purposes. The new BSP can take over the > + execution of the old BSP and continue seamlessly from where the old one left > + off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT > + is signaled. > + > + If the BSP cannot be switched prior to the return from this service, then > + EFI_UNSUPPORTED must be returned. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an > + enabled AP. Otherwise, it will be disabled. > + > + @retval EFI_SUCCESS BSP successfully switched. > + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to > + this service returning. > + @retval EFI_UNSUPPORTED Switching the BSP is not supported. > + @retval EFI_SUCCESS The calling processor is an AP. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or > + a disabled AP. > + @retval EFI_NOT_READY The specified AP is busy. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +SwitchBSP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableOldBSP > + ) > +{ > + return MpInitLibSwitchBSP (This, ProcessorNumber, EnableOldBSP); > +} > + > +/** > + This service lets the caller enable or disable an AP from this point onward. > + This service may only be called from the BSP. > + > + This service allows the caller enable or disable an AP from this point onward. > + The caller can optionally specify the health status of the AP by Health. If > + an AP is being disabled, then the state of the disabled AP is implementation > + dependent. If an AP is enabled, then the implementation must guarantee that a > + complete initialization sequence is performed on the AP, so the AP is in a state > + that is compatible with an MP operating system. This service may not be supported > + after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled. > + > + If the enable or disable AP operation cannot be completed prior to the return > + from this service, then EFI_UNSUPPORTED must be returned. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the processor for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that specifies > + the new health status of the AP. This flag > + corresponds to StatusFlag defined in > + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only > + the PROCESSOR_HEALTH_STATUS_BIT is used. All other > + bits are ignored. If it is NULL, this parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed > + prior to this service returning. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +EnableDisableAP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableAP, > + IN UINT32 *HealthFlag OPTIONAL > + ) > +{ > + return MpInitLibEnableDisableAP (This, ProcessorNumber, EnableAP, HealthFlag); > +} > + > +/** > + This return the handle number for the calling processor. This service may be > + called from the BSP and APs. > + > + This service returns the processor handle number for the calling processor. > + The returned value is in the range from 0 to the total number of logical > + processors minus 1. The total number of logical processors can be retrieved > + with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be > + called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER > + is returned. Otherwise, the current processors handle number is returned in > + ProcessorNumber, and EFI_SUCCESS is returned. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[out] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + > + @retval EFI_SUCCESS The current processor handle number was returned > + in ProcessorNumber. > + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +WhoAmI ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + OUT UINTN *ProcessorNumber > + ) > +{ > + return MpInitLibWhoAmI (This, ProcessorNumber); > +} > + > +EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = { > + GetNumberOfProcessors, > + GetProcessorInfo, > + StartupAllAPs, > + StartupThisAP, > + SwitchBSP, > + EnableDisableAP, > + WhoAmI > +}; > + > +/** Initialize multi-processor support. > + > +**/ > +VOID > +InitializeMpSupport ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE Handle; > + UINTN MaxCpus; > + EFI_HOB_GENERIC_HEADER *Hob; > + VOID *HobData; > + UINTN HobDataSize; > + ARM_PROCESSOR_TABLE CpuInfo; > + > + MaxCpus = 1; > + ZeroMem (&CpuInfo, sizeof (ARM_PROCESSOR_TABLE)); > + > + DEBUG ((DEBUG_INFO, "Starting MP services")); > + > + Hob = GetFirstGuidHob (&gArmMpCoreInfoGuid); > + if (Hob != NULL) { > + HobData = GET_GUID_HOB_DATA (Hob); > + HobDataSize = GET_GUID_HOB_DATA_SIZE (Hob); > + CpuInfo.ArmCpus = (ARM_CORE_INFO *)HobData; > + CpuInfo.NumberOfEntries = HobDataSize / sizeof (ARM_CORE_INFO); > + MaxCpus = CpuInfo.NumberOfEntries; > + } > + > + if (MaxCpus == 1) { > + DEBUG ((DEBUG_WARN, "Trying to use EFI_MP_SERVICES_PROTOCOL on a UP system")); > + // We are not MP so nothing to do > + return; > + } > + > + MpInitLibInitialize (MaxCpus, &CpuInfo); > + > + // > + // Now install the MP services protocol. > + // > + Handle = NULL; > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Handle, > + &gEfiMpServiceProtocolGuid, > + &mMpServicesTemplate, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > +} > diff --git a/ArmPkg/Include/Library/MpInitLib.h b/ArmPkg/Include/Library/MpInitLib.h > new file mode 100644 > index 000000000000..a4b80c18a9e8 > --- /dev/null > +++ b/ArmPkg/Include/Library/MpInitLib.h > @@ -0,0 +1,366 @@ > +/** @file > + > +Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> > +Portions copyright (c) 2011, Apple Inc. All rights reserved. > + > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef MP_INITLIB_H_ > +#define MP_INITLIB_H_ > + > +#include <Protocol/Cpu.h> > +#include <Protocol/MpService.h> > +#include <Library/BaseLib.h> > +#include <Library/UefiLib.h> > +#include <Guid/ArmMpCoreInfo.h> > + > + > +/** > + This service retrieves the number of logical processor in the platform > + and the number of those logical processors that are enabled on this boot. > + This service may only be called from the BSP. > + > + @param[in] This A pointer to the > + EFI_MP_SERVICES_PROTOCOL instance. > + @param[out] NumberOfProcessors Pointer to the total number of logical > + processors in the system, including > + the BSP and disabled APs. > + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled > + logical processors that exist in the > + system, including the BSP. > + > + @retval EFI_SUCCESS The number of logical processors and enabled > + logical processors was retrieved. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. > + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibGetNumberOfProcessors ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + OUT UINTN *NumberOfProcessors, > + OUT UINTN *NumberOfEnabledProcessors > + ); > + > +/** > + Gets detailed MP-related information on the requested processor at the > + instant this call is made. This service may only be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] ProcessorIndex The index of the processor. > + @param[out] ProcessorInfoBuffer A pointer to the buffer where information > + for the requested processor is deposited. > + > + @retval EFI_SUCCESS Processor information was returned. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist in the platform. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibGetProcessorInfo ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorIndex, > + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer > + ); > + > + > +/** > + This service executes a caller provided function on all enabled APs. APs can > + run either simultaneously or one at a time in sequence. This service supports > + both blocking and non-blocking requests. The non-blocking requests use EFI > + events so the BSP can detect when the APs have finished. This service may only > + be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs execute > + the function specified by Procedure one by > + one, in ascending order of processor > + handle number. If FALSE, then all the > + enabled APs execute the function specified > + by Procedure simultaneously. > + @param[in] WaitEvent The event created by the caller with > + CreateEvent() service. If it is NULL, > + then execute in blocking mode. BSP waits > + until all APs finish or > + TimeoutInMicroseconds expires. If it's > + not NULL, then execute in non-blocking > + mode. BSP requests the function specified > + by Procedure to be started on all the > + enabled APs, and go on executing > + immediately. If all return from Procedure, > + or TimeoutInMicroseconds expires, this > + event is signaled. The BSP can use the > + CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @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 all APs return from Procedure, then > + Procedure on the failed APs is terminated. > + All enabled APs are available for next > + function assigned by > + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() > + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored. > + Otherwise, if all APs finish successfully, > + then its content is set to NULL. If not > + all APs finish before timeout expires, > + then its content is set to address of the > + buffer holding handle numbers of the > + failed APs. > + The buffer is allocated by MP Service > + Protocol, and it's the caller's > + responsibility to free the buffer with > + FreePool() service. > + In blocking mode, it is ready for > + consumption when the call returns. In > + non-blocking mode, it is ready when > + WaitEvent is signaled. The list of failed > + CPU is terminated by END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finished before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has been > + dispatched to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_DEVICE_ERROR Caller processor is AP. > + @retval EFI_NOT_STARTED No enabled APs exist in the system. > + @retval EFI_NOT_READY Any enabled APs are busy. > + @retval EFI_TIMEOUT In blocking mode, the timeout expired before > + all enabled APs have finished. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupAllAPs ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ); > + > +/** > + This service lets the caller get one enabled AP to execute a caller-provided > + function. The caller can request the BSP to either wait for the completion > + of the AP or just proceed with the next task by using the EFI event mechanism. > + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking > + execution support. This service may only be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The range is > + from 0 to the total number of logical > + processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until all APs finish > + or TimeoutInMicroseconds expires. If it's > + not NULL, then execute in non-blocking mode. > + BSP requests the function specified by > + Procedure to be started on all the enabled > + APs, and go on executing immediately. If > + all return from Procedure or TimeoutInMicroseconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @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 > + all APs return from Procedure, then Procedure > + on the failed APs is terminated. All enabled > + APs are available for next function assigned > + by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() > + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] Finished If NULL, this parameter is ignored. In > + blocking mode, this parameter is ignored. > + In non-blocking mode, if AP returns from > + Procedure before the timeout expires, its > + content is set to TRUE. Otherwise, the > + value is set to FALSE. The caller can > + determine if the AP returned from Procedure > + by evaluating this value. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finished before > + the timeout expires. > + @retval EFI_SUCCESS In non-blocking mode, the function has been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_TIMEOUT In blocking mode, the timeout expired before > + the specified AP has finished. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupThisAP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ); > + > +/** > + This service switches the requested AP to be the BSP from that point onward. > + This service changes the BSP for all purposes. This call can only be > + performed by the current BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an > + enabled AP. Otherwise, it will be disabled. > + > + @retval EFI_SUCCESS BSP successfully switched. > + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to > + this service returning. > + @retval EFI_UNSUPPORTED Switching the BSP is not supported. > + @retval EFI_SUCCESS The calling processor is an AP. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or > + a disabled AP. > + @retval EFI_NOT_READY The specified AP is busy. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibSwitchBSP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableOldBSP > + ); > + > +/** > + This service lets the caller enable or disable an AP from this point onward. > + This service may only be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the processor for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that specifies > + the new health status of the AP. This flag > + corresponds to StatusFlag defined in > + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only > + the PROCESSOR_HEALTH_STATUS_BIT is used. All other > + bits are ignored. If it is NULL, this parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed > + prior to this service returning. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibEnableDisableAP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableAP, > + IN UINT32 *HealthFlag OPTIONAL > + ); > + > +/** > + This return the handle number for the calling processor. This service may be > + called from the BSP and APs. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[out] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + > + @retval EFI_SUCCESS The current processor handle number was returned > + in ProcessorNumber. > + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibWhoAmI ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + OUT UINTN *ProcessorNumber > + ); > + > +/** Initializes the MP Services system data > + > + @param NumberOfProcessors The number of processors, both BSP and AP. > + @param CpuInfo CPU information gathered earlier during boot. > + > +**/ > +VOID > +MpInitLibInitialize ( > + IN UINTN NumberOfProcessors, > + IN ARM_PROCESSOR_TABLE *CpuInfo > + ); > + > + > + > +#endif /* MP_INITLIB_H_ */ > diff --git a/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S > new file mode 100644 > index 000000000000..8f7019a1c62c > --- /dev/null > +++ b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S > @@ -0,0 +1,65 @@ > +#=============================================================================== > +# Copyright (c) 2021 NUVIA Inc. All rights reserved. > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +#=============================================================================== > + > +.text > +.align 3 > + > +#include <AsmMacroIoLibV8.h> > +#include <IndustryStandard/ArmStdSmc.h> > + > +#include "InternalMpInitLib.h" > + > +GCC_ASM_IMPORT (gApStacksBase) > +GCC_ASM_IMPORT (gProcessorIDs) > +GCC_ASM_IMPORT (ApProcedure) > +GCC_ASM_IMPORT (gApStackSize) > + > +GCC_ASM_EXPORT (ApEntryPoint) > + > +StartupAddr: .8byte ASM_PFX(ApProcedure) > + > +// Entry-point for the AP > +// VOID > +// ApEntryPoint ( > +// VOID > +// ); > +ASM_PFX(ApEntryPoint): > + mrs x0, mpidr_el1 > + // Mask the non-affinity bits > + ldr x1, =0xff00ffffff > + and x0, x0, x1 > + ldr x1, gProcessorIDs > + mov x2, 0 // x2 = processor index > + mov x3, 0 // x3 = address offset > + > +// Find index in gProcessorIDs for current processor > +1: > + ldr x4, [x1, x3] // x4 = gProcessorIDs + x3 > + ldr x5, =0xffffffffff > + cmp x4, x5 // check if we've reached the end of gProcessorIDs > + beq ProcessorNotFound > + add x3, x3, 8 // x3 += sizeof (*gProcessorIDs) > + add x2, x2, 1 // x2++ > + cmp x0, x4 // if mpidr_el1 != *(gProcessorIDs + x3) then loop > + bne 1b > + sub x2, x2, 1 > + > +// Calculate stack address > + // x2 contains the index for the current processor > + ldr x0, gApStacksBase > + ldr x1, gApStackSize > + mul x3, x2, x1 // x3 = ProcessorIndex * gApStackSize > + add x4, x0, x3 // x4 = gApStacksBase + x3 > + add sp, x4, x1 // sp = x4 + gApStackSize > + > + ldr x0, StartupAddr // ASM_PFX(ApProcedure) > + blr x0 // doesn't return > + > +ProcessorNotFound: > +// Turn off the processor > + MOV32 (w0, ARM_SMC_ID_PSCI_CPU_OFF) > + smc #0 > + b . > diff --git a/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > new file mode 100644 > index 000000000000..2275b6cca33a > --- /dev/null > +++ b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > @@ -0,0 +1,53 @@ > +#/** @file > +# > +# Component description file for the DxeMpInitLib module. > +# > +# Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +#**/ > + > +[Defines] > + INF_VERSION = 1.29 > + BASE_NAME = DxeMpInitLib > + FILE_GUID = c9ca773c-8ae4-4b74-82fd-f7345503294e > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + LIBRARY_CLASS = MpInitLib|DXE_DRIVER > + > +# > +# The following information is for reference only and not required by the build tools. > +# > +# VALID_ARCHITECTURES = AARCH64 > +# > + > +[Sources.AARCH64] > + AArch64/MpFuncs.S > + > +[Sources] > + DxeMpLib.c > + InternalMpInitLib.h > + > +[Packages] > + ArmPkg/ArmPkg.dec > + MdeModulePkg/MdeModulePkg.dec > + MdePkg/MdePkg.dec > + > +[LibraryClasses] > + ArmLib > + ArmSmcLib > + BaseLib > + BaseMemoryLib > + DebugLib > + HobLib > + MemoryAllocationLib > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + UefiLib > + > +[Protocols] > + gEfiMpServiceProtocolGuid > + > +[Guids] > + gArmMpCoreInfoGuid > diff --git a/ArmPkg/Library/MpInitLib/DxeMpLib.c b/ArmPkg/Library/MpInitLib/DxeMpLib.c > new file mode 100644 > index 000000000000..e8d8808a3225 > --- /dev/null > +++ b/ArmPkg/Library/MpInitLib/DxeMpLib.c > @@ -0,0 +1,1477 @@ > +/** @file > + Construct MP Services Protocol. > + > + Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> > + Portions Copyright (c) 2011, Apple Inc. All rights reserved. > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include <Ppi/ArmMpCoreInfo.h> > +#include <Library/ArmLib.h> > +#include <Library/ArmSmcLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/DebugLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/MpInitLib.h> > +#include <Library/UefiBootServicesTableLib.h> > +#include <Library/UefiDriverEntryPoint.h> > +#include <IndustryStandard/ArmStdSmc.h> > + > +#include "InternalMpInitLib.h" > + > +#define POLL_INTERVAL_US 50000 > + > +#define GET_MPIDR_AFFINITY_BITS(x) ((x) & 0xFF00FFFFFF) > + > +#define MPIDR_MT_BIT BIT24 > + > +STATIC CPU_MP_DATA mCpuMpData; > +STATIC BOOLEAN mNonBlockingModeAllowed; > +UINT64 *gApStacksBase; > +UINT64 *gProcessorIDs; > +CONST UINT64 gApStackSize = AP_STACK_SIZE; > + > +/** C entry-point for the AP. > + This function gets called from the assembly function ApEntryPoint. > + > +**/ > +VOID > +ApProcedure ( > + VOID > + ) > +{ > + ARM_SMC_ARGS Args; > + EFI_AP_PROCEDURE UserApProcedure; > + VOID *UserApParameter; > + UINTN ProcessorIndex; > + > + MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex); > + > + /* Fetch the user-supplied procedure and parameter to execute */ > + UserApProcedure = mCpuMpData.CpuData[ProcessorIndex].Procedure; > + UserApParameter = mCpuMpData.CpuData[ProcessorIndex].Parameter; > + > + UserApProcedure (UserApParameter); > + > + mCpuMpData.CpuData[ProcessorIndex].State = CpuStateFinished; > + > + /* Since we're finished with this AP, turn it off */ > + Args.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF; > + ArmCallSmc (&Args); > + > + /* Should never be reached */ > + ASSERT (FALSE); > + CpuDeadLoop (); > +} > + > +/** Turns on the specified core using PSCI and executes the user-supplied > + function that's been configured via a previous call to SetApProcedure. > + > + @param ProcessorIndex The index of the core to turn on. > + > + @retval EFI_SUCCESS Success. > + @retval EFI_DEVICE_ERROR The processor could not be turned on. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +DispatchCpu ( > + IN UINTN ProcessorIndex > + ) > +{ > + ARM_SMC_ARGS Args; > + EFI_STATUS Status; > + > + Status = EFI_SUCCESS; > + > + mCpuMpData.CpuData[ProcessorIndex].State = CpuStateBusy; > + > + /* Turn the AP on */ > + if (sizeof (Args.Arg0) == sizeof (UINT32)) { > + Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH32; > + } else { > + Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH64; > + } > + > + Args.Arg1 = gProcessorIDs[ProcessorIndex]; > + Args.Arg2 = (UINTN)ApEntryPoint; > + > + ArmCallSmc (&Args); > + > + if (Args.Arg0 != ARM_SMC_PSCI_RET_SUCCESS) { > + DEBUG ((DEBUG_ERROR, "PSCI_CPU_ON call failed: %d", Args.Arg0)); > + Status = EFI_DEVICE_ERROR; > + } > + > + return Status; > +} > + > +/** Returns whether the specified processor is the BSP. > + > + @param[in] ProcessorIndex The index the processor to check. > + > + @return TRUE if the processor is the BSP, FALSE otherwise. > +**/ > +STATIC > +BOOLEAN > +IsProcessorBSP ( > + UINTN ProcessorIndex > + ) > +{ > + EFI_PROCESSOR_INFORMATION *CpuInfo; > + > + CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info; > + > + return (CpuInfo->StatusFlag & PROCESSOR_AS_BSP_BIT) != 0; > +} > + > +/** Returns whether the processor executing this function is the BSP. > + > + @return Whether the current processor is the BSP. > +**/ > +STATIC > +BOOLEAN > +IsCurrentProcessorBSP ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + UINTN ProcessorIndex; > + > + Status = MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex); > + if (EFI_ERROR (Status)) { > + ASSERT (0); > + return FALSE; > + } > + > + return IsProcessorBSP (ProcessorIndex); > +} > + > +/** Get the Application Processors state. > + > + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP. > + > + @return The AP status. > +**/ > +CPU_STATE > +GetApState ( > + IN CPU_AP_DATA *CpuData > + ) > +{ > + return CpuData->State; > +} > + > +/** Configures the processor context with the user-supplied procedure and > + argument. > + > + @param CpuData The processor context. > + @param Procedure The user-supplied procedure. > + @param ProcedureArgument The user-supplied procedure argument. > + > +**/ > +STATIC > +VOID > +SetApProcedure ( > + IN CPU_AP_DATA *CpuData, > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArgument > + ) > +{ > + ASSERT (CpuData != NULL); > + ASSERT (Procedure != NULL); > + > + CpuData->Parameter = ProcedureArgument; > + CpuData->Procedure = Procedure; > +} > + > +/** Returns the index of the next processor that is blocked. > + > + @param[out] NextNumber The index of the next blocked processor. > + > + @retval EFI_SUCCESS Successfully found the next blocked processor. > + @retval EFI_NOT_FOUND There are no blocked processors. > + > +**/ > +STATIC > +EFI_STATUS > +GetNextBlockedNumber ( > + OUT UINTN *NextNumber > + ) > +{ > + UINTN Index; > + CPU_STATE State; > + CPU_AP_DATA *CpuData; > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + if (IsProcessorBSP (Index)) { > + // Skip BSP > + continue; > + } > + > + State = CpuData->State; > + > + if (State == CpuStateBlocked) { > + *NextNumber = Index; > + return EFI_SUCCESS; > + } > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** Stalls the BSP for the minimum of POLL_INTERVAL_US and Timeout. > + > + @param[in] Timeout The time limit in microseconds remaining for > + APs to return from Procedure. > + > + @retval StallTime Time of execution stall. > +**/ > +STATIC > +UINTN > +CalculateAndStallInterval ( > + IN UINTN Timeout > + ) > +{ > + UINTN StallTime; > + > + if ((Timeout < POLL_INTERVAL_US) && (Timeout != 0)) { > + StallTime = Timeout; > + } else { > + StallTime = POLL_INTERVAL_US; > + } > + > + gBS->Stall (StallTime); > + > + return StallTime; > +} > + > +/** > + This service retrieves the number of logical processor in the platform > + and the number of those logical processors that are enabled on this boot. > + This service may only be called from the BSP. > + > + @param[in] This A pointer to the > + EFI_MP_SERVICES_PROTOCOL instance. > + @param[out] NumberOfProcessors Pointer to the total number of logical > + processors in the system, including > + the BSP and disabled APs. > + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled > + logical processors that exist in the > + system, including the BSP. > + > + @retval EFI_SUCCESS The number of logical processors and enabled > + logical processors was retrieved. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. > + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibGetNumberOfProcessors ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + OUT UINTN *NumberOfProcessors, > + OUT UINTN *NumberOfEnabledProcessors > + ) > +{ > + if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!IsCurrentProcessorBSP ()) { > + return EFI_DEVICE_ERROR; > + } > + > + *NumberOfProcessors = mCpuMpData.NumberOfProcessors; > + *NumberOfEnabledProcessors = mCpuMpData.NumberOfEnabledProcessors; > + return EFI_SUCCESS; > +} > + > +/** > + Gets detailed MP-related information on the requested processor at the > + instant this call is made. This service may only be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] ProcessorIndex The index of the processor. > + @param[out] ProcessorInfoBuffer A pointer to the buffer where information > + for the requested processor is deposited. > + > + @retval EFI_SUCCESS Processor information was returned. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist in the platform. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibGetProcessorInfo ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorIndex, > + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer > + ) > +{ > + if (ProcessorInfoBuffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!IsCurrentProcessorBSP ()) { > + return EFI_DEVICE_ERROR; > + } > + > + ProcessorIndex &= ~CPU_V2_EXTENDED_TOPOLOGY; > + > + if (ProcessorIndex >= mCpuMpData.NumberOfProcessors) { > + return EFI_NOT_FOUND; > + } > + > + CopyMem ( > + ProcessorInfoBuffer, > + &mCpuMpData.CpuData[ProcessorIndex], > + sizeof (EFI_PROCESSOR_INFORMATION) > + ); > + return EFI_SUCCESS; > +} > + > +/** Returns whether the specified processor is enabled. > + > + @param[in] ProcessorIndex The index of the processor to check. > + > + @return TRUE if the processor is enabled, FALSE otherwise. > +**/ > +STATIC > +BOOLEAN > +IsProcessorEnabled ( > + UINTN ProcessorIndex > + ) > +{ > + EFI_PROCESSOR_INFORMATION *CpuInfo; > + > + CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info; > + > + return (CpuInfo->StatusFlag & PROCESSOR_ENABLED_BIT) != 0; > +} > + > +/** Returns whether all processors are in the idle state. > + > + @return Whether all the processors are idle. > + > +**/ > +STATIC > +BOOLEAN > +CheckAllCpusReady ( > + VOID > + ) > +{ > + UINTN Index; > + CPU_AP_DATA *CpuData; > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + if (IsProcessorBSP (Index)) { > + // Skip BSP > + continue; > + } > + > + if (!IsProcessorEnabled (Index)) { > + // Skip Disabled processors > + continue; > + } > + > + if (GetApState (CpuData) != CpuStateIdle) { > + return FALSE; > + } > + } > + > + return TRUE; > +} > + > +/** Sets up the state for the StartupAllAPs function. > + > + @param SingleThread Whether the APs will execute sequentially. > + > +**/ > +STATIC > +VOID > +StartupAllAPsPrepareState ( > + IN BOOLEAN SingleThread > + ) > +{ > + UINTN Index; > + CPU_STATE APInitialState; > + CPU_AP_DATA *CpuData; > + > + mCpuMpData.FinishCount = 0; > + mCpuMpData.StartCount = 0; > + mCpuMpData.SingleThread = SingleThread; > + > + APInitialState = CpuStateReady; > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + > + // > + // Get APs prepared, and put failing APs into FailedCpuList. > + // If "SingleThread", only 1 AP will put into ready state, other AP will be > + // put into ready state 1 by 1, until the previous 1 finished its task. > + // If not "SingleThread", all APs are put into ready state from the > + // beginning > + // > + > + if (IsProcessorBSP (Index)) { > + // Skip BSP > + continue; > + } > + > + if (!IsProcessorEnabled (Index)) { > + // Skip Disabled processors > + if (mCpuMpData.FailedList != NULL) { > + mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index; > + } > + > + continue; > + } > + > + ASSERT (GetApState (CpuData) == CpuStateIdle); > + CpuData->State = APInitialState; > + > + mCpuMpData.StartCount++; > + if (SingleThread) { > + APInitialState = CpuStateBlocked; > + } > + } > +} > + > +/** Handles execution of StartupAllAPs when a WaitEvent has been specified. > + > + @param Procedure The user-supplied procedure. > + @param ProcedureArgument The user-supplied procedure argument. > + @param WaitEvent The wait event to be signaled when the work is > + complete or a timeout has occurred. > + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero > + indicates an infinite timeout. > + > + @return EFI_SUCCESS on success. > +**/ > +STATIC > +EFI_STATUS > +StartupAllAPsWithWaitEvent ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArgument, > + IN EFI_EVENT WaitEvent, > + IN UINTN TimeoutInMicroseconds > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + CPU_AP_DATA *CpuData; > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + if (IsProcessorBSP (Index)) { > + // Skip BSP > + continue; > + } > + > + if (!IsProcessorEnabled (Index)) { > + // Skip Disabled processors > + continue; > + } > + > + if (GetApState (CpuData) == CpuStateReady) { > + SetApProcedure (CpuData, Procedure, ProcedureArgument); > + } > + } > + > + // > + // Save data into private data structure, and create timer to poll AP state > + // before exiting > + // > + mCpuMpData.Procedure = Procedure; > + mCpuMpData.ProcedureArgument = ProcedureArgument; > + mCpuMpData.WaitEvent = WaitEvent; > + mCpuMpData.Timeout = TimeoutInMicroseconds; > + mCpuMpData.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0); > + Status = gBS->SetTimer ( > + mCpuMpData.CheckAllAPsEvent, > + TimerPeriodic, > + POLL_INTERVAL_US > + ); > + return Status; > +} > + > +/** Handles execution of StartupAllAPs when no wait event has been specified. > + > + @param Procedure The user-supplied procedure. > + @param ProcedureArgument The user-supplied procedure argument. > + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero > + indicates an infinite timeout. > + @param SingleThread Whether the APs will execute sequentially. > + @param FailedCpuList User-supplied pointer for list of failed CPUs. > + > + @return EFI_SUCCESS on success. > +**/ > +STATIC > +EFI_STATUS > +StartupAllAPsNoWaitEvent ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArgument, > + IN UINTN TimeoutInMicroseconds, > + IN BOOLEAN SingleThread, > + IN UINTN **FailedCpuList > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + UINTN NextIndex; > + UINTN Timeout; > + CPU_AP_DATA *CpuData; > + > + Timeout = TimeoutInMicroseconds; > + > + while (TRUE) { > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + if (IsProcessorBSP (Index)) { > + // Skip BSP > + continue; > + } > + > + if (!IsProcessorEnabled (Index)) { > + // Skip Disabled processors > + continue; > + } > + > + switch (GetApState (CpuData)) { > + case CpuStateReady: > + SetApProcedure (CpuData, Procedure, ProcedureArgument); > + Status = DispatchCpu (Index); > + if (EFI_ERROR (Status)) { > + CpuData->State = CpuStateIdle; > + Status = EFI_NOT_READY; > + goto Done; > + } > + > + break; > + > + case CpuStateFinished: > + mCpuMpData.FinishCount++; > + if (SingleThread) { > + Status = GetNextBlockedNumber (&NextIndex); > + if (!EFI_ERROR (Status)) { > + mCpuMpData.CpuData[NextIndex].State = CpuStateReady; > + } > + } > + > + CpuData->State = CpuStateIdle; > + break; > + > + default: > + break; > + } > + } > + > + if (mCpuMpData.FinishCount == mCpuMpData.StartCount) { > + Status = EFI_SUCCESS; > + goto Done; > + } > + > + if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) { > + Status = EFI_TIMEOUT; > + goto Done; > + } > + > + Timeout -= CalculateAndStallInterval (Timeout); > + } > + > +Done: > + if (FailedCpuList != NULL) { > + if (mCpuMpData.FailedListIndex == 0) { > + FreePool (*FailedCpuList); > + *FailedCpuList = NULL; > + } > + } > + > + return Status; > +} > + > +/** > + This service executes a caller provided function on all enabled APs. APs can > + run either simultaneously or one at a time in sequence. This service supports > + both blocking and non-blocking requests. The non-blocking requests use EFI > + events so the BSP can detect when the APs have finished. This service may only > + be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs execute > + the function specified by Procedure one by > + one, in ascending order of processor > + handle number. If FALSE, then all the > + enabled APs execute the function specified > + by Procedure simultaneously. > + @param[in] WaitEvent The event created by the caller with > + CreateEvent() service. If it is NULL, > + then execute in blocking mode. BSP waits > + until all APs finish or > + TimeoutInMicroseconds expires. If it's > + not NULL, then execute in non-blocking > + mode. BSP requests the function specified > + by Procedure to be started on all the > + enabled APs, and go on executing > + immediately. If all return from Procedure, > + or TimeoutInMicroseconds expires, this > + event is signaled. The BSP can use the > + CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @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 all APs return from Procedure, then > + Procedure on the failed APs is terminated. > + All enabled APs are available for next > + function assigned by > + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() > + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored. > + Otherwise, if all APs finish successfully, > + then its content is set to NULL. If not > + all APs finish before timeout expires, > + then its content is set to address of the > + buffer holding handle numbers of the > + failed APs. > + The buffer is allocated by MP Service > + Protocol, and it's the caller's > + responsibility to free the buffer with > + FreePool() service. > + In blocking mode, it is ready for > + consumption when the call returns. In > + non-blocking mode, it is ready when > + WaitEvent is signaled. The list of failed > + CPU is terminated by END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finished before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has been > + dispatched to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_DEVICE_ERROR Caller processor is AP. > + @retval EFI_NOT_STARTED No enabled APs exist in the system. > + @retval EFI_NOT_READY Any enabled APs are busy. > + @retval EFI_TIMEOUT In blocking mode, the timeout expired before > + all enabled APs have finished. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupAllAPs ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + > + if (!IsCurrentProcessorBSP ()) { > + return EFI_DEVICE_ERROR; > + } > + > + if (mCpuMpData.NumberOfProcessors == 1) { > + return EFI_NOT_STARTED; > + } > + > + if (Procedure == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) { > + return EFI_UNSUPPORTED; > + } > + > + if (!CheckAllCpusReady ()) { > + return EFI_NOT_READY; > + } > + > + if (FailedCpuList != NULL) { > + mCpuMpData.FailedList = AllocatePool ( > + (mCpuMpData.NumberOfProcessors + 1) * > + sizeof (UINTN) > + ); > + if (mCpuMpData.FailedList == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + SetMemN ( > + mCpuMpData.FailedList, > + (mCpuMpData.NumberOfProcessors + 1) * > + sizeof (UINTN), > + END_OF_CPU_LIST > + ); > + mCpuMpData.FailedListIndex = 0; > + *FailedCpuList = mCpuMpData.FailedList; > + } > + > + StartupAllAPsPrepareState (SingleThread); > + > + if (WaitEvent != NULL) { > + Status = StartupAllAPsWithWaitEvent ( > + Procedure, > + ProcedureArgument, > + WaitEvent, > + TimeoutInMicroseconds > + ); > + } else { > + Status = StartupAllAPsNoWaitEvent ( > + Procedure, > + ProcedureArgument, > + TimeoutInMicroseconds, > + SingleThread, > + FailedCpuList > + ); > + } > + > + return Status; > +} > + > +/** > + This service lets the caller get one enabled AP to execute a caller-provided > + function. The caller can request the BSP to either wait for the completion > + of the AP or just proceed with the next task by using the EFI event mechanism. > + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking > + execution support. This service may only be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL > + instance. > + @param[in] Procedure A pointer to the function to be run on > + enabled APs of the system. See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The range is > + from 0 to the total number of logical > + processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller with CreateEvent() > + service. If it is NULL, then execute in > + blocking mode. BSP waits until all APs finish > + or TimeoutInMicroseconds expires. If it's > + not NULL, then execute in non-blocking mode. > + BSP requests the function specified by > + Procedure to be started on all the enabled > + APs, and go on executing immediately. If > + all return from Procedure or TimeoutInMicroseconds > + expires, this event is signaled. The BSP > + can use the CheckEvent() or WaitForEvent() > + services to check the state of event. Type > + EFI_EVENT is defined in CreateEvent() in > + the Unified Extensible Firmware Interface > + Specification. > + @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 > + all APs return from Procedure, then Procedure > + on the failed APs is terminated. All enabled > + APs are available for next function assigned > + by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() > + or EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). > + If the timeout expires in blocking mode, > + BSP returns EFI_TIMEOUT. If the timeout > + expires in non-blocking mode, WaitEvent > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedure for > + all APs. > + @param[out] Finished If NULL, this parameter is ignored. In > + blocking mode, this parameter is ignored. > + In non-blocking mode, if AP returns from > + Procedure before the timeout expires, its > + content is set to TRUE. Otherwise, the > + value is set to FALSE. The caller can > + determine if the AP returned from Procedure > + by evaluating this value. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finished before > + the timeout expires. > + @retval EFI_SUCCESS In non-blocking mode, the function has been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_TIMEOUT In blocking mode, the timeout expired before > + the specified AP has finished. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupThisAP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + UINTN Timeout; > + CPU_AP_DATA *CpuData; > + > + if (!IsCurrentProcessorBSP ()) { > + return EFI_DEVICE_ERROR; > + } > + > + if (Procedure == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) { > + return EFI_NOT_FOUND; > + } > + > + CpuData = &mCpuMpData.CpuData[ProcessorNumber]; > + > + if (IsProcessorBSP (ProcessorNumber)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (!IsProcessorEnabled (ProcessorNumber)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (GetApState (CpuData) != CpuStateIdle) { > + return EFI_NOT_READY; > + } > + > + if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) { > + return EFI_UNSUPPORTED; > + } > + > + Timeout = TimeoutInMicroseconds; > + > + mCpuMpData.StartCount = 1; > + mCpuMpData.FinishCount = 0; > + > + SetApProcedure ( > + CpuData, > + Procedure, > + ProcedureArgument > + ); > + > + Status = DispatchCpu (ProcessorNumber); > + if (EFI_ERROR (Status)) { > + CpuData->State = CpuStateIdle; > + return EFI_NOT_READY; > + } > + > + if (WaitEvent != NULL) { > + // Non Blocking > + mCpuMpData.WaitEvent = WaitEvent; > + gBS->SetTimer ( > + CpuData->CheckThisAPEvent, > + TimerPeriodic, > + POLL_INTERVAL_US > + ); > + return EFI_SUCCESS; > + } > + > + // Blocking > + while (TRUE) { > + if (GetApState (CpuData) == CpuStateFinished) { > + CpuData->State = CpuStateIdle; > + break; > + } > + > + if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) { > + return EFI_TIMEOUT; > + } > + > + Timeout -= CalculateAndStallInterval (Timeout); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This service switches the requested AP to be the BSP from that point onward. > + This service changes the BSP for all purposes. This call can only be > + performed by the current BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an > + enabled AP. Otherwise, it will be disabled. > + > + @retval EFI_SUCCESS BSP successfully switched. > + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to > + this service returning. > + @retval EFI_UNSUPPORTED Switching the BSP is not supported. > + @retval EFI_SUCCESS The calling processor is an AP. > + @retval EFI_NOT_FOUND The processor with the handle specified by > + ProcessorNumber does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or > + a disabled AP. > + @retval EFI_NOT_READY The specified AP is busy. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibSwitchBSP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableOldBSP > + ) > +{ > + // Skip for now as we need switch a bunch of stack stuff around and it's > + // complex. May not be worth it? > + return EFI_UNSUPPORTED; > +} > + > +/** > + This service lets the caller enable or disable an AP from this point onward. > + This service may only be called from the BSP. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[in] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the processor for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that specifies > + the new health status of the AP. This flag > + corresponds to StatusFlag defined in > + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only > + the PROCESSOR_HEALTH_STATUS_BIT is used. All other > + bits are ignored. If it is NULL, this parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed > + prior to this service returning. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibEnableDisableAP ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableAP, > + IN UINT32 *HealthFlag OPTIONAL > + ) > +{ > + UINTN StatusFlag; > + CPU_AP_DATA *CpuData; > + > + StatusFlag = mCpuMpData.CpuData[ProcessorNumber].Info.StatusFlag; > + CpuData = &mCpuMpData.CpuData[ProcessorNumber]; > + > + if (!IsCurrentProcessorBSP ()) { > + return EFI_DEVICE_ERROR; > + } > + > + if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) { > + return EFI_NOT_FOUND; > + } > + > + if (IsProcessorBSP (ProcessorNumber)) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (GetApState (CpuData) != CpuStateIdle) { > + return EFI_UNSUPPORTED; > + } > + > + if (EnableAP) { > + if (!IsProcessorEnabled (ProcessorNumber)) { > + mCpuMpData.NumberOfEnabledProcessors++; > + } > + > + StatusFlag |= PROCESSOR_ENABLED_BIT; > + } else { > + if (IsProcessorEnabled (ProcessorNumber)) { > + mCpuMpData.NumberOfEnabledProcessors--; > + } > + > + StatusFlag &= ~PROCESSOR_ENABLED_BIT; > + } > + > + if (HealthFlag != NULL) { > + StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT; > + StatusFlag |= (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This return the handle number for the calling processor. This service may be > + called from the BSP and APs. > + > + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance. > + @param[out] ProcessorNumber The handle number of AP that is to become the new > + BSP. The range is from 0 to the total number of > + logical processors minus 1. The total number of > + logical processors can be retrieved by > + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). > + > + @retval EFI_SUCCESS The current processor handle number was returned > + in ProcessorNumber. > + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibWhoAmI ( > + IN EFI_MP_SERVICES_PROTOCOL *This, > + OUT UINTN *ProcessorNumber > + ) > +{ > + UINTN Index; > + UINT64 ProcessorId; > + CPU_AP_DATA *CpuData; > + > + if (ProcessorNumber == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + ProcessorId = GET_MPIDR_AFFINITY_BITS (ArmReadMpidr ()); > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + if (CpuData->Info.ProcessorId == ProcessorId) { > + break; > + } > + } > + > + *ProcessorNumber = Index; > + return EFI_SUCCESS; > +} > + > +/** Adds the specified processor the list of failed processors. > + > + @param ProcessorIndex The processor index to add. > + @param ApState Processor state. > + > +**/ > +STATIC > +VOID > +AddProcessorToFailedList ( > + UINTN ProcessorIndex, > + CPU_STATE ApState > + ) > +{ > + UINTN Index; > + BOOLEAN Found; > + > + Found = FALSE; > + > + if (ApState == CpuStateIdle) { > + return; > + } > + > + // If we are retrying make sure we don't double count > + for (Index = 0; Index < mCpuMpData.FailedListIndex; Index++) { > + if (mCpuMpData.FailedList[Index] == ProcessorIndex) { > + Found = TRUE; > + break; > + } > + } > + > + /* If the CPU isn't already in the FailedList, add it */ > + if (!Found) { > + mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index; > + } > +} > + > +/** Handles the StartupAllAPs case where the timeout has occurred. > + > +**/ > +STATIC > +VOID > +ProcessStartupAllAPsTimeout ( > + VOID > + ) > +{ > + CPU_AP_DATA *CpuData; > + UINTN Index; > + > + if (mCpuMpData.FailedList == NULL) { > + return; > + } > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + CpuData = &mCpuMpData.CpuData[Index]; > + if (IsProcessorBSP (Index)) { > + // Skip BSP > + continue; > + } > + > + if (!IsProcessorEnabled (Index)) { > + // Skip Disabled processors > + continue; > + } > + > + CpuData = &mCpuMpData.CpuData[Index]; > + AddProcessorToFailedList (Index, GetApState (CpuData)); > + } > +} > + > +/** Updates the status of the APs. > + > + @param[in] ProcessorIndex The index of the AP to update. > +**/ > +STATIC > +VOID > +UpdateApStatus ( > + IN UINTN ProcessorIndex > + ) > +{ > + EFI_STATUS Status; > + CPU_AP_DATA *CpuData; > + CPU_AP_DATA *NextCpuData; > + CPU_STATE State; > + UINTN NextNumber; > + > + CpuData = &mCpuMpData.CpuData[ProcessorIndex]; > + > + if (IsProcessorBSP (ProcessorIndex)) { > + // Skip BSP > + return; > + } > + > + if (!IsProcessorEnabled (ProcessorIndex)) { > + // Skip Disabled processors > + return; > + } > + > + State = GetApState (CpuData); > + > + switch (State) { > + case CpuStateFinished: > + if (mCpuMpData.SingleThread) { > + Status = GetNextBlockedNumber (&NextNumber); > + if (!EFI_ERROR (Status)) { > + NextCpuData = &mCpuMpData.CpuData[NextNumber]; > + > + NextCpuData->State = CpuStateReady; > + > + SetApProcedure ( > + NextCpuData, > + mCpuMpData.Procedure, > + mCpuMpData.ProcedureArgument > + ); > + } > + } > + > + CpuData->State = CpuStateIdle; > + mCpuMpData.FinishCount++; > + break; > + > + default: > + break; > + } > +} > + > +/** > + If a timeout is specified in StartupAllAps(), a timer is set, which invokes > + this procedure periodically to check whether all APs have finished. > + > + @param[in] Event The WaitEvent the user supplied. > + @param[in] Context The event context. > +**/ > +STATIC > +VOID > +EFIAPI > +CheckAllAPsStatus ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + UINTN Index; > + > + if (mCpuMpData.TimeoutActive) { > + mCpuMpData.Timeout -= CalculateAndStallInterval (mCpuMpData.Timeout); > + } > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + UpdateApStatus (Index); > + } > + > + if (mCpuMpData.TimeoutActive && (mCpuMpData.Timeout == 0)) { > + ProcessStartupAllAPsTimeout (); > + > + // Force terminal exit > + mCpuMpData.FinishCount = mCpuMpData.StartCount; > + } > + > + if (mCpuMpData.FinishCount != mCpuMpData.StartCount) { > + return; > + } > + > + gBS->SetTimer ( > + mCpuMpData.CheckAllAPsEvent, > + TimerCancel, > + 0 > + ); > + > + if (mCpuMpData.FailedListIndex == 0) { > + if (mCpuMpData.FailedList != NULL) { > + FreePool (mCpuMpData.FailedList); > + mCpuMpData.FailedList = NULL; > + } > + } > + > + gBS->SignalEvent (mCpuMpData.WaitEvent); > +} > + > +/** Invoked periodically via a timer to check the state of the processor. > + > + @param Event The event supplied by the timer expiration. > + @param Context The processor context. > + > +**/ > +STATIC > +VOID > +EFIAPI > +CheckThisAPStatus ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + CPU_AP_DATA *CpuData; > + CPU_STATE State; > + > + CpuData = Context; > + CpuData->TimeTaken += POLL_INTERVAL_US; > + > + State = GetApState (CpuData); > + > + if (State == CpuStateFinished) { > + Status = gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0); > + ASSERT_EFI_ERROR (Status); > + > + if (mCpuMpData.WaitEvent != NULL) { > + Status = gBS->SignalEvent (mCpuMpData.WaitEvent); > + ASSERT_EFI_ERROR (Status); > + } > + > + CpuData->State = CpuStateIdle; > + } > + > + if (CpuData->TimeTaken > CpuData->Timeout) { > + if (mCpuMpData.WaitEvent != NULL) { > + Status = gBS->SignalEvent (mCpuMpData.WaitEvent); > + ASSERT_EFI_ERROR (Status); > + } > + } > +} > + > +/** > + This function is called by all processors (both BSP and AP) once and collects > + MP related data. > + > + @param BSP TRUE if the processor is the BSP. > + @param Mpidr The MPIDR for the specified processor. This should be > + the full MPIDR and not only the affinity bits. > + @param ProcessorIndex The index of the processor. > + > + @return EFI_SUCCESS if the data for the processor collected and filled in. > + > +**/ > +STATIC > +EFI_STATUS > +FillInProcessorInformation ( > + IN BOOLEAN BSP, > + IN UINTN Mpidr, > + IN UINTN ProcessorIndex > + ) > +{ > + EFI_PROCESSOR_INFORMATION *CpuInfo; > + > + CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info; > + > + CpuInfo->ProcessorId = GET_MPIDR_AFFINITY_BITS (Mpidr); > + CpuInfo->StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT; > + > + if (BSP) { > + CpuInfo->StatusFlag |= PROCESSOR_AS_BSP_BIT; > + } > + > + if (Mpidr & MPIDR_MT_BIT) { > + CpuInfo->Location.Package = GET_MPIDR_AFF2 (Mpidr); > + CpuInfo->Location.Core = GET_MPIDR_AFF1 (Mpidr); > + CpuInfo->Location.Thread = GET_MPIDR_AFF0 (Mpidr); > + > + CpuInfo->ExtendedInformation.Location2.Package = GET_MPIDR_AFF3 (Mpidr); > + CpuInfo->ExtendedInformation.Location2.Die = GET_MPIDR_AFF2 (Mpidr); > + CpuInfo->ExtendedInformation.Location2.Core = GET_MPIDR_AFF1 (Mpidr); > + CpuInfo->ExtendedInformation.Location2.Thread = GET_MPIDR_AFF0 (Mpidr); > + } else { > + CpuInfo->Location.Package = GET_MPIDR_AFF1 (Mpidr); > + CpuInfo->Location.Core = GET_MPIDR_AFF0 (Mpidr); > + CpuInfo->Location.Thread = 0; > + > + CpuInfo->ExtendedInformation.Location2.Package = GET_MPIDR_AFF2 (Mpidr); > + CpuInfo->ExtendedInformation.Location2.Die = GET_MPIDR_AFF1 (Mpidr); > + CpuInfo->ExtendedInformation.Location2.Core = GET_MPIDR_AFF0 (Mpidr); > + CpuInfo->ExtendedInformation.Location2.Thread = 0; > + } > + > + CpuInfo->ExtendedInformation.Location2.Package = 0; > + CpuInfo->ExtendedInformation.Location2.Module = 0; > + CpuInfo->ExtendedInformation.Location2.Tile = 0; > + > + mCpuMpData.CpuData[ProcessorIndex].State = BSP ? CpuStateBusy : CpuStateIdle; > + > + mCpuMpData.CpuData[ProcessorIndex].Procedure = NULL; > + mCpuMpData.CpuData[ProcessorIndex].Parameter = NULL; > + > + return EFI_SUCCESS; > +} > + > +/** Initializes the MP Services system data > + > + @param NumberOfProcessors The number of processors, both BSP and AP. > + @param CpuInfo CPU information gathered earlier during boot. > + > +**/ > +VOID > +MpInitLibInitialize ( > + IN UINTN NumberOfProcessors, > + IN ARM_PROCESSOR_TABLE *CpuInfo > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + EFI_EVENT ReadyToBootEvent; > + > + // > + // Clear the data structure area first. > + // > + ZeroMem (&mCpuMpData, sizeof (CPU_MP_DATA)); > + // > + // First BSP fills and inits all known values, including its own records. > + // > + mCpuMpData.NumberOfProcessors = NumberOfProcessors; > + mCpuMpData.NumberOfEnabledProcessors = NumberOfProcessors; > + > + mCpuMpData.CpuData = AllocateZeroPool ( > + mCpuMpData.NumberOfProcessors * > + sizeof (CPU_AP_DATA) > + ); > + ASSERT (mCpuMpData.CpuData != NULL); > + > + /* Allocate one extra for the NULL entry at the end */ > + gProcessorIDs = AllocatePool ((mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64)); > + ASSERT (gProcessorIDs != NULL); > + > + FillInProcessorInformation (TRUE, CpuInfo->ArmCpus[0].Mpidr, 0); > + gProcessorIDs[0] = mCpuMpData.CpuData[0].Info.ProcessorId; > + > + Status = gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + CheckAllAPsStatus, > + NULL, > + &mCpuMpData.CheckAllAPsEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + gApStacksBase = AllocatePool ( > + mCpuMpData.NumberOfProcessors * > + gApStackSize > + ); > + ASSERT (gApStacksBase != NULL); > + > + for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) { > + if (IsProcessorBSP (Index)) { > + /* Skip BSP */ > + continue; > + } > + > + FillInProcessorInformation (FALSE, CpuInfo->ArmCpus[Index].Mpidr, Index); > + > + gProcessorIDs[Index] = mCpuMpData.CpuData[Index].Info.ProcessorId; > + > + Status = gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_CALLBACK, > + CheckThisAPStatus, > + (VOID *)&mCpuMpData.CpuData[Index], > + &mCpuMpData.CpuData[Index].CheckThisAPEvent > + ); > + ASSERT (Status == EFI_SUCCESS); > + } > + > + Status = EfiCreateEventReadyToBootEx ( > + TPL_CALLBACK, > + ReadyToBootSignaled, > + NULL, > + &ReadyToBootEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + gProcessorIDs[Index] = MAX_UINT32; > +} > + > +/** > + Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is > + signaled. After this point, non-blocking mode is no longer allowed. > + > + @param Event Event whose notification function is being invoked. > + @param Context The pointer to the notification function's context, > + which is implementation-dependent. > + > +**/ > +STATIC > +VOID > +EFIAPI > +ReadyToBootSignaled ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + mNonBlockingModeAllowed = FALSE; > +} > diff --git a/ArmPkg/Library/MpInitLib/InternalMpInitLib.h b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h > new file mode 100644 > index 000000000000..461d85ffd28f > --- /dev/null > +++ b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h > @@ -0,0 +1,359 @@ > +/** @file > + > +Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> > +Portions copyright (c) 2011, Apple Inc. All rights reserved. > + > +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef MP_INTERNAL_INIT_LIB_H_ > +#define MP_INTERNAL_INIT_LIB_H_ > + > +#include <Protocol/Cpu.h> > +#include <Protocol/MpService.h> > + > +#include <Library/BaseLib.h> > +#include <Library/UefiLib.h> > + > + > +#define AP_STACK_SIZE 0x1000 > + > +// > +// Internal Data Structures > +// > + > +// > +// AP state > +// > +// The state transitions for an AP when it process a procedure are: > +// Idle ----> Ready ----> Busy ----> Idle > +// [BSP] [AP] [AP] > +// > +typedef enum { > + CpuStateIdle, > + CpuStateReady, > + CpuStateBlocked, > + CpuStateBusy, > + CpuStateFinished, > + CpuStateDisabled > +} CPU_STATE; > + > +// > +// Define Individual Processor Data block. > +// > +typedef struct { > + EFI_PROCESSOR_INFORMATION Info; > + EFI_AP_PROCEDURE Procedure; > + VOID *Parameter; > + CPU_STATE State; > + EFI_EVENT CheckThisAPEvent; > + UINTN Timeout; > + UINTN TimeTaken; > +} CPU_AP_DATA; > + > +// > +// Define MP data block which consumes individual processor block. > +// > +typedef struct { > + UINTN NumberOfProcessors; > + UINTN NumberOfEnabledProcessors; > + EFI_EVENT CheckAllAPsEvent; > + EFI_EVENT WaitEvent; > + UINTN FinishCount; > + UINTN StartCount; > + EFI_AP_PROCEDURE Procedure; > + VOID *ProcedureArgument; > + BOOLEAN SingleThread; > + UINTN StartedNumber; > + CPU_AP_DATA *CpuData; > + UINTN Timeout; > + UINTN *FailedList; > + UINTN FailedListIndex; > + BOOLEAN TimeoutActive; > +} CPU_MP_DATA; > + > +EFI_STATUS > +EFIAPI > +CpuMpServicesInit ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ); > + > +extern EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate; > + > +/** Secondary core entry point. > + > +**/ > +VOID ApEntryPoint ( > + VOID > + ); > + > +/** C entry-point for the AP. > + This function gets called from the assembly function ApEntryPoint. > +**/ > +VOID > +ApProcedure ( > + VOID > + ); > + > +/** Turns on the specified core using PSCI and executes the user-supplied > + function that's been configured via a previous call to SetApProcedure. > + > + @param ProcessorIndex The index of the core to turn on. > + > + @retval EFI_SUCCESS The processor was successfully turned on. > + @retval EFI_DEVICE_ERROR An error occurred turning the processor on. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +DispatchCpu ( > + IN UINTN ProcessorIndex > + ); > + > +/** Returns whether the specified processor is the BSP. > + > + @param[in] ProcessorIndex The index the processor to check. > + > + @return TRUE if the processor is the BSP, FALSE otherwise. > +**/ > +STATIC > +BOOLEAN > +IsProcessorBSP ( > + UINTN ProcessorIndex > + ); > + > +/** Returns whether the processor executing this function is the BSP. > + > + @return Whether the current processor is the BSP. > +**/ > +STATIC > +BOOLEAN > +IsCurrentProcessorBSP ( > + VOID > + ); > + > +/** Returns whether the specified processor is enabled. > + > + @param[in] ProcessorIndex The index of the processor to check. > + > + @return TRUE if the processor is enabled, FALSE otherwise. > +**/ > +STATIC > +BOOLEAN > +IsProcessorEnabled ( > + UINTN ProcessorIndex > + ); > + > +/** Configures the processor context with the user-supplied procedure and > + argument. > + > + @param CpuData The processor context. > + @param Procedure The user-supplied procedure. > + @param ProcedureArgument The user-supplied procedure argument. > + > +**/ > +STATIC > +VOID > +SetApProcedure ( > + IN CPU_AP_DATA *CpuData, > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArgument > + ); > + > +/** > + Get the Application Processors state. > + > + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP > + > + @return The AP status > +**/ > +CPU_STATE > +GetApState ( > + IN CPU_AP_DATA *CpuData > + ); > + > +/** Returns the index of the next processor that is blocked. > + > + @param[out] NextNumber The index of the next blocked processor. > + > + @retval EFI_SUCCESS Successfully found the next blocked processor. > + @retval EFI_NOT_FOUND There are no blocked processors. > + > +**/ > +STATIC > +EFI_STATUS > +GetNextBlockedNumber ( > + OUT UINTN *NextNumber > + ); > + > +/** Stalls the BSP for the minimum of gPollInterval and Timeout. > + > + @param[in] Timeout The time limit in microseconds remaining for > + APs to return from Procedure. > + > + @retval StallTime Time of execution stall. > +**/ > +STATIC > +UINTN > +CalculateAndStallInterval ( > + IN UINTN Timeout > + ); > + > +/** Returns whether all processors are in the idle state. > + > + @return Whether all the processors are idle. > + > +**/ > +STATIC > +BOOLEAN > +CheckAllCpusReady ( > + VOID > + ); > + > +/** Sets up the state for the StartupAllAPs function. > + > + @param SingleThread Whether the APs will execute sequentially. > + > +**/ > +STATIC > +VOID > +StartupAllAPsPrepareState ( > + IN BOOLEAN SingleThread > + ); > + > +/** Handles execution of StartupAllAPs when a WaitEvent has been specified. > + > + @param Procedure The user-supplied procedure. > + @param ProcedureArgument The user-supplied procedure argument. > + @param WaitEvent The wait event to be signaled when the work is > + complete or a timeout has occurred. > + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero > + indicates an infinite timeout. > + > + @return EFI_SUCCESS on success. > +**/ > +STATIC > +EFI_STATUS > +StartupAllAPsWithWaitEvent ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArgument, > + IN EFI_EVENT WaitEvent, > + IN UINTN TimeoutInMicroseconds > + ); > + > +/** Handles execution of StartupAllAPs when no wait event has been specified. > + > + @param Procedure The user-supplied procedure. > + @param ProcedureArgument The user-supplied procedure argument. > + @param TimeoutInMicroseconds The timeout for the work to be completed. Zero > + indicates an infinite timeout. > + @param SingleThread Whether the APs will execute sequentially. > + @param FailedCpuList User-supplied pointer for list of failed CPUs. > + > + @return EFI_SUCCESS on success. > +**/ > +STATIC > +EFI_STATUS > +StartupAllAPsNoWaitEvent ( > + IN EFI_AP_PROCEDURE Procedure, > + IN VOID *ProcedureArgument, > + IN UINTN TimeoutInMicroseconds, > + IN BOOLEAN SingleThread, > + IN UINTN **FailedCpuList > + ); > + > + > +/** Adds the specified processor the list of failed processors. > + > + @param ProcessorIndex The processor index to add. > + @param ApState Processor state. > + > +**/ > +STATIC > +VOID > +AddProcessorToFailedList ( > + UINTN ProcessorIndex, > + CPU_STATE ApState > + ); > + > +/** Handles the StartupAllAPs case where the timeout has occurred. > + > +**/ > +STATIC > +VOID > +ProcessStartupAllAPsTimeout ( > + VOID > + ); > + > +/** > + If a timeout is specified in StartupAllAps(), a timer is set, which invokes > + this procedure periodically to check whether all APs have finished. > + > + @param[in] Event The WaitEvent the user supplied. > + @param[in] Context The event context. > +**/ > +STATIC > +VOID > +EFIAPI > +CheckAllAPsStatus ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ); > + > +/** Invoked periodically via a timer to check the state of the processor. > + > + @param Event The event supplied by the timer expiration. > + @param Context The processor context. > + > +**/ > +STATIC > +VOID > +EFIAPI > +CheckThisAPStatus ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ); > + > +/** > + This function is called by all processors (both BSP and AP) once and collects > + MP related data. > + > + @param BSP TRUE if the processor is the BSP. > + @param Mpidr The MPIDR for the specified processor. This should be > + the full MPIDR and not only the affinity bits. > + @param ProcessorIndex The index of the processor. > + > + @return EFI_SUCCESS if the data for the processor collected and filled in. > + > +**/ > +STATIC > +EFI_STATUS > +FillInProcessorInformation ( > + IN BOOLEAN BSP, > + IN UINTN Mpidr, > + IN UINTN ProcessorIndex > + ); > + > +/** > + Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is > + signaled. After this point, non-blocking mode is no longer allowed. > + > + @param Event Event whose notification function is being invoked. > + @param Context The pointer to the notification function's context, > + which is implementation-dependent. > + > +**/ > +STATIC > +VOID > +EFIAPI > +ReadyToBootSignaled ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ); > + > + > +#endif /* MP_INTERNAL_INIT_LIB_H_ */ > diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc > index 5a1598d90ca7..af6e48fd6cfc 100644 > --- a/ArmVirtPkg/ArmVirt.dsc.inc > +++ b/ArmVirtPkg/ArmVirt.dsc.inc > @@ -261,6 +261,9 @@ > [LibraryClasses.ARM] > ArmSoftFloatLib|ArmPkg/Library/ArmSoftFloatLib/ArmSoftFloatLib.inf > > +[LibraryClasses.AARCH64] > + MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > + > [BuildOptions] > RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG > > -- > 2.31.1 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL 2021-12-15 17:55 ` Ard Biesheuvel @ 2021-12-15 18:15 ` Rebecca Cran 0 siblings, 0 replies; 9+ messages in thread From: Rebecca Cran @ 2021-12-15 18:15 UTC (permalink / raw) To: Ard Biesheuvel Cc: edk2-devel-groups-io, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar On 12/15/21 10:55 AM, Ard Biesheuvel wrote: > > Perhaps I misunderstood your question about splitting up this patch, > as surely, adding a completely new library can be broken out into a > separate one? Oh, of course it can! I just need to also split out the change to CpuDxe.inf. -- Rebecca Cran ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL 2021-12-15 17:46 ` [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL Rebecca Cran 2021-12-15 17:55 ` Ard Biesheuvel @ 2021-12-15 21:26 ` Rebecca Cran [not found] ` <16C10ACB9CD70BF0.6360@groups.io> 2 siblings, 0 replies; 9+ messages in thread From: Rebecca Cran @ 2021-12-15 21:26 UTC (permalink / raw) To: devel, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar [-- Attachment #1: Type: text/plain, Size: 1380 bytes --] On 12/15/21 10:46 AM, Rebecca Cran wrote: > diff --git a/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > new file mode 100644 > index 000000000000..2275b6cca33a > --- /dev/null > +++ b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf > @@ -0,0 +1,53 @@ > +#/** @file > +# > +# Component description file for the DxeMpInitLib module. > +# > +# Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +#**/ > + > +[Defines] > + INF_VERSION = 1.29 I'm having problems getting the CI Ecc check to pass this file: it keep saying: ERROR - EFI coding style error ERROR - *Error code: 9001 ERROR - *The file headers should follow Doxygen special documentation blocks in section 2.3.5 ERROR - *file: D:\a\1\s\Build\.pytool\Plugin\EccCheck\ArmPkg\Library\MpInitLib\DxeMpInitLib.inf ERROR - *Line number: 1 ERROR - *Header comment section must have Abstract information. ERROR - --->Test Failed: EccCheck Test NO-TARGET returned 1 I've tried copying other .inf files in the tree: with the style above, removing the C-style "/**" and "**/" and adding an extra "#" (i.e. "## @file") without any success. I've also moved the comment up to line 2 with no success. I was wondering if anyone could help me come up with a header that can pass CI? Thanks. Rebecca Cran [-- Attachment #2: Type: text/html, Size: 9262 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <16C10ACB9CD70BF0.6360@groups.io>]
* Re: [edk2-devel] [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL [not found] ` <16C10ACB9CD70BF0.6360@groups.io> @ 2021-12-16 2:45 ` Rebecca Cran 0 siblings, 0 replies; 9+ messages in thread From: Rebecca Cran @ 2021-12-16 2:45 UTC (permalink / raw) To: devel, Ard Biesheuvel, Gerd Hoffmann, Samer El-Haj-Mahmoud, Leif Lindholm, Sami Mujawar [-- Attachment #1: Type: text/plain, Size: 1608 bytes --] I figured it out: it didn't like the generic wording "Component description file". -- Rebecca Cran On 12/15/21 2:26 PM, Rebecca Cran via groups.io wrote: > On 12/15/21 10:46 AM, Rebecca Cran wrote: >> diff --git a/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf >> new file mode 100644 >> index 000000000000..2275b6cca33a >> --- /dev/null >> +++ b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf >> @@ -0,0 +1,53 @@ >> +#/** @file >> +# >> +# Component description file for the DxeMpInitLib module. >> +# >> +# Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> >> +# >> +# SPDX-License-Identifier: BSD-2-Clause-Patent >> +# >> +#**/ >> + >> +[Defines] >> + INF_VERSION = 1.29 > > I'm having problems getting the CI Ecc check to pass this file: it > keep saying: > > ERROR - EFI coding style error > ERROR - *Error code: 9001 > ERROR - *The file headers should follow Doxygen special documentation > blocks in section 2.3.5 > ERROR - *file: > D:\a\1\s\Build\.pytool\Plugin\EccCheck\ArmPkg\Library\MpInitLib\DxeMpInitLib.inf > ERROR - *Line number: 1 > ERROR - *Header comment section must have Abstract information. > > ERROR - --->Test Failed: EccCheck Test NO-TARGET returned 1 > > > I've tried copying other .inf files in the tree: with the style above, > removing the C-style "/**" and "**/" and adding an extra "#" (i.e. "## > @file") without any success. > > I've also moved the comment up to line 2 with no success. I was > wondering if anyone could help me come up with a header that can pass CI? > > > Thanks. > Rebecca Cran > > [-- Attachment #2: Type: text/html, Size: 10034 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2021-12-16 2:45 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-12-15 17:46 [PATCH v2 0/2] ArmPkg,ArmVirtPkg: Add support EFI_MP_SERVICES_PROTOCOL on AARCH64 Rebecca Cran 2021-12-15 17:46 ` [PATCH v2 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct Rebecca Cran 2021-12-15 17:53 ` Ard Biesheuvel 2021-12-15 20:33 ` Rebecca Cran 2021-12-15 17:46 ` [PATCH v2 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL Rebecca Cran 2021-12-15 17:55 ` Ard Biesheuvel 2021-12-15 18:15 ` Rebecca Cran 2021-12-15 21:26 ` Rebecca Cran [not found] ` <16C10ACB9CD70BF0.6360@groups.io> 2021-12-16 2:45 ` [edk2-devel] " Rebecca Cran
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox