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>
		
			
				
	
	
		
			346 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
  Four test cases are created in this Unit Test module.
 | 
						|
  a.Test if exception handler can be registered/unregistered for no error code exception
 | 
						|
    In this test case, only no error code exception is triggered and tested by INTn instruction.
 | 
						|
    The special hanlder for these exception will modify a global variable for check.
 | 
						|
 | 
						|
  b.Test if exception handler can be registered/unregistered for GP and PF.
 | 
						|
    In this test case, GP exception is triggered and tested by setting CR4_RESERVED_BIT to 1.
 | 
						|
    PF exception is triggered and tested by writting to not-present or RO addres.
 | 
						|
    The special hanlder for these exceptions will set a global vartiable for check and adjust Rip to return from fault exception.
 | 
						|
 | 
						|
  c.Test if Cpu Context is consistent before and after exception.
 | 
						|
    In this test case:
 | 
						|
      1. Set Cpu register to mExpectedContextInHandler before exception.
 | 
						|
      2. Trigger exception specified by ExceptionType.
 | 
						|
      3. Store SystemContext in mActualContextInHandler and set SystemContext to mExpectedContextAfterException in handler.
 | 
						|
      4. After return from exception, store Cpu registers in mActualContextAfterException.
 | 
						|
    The expectation is:
 | 
						|
      1. Register values in mActualContextInHandler are the same with register values in mExpectedContextInHandler.
 | 
						|
      2. Register values in mActualContextAfterException are the same with register values mActualContextAfterException.
 | 
						|
 | 
						|
  d.Test if stack overflow can be captured by CpuStackGuard in both Bsp and AP.
 | 
						|
    In this test case, stack overflow is triggered by a funtion which calls itself continuously. This test case triggers stack
 | 
						|
    overflow in both BSP and AP. All AP use same Idt with Bsp. The expectation is:
 | 
						|
      1. PF exception is triggered (leading to a DF if sepereated stack is not prepared for PF) when Rsp <= StackBase + SIZE_4KB
 | 
						|
         since [StackBase, StackBase + SIZE_4KB] is marked as not present in page table when PcdCpuStackGuard is TRUE.
 | 
						|
      2. Stack for PF/DF exception handler in both Bsp and AP is succussfully switched by InitializeSeparateExceptionStacks.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#ifndef CPU_EXCEPTION_HANDLER_TEST_H_
 | 
						|
#define CPU_EXCEPTION_HANDLER_TEST_H_
 | 
						|
 | 
						|
#include <Uefi.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/UnitTestLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/UnitTestHostBaseLib.h>
 | 
						|
#include <Library/CpuExceptionHandlerLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
#include <Library/SerialPortLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Library/CpuPageTableLib.h>
 | 
						|
#include <Guid/MemoryAllocationHob.h>
 | 
						|
#include <Protocol/MpService.h>
 | 
						|
#include <PiPei.h>
 | 
						|
#include <Ppi/MpServices2.h>
 | 
						|
 | 
						|
#define UNIT_TEST_APP_NAME     "Cpu Exception Handler Lib Unit Tests"
 | 
						|
#define UNIT_TEST_APP_VERSION  "1.0"
 | 
						|
 | 
						|
#define  CPU_INTERRUPT_NUM       256
 | 
						|
#define  SPEC_MAX_EXCEPTION_NUM  22
 | 
						|
#define  CR4_RESERVED_BIT        BIT15
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  IA32_DESCRIPTOR    OriginalGdtr;
 | 
						|
  IA32_DESCRIPTOR    OriginalIdtr;
 | 
						|
  UINT16             Tr;
 | 
						|
} CPU_REGISTER_BUFFER;
 | 
						|
 | 
						|
typedef union {
 | 
						|
  EDKII_PEI_MP_SERVICES2_PPI    *Ppi;
 | 
						|
  EFI_MP_SERVICES_PROTOCOL      *Protocol;
 | 
						|
} MP_SERVICES;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  VOID          *Buffer;
 | 
						|
  UINTN         BufferSize;
 | 
						|
  EFI_STATUS    Status;
 | 
						|
} EXCEPTION_STACK_SWITCH_CONTEXT;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  UINT64    Rdi;
 | 
						|
  UINT64    Rsi;
 | 
						|
  UINT64    Rbx;
 | 
						|
  UINT64    Rdx;
 | 
						|
  UINT64    Rcx;
 | 
						|
  UINT64    Rax;
 | 
						|
  UINT64    R8;
 | 
						|
  UINT64    R9;
 | 
						|
  UINT64    R10;
 | 
						|
  UINT64    R11;
 | 
						|
  UINT64    R12;
 | 
						|
  UINT64    R13;
 | 
						|
  UINT64    R14;
 | 
						|
  UINT64    R15;
 | 
						|
} GENERAL_REGISTER;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  UINT32    Edi;
 | 
						|
  UINT32    Esi;
 | 
						|
  UINT32    Ebx;
 | 
						|
  UINT32    Edx;
 | 
						|
  UINT32    Ecx;
 | 
						|
  UINT32    Eax;
 | 
						|
} GENERAL_REGISTER_IA32;
 | 
						|
 | 
						|
