Explorar el Código

UefiCpuPkg/Test: Add unit tests for MP service PPI and Protocol

The code changes add unit tests based on current UnitTestFramework.
EdkiiPeiMpServices2PpiPeiUnitTest PEI module is used to test
EdkiiPeiMpServices2Ppi and EfiMpServiceProtocolDxeUnitTest DXE driver is
used to test EfiMpServiceProtocol.

Signed-off-by: Jason Lou <yun.lou@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Jason Lou hace 1 año
padre
commit
9d6915ca91

+ 46 - 0
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

+ 477 - 0
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;
+}

+ 46 - 0
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

+ 244 - 0
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;
+}

+ 1776 - 0
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;
+}

+ 627 - 0
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

+ 2 - 0
UefiCpuPkg/UefiCpuPkg.dsc

@@ -181,6 +181,8 @@
   UefiCpuPkg/Library/SmmCpuRendezvousLib/SmmCpuRendezvousLib.inf
   UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableLib.inf
   UefiCpuPkg/Library/CpuExceptionHandlerLib/UnitTest/PeiCpuExceptionHandlerLibUnitTest.inf
+  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EdkiiPeiMpServices2PpiPeiUnitTest.inf
+  UefiCpuPkg/Test/UnitTest/EfiMpServicesPpiProtocol/EfiMpServiceProtocolDxeUnitTest.inf
 
 [Components.X64]
   UefiCpuPkg/Library/CpuExceptionHandlerLib/UnitTest/DxeCpuExceptionHandlerLibUnitTest.inf