2 CPU Exception Library provides DXE/SMM CPU common exception handler.
4 Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "CpuExceptionCommon.h"
16 #include <Library/DebugLib.h>
19 // Spinlock for CPU information display
21 SPIN_LOCK mDisplayMessageSpinLock
;
24 // Image align size for DXE/SMM
26 CONST UINTN mImageAlignSize
= SIZE_4KB
;
28 RESERVED_VECTORS_DATA mReservedVectorsData
[CPU_EXCEPTION_NUM
];
29 EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable
[CPU_EXCEPTION_NUM
];
30 EFI_CPU_INTERRUPT_HANDLER
*mExternalInterruptHandler
= NULL
;
31 UINTN mEnabledInterruptNum
= 0;
34 Common exception handler.
36 @param ExceptionType Exception type.
37 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
41 CommonExceptionHandler (
42 IN EFI_EXCEPTION_TYPE ExceptionType
,
43 IN EFI_SYSTEM_CONTEXT SystemContext
46 EXCEPTION_HANDLER_CONTEXT
*ExceptionHandlerContext
;
48 ExceptionHandlerContext
= (EXCEPTION_HANDLER_CONTEXT
*) (UINTN
) (SystemContext
.SystemContextIa32
);
50 switch (mReservedVectors
[ExceptionType
].Attribute
) {
51 case EFI_VECTOR_HANDOFF_HOOK_BEFORE
:
53 // Need to jmp to old IDT handler after this exception handler
55 ExceptionHandlerContext
->ExceptionDataFlag
= (mErrorCodeFlag
& (1 << ExceptionType
)) ? TRUE
: FALSE
;
56 ExceptionHandlerContext
->OldIdtHandler
= mReservedVectors
[ExceptionType
].ExceptonHandler
;
58 case EFI_VECTOR_HANDOFF_HOOK_AFTER
:
61 // If if anyone has gotten SPIN_LOCK for owner running hook after
63 if (AcquireSpinLockOrFail (&mReservedVectors
[ExceptionType
].SpinLock
)) {
65 // Need to execute old IDT handler before running this exception handler
67 mReservedVectors
[ExceptionType
].ApicId
= GetApicId ();
68 ArchSaveExceptionContext (ExceptionType
, SystemContext
);
69 ExceptionHandlerContext
->ExceptionDataFlag
= (mErrorCodeFlag
& (1 << ExceptionType
)) ? TRUE
: FALSE
;
70 ExceptionHandlerContext
->OldIdtHandler
= mReservedVectors
[ExceptionType
].ExceptonHandler
;
74 // If failed to acquire SPIN_LOCK, check if it was locked by processor itself
76 if (mReservedVectors
[ExceptionType
].ApicId
== GetApicId ()) {
78 // Old IDT handler has been executed, then retore CPU exception content to
79 // run new exception handler.
81 ArchRestoreExceptionContext (ExceptionType
, SystemContext
);
83 // Rlease spin lock for ApicId
85 ReleaseSpinLock (&mReservedVectors
[ExceptionType
].SpinLock
);
95 // It should never reach here
101 if (mExternalInterruptHandler
[ExceptionType
] != NULL
) {
102 (mExternalInterruptHandler
[ExceptionType
]) (ExceptionType
, SystemContext
);
103 } else if (ExceptionType
< CPU_EXCEPTION_NUM
) {
105 // Get Spinlock to display CPU information
107 while (!AcquireSpinLockOrFail (&mDisplayMessageSpinLock
)) {
111 // Display ExceptionType, CPU information and Image information
113 DumpCpuContent (ExceptionType
, SystemContext
);
115 // Release Spinlock of output message
117 ReleaseSpinLock (&mDisplayMessageSpinLock
);
119 // Enter a dead loop if needn't to execute old IDT handler further
121 if (mReservedVectors
[ExceptionType
].Attribute
!= EFI_VECTOR_HANDOFF_HOOK_BEFORE
) {
128 Internal worker function to update IDT entries accordling to vector attributes.
130 @param[in] IdtTable Pointer to IDT table.
131 @param[in] TemplateMap Pointer to a buffer where the address map is returned.
132 @param[in] IdtEntryCount IDT entries number to be updated.
137 IN IA32_IDT_GATE_DESCRIPTOR
*IdtTable
,
138 IN EXCEPTION_HANDLER_TEMPLATE_MAP
*TemplateMap
,
139 IN UINTN IdtEntryCount
144 UINTN InterruptHandler
;
147 // Use current CS as the segment selector of interrupt gate in IDT
149 CodeSegment
= AsmReadCs ();
151 for (Index
= 0; Index
< IdtEntryCount
; Index
++) {
152 IdtTable
[Index
].Bits
.Selector
= CodeSegment
;
154 // Check reserved vectors attributes
156 switch (mReservedVectors
[Index
].Attribute
) {
157 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK
:
159 // Keep original IDT entry
162 case EFI_VECTOR_HANDOFF_HOOK_AFTER
:
163 InitializeSpinLock (&mReservedVectors
[Index
].SpinLock
);
165 (VOID
*) mReservedVectors
[Index
].HookAfterStubHeaderCode
,
166 (VOID
*) TemplateMap
->HookAfterStubHeaderStart
,
167 TemplateMap
->ExceptionStubHeaderSize
170 (VOID
*) mReservedVectors
[Index
].HookAfterStubHeaderCode
,
172 (VOID
*) TemplateMap
->HookAfterStubHeaderStart
175 // Go on the following code
177 case EFI_VECTOR_HANDOFF_HOOK_BEFORE
:
179 // Save original IDT handler address
181 mReservedVectors
[Index
].ExceptonHandler
= ArchGetIdtHandler (&IdtTable
[Index
]);
183 // Go on the following code
187 // Update new IDT entry
189 InterruptHandler
= TemplateMap
->ExceptionStart
+ Index
* TemplateMap
->ExceptionStubHeaderSize
;
190 ArchUpdateIdtEntry (&IdtTable
[Index
], InterruptHandler
);
196 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()
198 mEnabledInterruptNum
= IdtEntryCount
;
202 Internal worker function to initialize exception handler.
204 @param[in] VectorInfo Pointer to reserved vector list.
206 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
207 with default exception handlers.
208 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
209 @retval EFI_UNSUPPORTED This function is not supported.
213 InitializeCpuExceptionHandlersWorker (
214 IN EFI_VECTOR_HANDOFF_INFO
*VectorInfo OPTIONAL
218 IA32_DESCRIPTOR IdtDescriptor
;
220 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap
;
221 IA32_IDT_GATE_DESCRIPTOR
*IdtTable
;
223 mReservedVectors
= mReservedVectorsData
;
224 SetMem ((VOID
*) mReservedVectors
, sizeof (RESERVED_VECTORS_DATA
) * CPU_EXCEPTION_NUM
, 0xff);
225 if (VectorInfo
!= NULL
) {
226 Status
= ReadAndVerifyVectorInfo (VectorInfo
, mReservedVectors
, CPU_EXCEPTION_NUM
);
227 if (EFI_ERROR (Status
)) {
228 return EFI_INVALID_PARAMETER
;
231 InitializeSpinLock (&mDisplayMessageSpinLock
);
233 mExternalInterruptHandler
= mExternalInterruptHandlerTable
;
235 // Read IDT descriptor and calculate IDT size
237 AsmReadIdtr (&IdtDescriptor
);
238 IdtEntryCount
= (IdtDescriptor
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
);
239 if (IdtEntryCount
> CPU_EXCEPTION_NUM
) {
241 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
243 IdtEntryCount
= CPU_EXCEPTION_NUM
;
246 IdtTable
= (IA32_IDT_GATE_DESCRIPTOR
*) IdtDescriptor
.Base
;
247 AsmGetTemplateAddressMap (&TemplateMap
);
248 ASSERT (TemplateMap
.ExceptionStubHeaderSize
<= HOOKAFTER_STUB_SIZE
);
249 UpdateIdtTable (IdtTable
, &TemplateMap
, IdtEntryCount
);
250 mEnabledInterruptNum
= IdtEntryCount
;
255 Registers a function to be called from the processor interrupt handler.
257 @param[in] InterruptType Defines which interrupt or exception to hook.
258 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
259 when a processor interrupt occurs. If this parameter is NULL, then the handler
262 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
263 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
264 previously installed.
265 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
266 previously installed.
267 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
268 or this function is not supported.
271 RegisterCpuInterruptHandlerWorker (
272 IN EFI_EXCEPTION_TYPE InterruptType
,
273 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
276 if (InterruptType
< 0 || InterruptType
>= (EFI_EXCEPTION_TYPE
)mEnabledInterruptNum
||
277 mReservedVectors
[InterruptType
].Attribute
== EFI_VECTOR_HANDOFF_DO_NOT_HOOK
) {
278 return EFI_UNSUPPORTED
;
281 if (InterruptHandler
== NULL
&& mExternalInterruptHandler
[InterruptType
] == NULL
) {
282 return EFI_INVALID_PARAMETER
;
285 if (InterruptHandler
!= NULL
&& mExternalInterruptHandler
[InterruptType
] != NULL
) {
286 return EFI_ALREADY_STARTED
;
289 mExternalInterruptHandler
[InterruptType
] = InterruptHandler
;