diff --git a/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf new file mode 100644 index 0000000000..0b2ddc5585 --- /dev/null +++ b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf @@ -0,0 +1,46 @@ +## @file +# PEIM that unit tests the EdkiiPeiMpServices2Ppi +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EdkiiPeiMpServices2PpiPeiUnitTest + FILE_GUID = A4914810-4D1E-445E-BD6F-F6821B852B5D + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeiEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + EfiMpServicesUnitTestCommom.c + EfiMpServicesUnitTestCommom.h + EdkiiPeiMpServices2PpiUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + PeimEntryPoint + PeiServicesLib + UnitTestPersistenceLib + UnitTestLib + +[Ppis] + gEdkiiPeiMpServices2PpiGuid ## CONSUMES + +[Depex] + gEdkiiPeiMpServices2PpiGuid diff --git a/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c new file mode 100644 index 0000000000..5c42a81d29 --- /dev/null +++ b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c @@ -0,0 +1,477 @@ +/** @file + PEI Module to test APIs defined in EdkiiPeiMpServices2Ppi. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include "EfiMpServicesUnitTestCommom.h" + +#define UNIT_TEST_NAME "EdkiiPeiMpServices2Ppi Unit Test" +#define UNIT_TEST_VERSION "0.1" + +/** + Get EDKII_PEI_MP_SERVICES2_PPI pointer. + + @param[out] MpServices Pointer to the buffer where EDKII_PEI_MP_SERVICES2_PPI is stored. + + @retval EFI_SUCCESS EDKII_PEI_MP_SERVICES2_PPI interface is returned + @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI interface is not found +**/ +EFI_STATUS +MpServicesUnitTestGetMpServices ( + OUT MP_SERVICES *MpServices + ) +{ + return PeiServicesLocatePpi (&gEdkiiPeiMpServices2PpiGuid, 0, NULL, (VOID **)&MpServices->Ppi); +} + +/** + Retrieve the number of logical processor in the platform and the number of those logical processors that + are enabled on this boot. + + @param[in] MpServices MP_SERVICES structure. + @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system, including + the BSP and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of processors in the system that are enabled. + + @retval EFI_SUCCESS Retrieve the number of logical processor successfully + @retval Others Retrieve the number of logical processor unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestGetNumberOfProcessors ( + IN MP_SERVICES MpServices, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + return MpServices.Ppi->GetNumberOfProcessors (MpServices.Ppi, NumberOfProcessors, NumberOfEnabledProcessors); +} + +/** + Get detailed information on the requested logical processor. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of the processor. + @param[out] ProcessorInfoBuffer Pointer to the buffer where the processor information is stored. + + @retval EFI_SUCCESS Get information on the requested logical processor successfully + @retval Others Get information on the requested logical processor unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestGetProcessorInfo ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + return MpServices.Ppi->GetProcessorInfo (MpServices.Ppi, ProcessorNumber, ProcessorInfoBuffer); +} + +/** + Execute a caller provided function on all enabled APs. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled APs of the system. + @param[in] SingleThread If TRUE, then all the enabled APs execute the function specified by Procedure + one by one, in ascending order of processor handle number. + If FALSE, then all the enabled APs execute the function specified by Procedure + simultaneously. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all APs. + + @retval EFI_SUCCESS Execute a caller provided function on all enabled APs successfully + @retval Others Execute a caller provided function on all enabled APs unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupAllAPs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ) +{ + return MpServices.Ppi->StartupAllAPs (MpServices.Ppi, Procedure, SingleThread, TimeoutInMicroSeconds, ProcedureArgument); +} + +/** + Caller gets one enabled AP to execute a caller-provided function. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled APs of the system. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all APs. + + + @retval EFI_SUCCESS Caller gets one enabled AP to execute a caller-provided function successfully + @retval Others Caller gets one enabled AP to execute a caller-provided function unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupThisAP ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ) +{ + return MpServices.Ppi->StartupThisAP (MpServices.Ppi, Procedure, ProcessorNumber, TimeoutInMicroSeconds, ProcedureArgument); +} + +/** + Switch the requested AP to be the BSP from that point onward. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of AP that is to become the new BSP. + @param[in] EnableOldBSP If TRUE, the old BSP will be listed as an enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS Switch the requested AP to be the BSP successfully + @retval Others Switch the requested AP to be the BSP unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestSwitchBSP ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + return MpServices.Ppi->SwitchBSP (MpServices.Ppi, ProcessorNumber, EnableOldBSP); +} + +/** + Caller enables or disables an AP from this point onward. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] EnableAP Specifies the new state for the processor for enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that specifies the new health status of the AP. + + @retval EFI_SUCCESS Caller enables or disables an AP successfully. + @retval Others Caller enables or disables an AP unsuccessfully. +**/ +EFI_STATUS +MpServicesUnitTestEnableDisableAP ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag + ) +{ + return MpServices.Ppi->EnableDisableAP (MpServices.Ppi, ProcessorNumber, EnableAP, HealthFlag); +} + +/** + Get the handle number for the calling processor. + + @param[in] MpServices MP_SERVICES structure. + @param[out] ProcessorNumber The handle number for the calling processor. + + @retval EFI_SUCCESS Get the handle number for the calling processor successfully. + @retval Others Get the handle number for the calling processor unsuccessfully. +**/ +EFI_STATUS +MpServicesUnitTestWhoAmI ( + IN MP_SERVICES MpServices, + OUT UINTN *ProcessorNumber + ) +{ + return MpServices.Ppi->WhoAmI (MpServices.Ppi, ProcessorNumber); +} + +/** + Execute a caller provided function on all enabled CPUs. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled CPUs of the system. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all enabled CPUs. + + @retval EFI_SUCCESS Execute a caller provided function on all enabled CPUs successfully + @retval Others Execute a caller provided function on all enabled CPUs unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupAllCPUs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ) +{ + return MpServices.Ppi->StartupAllCPUs (MpServices.Ppi, Procedure, TimeoutInMicroSeconds, ProcedureArgument); +} + +/** + Infinite loop procedure to be run on specified AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +ApInfiniteLoopProcedure ( + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + volatile BOOLEAN InfiniteLoop; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + Status = MpServicesUnitTestWhoAmI (LocalContext->MpServices, &ProcessorNumber); + ASSERT_EFI_ERROR (Status); + + if (ProcessorNumber == LocalContext->BspNumber) { + InfiniteLoop = FALSE; + } else { + InfiniteLoop = TRUE; + } + + while (InfiniteLoop) { + } +} + +/** + Procedure to run MP service StartupAllCPUs on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceStartupAllCPUsOnAp ( + IN OUT VOID *Buffer + ) +{ + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestStartupAllCPUs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + 0, + NULL + ); +} + +/** + Unit test of PEI MP service StartupAllCPU. + All CPUs should execute the Procedure. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllCPUs1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ProcessorIndex; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + SetMem (LocalContext->CommonBuffer, LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer), 0xFF); + Status = MpServicesUnitTestStartupAllCPUs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)StoreCpuNumbers, + 0, + (VOID *)LocalContext + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + for (ProcessorIndex = 0; ProcessorIndex < LocalContext->NumberOfProcessors; ProcessorIndex++) { + UT_ASSERT_TRUE (LocalContext->CommonBuffer[ProcessorIndex] == ProcessorIndex); + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of PEI MP service StartupAllCPU. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllCPUs2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceStartupAllCPUsOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of PEI MP service StartupAllCPU. + When called with all CPUs timeout, the return status should be EFI_TIMEOUT. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllCPUs3 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + Status = MpServicesUnitTestStartupAllCPUs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)ApInfiniteLoopProcedure, + RUN_PROCEDURE_TIMEOUT_VALUE, + (VOID *)LocalContext + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_TIMEOUT); + + return UNIT_TEST_PASSED; +} + +/** + Create test suite and unit tests only for EdkiiPeiMpServices2Ppi. + + @param[in] Framework A pointer to the framework that is being persisted. + @param[in] Context A pointer to the private data buffer. + + @retval EFI_SUCCESS Create test suite and unit tests successfully. + @retval Others Create test suite and unit tests unsuccessfully. +**/ +EFI_STATUS +AddTestCaseOnlyForEdkiiPeiMpServices2Ppi ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN MP_SERVICE_UT_CONTEXT *Context + ) +{ + EFI_STATUS Status; + UNIT_TEST_SUITE_HANDLE MpServiceStartupAllCPUsTestSuite; + + MpServiceStartupAllCPUsTestSuite = NULL; + + // + // Test StartupAllCPUs function + // + Status = CreateUnitTestSuite (&MpServiceStartupAllCPUsTestSuite, Framework, "Execute a caller provided function on all enabled CPUs", "MpServices.StartupAllCPUs", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceStartupAllCPUs Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceStartupAllCPUsTestSuite, "Test StartupAllCPUs 1", "TestStartupAllCPUs1", TestStartupAllCPUs1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupAllCPUsTestSuite, "Test StartupAllCPUs 2", "TestStartupAllCPUs2", TestStartupAllCPUs2, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupAllCPUsTestSuite, "Test StartupAllCPUs 3", "TestStartupAllCPUs3", TestStartupAllCPUs3, InitUTContext, CheckUTContext, Context); + + return EFI_SUCCESS; +} + +/** + Standard PEIM entry point for unit test execution from PEI. + Initialize the unit test framework, suite, and unit tests for the EdkiiPeiMpServices2Ppi and run the unit test. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Pointer to PEI Services table. + +**/ +EFI_STATUS +EFIAPI +PeiEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + MP_SERVICE_UT_CONTEXT Context; + + Framework = NULL; + Context.MpServices.Ppi = NULL; + Context.CommonBuffer = NULL; + Context.DisabledApNumber = NULL; + + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION)); + + // + // Start setting up the test framework for running the tests. + // + Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status)); + goto EXIT; + } + + // + // Create test suite and unit tests only for EdkiiPeiMpServices2Ppi. + // + Status = AddTestCaseOnlyForEdkiiPeiMpServices2Ppi (Framework, &Context); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in AddTestCaseOnlyForEdkiiPeiMpServices2Ppi. Status = %r\n", Status)); + goto EXIT; + } + + // + // Create test suite and unit tests for both EdkiiPeiMpServices2Ppi and EfiMpServiceProtocol. + // + Status = AddCommonTestCase (Framework, &Context); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in AddCommonTestCase. Status = %r\n", Status)); + goto EXIT; + } + + // + // Execute the tests. + // + Status = RunAllTestSuites (Framework); + +EXIT: + if (Framework != NULL) { + FreeUnitTestFramework (Framework); + } + + return Status; +} diff --git a/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf new file mode 100644 index 0000000000..1389092c06 --- /dev/null +++ b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf @@ -0,0 +1,46 @@ +## @file +# DXE driver that unit tests the EfiMpServiceProtocol +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EfiMpServiceProtocolDxeUnitTest + FILE_GUID = F1E468E2-A32D-4574-895D-6D82B27B08BC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + EfiMpServicesUnitTestCommom.c + EfiMpServicesUnitTestCommom.h + EfiMpServiceProtocolUnitTest.c + +[Packages] + MdePkg/MdePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UnitTestPersistenceLib + UnitTestLib + +[Protocols] + gEfiMpServiceProtocolGuid ## CONSUMES + +[Depex] + gEfiMpServiceProtocolGuid diff --git a/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c new file mode 100644 index 0000000000..57f8ba3c06 --- /dev/null +++ b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c @@ -0,0 +1,244 @@ +/** @file + PEI Module to test EfiMpServiceProtocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include "EfiMpServicesUnitTestCommom.h" + +#define UNIT_TEST_NAME "EfiMpServiceProtocol Unit Test" +#define UNIT_TEST_VERSION "0.1" + +/** + Get EFI_MP_SERVICES_PROTOCOL pointer. + + @param[out] MpServices Pointer to the buffer where EFI_MP_SERVICES_PROTOCOL is stored + + @retval EFI_SUCCESS EFI_MP_SERVICES_PROTOCOL interface is returned + @retval EFI_NOT_FOUND EFI_MP_SERVICES_PROTOCOL interface is not found +**/ +EFI_STATUS +MpServicesUnitTestGetMpServices ( + OUT MP_SERVICES *MpServices + ) +{ + return gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices->Protocol); +} + +/** + Retrieve the number of logical processor in the platform and the number of those logical processors that + are enabled on this boot. + + @param[in] MpServices MP_SERVICES structure. + @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system, including + the BSP and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of processors in the system that are enabled. + + @retval EFI_SUCCESS Retrieve the number of logical processor successfully + @retval Others Retrieve the number of logical processor unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestGetNumberOfProcessors ( + IN MP_SERVICES MpServices, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + return MpServices.Protocol->GetNumberOfProcessors (MpServices.Protocol, NumberOfProcessors, NumberOfEnabledProcessors); +} + +/** + Get detailed information on the requested logical processor. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of the processor. + @param[out] ProcessorInfoBuffer Pointer to the buffer where the processor information is stored. + + @retval EFI_SUCCESS Get information on the requested logical processor successfully + @retval Others Get information on the requested logical processor unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestGetProcessorInfo ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + return MpServices.Protocol->GetProcessorInfo (MpServices.Protocol, ProcessorNumber, ProcessorInfoBuffer); +} + +/** + Execute a caller provided function on all enabled APs. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled APs of the system. + @param[in] SingleThread If TRUE, then all the enabled APs execute the function specified by Procedure + one by one, in ascending order of processor handle number. + If FALSE, then all the enabled APs execute the function specified by Procedure + simultaneously. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all APs. + + @retval EFI_SUCCESS Execute a caller provided function on all enabled APs successfully + @retval Others Execute a caller provided function on all enabled APs unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupAllAPs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ) +{ + return MpServices.Protocol->StartupAllAPs (MpServices.Protocol, Procedure, SingleThread, NULL, TimeoutInMicroSeconds, ProcedureArgument, NULL); +} + +/** + Caller gets one enabled AP to execute a caller-provided function. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled APs of the system. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all APs. + + + @retval EFI_SUCCESS Caller gets one enabled AP to execute a caller-provided function successfully + @retval Others Caller gets one enabled AP to execute a caller-provided function unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupThisAP ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ) +{ + return MpServices.Protocol->StartupThisAP (MpServices.Protocol, Procedure, ProcessorNumber, NULL, TimeoutInMicroSeconds, ProcedureArgument, NULL); +} + +/** + Switch the requested AP to be the BSP from that point onward. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of AP that is to become the new BSP. + @param[in] EnableOldBSP If TRUE, the old BSP will be listed as an enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS Switch the requested AP to be the BSP successfully + @retval Others Switch the requested AP to be the BSP unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestSwitchBSP ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + return MpServices.Protocol->SwitchBSP (MpServices.Protocol, ProcessorNumber, EnableOldBSP); +} + +/** + Caller enables or disables an AP from this point onward. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] EnableAP Specifies the new state for the processor for enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that specifies the new health status of the AP. + + @retval EFI_SUCCESS Caller enables or disables an AP successfully. + @retval Others Caller enables or disables an AP unsuccessfully. +**/ +EFI_STATUS +MpServicesUnitTestEnableDisableAP ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag + ) +{ + return MpServices.Protocol->EnableDisableAP (MpServices.Protocol, ProcessorNumber, EnableAP, HealthFlag); +} + +/** + Get the handle number for the calling processor. + + @param[in] MpServices MP_SERVICES structure. + @param[out] ProcessorNumber The handle number for the calling processor. + + @retval EFI_SUCCESS Get the handle number for the calling processor successfully. + @retval Others Get the handle number for the calling processor unsuccessfully. +**/ +EFI_STATUS +MpServicesUnitTestWhoAmI ( + IN MP_SERVICES MpServices, + OUT UINTN *ProcessorNumber + ) +{ + return MpServices.Protocol->WhoAmI (MpServices.Protocol, ProcessorNumber); +} + +/** + Standard DXE driver or UEFI application entry point for unit test execution from DXE or UEFI Shell. + Initialize the unit test framework, suite, and unit tests for the EfiMpServiceProtocol and run the unit test. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + +**/ +EFI_STATUS +EFIAPI +DxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UNIT_TEST_FRAMEWORK_HANDLE Framework; + MP_SERVICE_UT_CONTEXT Context; + + Framework = NULL; + Context.MpServices.Ppi = NULL; + Context.CommonBuffer = NULL; + Context.DisabledApNumber = NULL; + + DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_NAME, UNIT_TEST_VERSION)); + + // + // Start setting up the test framework for running the tests. + // + Status = InitUnitTestFramework (&Framework, UNIT_TEST_NAME, gEfiCallerBaseName, UNIT_TEST_VERSION); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status)); + goto EXIT; + } + + // + // Create test suite and unit tests for both EdkiiPeiMpServices2Ppi and EfiMpServiceProtocol. + // + Status = AddCommonTestCase (Framework, &Context); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in AddCommonTestCase. Status = %r\n", Status)); + goto EXIT; + } + + // + // Execute the tests. + // + Status = RunAllTestSuites (Framework); + +EXIT: + if (Framework != NULL) { + FreeUnitTestFramework (Framework); + } + + return Status; +} diff --git a/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c new file mode 100644 index 0000000000..ff79c5e8d4 --- /dev/null +++ b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c @@ -0,0 +1,1776 @@ +/** @file + Common code to test EdkiiPeiMpServices2Ppi and EfiMpServiceProtocol. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "EfiMpServicesUnitTestCommom.h" + +/** + Prep routine for Unit test function. + To save the ProcessorNumber of disabled AP and temporarily enable it. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED Prep routine runs successful. + @retval UNIT_TEST_ERROR_TEST_FAILED Prep routine runs unsuccessful. +**/ +UNIT_TEST_STATUS +EFIAPI +InitUTContext ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + UINTN NumberOfDisabledAPs; + UINTN IndexOfDisabledAPs; + UINTN BspNumber; + UINTN ProcessorNumber; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + if (LocalContext->MpServices.Ppi != NULL) { + return UNIT_TEST_PASSED; + } + + Status = MpServicesUnitTestGetMpServices (&LocalContext->MpServices); + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestWhoAmI (LocalContext->MpServices, &BspNumber); + UT_ASSERT_NOT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, "%a: BspNumber = 0x%x\n", __FUNCTION__, BspNumber)); + + Status = MpServicesUnitTestGetNumberOfProcessors ( + LocalContext->MpServices, + &NumberOfProcessors, + &NumberOfEnabledProcessors + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + DEBUG (( + DEBUG_INFO, + "%a: NumberOfProcessors = 0x%x, NumberOfEnabledProcessors = 0x%x\n", + __FUNCTION__, + NumberOfProcessors, + NumberOfEnabledProcessors + )); + + LocalContext->BspNumber = BspNumber; + LocalContext->NumberOfProcessors = NumberOfProcessors; + LocalContext->NumberOfEnabledProcessors = NumberOfEnabledProcessors; + + LocalContext->CommonBuffer = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*LocalContext->CommonBuffer))); + UT_ASSERT_NOT_NULL (LocalContext->CommonBuffer); + + NumberOfDisabledAPs = NumberOfProcessors - NumberOfEnabledProcessors; + if ((NumberOfDisabledAPs > 0) && (LocalContext->DisabledApNumber == NULL)) { + LocalContext->DisabledApNumber = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfDisabledAPs * sizeof (*LocalContext->DisabledApNumber))); + UT_ASSERT_NOT_NULL (LocalContext->DisabledApNumber); + ZeroMem (LocalContext->DisabledApNumber, NumberOfDisabledAPs * sizeof (*LocalContext->DisabledApNumber)); + + for (ProcessorNumber = 0, IndexOfDisabledAPs = 0; ProcessorNumber < LocalContext->NumberOfProcessors; ProcessorNumber++) { + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + ProcessorNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + if (!(ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT)) { + // + // Save ProcessorNumber of disabled AP. + // + LocalContext->DisabledApNumber[IndexOfDisabledAPs] = ProcessorNumber; + IndexOfDisabledAPs++; + + DEBUG ((DEBUG_INFO, "%a: AP(0x%x) is disabled and temporarily enable it.\n", __FUNCTION__, ProcessorNumber)); + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ProcessorNumber, + TRUE, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + UT_ASSERT_TRUE (IndexOfDisabledAPs == NumberOfDisabledAPs); + } + + return UNIT_TEST_PASSED; +} + +/** + Cleanup routine for Unit test function. + If any processor is disabled unexpectedly then reenable it. + + @param[in] Context Context pointer for this test. +**/ +VOID +EFIAPI +CheckUTContext ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + UINTN BspNumber; + UINTN ProcessorNumber; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + ASSERT (LocalContext->MpServices.Ppi != NULL); + + Status = MpServicesUnitTestWhoAmI (LocalContext->MpServices, &BspNumber); + ASSERT_EFI_ERROR (Status); + + if (BspNumber != LocalContext->BspNumber) { + LocalContext->BspNumber = BspNumber; + DEBUG ((DEBUG_INFO, "%a: New BspNumber = 0x%x\n", __FUNCTION__, BspNumber)); + } + + ASSERT (BspNumber == LocalContext->BspNumber); + + Status = MpServicesUnitTestGetNumberOfProcessors ( + LocalContext->MpServices, + &NumberOfProcessors, + &NumberOfEnabledProcessors + ); + ASSERT_EFI_ERROR (Status); + + if (NumberOfProcessors != LocalContext->NumberOfProcessors) { + LocalContext->NumberOfProcessors = NumberOfProcessors; + DEBUG ((DEBUG_INFO, "%a: New NumberOfProcessors = 0x%x\n", __FUNCTION__, NumberOfProcessors)); + } + + if (NumberOfEnabledProcessors != LocalContext->NumberOfProcessors) { + DEBUG ((DEBUG_INFO, "%a: New NumberOfEnabledProcessors = 0x%x\n", __FUNCTION__, NumberOfEnabledProcessors)); + + for (ProcessorNumber = 0; ProcessorNumber < LocalContext->NumberOfProcessors; ProcessorNumber++) { + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + ProcessorNumber, + &ProcessorInfoBuffer + ); + ASSERT_EFI_ERROR (Status); + + if (!(ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT)) { + DEBUG ((DEBUG_INFO, "%a: AP(0x%x) is disabled unexpectedly and reenable it.\n", __FUNCTION__, ProcessorNumber)); + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ProcessorNumber, + TRUE, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + } + } +} + +/** + Cleanup routine for Unit test function. + It will be called by the last "AddTestCase" to restore AP state and free pointer. + + @param[in] Context Context pointer for this test. +**/ +VOID +EFIAPI +FreeUTContext ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NumberOfDisabledAPs; + UINTN IndexOfDisabledAPs; + MP_SERVICE_UT_CONTEXT *LocalContext; + + CheckUTContext (Context); + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + ASSERT (LocalContext->MpServices.Ppi != NULL); + + if (LocalContext->DisabledApNumber != NULL) { + NumberOfDisabledAPs = LocalContext->NumberOfProcessors - LocalContext->NumberOfEnabledProcessors; + for (IndexOfDisabledAPs = 0; IndexOfDisabledAPs < NumberOfDisabledAPs; IndexOfDisabledAPs++) { + DEBUG (( + DEBUG_INFO, + "%a: Disable AP(0x%x) to restore its state.\n", + __FUNCTION__, + LocalContext->DisabledApNumber[IndexOfDisabledAPs] + )); + + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + LocalContext->DisabledApNumber[IndexOfDisabledAPs], + FALSE, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + + FreePages (LocalContext->DisabledApNumber, EFI_SIZE_TO_PAGES (NumberOfDisabledAPs * sizeof (*LocalContext->DisabledApNumber))); + } + + if (LocalContext->CommonBuffer != NULL) { + FreePages (LocalContext->CommonBuffer, EFI_SIZE_TO_PAGES (LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer))); + } +} + +/** + Produce to store ProcessorNumber in the corresponding location of CommonBuffer. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +StoreCpuNumbers ( + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + Status = MpServicesUnitTestWhoAmI (LocalContext->MpServices, &ProcessorNumber); + ASSERT_EFI_ERROR (Status); + + // + // The layout of CommonBuffer (E.g. BspNumber = 2 and NumberOfProcessors = 6) + // Index 00 01 02 03 04 05 + // Value 00 01 02 03 04 05 + // + if (ProcessorNumber < LocalContext->NumberOfProcessors) { + LocalContext->CommonBuffer[ProcessorNumber] = ProcessorNumber; + } +} + +/** + Produce to store the ProcessorNumber of AP execution order in CommonBuffer. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +StoreAPsExecutionOrder ( + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + UINTN *ApCounter; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + Status = MpServicesUnitTestWhoAmI (LocalContext->MpServices, &ProcessorNumber); + ASSERT_EFI_ERROR (Status); + + // + // The layout of CommonBuffer (E.g. BspNumber = 2 and NumberOfProcessors = 6) + // Index 00 01 02 03 04 05 + // Value 00 01 03 04 05 ApCounter(5) + // + ApCounter = &(LocalContext->CommonBuffer[LocalContext->NumberOfProcessors - 1]); + LocalContext->CommonBuffer[*ApCounter] = ProcessorNumber; + (*ApCounter)++; +} + +/** + Infinite loop procedure to be run on specified CPU. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +InfiniteLoopProcedure ( + IN OUT VOID *Buffer + ) +{ + volatile BOOLEAN InfiniteLoop; + + InfiniteLoop = TRUE; + + while (InfiniteLoop) { + } +} + +/** + Empty procedure to be run on specified CPU. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +EmptyProcedure ( + IN OUT VOID *Buffer + ) +{ +} + +/** + Procedure to run MP service GetNumberOfProcessors on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceGetNumberOfProcessorsOnAp ( + IN OUT VOID *Buffer + ) +{ + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestGetNumberOfProcessors ( + LocalContext->MpServices, + &NumberOfProcessors, + &NumberOfEnabledProcessors + ); +} + +/** + Procedure to run MP service GetProcessorInfo on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceGetProcessorInfoOnAp ( + IN OUT VOID *Buffer + ) +{ + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + LocalContext->ApNumber, + &ProcessorInfoBuffer + ); +} + +/** + Procedure to run MP service EnableDisableAP on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceEnableDisableAPOnAp ( + IN OUT VOID *Buffer + ) +{ + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + LocalContext->ApNumber, + FALSE, + NULL + ); +} + +/** + Procedure to run MP service StartupThisAP on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceStartupThisAPOnAp ( + IN OUT VOID *Buffer + ) +{ + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + LocalContext->ApNumber, + 0, + NULL + ); +} + +/** + Procedure to run MP service StartupAllAPs on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceStartupAllAPsOnAp ( + IN OUT VOID *Buffer + ) +{ + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + FALSE, + 0, + NULL + ); +} + +/** + Procedure to run MP service SwitchBSP on AP. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +RunMpServiceSwitchBSPOnAp ( + IN OUT VOID *Buffer + ) +{ + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Buffer; + + LocalContext->ApProcedureReturnStatus = MpServicesUnitTestSwitchBSP ( + LocalContext->MpServices, + LocalContext->ApNumber, + TRUE + ); +} + +/** + Unit test of MP service WhoAmI. + The range of ProcessorNumber should be from 0 to NumberOfCPUs minus 1. + The ProcessorNumbers of all CPUs are unique. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestWhoAmI1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + UINTN ProcessorIndex; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + Status = MpServicesUnitTestWhoAmI ( + LocalContext->MpServices, + &ProcessorNumber + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (ProcessorNumber < LocalContext->NumberOfProcessors); + + SetMem (LocalContext->CommonBuffer, LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer), 0xFF); + LocalContext->CommonBuffer[ProcessorNumber] = ProcessorNumber; + + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)StoreCpuNumbers, + FALSE, + 0, + (VOID *)LocalContext + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + // + // The layout of CommonBuffer (E.g. BspNumber = 2 and NumberOfProcessors = 6) + // Index 00 01 02 03 04 05 + // Value 00 01 02 03 04 05 + // + for (ProcessorIndex = 0; ProcessorIndex < LocalContext->NumberOfProcessors; ProcessorIndex++) { + UT_ASSERT_TRUE (LocalContext->CommonBuffer[ProcessorIndex] == ProcessorIndex); + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service GetNumberOfProcessors. + NumberOfProcessors should be greater that 0 and not less than NumberOfEnabledProcessors. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetNumberOfProcessors1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + Status = MpServicesUnitTestGetNumberOfProcessors ( + LocalContext->MpServices, + &NumberOfProcessors, + &NumberOfEnabledProcessors + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (NumberOfProcessors > 0 && NumberOfProcessors >= NumberOfEnabledProcessors); + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service GetNumberOfProcessors. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetNumberOfProcessors2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceGetNumberOfProcessorsOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service GetNumberOfProcessors. + Call EnableDisableAP() to change the number of enabled AP. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetNumberOfProcessors3 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + FALSE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestGetNumberOfProcessors ( + LocalContext->MpServices, + &NumberOfProcessors, + &NumberOfEnabledProcessors + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (NumberOfProcessors == LocalContext->NumberOfProcessors); + + if (ApNumber < LocalContext->BspNumber) { + UT_ASSERT_TRUE (NumberOfEnabledProcessors == LocalContext->NumberOfProcessors - (ApNumber + 1)); + } else { + UT_ASSERT_TRUE (NumberOfEnabledProcessors == LocalContext->NumberOfProcessors - ApNumber); + } + } + } + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + TRUE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestGetNumberOfProcessors ( + LocalContext->MpServices, + &NumberOfProcessors, + &NumberOfEnabledProcessors + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE (NumberOfProcessors == LocalContext->NumberOfProcessors); + + if (ApNumber < LocalContext->BspNumber) { + UT_ASSERT_TRUE (NumberOfEnabledProcessors == ApNumber + 2); + } else { + UT_ASSERT_TRUE (NumberOfEnabledProcessors == ApNumber + 1); + } + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service GetProcessorInfo. + When all the parameters are valid, all reserved bits of StatusFlag in ProcessorInfoBuffer should be set to zero. + When all the parameters are valid, the StatusFlag should not have an invalid value (The BSP can never be in the disabled state.). + When called with nonexistent processor handle, the return status should be EFI_NOT_FOUND. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetProcessorInfo1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ProcessorNumber; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ProcessorNumber = 0; ProcessorNumber <= LocalContext->NumberOfProcessors; ProcessorNumber++) { + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + ProcessorNumber, + &ProcessorInfoBuffer + ); + + if (ProcessorNumber == LocalContext->NumberOfProcessors) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_NOT_FOUND); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE ((ProcessorInfoBuffer.StatusFlag & (UINT32) ~(PROCESSOR_AS_BSP_BIT|PROCESSOR_ENABLED_BIT|PROCESSOR_HEALTH_STATUS_BIT)) == 0); + + if (ProcessorNumber == LocalContext->BspNumber) { + UT_ASSERT_TRUE ((ProcessorInfoBuffer.StatusFlag & PROCESSOR_AS_BSP_BIT) && (ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT)); + } else { + UT_ASSERT_TRUE (!(ProcessorInfoBuffer.StatusFlag & PROCESSOR_AS_BSP_BIT)); + } + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service GetProcessorInfo. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetProcessorInfo2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceGetProcessorInfoOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service EnableDisableAP. + When called with BSP number, the return status should be EFI_INVALID_PARAMETER. + When called with a nonexistent processor handle, the return status should be EFI_NOT_FOUND. + The AP should be really Enable/Disabled. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestEnableDisableAP1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber <= LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + FALSE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else if (ApNumber == LocalContext->NumberOfProcessors) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_NOT_FOUND); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + ApNumber, + 0, + NULL + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + TRUE, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + ApNumber, + 0, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service EnableDisableAP. + When run this procedure on AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestEnableDisableAP2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceEnableDisableAPOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service EnableDisableAP. + When run this procedure on AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestEnableDisableAP3 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + UINT32 OldHealthFlag; + UINT32 NewHealthFlag; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + ApNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + OldHealthFlag = ProcessorInfoBuffer.StatusFlag & PROCESSOR_HEALTH_STATUS_BIT; + NewHealthFlag = OldHealthFlag ^ PROCESSOR_HEALTH_STATUS_BIT; + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + TRUE, + &NewHealthFlag + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + ApNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE ((ProcessorInfoBuffer.StatusFlag & PROCESSOR_HEALTH_STATUS_BIT) == NewHealthFlag); + + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + TRUE, + &OldHealthFlag + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupThisAP. + When called to startup a BSP, the return status should be EFI_INVALID_PARAMETER. + When called with a nonexistent processor handle, the return status should be EFI_NOT_FOUND. + The requested AP should execute the Procedure when called by StartupThisAP. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + UINTN ProcessorIndex; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber <= LocalContext->NumberOfProcessors; ApNumber++) { + SetMem (LocalContext->CommonBuffer, LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer), 0xFF); + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)StoreCpuNumbers, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else if (ApNumber == LocalContext->NumberOfProcessors) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_NOT_FOUND); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + for (ProcessorIndex = 0; ProcessorIndex < LocalContext->NumberOfProcessors; ProcessorIndex++) { + UT_ASSERT_TRUE ( + ((ProcessorIndex == ApNumber) && (LocalContext->CommonBuffer[ProcessorIndex] == ProcessorIndex)) || + ((ProcessorIndex != ApNumber) && (LocalContext->CommonBuffer[ProcessorIndex] == (UINTN) ~0)) + ); + } + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupThisAP. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceStartupThisAPOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupThisAP. + When timeout expired before the requested AP has finished, the return status should be EFI_TIMEOUT. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP3 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)InfiniteLoopProcedure, + ApNumber, + RUN_PROCEDURE_TIMEOUT_VALUE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_STATUS_EQUAL (Status, EFI_TIMEOUT); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupThisAP. + When called with disabled AP, the return status should be EFI_INVALID_PARAMETER. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP4 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + FALSE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + ApNumber, + 0, + NULL + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + TRUE, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + ApNumber, + 0, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupAllAPs. + All APs should execute the Procedure when called by StartupAllAPs. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ProcessorIndex; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + SetMem (LocalContext->CommonBuffer, LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer), 0xFF); + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)StoreCpuNumbers, + FALSE, + 0, + (VOID *)LocalContext + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + for (ProcessorIndex = 0; ProcessorIndex < LocalContext->NumberOfProcessors; ProcessorIndex++) { + UT_ASSERT_TRUE ( + ((ProcessorIndex == LocalContext->BspNumber) && (LocalContext->CommonBuffer[ProcessorIndex] == (UINTN) ~0)) || + ((ProcessorIndex != LocalContext->BspNumber) && (LocalContext->CommonBuffer[ProcessorIndex] == ProcessorIndex)) + ); + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupAllAPs. + When called in single thread, the return status should be EFI_SUCCESS and AP executes in ascending order + of processor handle number. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ProcessorIndex; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + ZeroMem (LocalContext->CommonBuffer, LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer)); + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)StoreAPsExecutionOrder, + TRUE, + 0, + (VOID *)LocalContext + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + // + // The layout of CommonBuffer (E.g. BspNumber = 2 and NumberOfProcessors = 6) + // Index 00 01 02 03 04 05 + // Value 00 01 03 04 05 ApCounter(5) + // + for (ProcessorIndex = 0; ProcessorIndex < LocalContext->NumberOfProcessors - 2; ProcessorIndex++) { + UT_ASSERT_TRUE (LocalContext->CommonBuffer[ProcessorIndex] < LocalContext->CommonBuffer[ProcessorIndex + 1]); + } + + UT_ASSERT_EQUAL (LocalContext->CommonBuffer[LocalContext->NumberOfProcessors - 1], LocalContext->NumberOfProcessors - 1); + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupAllAPs. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs3 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceStartupAllAPsOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupAllAPs. + When called with all AP timeout, the return status should be EFI_TIMEOUT. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs4 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)InfiniteLoopProcedure, + TRUE, + RUN_PROCEDURE_TIMEOUT_VALUE, + NULL + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_TIMEOUT); + + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)InfiniteLoopProcedure, + FALSE, + RUN_PROCEDURE_TIMEOUT_VALUE, + NULL + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_TIMEOUT); + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service StartupAllAPs. + When called with the empty Procedure on all disabled APs, the return status should be EFI_NOT_STARTED. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs5 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + FALSE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)EmptyProcedure, + FALSE, + 0, + NULL + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_NOT_STARTED); + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + ApNumber, + TRUE, + NULL + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service SwitchBSP. + When switch current BSP to be BSP, the return status should be EFI_INVALID_PARAMETER. + When switch nonexistent processor to be BSP, the return status should be EFI_NOT_FOUND. + After switch BSP, all APs(includes new AP) should execute the Procedure when called by StartupAllAP. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP1 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NewBspNumber; + UINTN ProcessorIndex; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (NewBspNumber = 0; NewBspNumber <= LocalContext->NumberOfProcessors; NewBspNumber++) { + Status = MpServicesUnitTestSwitchBSP ( + LocalContext->MpServices, + NewBspNumber, + TRUE + ); + + if (NewBspNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else if (NewBspNumber == LocalContext->NumberOfProcessors) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_NOT_FOUND); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + SetMem (LocalContext->CommonBuffer, LocalContext->NumberOfProcessors * sizeof (*LocalContext->CommonBuffer), 0xFF); + Status = MpServicesUnitTestStartupAllAPs ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)StoreCpuNumbers, + FALSE, + 0, + (VOID *)LocalContext + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + for (ProcessorIndex = 0; ProcessorIndex < LocalContext->NumberOfProcessors; ProcessorIndex++) { + UT_ASSERT_TRUE ( + ((ProcessorIndex == NewBspNumber) && (LocalContext->CommonBuffer[ProcessorIndex] == (UINTN) ~0)) || + ((ProcessorIndex != NewBspNumber) && (LocalContext->CommonBuffer[ProcessorIndex] == ProcessorIndex)) + ); + } + + Status = MpServicesUnitTestSwitchBSP ( + LocalContext->MpServices, + LocalContext->BspNumber, + TRUE + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service SwitchBSP. + When run this procedure on AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP2 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN ApNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (ApNumber = 0; ApNumber < LocalContext->NumberOfProcessors; ApNumber++) { + LocalContext->ApNumber = ApNumber; + Status = MpServicesUnitTestStartupThisAP ( + LocalContext->MpServices, + (EFI_AP_PROCEDURE)RunMpServiceSwitchBSPOnAp, + ApNumber, + 0, + (VOID *)LocalContext + ); + + if (ApNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_STATUS_EQUAL (LocalContext->ApProcedureReturnStatus, EFI_DEVICE_ERROR); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service SwitchBSP. + When switch a disabled AP to be BSP, the return status should be EFI_INVALID_PARAMETER. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP3 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NewBspNumber; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (NewBspNumber = 0; NewBspNumber < LocalContext->NumberOfProcessors; NewBspNumber++) { + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + NewBspNumber, + FALSE, + NULL + ); + + if (NewBspNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestSwitchBSP ( + LocalContext->MpServices, + NewBspNumber, + TRUE + ); + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + NewBspNumber, + TRUE, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Unit test of MP service SwitchBSP. + When SwitchBSP and EnableOldBSP is TRUE, the new BSP should be in the enabled state and the old BSP should + be in the enabled state. + When SwitchBSP and EnableOldBSP is False, the new BSP should be in the enabled state and the old BSP should + be in the disabled state. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP4 ( + IN UNIT_TEST_CONTEXT Context + ) +{ + EFI_STATUS Status; + UINTN NewBspNumber; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + MP_SERVICE_UT_CONTEXT *LocalContext; + + LocalContext = (MP_SERVICE_UT_CONTEXT *)Context; + + for (NewBspNumber = 0; NewBspNumber < LocalContext->NumberOfProcessors; NewBspNumber++) { + Status = MpServicesUnitTestSwitchBSP ( + LocalContext->MpServices, + NewBspNumber, + FALSE + ); + + if (NewBspNumber == LocalContext->BspNumber) { + UT_ASSERT_STATUS_EQUAL (Status, EFI_INVALID_PARAMETER); + } else { + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + NewBspNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE ( + (ProcessorInfoBuffer.StatusFlag & PROCESSOR_AS_BSP_BIT) && + (ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) + ); + + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + LocalContext->BspNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE ( + !(ProcessorInfoBuffer.StatusFlag & PROCESSOR_AS_BSP_BIT) && + !(ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) + ); + + Status = MpServicesUnitTestEnableDisableAP ( + LocalContext->MpServices, + LocalContext->BspNumber, + TRUE, + NULL + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestSwitchBSP ( + LocalContext->MpServices, + LocalContext->BspNumber, + TRUE + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + LocalContext->BspNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE ( + (ProcessorInfoBuffer.StatusFlag & PROCESSOR_AS_BSP_BIT) && + (ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) + ); + + Status = MpServicesUnitTestGetProcessorInfo ( + LocalContext->MpServices, + NewBspNumber, + &ProcessorInfoBuffer + ); + UT_ASSERT_NOT_EFI_ERROR (Status); + UT_ASSERT_TRUE ( + !(ProcessorInfoBuffer.StatusFlag & PROCESSOR_AS_BSP_BIT) && + (ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) + ); + } + } + + return UNIT_TEST_PASSED; +} + +/** + Create test suite and unit tests for both EdkiiPeiMpServices2Ppi and EfiMpServiceProtocol. + + @param[in] Framework A pointer to the framework that is being persisted. + @param[in] Context A pointer to the private data buffer. + + @retval EFI_SUCCESS Create test suite and unit tests successfully. + @retval Others Create test suite and unit tests unsuccessfully. +**/ +EFI_STATUS +AddCommonTestCase ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN MP_SERVICE_UT_CONTEXT *Context + ) +{ + EFI_STATUS Status; + UNIT_TEST_SUITE_HANDLE MpServiceWhoAmITestSuite; + UNIT_TEST_SUITE_HANDLE MpServiceGetNumberOfProcessorsTestSuite; + UNIT_TEST_SUITE_HANDLE MpServiceGetProcessorInfoTestSuite; + UNIT_TEST_SUITE_HANDLE MpServiceEnableDisableAPTestSuite; + UNIT_TEST_SUITE_HANDLE MpServiceStartupThisAPTestSuite; + UNIT_TEST_SUITE_HANDLE MpServiceStartupAllAPsTestSuite; + UNIT_TEST_SUITE_HANDLE MpServiceSwitchBSPTestSuite; + + MpServiceWhoAmITestSuite = NULL; + MpServiceGetNumberOfProcessorsTestSuite = NULL; + MpServiceGetProcessorInfoTestSuite = NULL; + MpServiceEnableDisableAPTestSuite = NULL; + MpServiceStartupThisAPTestSuite = NULL; + MpServiceStartupAllAPsTestSuite = NULL; + MpServiceSwitchBSPTestSuite = NULL; + + // + // Test WhoAmI function + // + Status = CreateUnitTestSuite (&MpServiceWhoAmITestSuite, Framework, "Identify the currently executing processor", "MpServices.WhoAmI", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceWhoAmI Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceWhoAmITestSuite, "Test WhoAmI 1", "TestWhoAmI1", TestWhoAmI1, InitUTContext, CheckUTContext, Context); + + // + // Test GetNumberOfProcessors function + // + Status = CreateUnitTestSuite (&MpServiceGetNumberOfProcessorsTestSuite, Framework, "Retrieve the number of logical processor", "MpServices.GetNumberOfProcessors", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceGetNumberOfProcessors Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceGetNumberOfProcessorsTestSuite, "Test GetNumberOfProcessors 1", "TestGetNumberOfProcessors1", TestGetNumberOfProcessors1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceGetNumberOfProcessorsTestSuite, "Test GetNumberOfProcessors 2", "TestGetNumberOfProcessors2", TestGetNumberOfProcessors2, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceGetNumberOfProcessorsTestSuite, "Test GetNumberOfProcessors 3", "TestGetNumberOfProcessors3", TestGetNumberOfProcessors3, InitUTContext, CheckUTContext, Context); + + // + // Test GetProcessorInfo function + // + Status = CreateUnitTestSuite (&MpServiceGetProcessorInfoTestSuite, Framework, "Get detailed information on the requested logical processor", "MpServices.GetProcessorInfo", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceGetProcessorInfo Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceGetProcessorInfoTestSuite, "Test GetProcessorInfo 1", "TestGetProcessorInfo1", TestGetProcessorInfo1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceGetProcessorInfoTestSuite, "Test GetProcessorInfo 2", "TestGetProcessorInfo2", TestGetProcessorInfo2, InitUTContext, CheckUTContext, Context); + + // + // Test EnableDisableAP function + // + Status = CreateUnitTestSuite (&MpServiceEnableDisableAPTestSuite, Framework, "Caller enables or disables an AP from this point onward", "MpServices.EnableDisableAP", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceEnableDisableAP Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceEnableDisableAPTestSuite, "Test EnableDisableAP 1", "TestEnableDisableAP1", TestEnableDisableAP1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceEnableDisableAPTestSuite, "Test EnableDisableAP 2", "TestEnableDisableAP2", TestEnableDisableAP2, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceEnableDisableAPTestSuite, "Test EnableDisableAP 3", "TestEnableDisableAP3", TestEnableDisableAP3, InitUTContext, CheckUTContext, Context); + + // + // Test StartupThisAP function + // + Status = CreateUnitTestSuite (&MpServiceStartupThisAPTestSuite, Framework, "Get the requested AP to execute a caller-provided function", "MpServices.StartupThisAP", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceStartupThisAP Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceStartupThisAPTestSuite, "Test StartupThisAP 1", "TestStartupThisAP1", TestStartupThisAP1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupThisAPTestSuite, "Test StartupThisAP 2", "TestStartupThisAP2", TestStartupThisAP2, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupThisAPTestSuite, "Test StartupThisAP 3", "TestStartupThisAP3", TestStartupThisAP3, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupThisAPTestSuite, "Test StartupThisAP 4", "TestStartupThisAP4", TestStartupThisAP4, InitUTContext, CheckUTContext, Context); + + // + // Test StartupAllAPs function + // + Status = CreateUnitTestSuite (&MpServiceStartupAllAPsTestSuite, Framework, "Execute a caller provided function on all enabled APs", "MpServices.StartupAllAPs", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceStartupAllAPs Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceStartupAllAPsTestSuite, "Test StartupAllAPs 1", "TestStartupAllAPs1", TestStartupAllAPs1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupAllAPsTestSuite, "Test StartupAllAPs 2", "TestStartupAllAPs2", TestStartupAllAPs2, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupAllAPsTestSuite, "Test StartupAllAPs 3", "TestStartupAllAPs3", TestStartupAllAPs3, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupAllAPsTestSuite, "Test StartupAllAPs 4", "TestStartupAllAPs4", TestStartupAllAPs4, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceStartupAllAPsTestSuite, "Test StartupAllAPs 5", "TestStartupAllAPs5", TestStartupAllAPs5, InitUTContext, CheckUTContext, Context); + + // + // Test SwitchBSP function + // + Status = CreateUnitTestSuite (&MpServiceSwitchBSPTestSuite, Framework, "Switch the requested AP to be the BSP from that point onward", "MpServices.SwitchBSP", NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MpServiceSwitchBSP Test Suite\n")); + return Status; + } + + AddTestCase (MpServiceSwitchBSPTestSuite, "Test SwitchBSP 1", "TestSwitchBSP1", TestSwitchBSP1, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceSwitchBSPTestSuite, "Test SwitchBSP 2", "TestSwitchBSP2", TestSwitchBSP2, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceSwitchBSPTestSuite, "Test SwitchBSP 3", "TestSwitchBSP3", TestSwitchBSP3, InitUTContext, CheckUTContext, Context); + AddTestCase (MpServiceSwitchBSPTestSuite, "Test SwitchBSP 4", "TestSwitchBSP4", TestSwitchBSP4, InitUTContext, FreeUTContext, Context); + + return EFI_SUCCESS; +} diff --git a/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h new file mode 100644 index 0000000000..abbbd2faba --- /dev/null +++ b/UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h @@ -0,0 +1,627 @@ +/** @file + Common header file for EfiMpServiceProtocolUnitTest DXE driver. + + Copyright (c) 2022, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EFI_MP_SERVICES_UNIT_TEST_COMMOM_H_ +#define EFI_MP_SERVICES_UNIT_TEST_COMMOM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RUN_PROCEDURE_TIMEOUT_VALUE 100000 // microseconds + +typedef union { + EDKII_PEI_MP_SERVICES2_PPI *Ppi; + EFI_MP_SERVICES_PROTOCOL *Protocol; +} MP_SERVICES; + +typedef struct { + MP_SERVICES MpServices; + UINTN BspNumber; + UINTN ApNumber; + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + UINTN *CommonBuffer; + EFI_STATUS ApProcedureReturnStatus; + UINTN *DisabledApNumber; +} MP_SERVICE_UT_CONTEXT; + +/** + Get EFI_MP_SERVICES_PROTOCOL pointer. + + @param[out] MpServices Pointer to the buffer where EFI_MP_SERVICES_PROTOCOL is stored + + @retval EFI_SUCCESS EFI_MP_SERVICES_PROTOCOL interface is returned + @retval EFI_NOT_FOUND EFI_MP_SERVICES_PROTOCOL interface is not found +**/ +EFI_STATUS +MpServicesUnitTestGetMpServices ( + OUT MP_SERVICES *MpServices + ); + +/** + Retrieve the number of logical processor in the platform and the number of those logical processors that + are enabled on this boot. + + @param[in] MpServices MP_SERVICES structure. + @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system, including + the BSP and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of processors in the system that are enabled. + + @retval EFI_SUCCESS Retrieve the number of logical processor successfully + @retval Others Retrieve the number of logical processor unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestGetNumberOfProcessors ( + IN MP_SERVICES MpServices, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ); + +/** + Get detailed information on the requested logical processor. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of the processor. + @param[out] ProcessorInfoBuffer Pointer to the buffer where the processor information is stored. + + @retval EFI_SUCCESS Get information on the requested logical processor successfully + @retval Others Get information on the requested logical processor unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestGetProcessorInfo ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ); + +/** + Execute a caller provided function on all enabled APs. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled APs of the system. + @param[in] SingleThread If TRUE, then all the enabled APs execute the function specified by Procedure + one by one, in ascending order of processor handle number. + If FALSE, then all the enabled APs execute the function specified by Procedure + simultaneously. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all APs. + + @retval EFI_SUCCESS Execute a caller provided function on all enabled APs successfully + @retval Others Execute a caller provided function on all enabled APs unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupAllAPs ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ); + +/** + Caller gets one enabled AP to execute a caller-provided function. + + @param[in] MpServices MP_SERVICES structure. + @param[in] Procedure Pointer to the function to be run on enabled APs of the system. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] TimeoutInMicroSeconds Indicates the time limit in microseconds for APs to return from Procedure, + for blocking mode only. Zero means infinity. + @param[in] ProcedureArgument The parameter passed into Procedure for all APs. + + @retval EFI_SUCCESS Caller gets one enabled AP to execute a caller-provided function successfully + @retval Others Caller gets one enabled AP to execute a caller-provided function unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestStartupThisAP ( + IN MP_SERVICES MpServices, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN UINTN TimeoutInMicroSeconds, + IN VOID *ProcedureArgument + ); + +/** + Switch the requested AP to be the BSP from that point onward. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of AP that is to become the new BSP. + @param[in] EnableOldBSP If TRUE, the old BSP will be listed as an enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS Switch the requested AP to be the BSP successfully + @retval Others Switch the requested AP to be the BSP unsuccessfully +**/ +EFI_STATUS +MpServicesUnitTestSwitchBSP ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ); + +/** + Caller enables or disables an AP from this point onward. + + @param[in] MpServices MP_SERVICES structure. + @param[in] ProcessorNumber The handle number of the AP. + @param[in] EnableAP Specifies the new state for the processor for enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that specifies the new health status of the AP. + + @retval EFI_SUCCESS Caller enables or disables an AP successfully. + @retval Others Caller enables or disables an AP unsuccessfully. +**/ +EFI_STATUS +MpServicesUnitTestEnableDisableAP ( + IN MP_SERVICES MpServices, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag + ); + +/** + Get the handle number for the calling processor. + + @param[in] MpServices MP_SERVICES structure. + @param[out] ProcessorNumber The handle number for the calling processor. + + @retval EFI_SUCCESS Get the handle number for the calling processor successfully. + @retval Others Get the handle number for the calling processor unsuccessfully. +**/ +EFI_STATUS +MpServicesUnitTestWhoAmI ( + IN MP_SERVICES MpServices, + OUT UINTN *ProcessorNumber + ); + +/** + Empty procedure to be run on specified CPU. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +EmptyProcedure ( + IN OUT VOID *Buffer + ); + +/** + Produce to store ProcessorNumber in CommonBuffer and be run on specified CPU. + + @param[in,out] Buffer The pointer to private data buffer. +**/ +VOID +StoreCpuNumbers ( + IN OUT VOID *Buffer + ); + +/** + Prep routine for Unit test function. + To save the ProcessorNumber of disabled AP and temporarily enable it. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED Prep routine runs successful. + @retval UNIT_TEST_ERROR_TEST_FAILED Prep routine runs unsuccessful. +**/ +UNIT_TEST_STATUS +EFIAPI +InitUTContext ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Cleanup routine for Unit test function. + If any processor is disabled unexpectedly then reenable it. + + @param[in] Context Context pointer for this test. +**/ +VOID +EFIAPI +CheckUTContext ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Cleanup routine for Unit test function. + It will be called by the last "AddTestCase" to restore AP state and free pointer. + + @param[in] Context Context pointer for this test. +**/ +VOID +EFIAPI +FreeUTContext ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service WhoAmI. + The range of ProcessorNumber should be from 0 to NumberOfCPUs minus 1. + The ProcessorNumbers of all CPUs are unique. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestWhoAmI1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service GetNumberOfProcessors. + NumberOfProcessors should be greater that 0 and not less than NumberOfEnabledProcessors. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetNumberOfProcessors1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service GetNumberOfProcessors. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetNumberOfProcessors2 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service GetNumberOfProcessors. + Call EnableDisableAP() to change the number of enabled AP. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetNumberOfProcessors3 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service GetProcessorInfo. + When all the parameters are valid, all reserved bits of StatusFlag in ProcessorInfoBuffer should be set to zero. + When all the parameters are valid, the StatusFlag should not have an invalid value (The BSP can never be in the disabled state.). + When called with nonexistent processor handle, the return status should be EFI_NOT_FOUND. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetProcessorInfo1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service GetProcessorInfo. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestGetProcessorInfo2 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service EnableDisableAP. + When called with BSP number, the return status should be EFI_INVALID_PARAMETER. + When called with a nonexistent processor handle, the return status should be EFI_NOT_FOUND. + The AP should be really Enable/Disabled. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestEnableDisableAP1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service EnableDisableAP. + When run this procedure on AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestEnableDisableAP2 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service EnableDisableAP. + When run this procedure on AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestEnableDisableAP3 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupThisAP. + When called to startup a BSP, the return status should be EFI_INVALID_PARAMETER. + When called with a nonexistent processor handle, the return status should be EFI_NOT_FOUND. + The requested AP should execute the Procedure when called by StartupThisAP. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupThisAP. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP2 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupThisAP. + When timeout expired before the requested AP has finished, the return status should be EFI_TIMEOUT. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP3 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupThisAP. + When called with disabled AP, the return status should be EFI_INVALID_PARAMETER. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupThisAP4 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupAllAPs. + All APs should execute the Procedure when called by StartupAllAPs. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupAllAPs. + When called in single thread, the return status should be EFI_SUCCESS and AP executes in ascending order + of processor handle number. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs2 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupAllAPs. + When this service is called from an AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs3 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupAllAPs. + When called with all AP timeout, the return status should be EFI_TIMEOUT. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs4 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service StartupAllAPs. + When called with the empty Procedure on all disabled APs, the return status should be EFI_NOT_STARTED. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestStartupAllAPs5 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service SwitchBSP. + When switch current BSP to be BSP, the return status should be EFI_INVALID_PARAMETER. + When switch nonexistent processor to be BSP, the return status should be EFI_NOT_FOUND. + After switch BSP, all APs(includes new AP) should execute the Procedure when called by StartupAllAP. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP1 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service SwitchBSP. + When run this procedure on AP, the return status should be EFI_DEVICE_ERROR. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP2 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service SwitchBSP. + When switch a disabled AP to be BSP, the return status should be EFI_INVALID_PARAMETER. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP3 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Unit test of MP service SwitchBSP. + When SwitchBSP and EnableOldBSP is TRUE, the new BSP should be in the enabled state and the old BSP should + be in the enabled state. + When SwitchBSP and EnableOldBSP is False, the new BSP should be in the enabled state and the old BSP should + be in the disabled state. + + @param[in] Context Context pointer for this test. + + @retval UNIT_TEST_PASSED The Unit test has completed and the test + case was successful. + @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed. +**/ +UNIT_TEST_STATUS +EFIAPI +TestSwitchBSP4 ( + IN UNIT_TEST_CONTEXT Context + ); + +/** + Create test suite and unit tests for both EdkiiPeiMpServices2Ppi and EfiMpServiceProtocol. + + @param[in] Framework A pointer to the framework that is being persisted. + @param[in] Context A pointer to the private data buffer. + + @retval EFI_SUCCESS Create test suite and unit tests successfully. + @retval Others Create test suite and unit tests unsuccessfully. +**/ +EFI_STATUS +AddCommonTestCase ( + IN UNIT_TEST_FRAMEWORK_HANDLE Framework, + IN MP_SERVICE_UT_CONTEXT *Context + ); + +#endif diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 6d89458ecb..0e1a99ddc0 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -181,6 +181,8 @@ UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf UefiCpuPkg/Library/CpuExceptionHandlerLib/UnitTest/PeiCpuExceptionHandlerLibUnitTest.inf + UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf + UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf [Components.X64] UefiCpuPkg/Library/CpuExceptionHandlerLib/UnitTest/DxeCpuExceptionHandlerLibUnitTest.inf