The previous change adds unit test for DxeCpuExeptionHandlerLib in 64bit mode. This change create a PEIM to add unit test for PeiCpuExceptionHandlerLib based on previous change.It can run in both 32bit and 64bit modes. Signed-off-by: Dun Tan <dun.tan@intel.com> Cc: Eric Dong <eric.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com>
		
			
				
	
	
		
			205 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Unit tests of the CpuExceptionHandlerLib.
 | 
						|
 | 
						|
  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "CpuExceptionHandlerTest.h"
 | 
						|
#include <Library/PeimEntryPoint.h>
 | 
						|
#include <Library/PeiServicesLib.h>
 | 
						|
#include <Library/PeiServicesTablePointerLib.h>
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize Bsp Idt with a new Idt table and return the IA32_DESCRIPTOR buffer.
 | 
						|
  In PEIM, store original PeiServicePointer before new Idt table.
 | 
						|
 | 
						|
  @return Pointer to the allocated IA32_DESCRIPTOR buffer.
 | 
						|
**/
 | 
						|
VOID *
 | 
						|
InitializeBspIdt (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN            *NewIdtTable;
 | 
						|
  IA32_DESCRIPTOR  *Idtr;
 | 
						|
 | 
						|
  Idtr = AllocateZeroPool (sizeof (IA32_DESCRIPTOR));
 | 
						|
  ASSERT (Idtr != NULL);
 | 
						|
  NewIdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM + sizeof (UINTN));
 | 
						|
  ASSERT (NewIdtTable != NULL);
 | 
						|
  //
 | 
						|
  // Store original PeiServicePointer before new Idt table
 | 
						|
  //
 | 
						|
  *NewIdtTable = (UINTN)GetPeiServicesTablePointer ();
 | 
						|
  NewIdtTable  = (UINTN *)((UINTN)NewIdtTable + sizeof (UINTN));
 | 
						|
 | 
						|
  Idtr->Base  = (UINTN)NewIdtTable;
 | 
						|
  Idtr->Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);
 | 
						|
 | 
						|
  AsmWriteIdtr (Idtr);
 | 
						|
  return Idtr;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
GetMpServices (
 | 
						|
  OUT MP_SERVICES  *MpServices
 | 
						|
  )
 | 
						|
{
 | 
						|
  return PeiServicesLocatePpi (&gEdkiiPeiMpServices2PpiGuid, 0, NULL, (VOID **)&MpServices->Ppi);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Entry point of CpuExceptionHandlerPeiTest PEIM.
 | 
						|
 | 
						|
  @param[in] FileHandle  Handle of the file being invoked.
 | 
						|
  @param[in] PeiServices Describes the list of possible PEI Services.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    The PEIM executed normally.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PeiEntryPoint (
 | 
						|
  IN EFI_PEI_FILE_HANDLE     FileHandle,
 | 
						|
  IN CONST EFI_PEI_SERVICES  **PeiServices
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  UNIT_TEST_FRAMEWORK_HANDLE  Framework;
 | 
						|
 | 
						|
  Framework = NULL;
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
 | 
						|
 | 
						|
  //
 | 
						|
  // Start setting up the test framework for running the tests.
 | 
						|
  //
 | 
						|
  Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
 | 
						|
    goto EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AddCommonTestCase (Framework);
 | 
						|
  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) {
 | 
						|
    FreeUnitTestFramework (Framework);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |