2 CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.
4 Copyright (c) 2012 - 2016, 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>
20 // Image align size for DXE/SMM
22 CONST UINTN mImageAlignSize
= SIZE_4KB
;
24 RESERVED_VECTORS_DATA mReservedVectorsData
[CPU_EXCEPTION_NUM
];
25 EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable
[CPU_EXCEPTION_NUM
];
26 EFI_CPU_INTERRUPT_HANDLER
*mExternalInterruptHandler
= NULL
;
27 UINTN mEnabledInterruptNum
= 0;
30 Internal worker function for common exception handler.
32 @param ExceptionType Exception type.
33 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
34 @param ExceptionHandlerData Pointer to exception handler data.
37 CommonExceptionHandlerWorker (
38 IN EFI_EXCEPTION_TYPE ExceptionType
,
39 IN EFI_SYSTEM_CONTEXT SystemContext
,
40 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
43 EXCEPTION_HANDLER_CONTEXT
*ExceptionHandlerContext
;
44 RESERVED_VECTORS_DATA
*ReservedVectors
;
45 EFI_CPU_INTERRUPT_HANDLER
*ExternalInterruptHandler
;
47 ExceptionHandlerContext
= (EXCEPTION_HANDLER_CONTEXT
*) (UINTN
) (SystemContext
.SystemContextIa32
);
48 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
49 ExternalInterruptHandler
= ExceptionHandlerData
->ExternalInterruptHandler
;
51 switch (ReservedVectors
[ExceptionType
].Attribute
) {
52 case EFI_VECTOR_HANDOFF_HOOK_BEFORE
:
54 // Need to jmp to old IDT handler after this exception handler
56 ExceptionHandlerContext
->ExceptionDataFlag
= (mErrorCodeFlag
& (1 << ExceptionType
)) ? TRUE
: FALSE
;
57 ExceptionHandlerContext
->OldIdtHandler
= ReservedVectors
[ExceptionType
].ExceptonHandler
;
59 case EFI_VECTOR_HANDOFF_HOOK_AFTER
:
62 // If if anyone has gotten SPIN_LOCK for owner running hook after
64 if (AcquireSpinLockOrFail (&ReservedVectors
[ExceptionType
].SpinLock
)) {
66 // Need to execute old IDT handler before running this exception handler
68 ReservedVectors
[ExceptionType
].ApicId
= GetApicId ();
69 ArchSaveExceptionContext (ExceptionType
, SystemContext
);
70 ExceptionHandlerContext
->ExceptionDataFlag
= (mErrorCodeFlag
& (1 << ExceptionType
)) ? TRUE
: FALSE
;
71 ExceptionHandlerContext
->OldIdtHandler
= ReservedVectors
[ExceptionType
].ExceptonHandler
;
75 // If failed to acquire SPIN_LOCK, check if it was locked by processor itself
77 if (ReservedVectors
[ExceptionType
].ApicId
== GetApicId ()) {
79 // Old IDT handler has been executed, then retore CPU exception content to
80 // run new exception handler.
82 ArchRestoreExceptionContext (ExceptionType
, SystemContext
);
84 // Rlease spin lock for ApicId
86 ReleaseSpinLock (&ReservedVectors
[ExceptionType
].SpinLock
);
96 // It should never reach here
102 if (ExternalInterruptHandler
!= NULL
&&
103 ExternalInterruptHandler
[ExceptionType
] != NULL
) {
104 (ExternalInterruptHandler
[ExceptionType
]) (ExceptionType
, SystemContext
);
105 } else if (ExceptionType
< CPU_EXCEPTION_NUM
) {
107 // Get Spinlock to display CPU information
109 while (!AcquireSpinLockOrFail (&ExceptionHandlerData
->DisplayMessageSpinLock
)) {
113 // Display ExceptionType, CPU information and Image information
115 DumpCpuContent (ExceptionType
, SystemContext
);
117 // Release Spinlock of output message
119 ReleaseSpinLock (&ExceptionHandlerData
->DisplayMessageSpinLock
);
121 // Enter a dead loop if needn't to execute old IDT handler further
123 if (ReservedVectors
[ExceptionType
].Attribute
!= EFI_VECTOR_HANDOFF_HOOK_BEFORE
) {
130 Internal worker function to update IDT entries accordling to vector attributes.
132 @param[in] IdtTable Pointer to IDT table.
133 @param[in] TemplateMap Pointer to a buffer where the address map is
135 @param[in] ExceptionHandlerData Pointer to exception handler data.
140 IN IA32_IDT_GATE_DESCRIPTOR
*IdtTable
,
141 IN EXCEPTION_HANDLER_TEMPLATE_MAP
*TemplateMap
,
142 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
147 UINTN InterruptHandler
;
148 RESERVED_VECTORS_DATA
*ReservedVectors
;
150 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
152 // Use current CS as the segment selector of interrupt gate in IDT
154 CodeSegment
= AsmReadCs ();
156 for (Index
= 0; Index
< ExceptionHandlerData
->IdtEntryCount
; Index
++) {
157 IdtTable
[Index
].Bits
.Selector
= CodeSegment
;
159 // Check reserved vectors attributes
161 switch (ReservedVectors
[Index
].Attribute
) {
162 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK
:
164 // Keep original IDT entry
167 case EFI_VECTOR_HANDOFF_HOOK_AFTER
:
168 InitializeSpinLock (&ReservedVectors
[Index
].SpinLock
);
170 (VOID
*) ReservedVectors
[Index
].HookAfterStubHeaderCode
,
171 (VOID
*) TemplateMap
->HookAfterStubHeaderStart
,
172 TemplateMap
->ExceptionStubHeaderSize
175 (VOID
*) ReservedVectors
[Index
].HookAfterStubHeaderCode
,
177 (VOID
*) TemplateMap
->HookAfterStubHeaderStart
180 // Go on the following code
182 case EFI_VECTOR_HANDOFF_HOOK_BEFORE
:
184 // Save original IDT handler address
186 ReservedVectors
[Index
].ExceptonHandler
= ArchGetIdtHandler (&IdtTable
[Index
]);
188 // Go on the following code
192 // Update new IDT entry
194 InterruptHandler
= TemplateMap
->ExceptionStart
+ Index
* TemplateMap
->ExceptionStubHeaderSize
;
195 ArchUpdateIdtEntry (&IdtTable
[Index
], InterruptHandler
);
201 // Save Interrupt number to global variable used for RegisterCpuInterruptHandler ()
203 mEnabledInterruptNum
= ExceptionHandlerData
->IdtEntryCount
;
207 Internal worker function to initialize exception handler.
209 @param[in] VectorInfo Pointer to reserved vector list.
210 @param[in, out] ExceptionHandlerData Pointer to exception handler data.
212 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
213 with default exception handlers.
214 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
215 @retval EFI_UNSUPPORTED This function is not supported.
219 InitializeCpuExceptionHandlersWorker (
220 IN EFI_VECTOR_HANDOFF_INFO
*VectorInfo OPTIONAL
,
221 IN OUT EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
225 IA32_DESCRIPTOR IdtDescriptor
;
227 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap
;
228 IA32_IDT_GATE_DESCRIPTOR
*IdtTable
;
229 RESERVED_VECTORS_DATA
*ReservedVectors
;
231 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
232 SetMem ((VOID
*) ReservedVectors
, sizeof (RESERVED_VECTORS_DATA
) * CPU_EXCEPTION_NUM
, 0xff);
233 if (VectorInfo
!= NULL
) {
234 Status
= ReadAndVerifyVectorInfo (VectorInfo
, ReservedVectors
, CPU_EXCEPTION_NUM
);
235 if (EFI_ERROR (Status
)) {
236 return EFI_INVALID_PARAMETER
;
240 mExternalInterruptHandler
= mExternalInterruptHandlerTable
;
242 // Read IDT descriptor and calculate IDT size
244 AsmReadIdtr (&IdtDescriptor
);
245 IdtEntryCount
= (IdtDescriptor
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
);
246 if (IdtEntryCount
> CPU_EXCEPTION_NUM
) {
248 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
250 IdtEntryCount
= CPU_EXCEPTION_NUM
;
253 IdtTable
= (IA32_IDT_GATE_DESCRIPTOR
*) IdtDescriptor
.Base
;
254 AsmGetTemplateAddressMap (&TemplateMap
);
255 ASSERT (TemplateMap
.ExceptionStubHeaderSize
<= HOOKAFTER_STUB_SIZE
);
257 ExceptionHandlerData
->IdtEntryCount
= IdtEntryCount
;
258 UpdateIdtTable (IdtTable
, &TemplateMap
, ExceptionHandlerData
);
259 mEnabledInterruptNum
= IdtEntryCount
;
264 Registers a function to be called from the processor interrupt handler.
266 @param[in] InterruptType Defines which interrupt or exception to hook.
267 @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
268 when a processor interrupt occurs. If this parameter is NULL, then the handler
270 @param[in] ExceptionHandlerData Pointer to exception handler data.
272 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
273 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
274 previously installed.
275 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
276 previously installed.
277 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
278 or this function is not supported.
281 RegisterCpuInterruptHandlerWorker (
282 IN EFI_EXCEPTION_TYPE InterruptType
,
283 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
,
284 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
287 UINTN EnabledInterruptNum
;
288 RESERVED_VECTORS_DATA
*ReservedVectors
;
289 EFI_CPU_INTERRUPT_HANDLER
*ExternalInterruptHandler
;
291 EnabledInterruptNum
= ExceptionHandlerData
->IdtEntryCount
;
292 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
293 ExternalInterruptHandler
= ExceptionHandlerData
->ExternalInterruptHandler
;
295 if (InterruptType
< 0 || InterruptType
>= (EFI_EXCEPTION_TYPE
)EnabledInterruptNum
||
296 ReservedVectors
[InterruptType
].Attribute
== EFI_VECTOR_HANDOFF_DO_NOT_HOOK
) {
297 return EFI_UNSUPPORTED
;
300 if (InterruptHandler
== NULL
&& ExternalInterruptHandler
[InterruptType
] == NULL
) {
301 return EFI_INVALID_PARAMETER
;
304 if (InterruptHandler
!= NULL
&& ExternalInterruptHandler
[InterruptType
] != NULL
) {
305 return EFI_ALREADY_STARTED
;
308 ExternalInterruptHandler
[InterruptType
] = InterruptHandler
;