UefiCpuPkg: Add Unit tests for DxeCpuExceptionHandlerLib
Add target based unit tests for the DxeCpuExceptionHandlerLib. A DXE driver is created to test DxeCpuExceptionHandlerLib. 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 the test case, only no error code exception is triggered and tested by INTn instruction. b.Test if exception handler can be registered/unregistered for GP and PF. In the test case, GP exception is triggered and tested by setting CR4_RESERVED_BIT to 1. PF exception is triggered by writting to not-present or RO address. c.Test if CpuContext 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. 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:
@@ -0,0 +1,166 @@
|
||||
/** @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 mActualContextInHandler;
|
||||
GENERAL_REGISTER mActualContextAfterException;
|
||||
|
||||
//
|
||||
// In TestCpuContextConsistency, Cpu registers will be set to mExpectedContextInHandler/mExpectedContextAfterException.
|
||||
// Rcx in mExpectedContextInHandler is set runtime since Rcx is needed in assembly code.
|
||||
// For GP and PF, Rcx is set to FaultParameter. For other exception triggered by INTn, Rcx is set to ExceptionType.
|
||||
//
|
||||
GENERAL_REGISTER mExpectedContextInHandler = { 1, 2, 3, 4, 5, 0, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe };
|
||||
GENERAL_REGISTER mExpectedContextAfterException = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e };
|
||||
|
||||
/**
|
||||
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.SystemContextX64->Rip += 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 mActualContextInHandler.
|
||||
//
|
||||
mActualContextInHandler.Rdi = SystemContext.SystemContextX64->Rdi;
|
||||
mActualContextInHandler.Rsi = SystemContext.SystemContextX64->Rsi;
|
||||
mActualContextInHandler.Rbx = SystemContext.SystemContextX64->Rbx;
|
||||
mActualContextInHandler.Rdx = SystemContext.SystemContextX64->Rdx;
|
||||
mActualContextInHandler.Rcx = SystemContext.SystemContextX64->Rcx;
|
||||
mActualContextInHandler.Rax = SystemContext.SystemContextX64->Rax;
|
||||
mActualContextInHandler.R8 = SystemContext.SystemContextX64->R8;
|
||||
mActualContextInHandler.R9 = SystemContext.SystemContextX64->R9;
|
||||
mActualContextInHandler.R10 = SystemContext.SystemContextX64->R10;
|
||||
mActualContextInHandler.R11 = SystemContext.SystemContextX64->R11;
|
||||
mActualContextInHandler.R12 = SystemContext.SystemContextX64->R12;
|
||||
mActualContextInHandler.R13 = SystemContext.SystemContextX64->R13;
|
||||
mActualContextInHandler.R14 = SystemContext.SystemContextX64->R14;
|
||||
mActualContextInHandler.R15 = SystemContext.SystemContextX64->R15;
|
||||
|
||||
//
|
||||
// Modify cpu context. These registers will be stored in mActualContextAfterException.
|
||||
// Do not handle Rsp and Rbp. CpuExceptionHandlerLib doesn't set Rsp and Rbp register
|
||||
// to the value in SystemContext.
|
||||
//
|
||||
SystemContext.SystemContextX64->Rdi = mExpectedContextAfterException.Rdi;
|
||||
SystemContext.SystemContextX64->Rsi = mExpectedContextAfterException.Rsi;
|
||||
SystemContext.SystemContextX64->Rbx = mExpectedContextAfterException.Rbx;
|
||||
SystemContext.SystemContextX64->Rdx = mExpectedContextAfterException.Rdx;
|
||||
SystemContext.SystemContextX64->Rcx = mExpectedContextAfterException.Rcx;
|
||||
SystemContext.SystemContextX64->Rax = mExpectedContextAfterException.Rax;
|
||||
SystemContext.SystemContextX64->R8 = mExpectedContextAfterException.R8;
|
||||
SystemContext.SystemContextX64->R9 = mExpectedContextAfterException.R9;
|
||||
SystemContext.SystemContextX64->R10 = mExpectedContextAfterException.R10;
|
||||
SystemContext.SystemContextX64->R11 = mExpectedContextAfterException.R11;
|
||||
SystemContext.SystemContextX64->R12 = mExpectedContextAfterException.R12;
|
||||
SystemContext.SystemContextX64->R13 = mExpectedContextAfterException.R13;
|
||||
SystemContext.SystemContextX64->R14 = mExpectedContextAfterException.R14;
|
||||
SystemContext.SystemContextX64->R15 = mExpectedContextAfterException.R15;
|
||||
|
||||
//
|
||||
// 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 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
|
||||
)
|
||||
{
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.Rdi, mExpectedContextInHandler.Rdi);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.Rsi, mExpectedContextInHandler.Rsi);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.Rbx, mExpectedContextInHandler.Rbx);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.Rdx, mExpectedContextInHandler.Rdx);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.Rcx, mExpectedContextInHandler.Rcx);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.Rax, mExpectedContextInHandler.Rax);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R8, mExpectedContextInHandler.R8);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R9, mExpectedContextInHandler.R9);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R10, mExpectedContextInHandler.R10);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R11, mExpectedContextInHandler.R11);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R12, mExpectedContextInHandler.R12);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R13, mExpectedContextInHandler.R13);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R14, mExpectedContextInHandler.R14);
|
||||
UT_ASSERT_EQUAL (mActualContextInHandler.R15, mExpectedContextInHandler.R15);
|
||||
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.Rdi, mExpectedContextAfterException.Rdi);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.Rsi, mExpectedContextAfterException.Rsi);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.Rbx, mExpectedContextAfterException.Rbx);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.Rdx, mExpectedContextAfterException.Rdx);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.Rcx, mExpectedContextAfterException.Rcx);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.Rax, mExpectedContextAfterException.Rax);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R8, mExpectedContextAfterException.R8);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R9, mExpectedContextAfterException.R9);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R10, mExpectedContextAfterException.R10);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R11, mExpectedContextAfterException.R11);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R12, mExpectedContextAfterException.R12);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R13, mExpectedContextAfterException.R13);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R14, mExpectedContextAfterException.R14);
|
||||
UT_ASSERT_EQUAL (mActualContextAfterException.R15, mExpectedContextAfterException.R15);
|
||||
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.SystemContextX64->Rsp;
|
||||
mRspAddress[1] = (UINTN)(&LocalVariable);
|
||||
|
||||
return;
|
||||
}
|
@@ -0,0 +1,256 @@
|
||||
;------------------------------------------------------------------------------
|
||||
;
|
||||
; Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
|
||||
; SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
;
|
||||
; Module Name:
|
||||
;
|
||||
; ArchExceptionHandlerTestAsm.nasm
|
||||
;
|
||||
; Abstract:
|
||||
;
|
||||
; x64 CPU Exception Handler Lib Unit test
|
||||
;
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
DEFAULT REL
|
||||
SECTION .text
|
||||
|
||||
struc GENERAL_REGISTER
|
||||
.Rdi: resq 1
|
||||
.Rsi: resq 1
|
||||
.Rbx: resq 1
|
||||
.Rdx: resq 1
|
||||
.Rcx: resq 1
|
||||
.Rax: resq 1
|
||||
.R8: resq 1
|
||||
.R9: resq 1
|
||||
.R10: resq 1
|
||||
.R11: resq 1
|
||||
.R12: resq 1
|
||||
.R13: resq 1
|
||||
.R14: resq 1
|
||||
.R15: resq 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
|
||||
;
|
||||
push rcx
|
||||
lea rcx, [ASM_PFX(mFaultInstructionLength)]
|
||||
mov qword[rcx], TriggerGPExceptionAfter - TriggerGPExceptionBefore
|
||||
pop rcx
|
||||
TriggerGPExceptionBefore:
|
||||
mov cr4, rcx
|
||||
TriggerGPExceptionAfter:
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; VOID
|
||||
; EFIAPI
|
||||
; TriggerPFException (
|
||||
; UINTN PFAddress
|
||||
; );
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(TriggerPFException)
|
||||
ASM_PFX(TriggerPFException):
|
||||
push rcx
|
||||
lea rcx, [ASM_PFX(mFaultInstructionLength)]
|
||||
mov qword[rcx], TriggerPFExceptionAfter - TriggerPFExceptionBefore
|
||||
pop rcx
|
||||
TriggerPFExceptionBefore:
|
||||
mov qword[rcx], 0x1
|
||||
TriggerPFExceptionAfter:
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; ModifyRcxInGlobalBeforeException;
|
||||
; This function is writed by assebly code because it's only called in this file.
|
||||
; It's used to set Rcx in mExpectedContextInHandler for different exception.
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(ModifyRcxInGlobalBeforeException)
|
||||
ASM_PFX(ModifyRcxInGlobalBeforeException):
|
||||
push rax
|
||||
lea rax, [ASM_PFX(mExpectedContextInHandler)]
|
||||
mov [rax + GENERAL_REGISTER.Rcx], rcx
|
||||
pop rax
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
;VOID
|
||||
;EFIAPI
|
||||
;AsmTestConsistencyOfCpuContext (
|
||||
; IN EFI_EXCEPTION_TYPE ExceptionType
|
||||
; IN UINTN FaultParameter OPTIONAL
|
||||
; );
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(AsmTestConsistencyOfCpuContext)
|
||||
ASM_PFX(AsmTestConsistencyOfCpuContext):
|
||||
;
|
||||
; Push original register
|
||||
;
|
||||
push r15
|
||||
push r14
|
||||
push r13
|
||||
push r12
|
||||
push r11
|
||||
push r10
|
||||
push r9
|
||||
push r8
|
||||
push rax
|
||||
push rcx
|
||||
push rbx
|
||||
push rsi
|
||||
push rdi
|
||||
push rdx
|
||||
push rdx
|
||||
|
||||
;
|
||||
; Modify registers to mExpectedContextInHandler. Do not handle Rsp and Rbp.
|
||||
; CpuExceptionHandlerLib doesn't set Rsp and Rsp register to the value in SystemContext.
|
||||
;
|
||||
lea r15, [ASM_PFX(mExpectedContextInHandler)]
|
||||
mov rdi, [r15 + GENERAL_REGISTER.Rdi]
|
||||
mov rsi, [r15 + GENERAL_REGISTER.Rsi]
|
||||
mov rbx, [r15 + GENERAL_REGISTER.Rbx]
|
||||
mov rdx, [r15 + GENERAL_REGISTER.Rdx]
|
||||
mov rax, [r15 + GENERAL_REGISTER.Rax]
|
||||
mov r8, [r15 + GENERAL_REGISTER.R8]
|
||||
mov r9, [r15 + GENERAL_REGISTER.R9]
|
||||
mov r10, [r15 + GENERAL_REGISTER.R10]
|
||||
mov r11, [r15 + GENERAL_REGISTER.R11]
|
||||
mov r12, [r15 + GENERAL_REGISTER.R12]
|
||||
mov r13, [r15 + GENERAL_REGISTER.R13]
|
||||
mov r14, [r15 + GENERAL_REGISTER.R14]
|
||||
mov r15, [r15 + GENERAL_REGISTER.R15]
|
||||
|
||||
cmp rcx, 0xd
|
||||
jz GPException
|
||||
cmp rcx, 0xe
|
||||
jz PFException
|
||||
jmp INTnException
|
||||
|
||||
PFException:
|
||||
pop rcx ; Pop rdx(PFAddress) to rcx.
|
||||
call ASM_PFX(ModifyRcxInGlobalBeforeException) ; Set mExpectedContextInHandler.Rcx to PFAddress.
|
||||
call ASM_PFX(TriggerPFException)
|
||||
jmp AfterException
|
||||
|
||||
GPException:
|
||||
pop rcx ; Pop rdx(Cr4ReservedBit) to rcx.
|
||||
call ASM_PFX(ModifyRcxInGlobalBeforeException) ; Set mExpectedContextInHandler.Rcx to Cr4ReservedBit.
|
||||
call ASM_PFX(TriggerGPException)
|
||||
jmp AfterException
|
||||
|
||||
INTnException:
|
||||
;
|
||||
; Modify Rcx in mExpectedContextInHandler.
|
||||
;
|
||||
add Rsp, 8 ; Discard the extra Rdx in stack. Rcx is ExceptionType now.
|
||||
call ASM_PFX(ModifyRcxInGlobalBeforeException) ; Set mExpectedContextInHandler.Rcx to ExceptionType.
|
||||
call ASM_PFX(TriggerINTnException)
|
||||
|
||||
AfterException:
|
||||
;
|
||||
; Save registers in mActualContextAfterException
|
||||
;
|
||||
push rax
|
||||
lea rax, [ASM_PFX(mActualContextAfterException)]
|
||||
mov [rax + GENERAL_REGISTER.Rdi], rdi
|
||||
mov [rax + GENERAL_REGISTER.Rsi], rsi
|
||||
mov [rax + GENERAL_REGISTER.Rbx], rbx
|
||||
mov [rax + GENERAL_REGISTER.Rdx], rdx
|
||||
mov [rax + GENERAL_REGISTER.Rcx], rcx
|
||||
pop rcx
|
||||
mov [rax + GENERAL_REGISTER.Rax], rcx
|
||||
mov [rax + GENERAL_REGISTER.R8], r8
|
||||
mov [rax + GENERAL_REGISTER.R9], r9
|
||||
mov [rax + GENERAL_REGISTER.R10], r10
|
||||
mov [rax + GENERAL_REGISTER.R11], r11
|
||||
mov [rax + GENERAL_REGISTER.R12], r12
|
||||
mov [rax + GENERAL_REGISTER.R13], r13
|
||||
mov [rax + GENERAL_REGISTER.R14], r14
|
||||
mov [rax + GENERAL_REGISTER.R15], r15
|
||||
|
||||
;
|
||||
; restore original register
|
||||
;
|
||||
pop rdx
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbx
|
||||
pop rcx
|
||||
pop rax
|
||||
pop r8
|
||||
pop r9
|
||||
pop r10
|
||||
pop r11
|
||||
pop r12
|
||||
pop r13
|
||||
pop r14
|
||||
pop r15
|
||||
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; VOID
|
||||
; EFIAPI
|
||||
; TriggerStackOverflow (
|
||||
; VOID
|
||||
; );
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(TriggerStackOverflow)
|
||||
ASM_PFX(TriggerStackOverflow):
|
||||
push rcx
|
||||
lea rcx, [ASM_PFX(mFaultInstructionLength)]
|
||||
mov qword[rcx], TriggerCpuStackGuardAfter - TriggerCpuStackGuardBefore
|
||||
pop rcx
|
||||
TriggerCpuStackGuardBefore:
|
||||
call TriggerCpuStackGuardBefore
|
||||
TriggerCpuStackGuardAfter:
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; VOID
|
||||
; EFIAPI
|
||||
; TriggerINTnException (
|
||||
; IN EFI_EXCEPTION_TYPE ExceptionType
|
||||
; );
|
||||
;------------------------------------------------------------------------------
|
||||
global ASM_PFX(TriggerINTnException)
|
||||
ASM_PFX(TriggerINTnException):
|
||||
push rax
|
||||
push rdx
|
||||
push rcx
|
||||
lea rax, [AsmTriggerException1 - AsmTriggerException0]
|
||||
mul rcx
|
||||
mov rcx, AsmTriggerException0
|
||||
add rax, rcx
|
||||
pop rcx
|
||||
pop rdx
|
||||
jmp rax
|
||||
;
|
||||
; rax = AsmTriggerException0 + (AsmTriggerException1 - AsmTriggerException0) * rcx
|
||||
;
|
||||
%assign Vector 0
|
||||
%rep 22
|
||||
AsmTriggerException %+ Vector:
|
||||
pop rax
|
||||
INT Vector
|
||||
ret
|
||||
%assign Vector Vector+1
|
||||
%endrep
|
Reference in New Issue
Block a user