[edk2-devel] [PATCH v4 3/3] MdeModulePkg: Add new Application/MpServicesTest application
Rebecca Cran
quic_rcran at quicinc.com
Sun Jan 8 04:56:20 UTC 2023
Thanks! I've fixed all the issues you noted and will send out a v5 patch
in the next couple of days.
--
Rebecca Cran
On 1/6/23 15:33, Kun Qin wrote:
> Hi Rebecca,
>
> Thanks for sharing this patch. I found a few minor issues when running
> this test app. Please see comments with [KQ] below.
>
> Regards,
> Kun
>
> On 1/4/2023 7:37 AM, Rebecca Cran wrote:
>> The MpServicesTest application exercises the EFI_MP_SERVICES_PROTOCOL.
>>
>> usage:
>> MpServicesTest -A [-O]
>> MpServicesTest -T <Timeout>
>> MpServicesTest -S <Processor #>
>> MpServicesTest -P
>> MpServicesTest -U
>> MpServicesTest -W
>> MpServicesTest -E <Processor #>
>> MpServicesTest -D <Processor #>
>> 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 <rebecca at quicinc.com>
>> ---
>> MdeModulePkg/MdeModulePkg.dsc | 2 +
>> MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf | 40 ++
>> MdeModulePkg/Application/MpServicesTest/Options.h | 39 ++
>> MdeModulePkg/Application/MpServicesTest/MpServicesTest.c | 560
>> ++++++++++++++++++++
>> MdeModulePkg/Application/MpServicesTest/Options.c | 164 ++++++
>> 5 files changed, 805 insertions(+)
>>
>> diff --git a/MdeModulePkg/MdeModulePkg.dsc
>> b/MdeModulePkg/MdeModulePkg.dsc
>> index 659482ab737f..6992b3ae8db6 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.<BR>
>> +#
>> +# 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.<BR>
>> + 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..3f3d9752d500
>> --- /dev/null
>> +++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c
>> @@ -0,0 +1,560 @@
>> +/** @file
>> + UEFI Application to exercise EFI_MP_SERVICES_PROTOCOL.
>> +
>> + Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights
>> reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include <Uefi.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/PrintLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Pi/PiMultiPhase.h>
>> +#include <Protocol/MpService.h>
>> +
>> +#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;
> [KQ] The NumCpu and NumEnabledCpu probably should be initialized to 0s?
> Otherwise if the
> GetNumberOfProcessors function somehow fails, the rest of the call will
> essentially be no-op,
> instead of running into undefined number of CPUs.
>> +
>> + 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
>> + )
>> +{
>> + UINT32 Index;
> [KQ] The Index of UINT32 compared to NumCpus of UINTN could make some
> compilers unhappy.
>> +
>> + 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++) {
> [KQ] This Index increment could cause the loop not ending as expected.
>> + 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;
>> + }
>> +
> [KQ] I guess the above double calls are not intended?
>> + 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 %s, %u%s timeout...",
>> + (RunAPsSequentially) ? L"TRUE" : L"FALSE",
>> + 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
> [KQ] These parameters should have the "IN" attributes?
>> + )
>> +{
>> + 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
> [KQ] These parameters should have the "IN" attributes?
>> + )
>> +{
>> + 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..e820c061e1ec
>> --- /dev/null
>> +++ b/MdeModulePkg/Application/MpServicesTest/Options.c
>> @@ -0,0 +1,164 @@
>> +/** @file
>> + Options handling code.
>> +
>> + Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights
>> reserved.<BR>
>> + Copyright (c) 2010-2019 Finnbarr P. Murphy. All rights
>> reserved.<BR>
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#include <Uefi.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Protocol/ShellParameters.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +
>> +#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;
>> +}
>> +
>> +/**
>> + Print app usage.
>> +**/
>> +STATIC
>> +VOID
>> +PrintUsage (
>> + VOID
>> + )
>> +{
>> + Print (L"MpServicesTest: usage\n");
>> + Print (L" MpServicesTest -A [-O]\n");
>> + Print (L" MpServicesTest -T <Timeout>\n");
>> + Print (L" MpServicesTest -S <Processor #>\n");
>> + Print (L" MpServicesTest -P\n");
>> + Print (L" MpServicesTest -U\n");
>> + Print (L" MpServicesTest -W\n");
>> + Print (L" MpServicesTest -E <Processor #>\n");
>> + Print (L" MpServicesTest -D <Processor #>\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;
>> + UINT32 ArgIndex;
> [KQ] Similar to the other comment, ArgIndex is of UINT32 is compared to
> Argc of UINTN could make some compilers unhappy.
>> + 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 = StrDecimalToUintnS (Argv[ArgIndex + 1], NULL, 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;
>> +}
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#98154): https://edk2.groups.io/g/devel/message/98154
Mute This Topic: https://groups.io/mt/96091002/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-
More information about the edk2-devel-archive
mailing list