diff options
author | Jeff Fan <jeff.fan@intel.com> | 2013-11-22 06:24:41 +0000 |
---|---|---|
committer | vanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524> | 2013-11-22 06:24:41 +0000 |
commit | e41aad152135f27ae1da142454af85a6597719ee (patch) | |
tree | 07138e5c40f53ca941863f27f8ad409019556077 /UefiCpuPkg/Library/CpuExceptionHandlerLib | |
parent | 57f360f2615818366b39ff21fcd0201154be4ab2 (diff) | |
download | edk2-e41aad152135f27ae1da142454af85a6597719ee.zip edk2-e41aad152135f27ae1da142454af85a6597719ee.tar.gz edk2-e41aad152135f27ae1da142454af85a6597719ee.tar.bz2 |
1. Separated DxeSmmCpuExceptionHandlerLib.inf into 2 instance DxeCpuExceptionHandlerLib.inf and SmmCpuExceptionHandlerLib.inf.
2. Updated CPU Exception Handler Library instance according to the new CPU Exception Handler Library class definitions.
3. Updated CPU Exception Handler Library instance to handle the vector attributes defined in PI 1.2.1.
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Hot Tian <hot.tian@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14885 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'UefiCpuPkg/Library/CpuExceptionHandlerLib')
17 files changed, 1864 insertions, 514 deletions
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c index b1c6923..c075d5f 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c @@ -1,7 +1,7 @@ /** @file
CPU Exception Hanlder Library common functions.
- Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -15,12 +15,13 @@ #include "CpuExceptionCommon.h"
//
-// Error code flag indicating whether or not an error code will be
+// Error code flag indicating whether or not an error code will be
// pushed on the stack if an exception occurs.
//
// 1 means an error code will be pushed, otherwise 0
//
-UINT32 mErrorCodeFlag = 0x00027d00;
+CONST UINT32 mErrorCodeFlag = 0x00027d00;
+RESERVED_VECTORS_DATA *mReservedVectors = NULL;
//
// Define the maximum message length
@@ -133,3 +134,35 @@ FindModuleImageBase ( return Pe32Data;
}
+/**
+ Read and save reserved vector information
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[out] ReservedVector Pointer to reserved vector data buffer.
+ @param[in] VectorCount Vector number to be updated.
+
+ @return EFI_SUCCESS Read and save vector info successfully.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+
+**/
+EFI_STATUS
+ReadAndVerifyVectorInfo (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo,
+ OUT RESERVED_VECTORS_DATA *ReservedVector,
+ IN UINTN VectorCount
+ )
+{
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ if (VectorInfo->Attribute > EFI_VECTOR_HANDOFF_HOOK_AFTER) {
+ //
+ // If vector attrubute is invalid
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ if (VectorInfo->VectorNumber < VectorCount) {
+ ReservedVector[VectorInfo->VectorNumber].Attribute = VectorInfo->Attribute;
+ }
+ VectorInfo ++;
+ }
+ return EFI_SUCCESS;
+}
\ No newline at end of file diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h index 66847ea..6b0ccfe 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h @@ -1,7 +1,7 @@ /** @file
Common header file for CPU Exception Handler Library.
- Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -15,23 +15,36 @@ #ifndef _CPU_EXCEPTION_COMMON_H_
#define _CPU_EXCEPTION_COMMON_H_
+#include <Ppi/VectorHandoffInfo.h>
+#include <Protocol/Cpu.h>
#include <Library/BaseLib.h>
#include <Library/SerialPortLib.h>
#include <Library/PrintLib.h>
#include <Library/LocalApicLib.h>
#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SynchronizationLib.h>
+
+#define CPU_EXCEPTION_NUM 32
+#define CPU_INTERRUPT_NUM 256
+#define HOOKAFTER_STUB_SIZE 16
+
+#include "ArchInterruptDefs.h"
-#define CPU_EXCEPTION_NUM 32
//
// Record exception handler information
//
typedef struct {
UINTN ExceptionStart;
UINTN ExceptionStubHeaderSize;
+ UINTN HookAfterStubHeaderStart;
} EXCEPTION_HANDLER_TEMPLATE_MAP;
-extern UINT32 mErrorCodeFlag;
-extern CONST UINTN mImageAlignSize;
+extern CONST UINT32 mErrorCodeFlag;
+extern CONST UINTN mImageAlignSize;
+extern CONST UINTN mDoFarReturnFlag;
+extern RESERVED_VECTORS_DATA *mReservedVectors;
/**
Return address map of exception handler template so that C code can generate
@@ -41,17 +54,33 @@ extern CONST UINTN mImageAlignSize; **/
VOID
EFIAPI
-GetTemplateAddressMap (
+AsmGetTemplateAddressMap (
OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
);
/**
- Internal function to setup CPU exception handlers.
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+
+ @param IdtEntry Pointer to IDT entry to be updated.
+ @param InterruptHandler IDT handler value.
**/
VOID
-InternalSetupCpuExceptionHandlers (
- VOID
+ArchUpdateIdtEntry (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN UINTN InterruptHandler
+ );
+
+/**
+ Read IDT handler value from IDT entry.
+
+ @param IdtEntry Pointer to IDT entry to be read.
+
+**/
+UINTN
+ArchGetIdtHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
);
/**
@@ -92,8 +121,120 @@ FindModuleImageBase ( **/
VOID
DumpCpuContent (
- IN UINTN InterruptType,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext
);
+/**
+ Internal worker function to initialize exception handler.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+InitializeCpuExceptionHandlersWorker (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ );
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+*/
+EFI_STATUS
+RegisterCpuInterruptHandlerWorker (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+/**
+ Internal worker function to update IDT entries accordling to vector attributes.
+
+ @param[in] IdtTable Pointer to IDT table.
+ @param[in] TemplateMap Pointer to a buffer where the address map is returned.
+ @param[in] IdtEntryCount IDT entries number to be updated.
+
+**/
+VOID
+UpdateIdtTable (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
+ IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,
+ IN UINTN IdtEntryCount
+ );
+
+/**
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+ArchSaveExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+ArchRestoreExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Fix up the vector number in the vector code.
+
+ @param[in] VectorBase Base address of the vector handler.
+ @param[in] VectorNum Index of vector.
+
+**/
+VOID
+EFIAPI
+AsmVectorNumFixup (
+ IN VOID *VectorBase,
+ IN UINT8 VectorNum
+ );
+
+/**
+ Read and save reserved vector information
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[out] ReservedVector Pointer to reserved vector data buffer.
+ @param[in] VectorCount Vector number to be updated.
+
+ @return EFI_SUCCESS Read and save vector info successfully.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+
+**/
+EFI_STATUS
+ReadAndVerifyVectorInfo (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo,
+ OUT RESERVED_VECTORS_DATA *ReservedVector,
+ IN UINTN VectorCount
+ );
+
#endif
+
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf index 9f0f2d9..454307b 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf @@ -1,9 +1,9 @@ ## @file
-# Component description file for DXE/SMM CPU Exception Handler Library instance.
+# Component description file for DXE CPU Exception Handler Library instance.
#
-# This library instance supports DXE SMM module only.
+# This library instance supports DXE module only.
#
-# Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@@ -16,11 +16,11 @@ [Defines]
INF_VERSION = 0x00010005
- BASE_NAME = DxeSmmCpuExceptionHandlerLib
- FILE_GUID = EC629480-BD36-4e8e-8AB2-D28BF0D45864
+ BASE_NAME = DxeCpuExceptionHandlerLib
+ FILE_GUID = B6E9835A-EDCF-4748-98A8-27D3C722E02D
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
- LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
+ LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER UEFI_APPLICATION
#
# The following information is for reference only and not required by the build tools.
@@ -32,16 +32,19 @@ Ia32/ExceptionHandlerAsm.asm |MSFT
Ia32/ExceptionHandlerAsm.S |GCC
Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
[Sources.X64]
X64/ExceptionHandlerAsm.asm |MSFT
X64/ExceptionHandlerAsm.S |GCC
X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
[Sources.common]
CpuExceptionCommon.h
CpuExceptionCommon.c
DxeSmmCpuException.c
+ DxeException.c
[Packages]
MdePkg/MdePkg.dec
@@ -55,3 +58,9 @@ SynchronizationLib
LocalApicLib
PeCoffGetEntryPointLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ DebugLib
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c new file mode 100644 index 0000000..b4b844c --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c @@ -0,0 +1,170 @@ +/** @file
+ CPU exception handler library implemenation for DXE modules.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include "CpuExceptionCommon.h"
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+CONST UINTN mDoFarReturnFlag = 0;
+
+extern SPIN_LOCK mDisplayMessageSpinLock;
+extern EFI_CPU_INTERRUPT_HANDLER *mExternalInterruptHandler;
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return InitializeCpuExceptionHandlersWorker (VectorInfo);
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN IdtEntryCount;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+ UINTN Index;
+ UINTN InterruptEntry;
+ UINT8 *InterruptEntryCode;
+
+ mReservedVectors = AllocatePool (sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM);
+ ASSERT (mReservedVectors != NULL);
+ SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM, 0xff);
+ if (VectorInfo != NULL) {
+ Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_INTERRUPT_NUM);
+ if (EFI_ERROR (Status)) {
+ FreePool (mReservedVectors);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ InitializeSpinLock (&mDisplayMessageSpinLock);
+ mExternalInterruptHandler = AllocateZeroPool (sizeof (EFI_CPU_INTERRUPT_HANDLER) * CPU_INTERRUPT_NUM);
+ ASSERT (mExternalInterruptHandler != NULL);
+
+ //
+ // Read IDT descriptor and calculate IDT size
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
+ if (IdtEntryCount > CPU_INTERRUPT_NUM) {
+ IdtEntryCount = CPU_INTERRUPT_NUM;
+ }
+ //
+ // Create Interrupt Descriptor Table and Copy the old IDT table in
+ //
+ IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM);
+ ASSERT (IdtTable != NULL);
+ CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount);
+
+ AsmGetTemplateAddressMap (&TemplateMap);
+ ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
+ InterruptEntryCode = AllocatePool (TemplateMap.ExceptionStubHeaderSize * CPU_INTERRUPT_NUM);
+ ASSERT (InterruptEntryCode != NULL);
+
+ InterruptEntry = (UINTN) InterruptEntryCode;
+ for (Index = 0; Index < CPU_INTERRUPT_NUM; Index ++) {
+ CopyMem (
+ (VOID *) InterruptEntry,
+ (VOID *) TemplateMap.ExceptionStart,
+ TemplateMap.ExceptionStubHeaderSize
+ );
+ AsmVectorNumFixup ((VOID *) InterruptEntry, (UINT8) Index);
+ InterruptEntry += TemplateMap.ExceptionStubHeaderSize;
+ }
+
+ TemplateMap.ExceptionStart = (UINTN) InterruptEntryCode;
+ UpdateIdtTable (IdtTable, &TemplateMap, CPU_INTERRUPT_NUM);
+
+ //
+ // Load Interrupt Descriptor Table
+ //
+ IdtDescriptor.Base = (UINTN) IdtTable;
+ IdtDescriptor.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &IdtDescriptor);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+*/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler);
+}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c index 682def4..aed5cf8 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeSmmCpuException.c @@ -1,7 +1,7 @@ /** @file
- CPU Exception Library provides DXE/SMM CPU exception handler.
+ CPU Exception Library provides DXE/SMM CPU common exception handler.
-Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
@@ -12,10 +12,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/
-#include <PiDxe.h>
-
#include "CpuExceptionCommon.h"
-#include <Library/SynchronizationLib.h>
+#include <Library/DebugLib.h>
//
// Spinlock for CPU information display
@@ -27,6 +25,11 @@ SPIN_LOCK mDisplayMessageSpinLock; //
CONST UINTN mImageAlignSize = SIZE_4KB;
+RESERVED_VECTORS_DATA mReservedVectorsData[CPU_EXCEPTION_NUM];
+EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_EXCEPTION_NUM];
+EFI_CPU_INTERRUPT_HANDLER *mExternalInterruptHandler = NULL;
+UINTN mEnabledInterruptNum = 0;
+
/**
Common exception handler.
@@ -36,49 +39,250 @@ CONST UINTN mImageAlignSize = SIZE_4KB; VOID
EFIAPI
CommonExceptionHandler (
- IN EFI_EXCEPTION_TYPE ExceptionType,
- IN EFI_SYSTEM_CONTEXT SystemContext
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
)
{
- //
- // Get Spinlock to display CPU information
- //
- while (!AcquireSpinLockOrFail (&mDisplayMessageSpinLock)) {
- CpuPause ();
+ EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;
+
+ ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);
+
+ switch (mReservedVectors[ExceptionType].Attribute) {
+ case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
+ //
+ // Need to jmp to old IDT handler after this exception handler
+ //
+ ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
+ ExceptionHandlerContext->OldIdtHandler = mReservedVectors[ExceptionType].ExceptonHandler;
+ break;
+ case EFI_VECTOR_HANDOFF_HOOK_AFTER:
+ while (TRUE) {
+ //
+ // If if anyone has gotten SPIN_LOCK for owner running hook after
+ //
+ if (AcquireSpinLockOrFail (&mReservedVectors[ExceptionType].SpinLock)) {
+ //
+ // Need to execute old IDT handler before running this exception handler
+ //
+ mReservedVectors[ExceptionType].ApicId = GetApicId ();
+ ArchSaveExceptionContext (ExceptionType, SystemContext);
+ ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
+ ExceptionHandlerContext->OldIdtHandler = mReservedVectors[ExceptionType].ExceptonHandler;
+ return;
+ }
+ //
+ // If failed to acquire SPIN_LOCK, check if it was locked by processor itself
+ //
+ if (mReservedVectors[ExceptionType].ApicId == GetApicId ()) {
+ //
+ // Old IDT handler has been executed, then retore CPU exception content to
+ // run new exception handler.
+ //
+ ArchRestoreExceptionContext (ExceptionType, SystemContext);
+ //
+ // Rlease spin lock for ApicId
+ //
+ ReleaseSpinLock (&mReservedVectors[ExceptionType].SpinLock);
+ break;
+ }
+ CpuPause ();
+ }
+ break;
+ case 0xffffffff:
+ break;
+ default:
+ //
+ // It should never reach here
+ //
+ CpuDeadLoop ();
+ break;
}
+
+ if (mExternalInterruptHandler[ExceptionType] != NULL) {
+ (mExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);
+ } else {
+ //
+ // Get Spinlock to display CPU information
+ //
+ while (!AcquireSpinLockOrFail (&mDisplayMessageSpinLock)) {
+ CpuPause ();
+ }
+ //
+ // Display ExceptionType, CPU information and Image information
+ //
+ DumpCpuContent (ExceptionType, SystemContext);
+ //
+ // Release Spinlock of output message
+ //
+ ReleaseSpinLock (&mDisplayMessageSpinLock);
+ //
+ // Enter a dead loop if needn't to execute old IDT handler further
+ //
+ if (mReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {
+ CpuDeadLoop ();
+ }
+ }
+}
- //
- // Display ExceptionType, CPU information and Image information
- //
- DumpCpuContent (ExceptionType, SystemContext);
+/**
+ Internal worker function to update IDT entries accordling to vector attributes.
+
+ @param[in] IdtTable Pointer to IDT table.
+ @param[in] TemplateMap Pointer to a buffer where the address map is returned.
+ @param[in] IdtEntryCount IDT entries number to be updated.
+
+**/
+VOID
+UpdateIdtTable (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
+ IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,
+ IN UINTN IdtEntryCount
+ )
+{
+ UINT16 CodeSegment;
+ UINTN Index;
+ UINTN InterruptHandler;
//
- // Release Spinlock
+ // Use current CS as the segment selector of interrupt gate in IDT
//
- ReleaseSpinLock (&mDisplayMessageSpinLock);
+ CodeSegment = AsmReadCs ();
+ for (Index = 0; Index < IdtEntryCount; Index ++) {
+ IdtTable[Index].Bits.Selector = CodeSegment;
+ //
+ // Check reserved vectors attributes
+ //
+ switch (mReservedVectors[Index].Attribute) {
+ case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:
+ //
+ // Keep original IDT entry
+ //
+ continue;
+ case EFI_VECTOR_HANDOFF_HOOK_AFTER:
+ InitializeSpinLock (&mReservedVectors[Index].SpinLock);
+ CopyMem (
+ (VOID *) mReservedVectors[Index].HookAfterStubHeaderCode,
+ (VOID *) TemplateMap->HookAfterStubHeaderStart,
+ TemplateMap->ExceptionStubHeaderSize
+ );
+ AsmVectorNumFixup ((VOID *) mReservedVectors[Index].HookAfterStubHeaderCode, (UINT8) Index);
+ //
+ // Go on the following code
+ //
+ case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
+ //
+ // Save original IDT handler address
+ //
+ mReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);
+ //
+ // Go on the following code
+ //
+ default:
+ //
+ // Update new IDT entry
+ //
+ InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;
+ ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
+ break;
+ }
+ }
+
//
- // Enter a dead loop.
+ // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()
//
- CpuDeadLoop ();
+ mEnabledInterruptNum = IdtEntryCount;
}
/**
- Setup CPU exception handlers.
+ Internal worker function to initialize exception handler.
- This API will setups the CPU exception handler to display CPU contents and run into
- CpuDeadLoop().
- Note: Before invoking this API, caller must allocate memory for IDT table and load
- IDTR by AsmWriteIdtr().
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
**/
-VOID
-EFIAPI
-SetupCpuExceptionHandlers (
- IN VOID
+EFI_STATUS
+InitializeCpuExceptionHandlersWorker (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
)
{
+ EFI_STATUS Status;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN IdtEntryCount;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+
+ mReservedVectors = mReservedVectorsData;
+ SetMem ((VOID *) mReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);
+ if (VectorInfo != NULL) {
+ Status = ReadAndVerifyVectorInfo (VectorInfo, mReservedVectors, CPU_EXCEPTION_NUM);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
InitializeSpinLock (&mDisplayMessageSpinLock);
- InternalSetupCpuExceptionHandlers ();
+
+ mExternalInterruptHandler = mExternalInterruptHandlerTable;
+ //
+ // Read IDT descriptor and calculate IDT size
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
+ if (IdtEntryCount > CPU_EXCEPTION_NUM) {
+ //
+ // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
+ //
+ IdtEntryCount = CPU_EXCEPTION_NUM;
+ }
+
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+ AsmGetTemplateAddressMap (&TemplateMap);
+ ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
+ UpdateIdtTable (IdtTable, &TemplateMap, IdtEntryCount);
+ mEnabledInterruptNum = IdtEntryCount;
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+*/
+EFI_STATUS
+RegisterCpuInterruptHandlerWorker (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ if (InterruptType < 0 || InterruptType > (EFI_EXCEPTION_TYPE)mEnabledInterruptNum ||
+ mReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (InterruptHandler == NULL && mExternalInterruptHandler[InterruptType] == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterruptHandler != NULL && mExternalInterruptHandler[InterruptType] != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mExternalInterruptHandler[InterruptType] = InterruptHandler;
+ return EFI_SUCCESS;
}
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c index a69f0d3..ba2cc6f 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c @@ -1,7 +1,7 @@ /** @file
IA32 CPU Exception Hanlder functons.
- Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -15,49 +15,87 @@ #include "CpuExceptionCommon.h"
/**
- Internal function to setup CPU exception handlers.
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+
+ @param IdtEntry Pointer to IDT entry to be updated.
+ @param InterruptHandler IDT handler value.
**/
VOID
-InternalSetupCpuExceptionHandlers (
- VOID
+ArchUpdateIdtEntry (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN UINTN InterruptHandler
+ )
+{
+ IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+}
+
+/**
+ Read IDT handler value from IDT entry.
+
+ @param IdtEntry Pointer to IDT entry to be read.
+
+**/
+UINTN
+ArchGetIdtHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
)
{
- IA32_DESCRIPTOR IdtDescriptor;
- UINTN IdtSize;
- EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
- UINT16 CodeSegment;
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINTN Index;
- UINTN InterruptHandler;;
+ return (UINTN)IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16);
+}
+
+/**
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+
+**/
+VOID
+ArchSaveExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ IA32_EFLAGS32 Eflags;
//
- // Read IDT descriptor and calculate IDT size
+ // Save Exception context in global variable
//
- AsmReadIdtr (&IdtDescriptor);
- IdtSize = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
- if (IdtSize > CPU_EXCEPTION_NUM) {
- //
- // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
- //
- IdtSize = CPU_EXCEPTION_NUM;
- }
-
+ mReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextIa32->Eflags;
+ mReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextIa32->Cs;
+ mReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextIa32->Eip;
+ mReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextIa32->ExceptionData;
+ //
+ // Clear IF flag to avoid old IDT handler enable interrupt by IRET
//
- // Use current CS as the segment selector of interrupt gate in IDT
+ Eflags.UintN = SystemContext.SystemContextIa32->Eflags;
+ Eflags.Bits.IF = 0;
+ SystemContext.SystemContextIa32->Eflags = Eflags.UintN;
//
- CodeSegment = AsmReadCs ();
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+ // Modify the EIP in stack, then old IDT handler will return to the stub code
+ //
+ SystemContext.SystemContextIa32->Eip = (UINTN) mReservedVectors[ExceptionType].HookAfterStubHeaderCode;
+}
- GetTemplateAddressMap (&TemplateMap);
+/**
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
- for (Index = 0; Index < IdtSize; Index ++) {
- InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize;
- IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[Index].Bits.Selector = CodeSegment;
- IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
- }
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+ArchRestoreExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ SystemContext.SystemContextIa32->Eflags = mReservedVectors[ExceptionType].OldFlags;
+ SystemContext.SystemContextIa32->Cs = mReservedVectors[ExceptionType].OldCs;
+ SystemContext.SystemContextIa32->Eip = mReservedVectors[ExceptionType].OldIp;
+ SystemContext.SystemContextIa32->ExceptionData = mReservedVectors[ExceptionType].ExceptionData;
}
/**
@@ -68,7 +106,7 @@ InternalSetupCpuExceptionHandlers ( **/
VOID
DumpCpuContent (
- IN UINTN ExceptionType,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h new file mode 100644 index 0000000..a8d3556 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h @@ -0,0 +1,44 @@ +/** @file
+ Ia32 arch definition for CPU Exception Handler Library.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ARCH_CPU_INTERRUPT_DEFS_H_
+#define _ARCH_CPU_INTERRUPT_DEFS_H_
+
+typedef struct {
+ EFI_SYSTEM_CONTEXT_IA32 SystemContext;
+ BOOLEAN ExceptionDataFlag;
+ UINTN OldIdtHandler;
+} EXCEPTION_HANDLER_CONTEXT;
+
+//
+// Register Structure Definitions
+//
+typedef struct {
+ EFI_STATUS_CODE_DATA Header;
+ EFI_SYSTEM_CONTEXT_IA32 SystemContext;
+} CPU_STATUS_CODE_TEMPLATE;
+
+typedef struct {
+ SPIN_LOCK SpinLock;
+ UINT32 ApicId;
+ UINT32 Attribute;
+ UINTN ExceptonHandler;
+ UINTN OldFlags;
+ UINTN OldCs;
+ UINTN OldIp;
+ UINTN ExceptionData;
+ UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE];
+} RESERVED_VECTORS_DATA;
+
+#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S index b9e881a..92c8dca 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.S @@ -1,6 +1,6 @@ #------------------------------------------------------------------------------
#*
-#* Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+#* Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
#* This program and the accompanying materials
#* are licensed and made available under the terms and conditions of the BSD License
#* which accompanies this distribution. The full text of the license may be found at
@@ -18,16 +18,15 @@ #------------------------------------------------------------------------------
-
-
-
#.MMX
#.XMM
ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
+ASM_GLOBAL ASM_PFX(HookAfterStubEnd)
-#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
+#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
+#EXTRN ASM_PFX(mDoFarReturnFlag):DWORD # Do far return flag
.text
@@ -35,101 +34,250 @@ ASM_GLOBAL ASM_PFX(CommonInterruptEntry) # exception handler stub table
#
Exception0Handle:
- pushl $0
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 0
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception1Handle:
- pushl $1
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 1
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception2Handle:
- pushl $2
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 2
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception3Handle:
- pushl $3
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 3
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception4Handle:
- pushl $4
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 4
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception5Handle:
- pushl $5
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 5
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception6Handle:
- pushl $6
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 6
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception7Handle:
- pushl $7
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 7
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception8Handle:
- pushl $8
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 8
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception9Handle:
- pushl $9
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 9
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception10Handle:
- pushl $10
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 10
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception11Handle:
- pushl $11
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 11
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception12Handle:
- pushl $12
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 12
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception13Handle:
- pushl $13
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 13
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception14Handle:
- pushl $14
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 14
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception15Handle:
- pushl $15
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 15
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception16Handle:
- pushl $16
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 16
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception17Handle:
- pushl $17
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 17
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception18Handle:
- pushl $18
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 18
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception19Handle:
- pushl $19
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 19
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception20Handle:
- pushl $20
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 20
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception21Handle:
- pushl $21
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 21
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception22Handle:
- pushl $22
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 22
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception23Handle:
- pushl $23
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 23
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception24Handle:
- pushl $24
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 24
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception25Handle:
- pushl $25
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 25
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception26Handle:
- pushl $26
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 26
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception27Handle:
- pushl $27
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 27
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception28Handle:
- pushl $28
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 28
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception29Handle:
- pushl $29
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 29
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception30Handle:
- pushl $30
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 30
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
Exception31Handle:
- pushl $31
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 31
+ pushl %eax
+ .byte 0xB8
+ .long ASM_PFX(CommonInterruptEntry)
+ jmp *%eax
+
+HookAfterStubBegin:
+ .byte 0x6a # push
+VectorNum:
+ .byte 0 # 0 will be fixed
+ pushl %eax
+ .byte 0xB8 # movl ASM_PFX(HookAfterStubHeaderEnd), %eax
+ .long ASM_PFX(HookAfterStubHeaderEnd)
+ jmp *%eax
+ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
+HookAfterStubHeaderEnd:
+ popl %eax
+ subl $8, %esp # reserve room for filling exception data later
+ pushl 8(%esp)
+ xchgl (%esp), %ecx # get vector number
+ bt %ecx, ASM_PFX(mErrorCodeFlag)
+ jnc NoErrorData
+ pushl (%esp) # addition push if exception data needed
+NoErrorData:
+ xchg (%esp), %ecx # restore ecx
+ pushl %eax
#---------------------------------------;
# CommonInterruptEntry ;
@@ -139,19 +287,17 @@ Exception31Handle: ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
ASM_PFX(CommonInterruptEntry):
cli
+ popl %eax
#
# All interrupt handlers are invoked through interrupt gates, so
# IF flag automatically cleared at the entry point
#
#
- # Calculate vector number
- #
- # Get the return address of call, actually, it is the
- # address of vector number.
+ # Get vector number from top of stack
#
xchgl (%esp), %ecx
- andl $0x0FFFF, %ecx
+ andl $0x0FF, %ecx # Vector number should be less than 256
cmpl $32, %ecx # Intel reserved vector for exceptions?
jae NoErrorCode
bt %ecx, ASM_PFX(mErrorCodeFlag)
@@ -241,6 +387,10 @@ ErrorCodeAndVectorOnStack: andl $0x0fffffff0, %esp
subl $12, %esp
+ subl $8, %esp
+ pushl $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ pushl $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+
#; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pushl %eax
pushl %ecx
@@ -405,18 +555,41 @@ ErrorCodeAndVectorOnStack: popl %ecx
popl %eax
+ popl -8(%ebp)
+ popl -4(%ebp)
movl %ebp, %esp
popl %ebp
addl $8, %esp
+ cmpl $0, -16(%esp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn
+ cmpl $1, -20(%esp) # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ jz ErrorCode
+ jmp *-16(%esp)
+ErrorCode:
+ subl $4, %esp
+ jmp *-12(%esp)
+
+DoReturn:
+ cmpl $0, ASM_PFX(mDoFarReturnFlag)
+ jz DoIret
+ pushl 8(%esp) # save EFLAGS
+ addl $16, %esp
+ pushl -8(%esp) # save CS in new location
+ pushl -8(%esp) # save EIP in new location
+ pushl -8(%esp) # save EFLAGS in new location
+ popfl # restore EFLAGS
+ retf # far return
+
+DoIret:
iretl
#---------------------------------------;
-# _GetTemplateAddressMap ;
-#----------------------------------------------------------------------------;
+# _AsmGetTemplateAddressMap ;
+#---------------------------------------;
#
# Protocol prototype
-# GetTemplateAddressMap (
+# AsmGetTemplateAddressMap (
# EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
# );
#
@@ -443,8 +616,8 @@ ErrorCodeAndVectorOnStack: #-------------------------------------------------------------------------------------
# AsmGetAddressMap (&AddressMap);
#-------------------------------------------------------------------------------------
-ASM_GLOBAL ASM_PFX(GetTemplateAddressMap)
-ASM_PFX(GetTemplateAddressMap):
+ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
+ASM_PFX(AsmGetTemplateAddressMap):
pushl %ebp
movl %esp,%ebp
@@ -453,8 +626,17 @@ ASM_PFX(GetTemplateAddressMap): movl 0x8(%ebp), %ebx
movl $Exception0Handle, (%ebx)
movl $(Exception1Handle - Exception0Handle), 0x4(%ebx)
+ movl $(HookAfterStubBegin), 0x8(%ebx)
popal
popl %ebp
ret
-
+#-------------------------------------------------------------------------------------
+# AsmVectorNumFixup (*VectorBase, VectorNum);
+#-------------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
+ASM_PFX(AsmVectorNumFixup):
+ movl 8(%esp), %eax
+ movl 4(%esp), %ecx
+ movb %al, (VectorNum - HookAfterStubBegin)(%ecx)
+ ret
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm index 869f18d..74d4e89 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.asm @@ -1,5 +1,5 @@ ;------------------------------------------------------------------------------ ;
-; Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+; Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
@@ -30,133 +30,77 @@ CommonExceptionHandler PROTO C .data
-CommonEntryAddr DD CommonInterruptEntry
-
-EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
+EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
+EXTRN mDoFarReturnFlag:DWORD ; Do far return flag
.code
+ALIGN 8
+
;
; exception handler stub table
;
-Exception0Handle:
- push 0
- jmp dword ptr [CommonEntryAddr]
-Exception1Handle:
- push 1
- jmp dword ptr [CommonEntryAddr]
-Exception2Handle:
- push 2
- jmp dword ptr [CommonEntryAddr]
-Exception3Handle:
- push 3
- jmp dword ptr [CommonEntryAddr]
-Exception4Handle:
- push 4
- jmp dword ptr [CommonEntryAddr]
-Exception5Handle:
- push 5
- jmp dword ptr [CommonEntryAddr]
-Exception6Handle:
- push 6
- jmp dword ptr [CommonEntryAddr]
-Exception7Handle:
- push 7
- jmp dword ptr [CommonEntryAddr]
-Exception8Handle:
- push 8
- jmp dword ptr [CommonEntryAddr]
-Exception9Handle:
- push 9
- jmp dword ptr [CommonEntryAddr]
-Exception10Handle:
- push 10
- jmp dword ptr [CommonEntryAddr]
-Exception11Handle:
- push 11
- jmp dword ptr [CommonEntryAddr]
-Exception12Handle:
- push 12
- jmp dword ptr [CommonEntryAddr]
-Exception13Handle:
- push 13
- jmp dword ptr [CommonEntryAddr]
-Exception14Handle:
- push 14
- jmp dword ptr [CommonEntryAddr]
-Exception15Handle:
- push 15
- jmp dword ptr [CommonEntryAddr]
-Exception16Handle:
- push 16
- jmp dword ptr [CommonEntryAddr]
-Exception17Handle:
- push 17
- jmp dword ptr [CommonEntryAddr]
-Exception18Handle:
- push 18
- jmp dword ptr [CommonEntryAddr]
-Exception19Handle:
- push 19
- jmp dword ptr [CommonEntryAddr]
-Exception20Handle:
- push 20
- jmp dword ptr [CommonEntryAddr]
-Exception21Handle:
- push 21
- jmp dword ptr [CommonEntryAddr]
-Exception22Handle:
- push 22
- jmp dword ptr [CommonEntryAddr]
-Exception23Handle:
- push 23
- jmp dword ptr [CommonEntryAddr]
-Exception24Handle:
- push 24
- jmp dword ptr [CommonEntryAddr]
-Exception25Handle:
- push 25
- jmp dword ptr [CommonEntryAddr]
-Exception26Handle:
- push 26
- jmp dword ptr [CommonEntryAddr]
-Exception27Handle:
- push 27
- jmp dword ptr [CommonEntryAddr]
-Exception28Handle:
- push 28
- jmp dword ptr [CommonEntryAddr]
-Exception29Handle:
- push 29
- jmp dword ptr [CommonEntryAddr]
-Exception30Handle:
- push 30
- jmp dword ptr [CommonEntryAddr]
-Exception31Handle:
- push 31
- jmp dword ptr [CommonEntryAddr]
+AsmIdtVectorBegin:
+REPEAT 32
+ db 6ah ; push #VectorNum
+ db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
+ push eax
+ mov eax, CommonInterruptEntry
+ jmp eax
+ENDM
+AsmIdtVectorEnd:
+
+HookAfterStubBegin:
+ db 6ah ; push
+VectorNum:
+ db 0 ; 0 will be fixed
+ push eax
+ mov eax, HookAfterStubHeaderEnd
+ jmp eax
+HookAfterStubHeaderEnd:
+ pop eax
+ sub esp, 8 ; reserve room for filling exception data later
+ push [esp + 8]
+ xchg ecx, [esp] ; get vector number
+ bt mErrorCodeFlag, ecx
+ jnc @F
+ push [esp] ; addition push if exception data needed
+@@:
+ xchg ecx, [esp] ; restore ecx
+ push eax
;----------------------------------------------------------------------------;
; CommonInterruptEntry ;
;----------------------------------------------------------------------------;
; The follow algorithm is used for the common interrupt routine.
; Entry from each interrupt with a push eax and eax=interrupt number
-
+; Stack:
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
CommonInterruptEntry PROC PUBLIC
cli
+ pop eax
;
; All interrupt handlers are invoked through interrupt gates, so
; IF flag automatically cleared at the entry point
;
;
- ; Calculate vector number
- ;
- ; Get the return address of call, actually, it is the
- ; address of vector number.
+ ; Get vector number from top of stack
;
xchg ecx, [esp]
- and ecx, 0FFFFh
+ and ecx, 0FFh ; Vector number should be less than 256
cmp ecx, 32 ; Intel reserved vector for exceptions?
jae NoErrorCode
bt mErrorCodeFlag, ecx
@@ -246,6 +190,10 @@ ErrorCodeAndVectorOnStack: and esp, 0fffffff0h
sub esp, 12
+ sub esp, 8
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+
;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
push eax
push ecx
@@ -411,19 +359,42 @@ ErrorCodeAndVectorOnStack: pop ecx
pop eax
+ pop dword ptr [ebp - 8]
+ pop dword ptr [ebp - 4]
mov esp, ebp
pop ebp
add esp, 8
+ cmp dword ptr [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn
+ cmp dword ptr [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ jz ErrorCode
+ jmp dword ptr [esp - 16]
+ErrorCode:
+ sub esp, 4
+ jmp dword ptr [esp - 12]
+
+DoReturn:
+ cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET
+ jz DoIret
+ push [esp + 8] ; save EFLAGS
+ add esp, 16
+ push [esp - 8] ; save CS in new location
+ push [esp - 8] ; save EIP in new location
+ push [esp - 8] ; save EFLAGS in new location
+ popfd ; restore EFLAGS
+ retf ; far return
+
+DoIret:
iretd
CommonInterruptEntry ENDP
;---------------------------------------;
-; _GetTemplateAddressMap ;
+; _AsmGetTemplateAddressMap ;
;----------------------------------------------------------------------------;
;
; Protocol prototype
-; GetTemplateAddressMap (
+; AsmGetTemplateAddressMap (
; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
; );
;
@@ -447,18 +418,28 @@ CommonInterruptEntry ENDP ;
; Destroys: Nothing
;-----------------------------------------------------------------------------;
-GetTemplateAddressMap proc near public
+AsmGetTemplateAddressMap proc near public
push ebp ; C prolog
mov ebp, esp
pushad
- mov ebx, dword ptr [ebp+08h]
- mov dword ptr [ebx], Exception0Handle
- mov dword ptr [ebx+4h], Exception1Handle - Exception0Handle
+ mov ebx, dword ptr [ebp + 08h]
+ mov dword ptr [ebx], AsmIdtVectorBegin
+ mov dword ptr [ebx + 4h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
+ mov dword ptr [ebx + 8h], HookAfterStubBegin
popad
pop ebp
ret
-GetTemplateAddressMap ENDP
-
+AsmGetTemplateAddressMap ENDP
+
+;-------------------------------------------------------------------------------------
+; AsmVectorNumFixup (*VectorBase, VectorNum);
+;-------------------------------------------------------------------------------------
+AsmVectorNumFixup proc near public
+ mov eax, dword ptr [esp + 8]
+ mov ecx, [esp + 4]
+ mov [ecx + (VectorNum - HookAfterStubBegin)], al
+ ret
+AsmVectorNumFixup ENDP
END
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c index ebd9fe3..f2e7c81 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c @@ -1,7 +1,7 @@ /** @file
- CPU Exception Library provides SEC/PEIM CPU exception handler.
+ CPU exception handler library implemenation for SEC/PEIM modules.
-Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
@@ -18,7 +18,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. //
// Image Aglinment size for SEC/PEI phase
//
-CONST UINTN mImageAlignSize = 4;
+CONST UINTN mImageAlignSize = 4;
+CONST UINTN mDoFarReturnFlag = 0;
/**
Common exception handler.
@@ -45,19 +46,138 @@ CommonExceptionHandler ( }
/**
- Setup CPU exception handlers.
-
- This API will setups the CPU exception handler to display CPU contents and run into
- CpuDeadLoop().
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
Note: Before invoking this API, caller must allocate memory for IDT table and load
IDTR by AsmWriteIdtr().
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
**/
-VOID
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ RESERVED_VECTORS_DATA ReservedVectorData[CPU_EXCEPTION_NUM];
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN IdtEntryCount;
+ UINT16 CodeSegment;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ UINTN Index;
+ UINTN InterruptHandler;
+
+ if (VectorInfo != NULL) {
+ SetMem ((VOID *) ReservedVectorData, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);
+ Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectorData, CPU_EXCEPTION_NUM);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Read IDT descriptor and calculate IDT size
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
+ if (IdtEntryCount > CPU_EXCEPTION_NUM) {
+ //
+ // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
+ //
+ IdtEntryCount = CPU_EXCEPTION_NUM;
+ }
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ AsmGetTemplateAddressMap (&TemplateMap);
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
+ for (Index = 0; Index < IdtEntryCount; Index ++) {
+ IdtTable[Index].Bits.Selector = CodeSegment;
+ //
+ // Check reserved vectors attributes if has, only EFI_VECTOR_HANDOFF_DO_NOT_HOOK
+ // supported in this instance
+ //
+ if (VectorInfo != NULL) {
+ if (ReservedVectorData[Index].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {
+ continue;
+ }
+ }
+ //
+ // Update IDT entry
+ //
+ InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize;
+ ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
EFIAPI
-SetupCpuExceptionHandlers (
- IN VOID
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
)
{
- InternalSetupCpuExceptionHandlers ();
+ return EFI_UNSUPPORTED;
}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+*/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
\ No newline at end of file diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf index 96ddaaf..c855362 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf @@ -3,7 +3,7 @@ #
# This library instance supports SEC/PEI module only.
#
-# Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@@ -32,11 +32,13 @@ Ia32/ExceptionHandlerAsm.asm |MSFT
Ia32/ExceptionHandlerAsm.S |GCC
Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
[Sources.X64]
X64/ExceptionHandlerAsm.asm |MSFT
X64/ExceptionHandlerAsm.S |GCC
X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
[Sources.common]
CpuExceptionCommon.h
@@ -54,3 +56,7 @@ PrintLib
LocalApicLib
PeCoffGetEntryPointLib
+ ReportStatusCodeLib
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf new file mode 100644 index 0000000..bee0c46 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf @@ -0,0 +1,65 @@ +## @file
+# Component description file for SMM CPU Exception Handler Library instance.
+#
+# This library instance supports SMM module only.
+#
+# Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCpuExceptionHandlerLib
+ FILE_GUID = 8D2C439B-3981-42ff-9CE5-1B50ECA502D6
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.Ia32]
+ Ia32/ExceptionHandlerAsm.asm |MSFT
+ Ia32/ExceptionHandlerAsm.S |GCC
+ Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
+
+[Sources.X64]
+ X64/ExceptionHandlerAsm.asm |MSFT
+ X64/ExceptionHandlerAsm.S |GCC
+ X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
+
+[Sources.common]
+ CpuExceptionCommon.h
+ CpuExceptionCommon.c
+ DxeSmmCpuException.c
+ SmmException.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ SerialPortLib
+ PrintLib
+ SynchronizationLib
+ LocalApicLib
+ PeCoffGetEntryPointLib
+ ReportStatusCodeLib
+ DebugLib
+
+[Ppis]
+ gEfiVectorHandoffInfoPpiGuid
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c new file mode 100644 index 0000000..c3f4425 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c @@ -0,0 +1,101 @@ +/** @file
+ CPU exception handler library implemenation for SMM modules.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include "CpuExceptionCommon.h"
+
+CONST UINTN mDoFarReturnFlag = 1;
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return InitializeCpuExceptionHandlersWorker (VectorInfo);
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+*/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler);
+}
\ No newline at end of file diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c index 664472a..1af2999 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c @@ -1,7 +1,7 @@ /** @file
x64 CPU Exception Hanlder.
- Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -15,61 +15,102 @@ #include "CpuExceptionCommon.h"
/**
- Internal function to setup CPU exception handlers.
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+ @param IdtEntry Pointer to IDT entry to be updated.
+ @param InterruptHandler IDT handler value.
**/
VOID
-InternalSetupCpuExceptionHandlers (
- VOID
+ArchUpdateIdtEntry (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN UINTN InterruptHandler
)
{
- IA32_DESCRIPTOR IdtDescriptor;
- UINTN IdtSize;
- EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
- UINT16 CodeSegment;
- IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
- UINTN Index;
- UINTN InterruptHandler;
+ IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+}
+
+/**
+ Read IDT handler value from IDT entry.
+
+ @param IdtEntry Pointer to IDT entry to be read.
+
+**/
+UINTN
+ArchGetIdtHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ )
+{
+ return IdtEntry->Bits.OffsetLow + (((UINTN) IdtEntry->Bits.OffsetHigh) << 16) +
+ (((UINTN) IdtEntry->Bits.OffsetUpper) << 32);
+}
+/**
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+ArchSaveExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ IA32_EFLAGS32 Eflags;
//
- // Read IDT descriptor and calculate IDT size
+ // Save Exception context in global variable
//
- AsmReadIdtr (&IdtDescriptor);
- IdtSize = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
- if (IdtSize > CPU_EXCEPTION_NUM) {
- //
- // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
- //
- IdtSize = CPU_EXCEPTION_NUM;
- }
-
+ mReservedVectors[ExceptionType].OldSs = SystemContext.SystemContextX64->Ss;
+ mReservedVectors[ExceptionType].OldSp = SystemContext.SystemContextX64->Rsp;
+ mReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextX64->Rflags;
+ mReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextX64->Cs;
+ mReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextX64->Rip;
+ mReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;
//
- // Use current CS as the segment selector of interrupt gate in IDT
+ // Clear IF flag to avoid old IDT handler enable interrupt by IRET
//
- CodeSegment = AsmReadCs ();
- IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
-
- GetTemplateAddressMap (&TemplateMap);
-
- for (Index = 0; Index < IdtSize; Index ++) {
- InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize;
- IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
- IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
- IdtEntry[Index].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
- IdtEntry[Index].Bits.Selector = CodeSegment;
- IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
- }
+ Eflags.UintN = SystemContext.SystemContextX64->Rflags;
+ Eflags.Bits.IF = 0;
+ SystemContext.SystemContextX64->Rflags = Eflags.UintN;
+ //
+ // Modify the EIP in stack, then old IDT handler will return to the stub code
+ //
+ SystemContext.SystemContextX64->Rip = (UINTN) mReservedVectors[ExceptionType].HookAfterStubHeaderCode;
}
/**
- Common exception handler.
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
@param ExceptionType Exception type.
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
**/
VOID
-DumpCpuContent (
+ArchRestoreExceptionContext (
IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ SystemContext.SystemContextX64->Ss = mReservedVectors[ExceptionType].OldSs;
+ SystemContext.SystemContextX64->Rsp = mReservedVectors[ExceptionType].OldSp;
+ SystemContext.SystemContextX64->Rflags = mReservedVectors[ExceptionType].OldFlags;
+ SystemContext.SystemContextX64->Cs = mReservedVectors[ExceptionType].OldCs;
+ SystemContext.SystemContextX64->Rip = mReservedVectors[ExceptionType].OldIp;
+ SystemContext.SystemContextX64->ExceptionData = mReservedVectors[ExceptionType].ExceptionData;
+}
+
+/**
+ Dump CPU content information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+DumpCpuContent (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h new file mode 100644 index 0000000..9064801 --- /dev/null +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h @@ -0,0 +1,46 @@ +/** @file
+ X64 arch definition for CPU Exception Handler Library.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ARCH_CPU_INTERRUPT_DEFS_H_
+#define _ARCH_CPU_INTERRUPT_DEFS_H_
+
+typedef struct {
+ EFI_SYSTEM_CONTEXT_X64 SystemContext;
+ BOOLEAN ExceptionDataFlag;
+ UINTN OldIdtHandler;
+} EXCEPTION_HANDLER_CONTEXT;
+
+//
+// Register Structure Definitions
+//
+typedef struct {
+ EFI_STATUS_CODE_DATA Header;
+ EFI_SYSTEM_CONTEXT_X64 SystemContext;
+} CPU_STATUS_CODE_TEMPLATE;
+
+typedef struct {
+ SPIN_LOCK SpinLock;
+ UINT32 ApicId;
+ UINT32 Attribute;
+ UINTN ExceptonHandler;
+ UINTN OldSs;
+ UINTN OldSp;
+ UINTN OldFlags;
+ UINTN OldCs;
+ UINTN OldIp;
+ UINTN ExceptionData;
+ UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE];
+} RESERVED_VECTORS_DATA;
+
+#endif
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S index cd10147..7d5672f 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.S @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ ;
-# Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@@ -21,114 +21,264 @@ #------------------------------------------------------------------------------
-#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
+ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
-
+#EXTRN ASM_PFX(mErrorCodeFlag):DWORD # Error code flags for exceptions
+#EXTRN ASM_PFX(mDoFarReturnFlag):QWORD # Do far return flag
.text
#
-# point to the external interrupt vector table
+# exception handler stub table
#
Exception0Handle:
- pushq $0
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 0
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception1Handle:
- pushq $1
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 1
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception2Handle:
- pushq $2
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 2
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception3Handle:
- pushq $3
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 3
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception4Handle:
- pushq $4
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 4
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception5Handle:
- pushq $5
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 5
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception6Handle:
- pushq $6
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 6
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception7Handle:
- pushq $7
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 7
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception8Handle:
- pushq $8
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 8
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception9Handle:
- pushq $9
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 9
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception10Handle:
- pushq $10
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 10
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception11Handle:
- pushq $11
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 11
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception12Handle:
- pushq $12
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 12
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception13Handle:
- pushq $13
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 13
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception14Handle:
- pushq $14
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 14
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception15Handle:
- pushq $15
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 15
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception16Handle:
- pushq $16
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 16
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception17Handle:
- pushq $17
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 17
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception18Handle:
- pushq $18
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 18
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception19Handle:
- pushq $19
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 19
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception20Handle:
- pushq $20
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 20
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception21Handle:
- pushq $21
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 21
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception22Handle:
- pushq $22
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 22
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception23Handle:
- pushq $23
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 23
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception24Handle:
- pushq $24
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 24
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception25Handle:
- pushq $25
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 25
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception26Handle:
- pushq $26
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 26
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception27Handle:
- pushq $27
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 27
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception28Handle:
- pushq $28
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 28
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception29Handle:
- pushq $29
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 29
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception30Handle:
- pushq $30
- jmp ASM_PFX(CommonInterruptEntry)
+ .byte 0x6a # push #VectorNum
+ .byte 30
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
Exception31Handle:
- pushq $31
- jmp ASM_PFX(CommonInterruptEntry)
-
+ .byte 0x6a # push #VectorNum
+ .byte 31
+ pushq %rax
+ .byte 0x48, 0xB8
+ .quad ASM_PFX(CommonInterruptEntry)
+ jmp *%rax
+
+HookAfterStubHeaderBegin:
+ .byte 0x6a # push
+VectorNum:
+ .byte 0 # 0 will be fixed
+ pushq %rax
+ .byte 0x48, 0xB8 # movq ASM_PFX(HookAfterStubHeaderEnd), %rax
+ .quad ASM_PFX(HookAfterStubHeaderEnd)
+ jmp *%rax
+ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
+ASM_PFX(HookAfterStubHeaderEnd):
+ movq %rsp, %rax
+ subq $8, %rsp
+ andl $0x0fffffff0, %esp
+ pushq %rcx
+ movq 8(%rax), %rcx
+ bt %ecx, ASM_PFX(mErrorCodeFlag)
+ jc NoErrorData
+ pushq (%rsp) # push additional rcx to make stack alignment
+NoErrorData:
+ xchgq (%rsp), %rcx # restore rcx, save Exception Number in stack
+ pushq (%rax) # push rax into stack to keep code consistence
#---------------------------------------;
# CommonInterruptEntry ;
@@ -138,6 +288,7 @@ Exception31Handle: ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
ASM_PFX(CommonInterruptEntry):
cli
+ popq %rax
#
# All interrupt handlers are invoked through interrupt gates, so
# IF flag automatically cleared at the entry point
@@ -145,7 +296,8 @@ ASM_PFX(CommonInterruptEntry): #
# Calculate vector number
#
- xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
+ xchgq (%rsp), %rcx # get the return address of call, actually, it is the address of vector number.
+ andq $0x0FF, %rcx
cmp $32, %ecx # Intel reserved vector for exceptions?
jae NoErrorCode
pushq %rax
@@ -165,6 +317,8 @@ NoErrorCode: CommonInterruptEntry_al_0000:
pushq %rbp
movq %rsp, %rbp
+ pushq $0 # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ pushq $0 # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
#
# Stack:
@@ -385,20 +539,53 @@ CommonInterruptEntry_al_0000: movq %rbp, %rsp
popq %rbp
addq $16, %rsp
+ cmpq $0, -32(%rsp) # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ cmpb $1, -40(%rsp)
+ jz ErrorCode
+ jmp *-32(%rsp)
+ErrorCode:
+ subq $8, %rsp
+ jmp *-24(%rsp)
+
+DoReturn:
+ cmpq $0, ASM_PFX(mDoFarReturnFlag) # Check if need to do far return instead of IRET
+ jz DoIret
+ pushq %rax
+ movq %rsp, %rax # save old RSP to rax
+ movq 0x20(%rsp), %rsp
+ pushq 0x10(%rax) # save CS in new location
+ pushq 0x8(%rax) # save EIP in new location
+ pushq 0x18(%rax) # save EFLAGS in new location
+ movq (%rax), %rax # restore rax
+ popfq # restore EFLAGS
+ .byte 0x48 # prefix to composite "retq" with next "retf"
+ retf # far return
+DoIret:
iretq
#-------------------------------------------------------------------------------------
-# AsmGetAddressMap (&AddressMap);
+# AsmGetTemplateAddressMap (&AddressMap);
#-------------------------------------------------------------------------------------
# comments here for definition of address map
-ASM_GLOBAL ASM_PFX(GetTemplateAddressMap)
-ASM_PFX(GetTemplateAddressMap):
+ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
+ASM_PFX(AsmGetTemplateAddressMap):
movabsq $Exception0Handle, %rax
movq %rax, (%rcx)
movq $(Exception1Handle - Exception0Handle), 0x08(%rcx)
+ movabsq $HookAfterStubHeaderBegin, %rax
+ movq %rax, 0x10(%rcx)
+ ret
+#-------------------------------------------------------------------------------------
+# AsmVectorNumFixup (*VectorBase, VectorNum);
+#-------------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
+ASM_PFX(AsmVectorNumFixup):
+ movq %rdx, %rax
+ movb %al, (VectorNum - HookAfterStubHeaderBegin)(%rcx)
ret
#END
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm index 2cc78db..f348efe 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm @@ -25,133 +25,79 @@ ;
externdef CommonExceptionHandler:near
-EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
+EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
+EXTRN mDoFarReturnFlag:QWORD ; Do far return flag
data SEGMENT
-CommonEntryAddr dq CommonInterruptEntry;
-
.code
-Exception0Handle:
- push 0
- jmp qword ptr [CommonEntryAddr]
-Exception1Handle:
- push 1
- jmp qword ptr [CommonEntryAddr]
-Exception2Handle:
- push 2
- jmp qword ptr [CommonEntryAddr]
-Exception3Handle:
- push 3
- jmp qword ptr [CommonEntryAddr]
-Exception4Handle:
- push 4
- jmp qword ptr [CommonEntryAddr]
-Exception5Handle:
- push 5
- jmp qword ptr [CommonEntryAddr]
-Exception6Handle:
- push 6
- jmp qword ptr [CommonEntryAddr]
-Exception7Handle:
- push 7
- jmp qword ptr [CommonEntryAddr]
-Exception8Handle:
- push 8
- jmp qword ptr [CommonEntryAddr]
-Exception9Handle:
- push 9
- jmp qword ptr [CommonEntryAddr]
-Exception10Handle:
- push 10
- jmp qword ptr [CommonEntryAddr]
-Exception11Handle:
- push 11
- jmp qword ptr [CommonEntryAddr]
-Exception12Handle:
- push 12
- jmp qword ptr [CommonEntryAddr]
-Exception13Handle:
- push 13
- jmp qword ptr [CommonEntryAddr]
-Exception14Handle:
- push 14
- jmp qword ptr [CommonEntryAddr]
-Exception15Handle:
- push 15
- jmp qword ptr [CommonEntryAddr]
-Exception16Handle:
- push 16
- jmp qword ptr [CommonEntryAddr]
-Exception17Handle:
- push 17
- jmp qword ptr [CommonEntryAddr]
-Exception18Handle:
- push 18
- jmp qword ptr [CommonEntryAddr]
-Exception19Handle:
- push 19
- jmp qword ptr [CommonEntryAddr]
-Exception20Handle:
- push 20
- jmp qword ptr [CommonEntryAddr]
-Exception21Handle:
- push 21
- jmp qword ptr [CommonEntryAddr]
-Exception22Handle:
- push 22
- jmp qword ptr [CommonEntryAddr]
-Exception23Handle:
- push 23
- jmp qword ptr [CommonEntryAddr]
-Exception24Handle:
- push 24
- jmp qword ptr [CommonEntryAddr]
-Exception25Handle:
- push 25
- jmp qword ptr [CommonEntryAddr]
-Exception26Handle:
- push 26
- jmp qword ptr [CommonEntryAddr]
-Exception27Handle:
- push 27
- jmp qword ptr [CommonEntryAddr]
-Exception28Handle:
- push 28
- jmp qword ptr [CommonEntryAddr]
-Exception29Handle:
- push 29
- jmp qword ptr [CommonEntryAddr]
-Exception30Handle:
- push 30
- jmp qword ptr [CommonEntryAddr]
-Exception31Handle:
- push 31
- jmp qword ptr [CommonEntryAddr]
-
-;CommonInterruptEntrypoint:
-;---------------------------------------;
-; _CommonEntry ;
-;----------------------------------------------------------------------------;
-; The follow algorithm is used for the common interrupt routine.
-; Entry from each interrupt with a push eax and eax=interrupt number
+ALIGN 8
+
+AsmIdtVectorBegin:
+REPEAT 32
+ db 6ah ; push #VectorNum
+ db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
+ push rax
+ mov rax, CommonInterruptEntry
+ jmp rax
+ENDM
+AsmIdtVectorEnd:
+
+HookAfterStubHeaderBegin:
+ db 6ah ; push
+@VectorNum:
+ db 0 ; 0 will be fixed
+ push rax
+ mov rax, HookAfterStubHeaderEnd
+ jmp rax
+HookAfterStubHeaderEnd:
+ mov rax, rsp
+ sub rsp, 8h
+ and sp, 0fff0h
+ push rcx
+ mov rcx, [rax + 8]
+ bt mErrorCodeFlag, ecx
+ jc @F
+ push [rsp] ; push additional rcx to make stack alignment
+@@:
+ xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
+ push [rax] ; push rax into stack to keep code consistence
;---------------------------------------;
; CommonInterruptEntry ;
;---------------------------------------;
; The follow algorithm is used for the common interrupt routine.
-
+; Entry from each interrupt with a push eax and eax=interrupt number
+; Stack frame would be as follows as specified in IA32 manuals:
+;
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + RBP +
+; +---------------------+ <-- RBP, 16-byte aligned
+; The follow algorithm is used for the common interrupt routine.
CommonInterruptEntry PROC PUBLIC
cli
+ pop rax
;
; All interrupt handlers are invoked through interrupt gates, so
; IF flag automatically cleared at the entry point
;
- ;
- ; Calculate vector number
- ;
- xchg rcx, [rsp] ; get the return address of call, actually, it is the address of vector number.
+ xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
+ and rcx, 0FFh
cmp ecx, 32 ; Intel reserved vector for exceptions?
jae NoErrorCode
bt mErrorCodeFlag, ecx
@@ -168,6 +114,8 @@ NoErrorCode: @@:
push rbp
mov rbp, rsp
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
;
; Stack:
@@ -389,6 +337,29 @@ NoErrorCode: mov rsp, rbp
pop rbp
add rsp, 16
+ cmp qword ptr [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn
+ cmp qword ptr [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ jz ErrorCode
+ jmp qword ptr [rsp - 32]
+ErrorCode:
+ sub rsp, 8
+ jmp qword ptr [rsp - 24]
+
+DoReturn:
+ cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET
+ jz DoIret
+ push rax
+ mov rax, rsp ; save old RSP to rax
+ mov rsp, [rsp + 20h]
+ push [rax + 10h] ; save CS in new location
+ push [rax + 8h] ; save EIP in new location
+ push [rax + 18h] ; save EFLAGS in new location
+ mov rax, [rax] ; restore rax
+ popfq ; restore EFLAGS
+ DB 48h ; prefix to composite "retq" with next "retf"
+ retf ; far return
+DoIret:
iretq
CommonInterruptEntry ENDP
@@ -397,11 +368,22 @@ CommonInterruptEntry ENDP ; GetTemplateAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
; comments here for definition of address map
-GetTemplateAddressMap PROC
- mov rax, offset Exception0Handle
- mov qword ptr [rcx], rax
- mov qword ptr [rcx+8h], Exception1Handle - Exception0Handle
- ret
-GetTemplateAddressMap ENDP
+AsmGetTemplateAddressMap PROC
+ mov rax, offset AsmIdtVectorBegin
+ mov qword ptr [rcx], rax
+ mov qword ptr [rcx + 8h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
+ mov rax, offset HookAfterStubHeaderBegin
+ mov qword ptr [rcx + 10h], rax
+ ret
+AsmGetTemplateAddressMap ENDP
+
+;-------------------------------------------------------------------------------------
+; AsmVectorNumFixup (*VectorBase, VectorNum);
+;-------------------------------------------------------------------------------------
+AsmVectorNumFixup PROC
+ mov rax, rdx
+ mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
+ ret
+AsmVectorNumFixup ENDP
END
|