[edk2-devel] [PATCH v2] UefiCpuPkg/Test: Add unit tests for MP service PPI and Protocol

Jason Lou posted 1 patch 1 year, 6 months ago
Failed in applying to current master (apply log)
UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c      |  477 ++++++
UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c        |  244 +++
UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c         | 1776 ++++++++++++++++++++
UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf |   46 +
UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf   |   46 +
UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h         |  627 +++++++
UefiCpuPkg/UefiCpuPkg.dsc                                                               |    5 +
7 files changed, 3221 insertions(+)
[edk2-devel] [PATCH v2] UefiCpuPkg/Test: Add unit tests for MP service PPI and Protocol
Posted by Jason Lou 1 year, 6 months ago
From: Jason Lou <yun.lou@intel.com>

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>
Cc: 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>
---
 UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c      |  477 ++++++
 UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c        |  244 +++
 UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c         | 1776 ++++++++++++++++++++
 UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf |   46 +
 UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf   |   46 +
 UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h         |  627 +++++++
 UefiCpuPkg/UefiCpuPkg.dsc                                                               |    5 +
 7 files changed, 3221 insertions(+)

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/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/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/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/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
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index f694b3a77c..db5fe654b5 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -63,6 +63,9 @@
   MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
   SmmCpuRendezvousLib|UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf
   CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
+  UnitTestPersistenceLib|UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf
+  UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf
+  UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf
 
 [LibraryClasses.common.SEC]
   PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
@@ -177,6 +180,8 @@
   UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf
   UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf
   UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
+  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf
+  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf
 
 [BuildOptions]
   *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
-- 
2.28.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#94940): https://edk2.groups.io/g/devel/message/94940
Mute This Topic: https://groups.io/mt/94236483/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v2] UefiCpuPkg/Test: Add unit tests for MP service PPI and Protocol
Posted by Ni, Ray 1 year, 6 months ago
Reviewed-by: Ray Ni <ray.ni@intel.com>

> -----Original Message-----
> From: Lou, Yun <yun.lou@intel.com>
> Sent: Monday, October 10, 2022 9:53 PM
> To: devel@edk2.groups.io
> Cc: Lou, Yun <yun.lou@intel.com>; Ni, Ray <ray.ni@intel.com>; Dong, Eric <eric.dong@intel.com>; Laszlo Ersek
> <lersek@redhat.com>; Kumar, Rahul R <rahul.r.kumar@intel.com>
> Subject: [PATCH v2] UefiCpuPkg/Test: Add unit tests for MP service PPI and Protocol
> 
> From: Jason Lou <yun.lou@intel.com>
> 
> 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>
> Cc: 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>
> ---
>  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiUnitTest.c      |  477 ++++++
>  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolUnitTest.c        |  244 +++
>  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.c         | 1776
> ++++++++++++++++++++
>  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf |   46 +
>  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf   |   46 +
>  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServicesUnitTestCommom.h         |  627 +++++++
>  UefiCpuPkg/UefiCpuPkg.dsc                                                               |    5 +
>  7 files changed, 3221 insertions(+)
> 
> 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/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/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/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/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
> 
> diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
> index f694b3a77c..db5fe654b5 100644
> --- a/UefiCpuPkg/UefiCpuPkg.dsc
> +++ b/UefiCpuPkg/UefiCpuPkg.dsc
> @@ -63,6 +63,9 @@
>    MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
> 
>    SmmCpuRendezvousLib|UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf
> 
>    CpuPageTableLib|UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
> 
> +  UnitTestPersistenceLib|UnitTestFrameworkPkg/Library/UnitTestPersistenceLibNull/UnitTestPersistenceLibNull.inf
> 
> +  UnitTestLib|UnitTestFrameworkPkg/Library/UnitTestLib/UnitTestLib.inf
> 
> +  UnitTestResultReportLib|UnitTestFrameworkPkg/Library/UnitTestResultReportLib/UnitTestResultReportLibDebugLib.inf
> 
> 
> 
>  [LibraryClasses.common.SEC]
> 
>    PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
> 
> @@ -177,6 +180,8 @@
>    UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf
> 
>    UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf
> 
>    UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
> 
> +  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf
> 
> +  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf
> 
> 
> 
>  [BuildOptions]
> 
>    *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
> 
> --
> 2.28.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#95195): https://edk2.groups.io/g/devel/message/95195
Mute This Topic: https://groups.io/mt/94236483/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-