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:
parent
beabde5875
commit
055eaacc34
@ -93,6 +93,15 @@ typedef struct {
|
|||||||
UINT64 R15;
|
UINT64 R15;
|
||||||
} GENERAL_REGISTER;
|
} GENERAL_REGISTER;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT32 Edi;
|
||||||
|
UINT32 Esi;
|
||||||
|
UINT32 Ebx;
|
||||||
|
UINT32 Edx;
|
||||||
|
UINT32 Ecx;
|
||||||
|
UINT32 Eax;
|
||||||
|
} GENERAL_REGISTER_IA32;
|
||||||
|
|
||||||
extern UINTN mFaultInstructionLength;
|
extern UINTN mFaultInstructionLength;
|
||||||
extern EFI_EXCEPTION_TYPE mExceptionType;
|
extern EFI_EXCEPTION_TYPE mExceptionType;
|
||||||
extern UINTN mRspAddress[];
|
extern UINTN mRspAddress[];
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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
|
@ -0,0 +1,61 @@
|
|||||||
|
## @file
|
||||||
|
# Unit tests of the PeiCpuExceptionHandlerLib instance.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
##
|
||||||
|
|
||||||
|
[Defines]
|
||||||
|
INF_VERSION = 0x00010006
|
||||||
|
BASE_NAME = CpuExceptionHandlerPeiTest
|
||||||
|
FILE_GUID = 39A96CF7-F369-4357-9234-4B52F98A007F
|
||||||
|
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.Ia32]
|
||||||
|
Ia32/ArchExceptionHandlerTestAsm.nasm
|
||||||
|
Ia32/ArchExceptionHandlerTest.c
|
||||||
|
|
||||||
|
[Sources.X64]
|
||||||
|
X64/ArchExceptionHandlerTestAsm.nasm
|
||||||
|
X64/ArchExceptionHandlerTest.c
|
||||||
|
|
||||||
|
[Sources.common]
|
||||||
|
CpuExceptionHandlerTest.h
|
||||||
|
CpuExceptionHandlerTestCommon.c
|
||||||
|
PeiCpuExceptionHandlerUnitTest.c
|
||||||
|
|
||||||
|
[Packages]
|
||||||
|
MdePkg/MdePkg.dec
|
||||||
|
MdeModulePkg/MdeModulePkg.dec
|
||||||
|
UefiCpuPkg/UefiCpuPkg.dec
|
||||||
|
|
||||||
|
[LibraryClasses]
|
||||||
|
BaseLib
|
||||||
|
BaseMemoryLib
|
||||||
|
DebugLib
|
||||||
|
UnitTestLib
|
||||||
|
MemoryAllocationLib
|
||||||
|
CpuExceptionHandlerLib
|
||||||
|
PeimEntryPoint
|
||||||
|
HobLib
|
||||||
|
PeiServicesLib
|
||||||
|
CpuPageTableLib
|
||||||
|
PeiServicesTablePointerLib
|
||||||
|
|
||||||
|
[Pcd]
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
|
||||||
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES
|
||||||
|
|
||||||
|
[Ppis]
|
||||||
|
gEdkiiPeiMpServices2PpiGuid ## CONSUMES
|
||||||
|
|
||||||
|
[Depex]
|
||||||
|
gEdkiiPeiMpServices2PpiGuid AND
|
||||||
|
gEfiPeiMemoryDiscoveredPpiGuid
|
@ -0,0 +1,204 @@
|
|||||||
|
/** @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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user