From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) by mx.groups.io with SMTP id smtpd.web11.7781.1673044429035849352 for ; Fri, 06 Jan 2023 14:33:49 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20210112 header.b=F2+90yIt; spf=pass (domain: gmail.com, ip: 209.85.210.174, mailfrom: kuqin12@gmail.com) Received: by mail-pf1-f174.google.com with SMTP id a184so2109237pfa.9 for ; Fri, 06 Jan 2023 14:33:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=Thvu4yBA3LXjDHD6FPYWJtY1gNKFpuIXxw1gN6X1kuU=; b=F2+90yItiyG4eotnFE0MQCx+LFwzytzivCNaxBlvAtuQhWOOQlgefjSuRAvwSCQrLk qYi6Ug/kWXc8s3z8UJ4rp8P1n26QWuugr0Yb0tH5OIPKCDfY0inq7LzssjfLMHi839lq 3nTSJCqeTw6k98ZHMRjdvfqqbDXAFUhyjf9yDwlBB8rD5NpKj+bhvUJ++SiKKFJiHSzV 8RKQA0wPv5wwXwOxbn6lFb3Q98ozf08/MtDS8Oa1RLAzSBznf45Ciy8D3uvxEfkW8v2H YWUhCVXSXzaHrP+L/6C7dGT/jTsCpsMIQVtyWThnVQ5PybjA6m0xdgotkyK9bFrltbth 1DDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Thvu4yBA3LXjDHD6FPYWJtY1gNKFpuIXxw1gN6X1kuU=; b=3KkT1Yqw+IuN4ygafQ77v+rPjE5Smi6GmtkzXQA3KmrXwYLC+dVAgX5F0sEafbFcLr sIYHH4sz0acD/RSmDaOOtKPmDSM2yXHo612KLQ4K3ndLqQvpH5bq8Y1ujoXqSts26EAH KuzPUxcjgCFitoH/ep7nLDWIDbzTmTmPbTliK5AGmTe2OFxS6AWNwXvCpXmb8Z/6u6xy Z8ZIelmxUhzF7/z+qNdSC2a5+E3eJ3N8ORQsif++hDX5+EpNZdBgPmkDJ498WABY+kbA 8e+LXu2c7OYljIxluqK4euzQq6J51HaNG026QRDyANqrEsw2iUE25zVCs0LFD3iWEMoX J5Pg== X-Gm-Message-State: AFqh2kri3+t/NZQBrQOLNsZ116bKPgFE+x/1iPEwBFbW+RAy0gSh9zWM u+tzo3laZYAsocl7dlSFKifnV3PX7xU= X-Google-Smtp-Source: AMrXdXtC3SVC0II+9Zm3ElpFjYXAu95bJT07xn/KAfErSarKIsyBLCAQg02AU4elknqb4visKU4eDA== X-Received: by 2002:a05:6a00:bca:b0:581:4ab0:abcd with SMTP id x10-20020a056a000bca00b005814ab0abcdmr42459646pfu.14.1673044427941; Fri, 06 Jan 2023 14:33:47 -0800 (PST) Return-Path: Received: from ?IPV6:2001:4898:d8:33:b00c:23a8:3ea:9ab? ([2001:4898:80e8:a:3025:23a8:3ea:9ab]) by smtp.gmail.com with ESMTPSA id 207-20020a6218d8000000b00580d877a50fsm1586048pfy.55.2023.01.06.14.33.47 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 06 Jan 2023 14:33:47 -0800 (PST) Message-ID: Date: Fri, 6 Jan 2023 14:33:46 -0800 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Thunderbird/102.6.1 Subject: Re: [edk2-devel] [PATCH v4 3/3] MdeModulePkg: Add new Application/MpServicesTest application To: devel@edk2.groups.io, rebecca@quicinc.com, Sami Mujawar , Ard Biesheuvel , Leif Lindholm , Jian J Wang , Liming Gao , Tiger Liu References: <20230104153727.345236-1-rebecca@quicinc.com> <20230104153727.345236-4-rebecca@quicinc.com> From: "Kun Qin" In-Reply-To: <20230104153727.345236-4-rebecca@quicinc.com> Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit 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 > 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 > --- > 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.
> +# > +# 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..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.
> + 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; [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.
> + 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; > +} > + > +/** > + 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; > + 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; > +}