UefiCpuPkg: Add Unit tests for PeiCpuExceptionHandlerLib

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>
This commit is contained in:
Tan, Dun
2022-10-17 14:35:40 +08:00
committed by mergify[bot]
parent beabde5875
commit 055eaacc34
5 changed files with 617 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
/** @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"
GENERAL_REGISTER_IA32 mActualContextInHandler;
GENERAL_REGISTER_IA32 mActualContextAfterException;
//
// In TestCpuContextConsistency, Cpu registers will be set to mExpectedContextInHandler/mExpectedContextAfterException.
// Ecx in mExpectedContextInHandler is set runtime since Ecx is needed in assembly code.
// For GP and PF, Ecx is set to FaultParameter. For other exception triggered by INTn, Ecx is set to ExceptionType.
//
GENERAL_REGISTER_IA32 mExpectedContextInHandler = { 1, 2, 3, 4, 5, 0 };
GENERAL_REGISTER_IA32 mExpectedContextAfterException = { 11, 12, 13, 14, 15, 16 };
/**
Special handler for fault exception.
Rip/Eip in SystemContext will be modified to the instruction 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
)
{
mExceptionType = ExceptionType;
SystemContext.SystemContextIa32->Eip += mFaultInstructionLength;
}
/**
Special handler for ConsistencyOfCpuContext test case.
@param ExceptionType Exception type.
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
**/
VOID
EFIAPI
AdjustCpuContextHandler (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
//
// Store SystemContext in exception handler.
//
mActualContextInHandler.Edi = SystemContext.SystemContextIa32->Edi;
mActualContextInHandler.Esi = SystemContext.SystemContextIa32->Esi;
mActualContextInHandler.Ebx = SystemContext.SystemContextIa32->Ebx;
mActualContextInHandler.Edx = SystemContext.SystemContextIa32->Edx;
mActualContextInHandler.Ecx = SystemContext.SystemContextIa32->Ecx;
mActualContextInHandler.Eax = SystemContext.SystemContextIa32->Eax;
//
// Modify cpu context. These registers will be stored in mActualContextAfterException.
// Do not handle Esp and Ebp in SystemContext. CpuExceptionHandlerLib doesn't set Esp and
// Esp register to the value in SystemContext.
//
SystemContext.SystemContextIa32->Edi = mExpectedContextAfterException.Edi;
SystemContext.SystemContextIa32->Esi = mExpectedContextAfterException.Esi;
SystemContext.SystemContextIa32->Ebx = mExpectedContextAfterException.Ebx;
SystemContext.SystemContextIa32->Edx = mExpectedContextAfterException.Edx;
SystemContext.SystemContextIa32->Ecx = mExpectedContextAfterException.Ecx;
SystemContext.SystemContextIa32->Eax = mExpectedContextAfterException.Eax;
//
// When fault exception happens, eip/rip points to the faulting instruction.
// For now, olny GP and PF are tested in fault exception.
//
if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) || (ExceptionType == EXCEPT_IA32_GP_FAULT)) {
AdjustRipForFaultHandler (ExceptionType, SystemContext);
}
}
/**
Compare cpu context in ConsistencyOfCpuContext test case.
1.Compare mActualContextInHandler with mExpectedContextInHandler.
2.Compare mActualContextAfterException with mExpectedContextAfterException.
@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
)
{
UT_ASSERT_EQUAL (mActualContextInHandler.Edi, mExpectedContextInHandler.Edi);
UT_ASSERT_EQUAL (mActualContextInHandler.Esi, mExpectedContextInHandler.Esi);
UT_ASSERT_EQUAL (mActualContextInHandler.Ebx, mExpectedContextInHandler.Ebx);
UT_ASSERT_EQUAL (mActualContextInHandler.Edx, mExpectedContextInHandler.Edx);
UT_ASSERT_EQUAL (mActualContextInHandler.Ecx, mExpectedContextInHandler.Ecx);
UT_ASSERT_EQUAL (mActualContextInHandler.Eax, mExpectedContextInHandler.Eax);
UT_ASSERT_EQUAL (mActualContextAfterException.Edi, mExpectedContextAfterException.Edi);
UT_ASSERT_EQUAL (mActualContextAfterException.Esi, mExpectedContextAfterException.Esi);
UT_ASSERT_EQUAL (mActualContextAfterException.Ebx, mExpectedContextAfterException.Ebx);
UT_ASSERT_EQUAL (mActualContextAfterException.Edx, mExpectedContextAfterException.Edx);
UT_ASSERT_EQUAL (mActualContextAfterException.Ecx, mExpectedContextAfterException.Ecx);
UT_ASSERT_EQUAL (mActualContextAfterException.Eax, mExpectedContextAfterException.Eax);
return UNIT_TEST_PASSED;
}
/**
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
)
{
UINTN LocalVariable;
AdjustRipForFaultHandler (ExceptionType, SystemContext);
mRspAddress[0] = (UINTN)SystemContext.SystemContextIa32->Esp;
mRspAddress[1] = (UINTN)(&LocalVariable);
return;
}

View File

@@ -0,0 +1,208 @@
;------------------------------------------------------------------------------
;
; Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
; Module Name:
;
; ArchExceptionHandlerTestAsm.nasm
;
; Abstract:
;
; ia32 CPU Exception Handler Lib Unit test
;
;------------------------------------------------------------------------------
SECTION .text
struc GENERAL_REGISTER_IA32
.Edi: resd 1
.Esi: resd 1
.Ebx: resd 1
.Edx: resd 1
.Ecx: resd 1
.Eax: resd 1
endstruc
extern ASM_PFX(mExpectedContextInHandler)
extern ASM_PFX(mActualContextAfterException)
extern ASM_PFX(mFaultInstructionLength)
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; TriggerGPException (
; UINTN Cr4ReservedBit
; );
;------------------------------------------------------------------------------
global ASM_PFX(TriggerGPException)
ASM_PFX(TriggerGPException):
;
; Set reserved bit 15 of cr4 to 1
;
lea ecx, [ASM_PFX(mFaultInstructionLength)]
mov dword[ecx], TriggerGPExceptionAfter - TriggerGPExceptionBefore
mov ecx, dword [esp + 0x4]
TriggerGPExceptionBefore:
mov cr4, ecx
TriggerGPExceptionAfter:
ret
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; TriggerPFException (
; UINTN PfAddress
; );
;------------------------------------------------------------------------------
global ASM_PFX(TriggerPFException)
ASM_PFX(TriggerPFException):
lea ecx, [ASM_PFX(mFaultInstructionLength)]
mov dword[ecx], TriggerPFExceptionAfter - TriggerPFExceptionBefore
mov ecx, dword [esp + 0x4]
TriggerPFExceptionBefore:
mov dword[ecx], 0x1
TriggerPFExceptionAfter:
ret
;------------------------------------------------------------------------------
; ModifyEcxInGlobalBeforeException;
; This function is writed by assebly code because it's only called in this file.
; It's used to set Ecx in mExpectedContextInHandler for different exception.
;------------------------------------------------------------------------------
global ASM_PFX(ModifyEcxInGlobalBeforeException)
ASM_PFX(ModifyEcxInGlobalBeforeException):
push eax
lea eax, [ASM_PFX(mExpectedContextInHandler)]
mov [eax + GENERAL_REGISTER_IA32.Ecx], ecx
pop eax
ret
;------------------------------------------------------------------------------
;VOID
;EFIAPI
;AsmTestConsistencyOfCpuContext (
; IN EFI_EXCEPTION_TYPE ExceptionType
; IN UINTN FaultParameter OPTIONAL
; );
;------------------------------------------------------------------------------
global ASM_PFX(AsmTestConsistencyOfCpuContext)
ASM_PFX(AsmTestConsistencyOfCpuContext):
;
; push 7 general register plus 4 bytes
;
pushad
;
; Modify register to mExpectedContextInHandler. Do not handle Esp and Ebp.
; CpuExceptionHandlerLib doesn't set Esp and Esp register to the value in SystemContext.
;
lea eax, [ASM_PFX(mExpectedContextInHandler)]
mov edi, [eax + GENERAL_REGISTER_IA32.Edi]
mov esi, [eax + GENERAL_REGISTER_IA32.Esi]
mov ebx, [eax + GENERAL_REGISTER_IA32.Ebx]
mov edx, [eax + GENERAL_REGISTER_IA32.Edx]
;
; Set ecx to ExceptionType
;
mov ecx, dword [esp + 0x24]
mov eax, [eax + GENERAL_REGISTER_IA32.Eax]
cmp ecx, 0xd
jz GPException
cmp ecx, 0xe
jz PFException
jmp INTnException
PFException:
mov ecx, dword [esp + 0x28] ; Set ecx to PFAddress.
call ASM_PFX(ModifyEcxInGlobalBeforeException) ; Set mExpectedContextInHandler.Ecx to PFAddress.
push ecx ; Push PfAddress into stack.
call ASM_PFX(TriggerPFException)
jmp AfterException
GPException:
mov ecx, dword [esp + 0x28] ; Set ecx to CR4_RESERVED_BIT.
call ASM_PFX(ModifyEcxInGlobalBeforeException) ; Set mExpectedContextInHandler.Ecx to CR4_RESERVED_BIT.
push ecx ; Push CR4_RESERVED_BIT into stack.
call ASM_PFX(TriggerGPException)
jmp AfterException
INTnException:
call ASM_PFX(ModifyEcxInGlobalBeforeException) ; Set mExpectedContextInHandler.Ecx to ExceptionType.
push ecx ; Push ExceptionType into stack.
call ASM_PFX(TriggerINTnException)
AfterException:
;
; Save register in mActualContextAfterException.
;
push eax
lea eax, [ASM_PFX(mActualContextAfterException)]
mov [eax + GENERAL_REGISTER_IA32.Edi], edi
mov [eax + GENERAL_REGISTER_IA32.Esi], esi
mov [eax + GENERAL_REGISTER_IA32.Ebx], ebx
mov [eax + GENERAL_REGISTER_IA32.Edx], edx
mov [eax + GENERAL_REGISTER_IA32.Ecx], ecx
pop ecx
mov [eax + GENERAL_REGISTER_IA32.Eax], ecx
add esp, 4
;
; restore original register
;
popad
ret
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; TriggerStackOverflow (
; VOID
; );
;------------------------------------------------------------------------------
global ASM_PFX(TriggerStackOverflow)
ASM_PFX(TriggerStackOverflow):
lea ecx, [ASM_PFX(mFaultInstructionLength)]
mov dword[ecx], TriggerCpuStackGuardAfter - TriggerCpuStackGuardBefore
TriggerCpuStackGuardBefore:
;
; Clear CR0.TS since it is set after return from a nested DF
;
call TriggerCpuStackGuardBefore
clts
TriggerCpuStackGuardAfter:
ret
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; TriggerINTnException (
; IN EFI_EXCEPTION_TYPE ExceptionType
; );
;------------------------------------------------------------------------------
global ASM_PFX(TriggerINTnException)
ASM_PFX(TriggerINTnException):
push eax
push edx
lea eax, [AsmTriggerException1 - AsmTriggerException0]
mov ecx, dword [esp + 0xc]
push ecx
mul ecx
mov ecx, AsmTriggerException0
add eax, ecx
pop ecx
pop edx
jmp eax
;
; eax = AsmTriggerException0 + (AsmTriggerException1 - AsmTriggerException0) * ecx
;
%assign Vector 0
%rep 22
AsmTriggerException %+ Vector:
pop eax
INT Vector
ret
%assign Vector Vector+1
%endrep