extern UINTN               mFaultInstructionLength;
 | 
						|
extern EFI_EXCEPTION_TYPE  mExceptionType;
 | 
						|
extern UINTN               mRspAddress[];
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Trigger no error code exception by INT n instruction.
 | 
						|
 | 
						|
  @param[in]  ExceptionType  No error code exception type.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TriggerINTnException (
 | 
						|
  IN  EFI_EXCEPTION_TYPE  ExceptionType
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Trigger GP exception by setting CR4_RESERVED_BIT to 1.
 | 
						|
 | 
						|
  @param[in]  Cr4ReservedBit  Cr4 reserved bit.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TriggerGPException (
 | 
						|
  UINTN  Cr4ReservedBit
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Trigger PF exception by write to not present or ReadOnly address.
 | 
						|
 | 
						|
  @param[in]  PFAddress  Not present or ReadOnly address in page table.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TriggerPFException (
 | 
						|
  UINTN  PFAddress
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Special handler for fault exception.
 | 
						|
  This handler sets Rip/Eip in SystemContext to the instruction address after the exception instruction.
 | 
						|
 | 
						|
  @param ExceptionType  Exception type.
 | 
						|
  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
AdjustRipForFaultHandler (
 | 
						|
  IN EFI_EXCEPTION_TYPE  ExceptionType,
 | 
						|
  IN EFI_SYSTEM_CONTEXT  SystemContext
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Test consistency of Cpu context. Four steps:
 | 
						|
  1. Set Cpu register to mExpectedContextInHandler before exception.
 | 
						|
  2. Trigger exception specified by ExceptionType.
 | 
						|
  3. Store SystemContext in mActualContextInHandler and set SystemContext to mExpectedContextAfterException in handler.
 | 
						|
  4. After return from exception, store Cpu registers in mActualContextAfterException.
 | 
						|
 | 
						|
  Rcx/Ecx in mExpectedContextInHandler is decided by different exception type runtime since Rcx/Ecx is needed in assembly code.
 | 
						|
  For GP and PF, Rcx/Ecx is set to FaultParameter. For other exception triggered by INTn, Rcx/Ecx is set to ExceptionType.
 | 
						|
 | 
						|
  @param[in] ExceptionType   Exception type.
 | 
						|
  @param[in] FaultParameter  Parameter for GP and PF. OPTIONAL
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
AsmTestConsistencyOfCpuContext (
 | 
						|
  IN  EFI_EXCEPTION_TYPE  ExceptionType,
 | 
						|
  IN  UINTN               FaultParameter   OPTIONAL
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Special handler for ConsistencyOfCpuContext test case. General register in SystemContext
 | 
						|
  is modified to mExpectedContextInHandler in this handler.
 | 
						|
 | 
						|
  @param ExceptionType  Exception type.
 | 
						|
  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
AdjustCpuContextHandler (
 | 
						|
  IN EFI_EXCEPTION_TYPE  ExceptionType,
 | 
						|
  IN EFI_SYSTEM_CONTEXT  SystemContext
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Compare cpu context in ConsistencyOfCpuContext test case.
 | 
						|
  1.Compare mActualContextInHandler with mExpectedContextInHandler.
 | 
						|
  2.Compare mActualContextAfterException with mActualContextAfterException.
 | 
						|
 | 
						|
  @retval  UNIT_TEST_PASSED             The Unit test has completed and it was successful.
 | 
						|
  @retval  UNIT_TEST_ERROR_TEST_FAILED  A test case assertion has failed.
 | 
						|
**/
 | 
						|
UNIT_TEST_STATUS
 | 
						|
CompareCpuContext (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Get EFI_MP_SERVICES_PROTOCOL/EDKII_PEI_MP_SERVICES2_PPI pointer.
 | 
						|
 | 
						|
  @param[out] MpServices    Pointer to the MP_SERVICES buffer
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       EFI_MP_SERVICES_PROTOCOL/PPI interface is returned
 | 
						|
  @retval EFI_NOT_FOUND     EFI_MP_SERVICES_PROTOCOL/PPI interface is not found
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetMpServices (
 | 
						|
  OUT MP_SERVICES  *MpServices
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Create CpuExceptionLibUnitTestSuite and add test case.
 | 
						|
 | 
						|
  @param[in]  FrameworkHandle    Unit test framework.
 | 
						|
 | 
						|
  @return  EFI_SUCCESS           The unit test suite was created.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  There are not enough resources available to
 | 
						|
                                 initialize the unit test suite.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AddCommonTestCase (
 | 
						|
  IN  UNIT_TEST_FRAMEWORK_HANDLE  Framework
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Trigger stack overflow by calling itself continuously.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TriggerStackOverflow (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/**
 | 
						|
  Special handler for CpuStackGuard test case.
 | 
						|
 | 
						|
  @param ExceptionType  Exception type.
 | 
						|
  @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
CpuStackGuardExceptionHandler (
 | 
						|
  IN EFI_EXCEPTION_TYPE  ExceptionType,
 | 
						|
  IN EFI_SYSTEM_CONTEXT  SystemContext
 | 
						|
  );
 | 
						|
 | 
						|
#endif
 |