summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/Test
diff options
context:
space:
mode:
authorJason Lou <yun.lou@intel.com>2022-10-10 21:52:42 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2022-10-17 08:03:06 +0000
commit9d6915ca91519271a79bc6190a31f0af89e339b2 (patch)
tree880654d561b1a5de52c5c253a6bb89b9722ad0cd /UefiCpuPkg/Test
parent6f1bb567aaaab8eb26db5188355d5a2587e99369 (diff)
downloadedk2-9d6915ca91519271a79bc6190a31f0af89e339b2.tar.gz
edk2-9d6915ca91519271a79bc6190a31f0af89e339b2.tar.bz2
edk2-9d6915ca91519271a79bc6190a31f0af89e339b2.zip
UefiCpuPkg/Test: Add unit tests for MP service PPI and Protocol
The code changes add unit tests based on current UnitTestFramework. EdkiiPeiMpServices2PpiPeiUnitTest PEI module is used to test EdkiiPeiMpServices2Ppi and EfiMpServiceProtocolDxeUnitTest DXE driver is used to test EfiMpServiceProtocol. Signed-off-by: Jason Lou <yun.lou@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Rahul Kumar <rahul1.kumar@intel.com>
Diffstat (limited to 'UefiCpuPkg/Test')
-rw-r--r--UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf46
-rw-r--r--UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c477
-rw-r--r--UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf46
-rw-r--r--UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c244
-rw-r--r--UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c1776
-rw-r--r--UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h627
6 files changed, 3216 insertions, 0 deletions
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.<BR>
+# 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.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#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.<BR>
+# 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.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#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.<BR>
+
+ 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.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EFI_MP_SERVICES_UNIT_TEST_COMMOM_H_
+#define EFI_MP_SERVICES_UNIT_TEST_COMMOM_H_
+
+#include <PiPei.h>
+#include <Ppi/MpServices2.h>
+#include <Protocol/MpService.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UnitTestLib.h>
+
+#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