No, it hasn't been merged yet. I did some work to finish off bug fixes and improvements last week, so I'll send out a new patch series: I was going to wait until people are back after Christmas and the New Year, but I may as well send it out now. -- Rebecca Cran On 12/26/22 23:19, Tiger Liu(BJ-RD) wrote: > > Hello: > > Does this MpServicesTest app have been merged into master branch? > > I could not find it in current GitHub code base. > > Thanks > > -----邮件原件----- > > 发件人: devel@edk2.groups.io > > 代表Rebecca Cran > > 发送时间: 2022年9月7日12:03 > > 收件人: devel@edk2.groups.io ; > ardb@kernel.org ; quic_llindhol@quicinc.com > ; Sami Mujawar >; Jian J Wang >; Liming Gao > > > 抄送: Rebecca Cran > > > 主题: [edk2-devel] [PATCH v2 2/2] MdeModulePkg: Add new > Application/MpServicesTest application > > The MpServicesTest application exercises the EFI_MP_SERVICES_PROTOCOL. > > usage: > >   MpServicesTest -A [-O] > >   MpServicesTest -T > >   MpServicesTest -S > >   MpServicesTest -P > >   MpServicesTest -U > >   MpServicesTest -W > >   MpServicesTest -E > >   MpServicesTest -D > >   MpServicesTest -h > > Parameter: > >   -A:  Run all APs. > >   -O:  Run APs sequentially (use with -A). > >   -T:  Specify timeout in milliseconds. Default is to wait forever. > >   -S:  Specify the single AP to run. > >   -P:  Print processor information. > >   -U:  Set the specified AP to the Unhealthy status (use with -E/-D). > >   -W:  Run WhoAmI and print index of BSP. > >   -E:  Enable the specified AP. > >   -D:  Disable the specified AP. > >   -h:  Print this help page. > > Signed-off-by: Rebecca Cran > > > Reviewed-by: Ard Biesheuvel > > > --- > > MdeModulePkg/MdeModulePkg.dsc |   2 + > > MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf |  40 ++ > > MdeModulePkg/Application/MpServicesTest/Options.h |  39 ++ > > MdeModulePkg/Application/MpServicesTest/MpServicesTest.c | 555 > ++++++++++++++++++++ > > MdeModulePkg/Application/MpServicesTest/Options.c | 215 ++++++++ > > 5 files changed, 851 insertions(+) > > diff --git a/MdeModulePkg/MdeModulePkg.dsc > b/MdeModulePkg/MdeModulePkg.dsc index 45a8ec84ad69..295ff4ddfcd8 100644 > > --- a/MdeModulePkg/MdeModulePkg.dsc > > +++ b/MdeModulePkg/MdeModulePkg.dsc > > @@ -166,6 +166,7 @@ [LibraryClasses.common.UEFI_APPLICATION] > > MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf > > DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf > > FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf > > + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf > >  [LibraryClasses.common.MM_STANDALONE] > > HobLib|MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf > > @@ -445,6 +446,7 @@ [Components] > > MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf > >  [Components.IA32, Components.X64, Components.AARCH64] > > + MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf > > MdeModulePkg/Universal/EbcDxe/EbcDxe.inf > > MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf > > MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf > > diff --git > a/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf > b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf > > new file mode 100644 > > index 000000000000..07ee4afec845 > > --- /dev/null > > +++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf > > @@ -0,0 +1,40 @@ > > +## @file > > +#  UEFI Application to exercise EFI_MP_SERVICES_PROTOCOL. > > +# > > +#  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights > > +reserved.
# #  SPDX-License-Identifier: BSD-2-Clause-Patent # ## > > + > > +[Defines] > > + INF_VERSION                    = 1.29 > > + BASE_NAME                      = MpServicesTest > > + FILE_GUID                      = 43e9defa-7209-4b0d-b136-cc4ca02cb469 > > + MODULE_TYPE                    = UEFI_APPLICATION > > + VERSION_STRING                 = 0.1 > > + ENTRY_POINT                    = UefiMain > > + > > +# > > +# The following information is for reference only and not required by > the build tools. > > +# > > +# VALID_ARCHITECTURES           = IA32 X64 AARCH64 > > +# > > + > > +[Sources] > > +  MpServicesTest.c > > +  Options.c > > +  Options.h > > + > > +[Packages] > > +  MdePkg/MdePkg.dec > > + > > +[LibraryClasses] > > +  BaseLib > > +  ShellLib > > + UefiApplicationEntryPoint > > +  UefiLib > > + > > +[Protocols] > > + gEfiMpServiceProtocolGuid    ## CONSUMES > > + > > diff --git a/MdeModulePkg/Application/MpServicesTest/Options.h > b/MdeModulePkg/Application/MpServicesTest/Options.h > > new file mode 100644 > > index 000000000000..cb28230ab095 > > --- /dev/null > > +++ b/MdeModulePkg/Application/MpServicesTest/Options.h > > @@ -0,0 +1,39 @@ > > +/** @file > > +  Options handling code. > > + > > +  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights > > +reserved.
> > + SPDX-License-Identifier: BSD-2-Clause-Patent **/ > > + > > +#ifndef MPSERVICESTEST_OPTIONS_H_ > > +#define MPSERVICESTEST_OPTIONS_H_ > > + > > +#define INFINITE_TIMEOUT  0 > > + > > +typedef struct { > > +  UINTN Timeout; > > +  UINTN ProcessorIndex; > > +  BOOLEAN RunAllAPs; > > +  BOOLEAN RunSingleAP; > > +  BOOLEAN DisableProcessor; > > +  BOOLEAN EnableProcessor; > > +  BOOLEAN SetProcessorHealthy; > > +  BOOLEAN SetProcessorUnhealthy; > > +  BOOLEAN PrintProcessorInformation; > > +  BOOLEAN PrintBspProcessorIndex; > > +  BOOLEAN RunAPsSequentially; > > +} MP_SERVICES_TEST_OPTIONS; > > + > > +/** > > +  Parses any arguments provided on the command line. > > + > > +  @param Options The arguments structure. > > + > > +  @return EFI_SUCCESS on success, or an error code. > > +**/ > > +EFI_STATUS > > +ParseArguments ( > > + MP_SERVICES_TEST_OPTIONS  *Options > > +  ); > > + > > +#endif /* MPSERVICESTEST_OPTIONS_H_ */ > > diff --git a/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c > b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c > > new file mode 100644 > > index 000000000000..1cea8f52f25d > > --- /dev/null > > +++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c > > @@ -0,0 +1,555 @@ > > +/** @file > > +  UEFI Application to exercise EFI_MP_SERVICES_PROTOCOL. > > + > > +  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights > > +reserved.
> > + SPDX-License-Identifier: BSD-2-Clause-Patent **/ > > + > > +#include > > +#include > > +#include > > +#include #include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "Options.h" > > + > > +#define APFUNC_BUFFER_LEN  256 > > + > > +typedef struct { > > + EFI_MP_SERVICES_PROTOCOL    *Mp; > > + CHAR16                      **Buffer; > > +} APFUNC_ARG; > > + > > +/** The procedure to run with the MP Services interface. > > + > > +  @param Arg The procedure argument. > > + > > +**/ > > +STATIC > > +VOID > > +EFIAPI > > +ApFunction ( > > +  IN OUT VOID  *Arg > > +  ) > > +{ > > +  APFUNC_ARG *Param; > > +  UINTN ProcessorId; > > + > > +  if (Arg != NULL) { > > +    Param = Arg; > > + > > + Param->Mp->WhoAmI (Param->Mp, &ProcessorId); > > +    UnicodeSPrint (Param->Buffer[ProcessorId], APFUNC_BUFFER_LEN, > > +L"Hello from CPU %ld\n", ProcessorId); > > +  } > > +} > > + > > +/** > > +  Fetches the number of processors and which processor is the BSP. > > + > > +  @param Mp  MP Services Protocol. > > +  @param NumProcessors Number of processors. > > +  @param BspIndex      The index of the BSP. > > +**/ > > +STATIC > > +EFI_STATUS > > +GetProcessorInformation ( > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > +  OUT UINTN                     *NumProcessors, > > +  OUT UINTN                     *BspIndex > > +  ) > > +{ > > +  EFI_STATUS Status; > > +  UINTN NumEnabledProcessors; > > + > > +  Status = Mp->GetNumberOfProcessors (Mp, NumProcessors, > > + &NumEnabledProcessors);  if (EFI_ERROR (Status)) { > > +    return Status; > > +  } > > + > > +  Status = Mp->WhoAmI (Mp, BspIndex); > > +  if (EFI_ERROR (Status)) { > > +    return Status; > > +  } > > + > > +  return EFI_SUCCESS; > > +} > > + > > +/** Displays information returned from MP Services Protocol. > > + > > +  @param Mp The MP Services Protocol > > +  @param BspIndex On return, contains the index of the BSP. > > + > > +  @return The number of CPUs in the system. > > + > > +**/ > > +STATIC > > +UINTN > > +PrintProcessorInformation ( > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > +  OUT UINTN                     *BspIndex > > +  ) > > +{ > > + EFI_STATUS                 Status; > > + EFI_PROCESSOR_INFORMATION  CpuInfo; > > + UINTN                      Index; > > + UINTN                      NumCpu; > > + UINTN                      NumEnabledCpu; > > + > > +  Status = Mp->GetNumberOfProcessors (Mp, &NumCpu, &NumEnabledCpu);  if > > + (EFI_ERROR (Status)) { > > +    Print (L"GetNumberOfProcessors failed: %r\n", Status);  } else { > > +    Print (L"Number of CPUs: %ld, Enabled: %d\n", NumCpu, > > + NumEnabledCpu);  } > > + > > +  for (Index = 0; Index < NumCpu; Index++) { > > +    Status = Mp->GetProcessorInfo (Mp, CPU_V2_EXTENDED_TOPOLOGY | > Index, &CpuInfo); > > +    if (EFI_ERROR (Status)) { > > +      Print (L"GetProcessorInfo for Processor %d failed: %r\n", > Index, Status); > > +    } else { > > +      Print ( > > +        L"Processor %d:\n" > > +        L"\tID: %016lx\n" > > +        L"\tStatus: %s | ", > > +        Index, > > + CpuInfo.ProcessorId, > > + (CpuInfo.StatusFlag & PROCESSOR_AS_BSP_BIT) ? L"BSP" : L"AP" > > +        ); > > + > > +      if ((CpuInfo.StatusFlag & PROCESSOR_AS_BSP_BIT) && (BspIndex != > NULL)) { > > +        *BspIndex = Index; > > +      } > > + > > +      Print (L"%s | ", (CpuInfo.StatusFlag & PROCESSOR_ENABLED_BIT) ? > L"Enabled" : L"Disabled"); > > +      Print (L"%s\n", (CpuInfo.StatusFlag & > > + PROCESSOR_HEALTH_STATUS_BIT) ? L"Healthy" : L"Faulted"); > > + > > +      Print ( > > + L"\tLocation: Package %d, Core %d, Thread %d\n" > > +        L"\tExtended Information: Package %d, Module %d, Tile %d, Die > %d, Core %d, Thread %d\n\n", > > + CpuInfo.Location.Package, > > + CpuInfo.Location.Core, > > + CpuInfo.Location.Thread, > > + CpuInfo.ExtendedInformation.Location2.Package, > > + CpuInfo.ExtendedInformation.Location2.Module, > > + CpuInfo.ExtendedInformation.Location2.Tile, > > + CpuInfo.ExtendedInformation.Location2.Die, > > + CpuInfo.ExtendedInformation.Location2.Core, > > + CpuInfo.ExtendedInformation.Location2.Thread > > +        ); > > +    } > > +  } > > + > > +  return NumCpu; > > +} > > + > > +/** Allocates memory in ApArg for the single AP specified. > > + > > +  @param ApArg          Pointer to the AP argument structure. > > +  @param Mp             The MP Services Protocol. > > +  @param ProcessorIndex The index of the AP. > > + > > +  @retval EFI_SUCCESS          Memory was successfully allocated. > > +  @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > > + > > +**/ > > +STATIC > > +EFI_STATUS > > +AllocateApFuncBufferSingleAP ( > > +  IN APFUNC_ARG                *ApArg, > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > +  IN UINTN                     ProcessorIndex > > +  ) > > +{ > > +  ApArg->Mp = Mp; > > + > > +  ApArg->Buffer = AllocateZeroPool ((ProcessorIndex + 1) * sizeof (VOID > > + *));  if (ApArg->Buffer == NULL) { > > +    Print (L"Failed to allocate buffer for AP buffer\n"); > > +    return EFI_OUT_OF_RESOURCES; > > +  } > > + > > + ApArg->Buffer[ProcessorIndex] = AllocateZeroPool (APFUNC_BUFFER_LEN); > > + if (ApArg->Buffer[ProcessorIndex] == NULL) { > > +    Print (L"Failed to allocate buffer for AP buffer\n"); > > +    FreePool (ApArg->Buffer); > > +    return EFI_OUT_OF_RESOURCES; > > +  } > > + > > +  return EFI_SUCCESS; > > +} > > + > > +/** Allocates memory in ApArg for all APs. > > + > > +  @param ApArg Pointer to the AP argument structure. > > +  @param Mp      The MP Services Protocol. > > +  @param NumCpus The number of CPUs. > > + > > +  @retval EFI_SUCCESS          Memory was successfully allocated. > > +  @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. > > + > > +**/ > > +STATIC > > +EFI_STATUS > > +AllocateApFuncBufferAllAPs ( > > +  IN APFUNC_ARG                *ApArg, > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > +  IN UINTN                     NumCpus > > +  ) > > +{ > > +  INT32  Index; > > + > > +  ApArg->Mp = Mp; > > + > > +  ApArg->Buffer = AllocateZeroPool (NumCpus * sizeof (VOID *));  if > > + (ApArg->Buffer == NULL) { > > +    Print (L"Failed to allocate buffer for AP message\n"); > > +    return EFI_OUT_OF_RESOURCES; > > +  } > > + > > +  for (Index = 0; Index < NumCpus; Index++) { > > + ApArg->Buffer[Index] = AllocateZeroPool (APFUNC_BUFFER_LEN); > > +    if (ApArg->Buffer[Index] == NULL) { > > +      Print (L"Failed to allocate buffer for AP message\n"); > > +      for (--Index; Index >= 0; Index++) { > > +        FreePool (ApArg->Buffer[Index]); > > +      } > > + > > +      FreePool (ApArg->Buffer); > > +      return EFI_OUT_OF_RESOURCES; > > +    } > > +  } > > + > > +  return EFI_SUCCESS; > > +} > > + > > +/** Frees memory in ApArg for all APs. > > + > > +  @param ApArg Pointer to the AP argument structure. > > +  @param NumCpus The number of CPUs. > > + > > +**/ > > +STATIC > > +VOID > > +FreeApFuncBuffer ( > > +  APFUNC_ARG *ApArg, > > +  UINTN NumCpus > > +  ) > > +{ > > +  UINTN  Index; > > + > > +  for (Index = 0; Index < NumCpus; Index++) { > > +    if (ApArg->Buffer[Index] != NULL) { > > +      FreePool (ApArg->Buffer[Index]); > > +    } > > +  } > > + > > +  FreePool (ApArg->Buffer); > > +} > > + > > +/** Runs a specified AP. > > + > > +  @param Mp             The MP Services Protocol. > > +  @param ProcessorIndex The processor index. > > +  @param Timeout        Timeout in milliseconds. > > + > > +  @return EFI_SUCCESS on success, or an error code. > > + > > +**/ > > +STATIC > > +EFI_STATUS > > +StartupThisAP ( > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > +  IN UINTN                     ProcessorIndex, > > +  IN UINTN                     Timeout > > +  ) > > +{ > > +  EFI_STATUS Status; > > +  APFUNC_ARG  ApArg; > > + > > +  Status = AllocateApFuncBufferSingleAP (&ApArg, Mp, ProcessorIndex); > > + if (EFI_ERROR (Status)) { > > +    return Status; > > +  } > > + > > +  Status = AllocateApFuncBufferSingleAP (&ApArg, Mp, ProcessorIndex); > > + if (EFI_ERROR (Status)) { > > +    return Status; > > +  } > > + > > +  Print ( > > +    L"StartupThisAP on Processor %d with %d%s timeout...", > > +    ProcessorIndex, > > +    Timeout, > > +    (Timeout == INFINITE_TIMEOUT) ? L" (infinite)" : L"ms" > > +    ); > > +  Status = Mp->StartupThisAP ( > > +                 Mp, > > + ApFunction, > > + ProcessorIndex, > > + NULL, > > + Timeout * 1000, > > + &ApArg, > > + NULL > > +                 ); > > +  if (EFI_ERROR (Status)) { > > +    Print (L"failed: %r\n", Status); > > +    return Status; > > +  } else { > > +    Print (L"done.\n"); > > +    Print (ApArg.Buffer[ProcessorIndex]);  } > > + > > +  FreeApFuncBuffer (&ApArg, ProcessorIndex + 1); > > + > > +  return EFI_SUCCESS; > > +} > > + > > +/** Runs all APs. > > + > > +  @param Mp                 The MP Services Protocol. > > +  @param NumCpus            The number of CPUs in the system. > > +  @param Timeout            Timeout in milliseconds. > > +  @param RunAPsSequentially Run APs sequentially (FALSE: run > > + simultaneously) > > + > > +  @return EFI_SUCCESS on success, or an error code. > > + > > +**/ > > +STATIC > > +EFI_STATUS > > +StartupAllAPs ( > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > +  IN UINTN                     NumCpus, > > +  IN UINTN                     Timeout, > > +  IN BOOLEAN                   RunAPsSequentially > > +  ) > > +{ > > +  EFI_STATUS Status; > > +  UINTN       Index; > > +  APFUNC_ARG  ApArg; > > + > > +  Status = AllocateApFuncBufferAllAPs (&ApArg, Mp, NumCpus);  if > > + (EFI_ERROR (Status)) { > > +    return Status; > > +  } > > + > > +  Print ( > > +    L"Running with SingleThread TRUE, %d%s timeout...", > > +    Timeout, > > +    (Timeout == INFINITE_TIMEOUT) ? L" (infinite)" : L"ms" > > +    ); > > +  Status = Mp->StartupAllAPs ( > > +                 Mp, > > + ApFunction, > > + RunAPsSequentially, > > + NULL, > > + Timeout * 1000, > > + &ApArg, > > + NULL > > +                 ); > > +  if (EFI_ERROR (Status)) { > > +    Print (L"failed: %r\n", Status); > > +    return Status; > > +  } else { > > +    Print (L"done.\n"); > > +    for (Index = 0; Index < NumCpus; Index++) { > > +      Print (ApArg.Buffer[Index]); > > +    } > > +  } > > + > > +  FreeApFuncBuffer (&ApArg, NumCpus); > > +  return EFI_SUCCESS; > > +} > > + > > +/** > > +  Enables the specified AP. > > + > > +  @param Mp               The MP Services Protocol. > > +  @param ProcessorIndex   The processor to enable. > > +  @param ProcessorHealthy The health status of the processor. > > + > > +  @return EFI_SUCCESS on success, or an error code. > > +**/ > > +STATIC > > +EFI_STATUS > > +EnableAP ( > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > + UINTN                        ProcessorIndex, > > + BOOLEAN                      ProcessorHealthy > > +  ) > > +{ > > +  EFI_STATUS Status; > > +  UINT32 HealthFlag; > > + > > +  if (ProcessorHealthy) { > > +    Print (L"Enabling Processor %d with HealthFlag healthy...", > ProcessorIndex); > > +    HealthFlag = PROCESSOR_HEALTH_STATUS_BIT;  } else { > > +    Print (L"Enabling Processor %d with HealthFlag faulted...", > ProcessorIndex); > > +    HealthFlag = 0; > > +  } > > + > > +  Status = Mp->EnableDisableAP (Mp, ProcessorIndex, TRUE, &HealthFlag); > > + if (EFI_ERROR (Status)) { > > +    Print (L"failed: %r\n", Status); > > +    return Status; > > +  } else { > > +    Print (L"done.\n"); > > +  } > > + > > +  return Status; > > +} > > + > > +/** > > +  Disables the specified AP. > > + > > +  @param Mp               The MP Services Protocol. > > +  @param ProcessorIndex   The processor to disable. > > +  @param ProcessorHealthy The health status of the processor. > > + > > +  @return EFI_SUCCESS on success, or an error code. > > +**/ > > +STATIC > > +EFI_STATUS > > +DisableAP ( > > +  IN EFI_MP_SERVICES_PROTOCOL  *Mp, > > + UINTN                        ProcessorIndex, > > + BOOLEAN                      ProcessorHealthy > > +  ) > > +{ > > +  EFI_STATUS Status; > > +  UINT32 HealthFlag; > > + > > +  if (ProcessorHealthy) { > > +    Print (L"Disabling Processor %d with HealthFlag healthy...", > ProcessorIndex); > > +    HealthFlag = PROCESSOR_HEALTH_STATUS_BIT;  } else { > > +    Print (L"Disabling Processor %d with HealthFlag faulted...", > ProcessorIndex); > > +    HealthFlag = 0; > > +  } > > + > > +  Status = Mp->EnableDisableAP (Mp, ProcessorIndex, FALSE, > > + &HealthFlag); if (EFI_ERROR (Status)) { > > +    Print (L"failed: %r\n", Status); > > +    return Status; > > +  } else { > > +    Print (L"done.\n"); > > +  } > > + > > +  return Status; > > +} > > + > > +/** > > +  The user Entry Point for Application. The user code starts with this > > +function > > +  as the real entry point for the application. > > + > > +  @param[in] ImageHandle    The firmware allocated handle for the EFI > image. > > +  @param[in] SystemTable    A pointer to the EFI System Table. > > + > > +  @retval EFI_SUCCESS       The entry point is executed successfully. > > +  @retval other             Some error occurs when executing this > entry point. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UefiMain ( > > +  IN EFI_HANDLE        ImageHandle, > > +  IN EFI_SYSTEM_TABLE  *SystemTable > > +  ) > > +{ > > + EFI_STATUS                Status; > > + EFI_MP_SERVICES_PROTOCOL  *Mp; > > + UINTN                     BspIndex; > > + UINTN                     CpuIndex; > > + UINTN                     NumCpus; > > + BOOLEAN                   ProcessorHealthy; > > + MP_SERVICES_TEST_OPTIONS  Options; > > + > > +  BspIndex = 0; > > + > > +  Status = gBS->LocateProtocol ( > > + &gEfiMpServiceProtocolGuid, > > + NULL, > > + (VOID **)&Mp > > +                  ); > > +  if (EFI_ERROR (Status)) { > > +    Print (L"Failed to locate EFI_MP_SERVICES_PROTOCOL (%r). Not > installed on platform?\n", Status); > > +    return EFI_NOT_FOUND; > > +  } > > + > > +  Status = ParseArguments (&Options); > > +  if (EFI_ERROR (Status)) { > > +    return EFI_INVALID_PARAMETER; > > +  } > > + > > +  Status = GetProcessorInformation (Mp, &NumCpus, &BspIndex); if > > + (EFI_ERROR (Status)) { > > +    Print (L"Error: Failed to fetch processor information.\n"); > > +    return Status; > > +  } > > + > > +  if (Options.PrintBspProcessorIndex) { > > +    Status = Mp->WhoAmI (Mp, &CpuIndex); > > +    if (EFI_ERROR (Status)) { > > +      Print (L"WhoAmI failed: %r\n", Status); > > +      return Status; > > +    } else { > > +      Print (L"BSP: %016lx\n", CpuIndex); > > +    } > > +  } > > + > > +  if (Options.PrintProcessorInformation) { > > +    NumCpus = PrintProcessorInformation (Mp, &BspIndex); > > +    if (NumCpus < 2) { > > +      Print (L"Error: Uniprocessor system found.\n"); > > +      return EFI_INVALID_PARAMETER; > > +    } > > +  } > > + > > +  if (Options.RunSingleAP) { > > +    Status = StartupThisAP ( > > +               Mp, > > + Options.ProcessorIndex, > > + Options.Timeout > > +               ); > > +    if (EFI_ERROR (Status)) { > > +      return Status; > > +    } > > +  } > > + > > +  if (Options.RunAllAPs) { > > +    Status = StartupAllAPs (Mp, NumCpus, Options.Timeout, > Options.RunAPsSequentially); > > +    if (EFI_ERROR (Status)) { > > +      return Status; > > +    } > > +  } > > + > > +  if (Options.EnableProcessor) { > > +    ProcessorHealthy = TRUE; > > +    if (Options.SetProcessorUnhealthy) { > > + ProcessorHealthy = FALSE; > > +    } > > + > > +    Status = EnableAP (Mp, Options.ProcessorIndex, ProcessorHealthy); > > +    if (EFI_ERROR (Status)) { > > +      return Status; > > +    } > > +  } > > + > > +  if (Options.DisableProcessor) { > > +    ProcessorHealthy = TRUE; > > +    if (Options.SetProcessorUnhealthy) { > > + ProcessorHealthy = FALSE; > > +    } > > + > > +    Status = DisableAP (Mp, Options.ProcessorIndex, ProcessorHealthy); > > +    if (EFI_ERROR (Status)) { > > +      return Status; > > +    } > > +  } > > + > > +  return EFI_SUCCESS; > > +} > > diff --git a/MdeModulePkg/Application/MpServicesTest/Options.c > b/MdeModulePkg/Application/MpServicesTest/Options.c > > new file mode 100644 > > index 000000000000..2ea2c94b7c74 > > --- /dev/null > > +++ b/MdeModulePkg/Application/MpServicesTest/Options.c > > @@ -0,0 +1,215 @@ > > +/** @file > > +  Options handling code. > > + > > +  Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights > reserved.
> > +  Copyright (c) 2010-2019  Finnbarr P. Murphy.   All rights reserved.
> > + SPDX-License-Identifier: BSD-2-Clause-Patent **/ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "Options.h" > > + > > +STATIC UINTN   Argc; > > +STATIC CHAR16 **Argv; > > + > > +/** > > + > > +  This function provides argc and argv. > > + > > +  @return Status > > +**/ > > +EFI_STATUS > > +GetArg ( > > +  VOID > > +  ) > > +{ > > + EFI_STATUS                     Status; > > + EFI_SHELL_PARAMETERS_PROTOCOL  *ShellParameters; > > + > > +  Status = gBS->HandleProtocol ( > > + gImageHandle, > > + &gEfiShellParametersProtocolGuid, > > +                  (VOID **)&ShellParameters > > +                  ); > > +  if (EFI_ERROR (Status)) { > > +    return Status; > > +  } > > + > > +  Argc = ShellParameters->Argc; > > +  Argv = ShellParameters->Argv; > > +  return EFI_SUCCESS; > > +} > > + > > +/** > > +  Checks if the character is a decimal digit. > > + > > +  @param Char The character to check. > > + > > +  @return TRUE if the character is a decimal digit. > > +**/ > > +BOOLEAN > > +IsUnicodeDecimalDigit ( > > +  CHAR16  Char > > +  ) > > +{ > > +  return ((BOOLEAN)(Char >= L'0' && Char <= L'9')); } > > + > > +/** > > +  Converts the string to an integer. > > + > > +  @param String The input string. > > +  @param Value  The converted number. > > + > > +  @return EFI_SUCCESS on success, or an error code. > > +**/ > > +EFI_STATUS > > +UnicodeStringToInteger ( > > +  CHAR16  *String, > > +  UINTN   *Value > > +  ) > > +{ > > +  UINTN  Result; > > + > > +  Result = 0; > > + > > +  if ((String == NULL) || (StrSize (String) == 0) || (Value == NULL)) { > > +    return (EFI_INVALID_PARAMETER); > > +  } > > + > > +  while (IsUnicodeDecimalDigit (*String)) { > > +    if (!(Result <= (DivU64x32 ((((UINT64) ~0) - (*String - L'0')), > 10)))) { > > +      return (EFI_DEVICE_ERROR); > > +    } > > + > > +    Result = MultU64x32 (Result, 10) + (*String - L'0'); > > +    String++; > > +  } > > + > > +  *Value = Result; > > + > > +  return (EFI_SUCCESS); > > +} > > + > > +/** > > +  Print app usage. > > +**/ > > +STATIC > > +VOID > > +PrintUsage ( > > +  VOID > > +  ) > > +{ > > +  Print (L"MpServicesTest:  usage\n"); > > +  Print (L" MpServicesTest -A [-O]\n"); > > +  Print (L" MpServicesTest -T \n"); > > +  Print (L" MpServicesTest -S \n"); > > +  Print (L" MpServicesTest -P\n"); > > +  Print (L" MpServicesTest -U\n"); > > +  Print (L" MpServicesTest -W\n"); > > +  Print (L" MpServicesTest -E \n"); > > +  Print (L" MpServicesTest -D \n"); > > +  Print (L" MpServicesTest -h\n"); > > +  Print (L"Parameter:\n"); > > +  Print (L"  -A: Run all APs.\n"); > > +  Print (L"  -O: Run APs sequentially (use with -A).\n"); > > +  Print (L"  -T: Specify timeout in milliseconds. Default is to wait > > +forever.\n"); > > +  Print (L"  -S: Specify the single AP to run.\n"); > > +  Print (L"  -P: Print processor information.\n"); > > +  Print (L"  -U: Set the specified AP to the Unhealthy status (use > > +with -E/-D).\n"); > > +  Print (L"  -W: Run WhoAmI and print index of BSP.\n"); > > +  Print (L"  -E: Enable the specified AP.\n"); > > +  Print (L"  -D: Disable the specified AP.\n"); > > +  Print (L"  -h: Print this help page.\n"); } > > + > > +/** > > +  Parses any arguments provided on the command line. > > + > > +  @param Options The arguments structure. > > + > > +  @return EFI_SUCCESS on success, or an error code. > > +**/ > > +EFI_STATUS > > +ParseArguments ( > > + MP_SERVICES_TEST_OPTIONS  *Options > > +  ) > > +{ > > +  EFI_STATUS Status; > > +  INT32 ArgIndex; > > +  CONST CHAR16 *Argument; > > +  BOOLEAN NeedsValue; > > +  UINTN     *Value; > > + > > +  Status = GetArg (); > > +  if (EFI_ERROR (Status)) { > > +    Print (L"Please use the UEFI Shell to run this application!\n", > Status); > > +    return Status; > > +  } > > + > > +  if (Argc == 1) { > > +    PrintUsage (); > > +  } > > + > > +  ZeroMem (Options, sizeof (MP_SERVICES_TEST_OPTIONS)); > > + > > +  for (ArgIndex = 1; ArgIndex < Argc; ArgIndex++) { > > +    Argument   = Argv[ArgIndex]; > > +    NeedsValue = FALSE; > > + > > +    if (StrCmp (Argument, L"-A") == 0) { > > + Options->RunAllAPs = TRUE; > > +    } else if (StrCmp (Argument, L"-O") == 0) { > > + Options->RunAPsSequentially = TRUE; > > +    } else if (StrCmp (Argument, L"-T") == 0) { > > +      NeedsValue = TRUE; > > +      Value      = &Options->Timeout; > > +    } else if (StrCmp (Argument, L"-S") == 0) { > > + Options->RunSingleAP = TRUE; > > + NeedsValue           = TRUE; > > + Value                = &Options->ProcessorIndex; > > +    } else if (StrCmp (Argument, L"-P") == 0) { > > + Options->PrintProcessorInformation = TRUE; > > +    } else if (StrCmp (Argument, L"-U") == 0) { > > + Options->SetProcessorUnhealthy = TRUE; > > +    } else if (StrCmp (Argument, L"-W") == 0) { > > + Options->PrintBspProcessorIndex = TRUE; > > +    } else if (StrCmp (Argument, L"-E") == 0) { > > + Options->EnableProcessor = TRUE; > > +  NeedsValue               = TRUE; > > + Value                    = &Options->ProcessorIndex; > > +    } else if (StrCmp (Argument, L"-D") == 0) { > > + Options->DisableProcessor = TRUE; > > + NeedsValue                = TRUE; > > + Value                     = &Options->ProcessorIndex; > > +    } else { > > +      PrintUsage (); > > +      ZeroMem (Options, sizeof (MP_SERVICES_TEST_OPTIONS)); > > +      return EFI_SUCCESS; > > +    } > > + > > +    if (NeedsValue) { > > +      if ((ArgIndex + 1) < Argc) { > > +        Status = UnicodeStringToInteger (Argv[ArgIndex + 1], Value); > > +        if (EFI_ERROR (Status)) { > > +          Print (L"Error: option value must be a positive integer.\n"); > > +          PrintUsage (); > > +          return EFI_INVALID_PARAMETER; > > +        } > > + > > +        ArgIndex++; > > +      } else { > > +        PrintUsage (); > > +        return EFI_INVALID_PARAMETER; > > +      } > > +    } > > +  } > > + > > +  return EFI_SUCCESS; > > +} > > -- > > 2.30.2 > > > > 保密声明: > 本邮件含有保密或专有信息,仅供指定收件人使用。严禁对本邮件或其内容做任何未经授权的查阅、使用、复制或转发。 > /CONFIDENTIAL NOTE: / > /This email contains confidential or legally privileged information > and is for the sole use of its intended recipient. Any unauthorized > review, use, copying or forwarding of this email or the content of > this email is strictly prohibited./ >