Hi, Rebecca: Got it! I think shell MP test tool is convenient than unit test infrastructure. Thanks 发件人: Rebecca Cran 发送时间: 2022年12月29日 8:01 收件人: devel@edk2.groups.io; Tiger Liu(BJ-RD) ; Rebecca Cran 主题: Re: [edk2-devel] [PATCH v2 2/2] MdeModulePkg: Add new Application/MpServicesTest application 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. 保密声明: 本邮件含有保密或专有信息,仅供指定收件人使用。严禁对本邮件或其内容做任何未经授权的查阅、使用、复制或转发。 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.