2 CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.
4 Copyright (c) 2012 - 2018, 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 Internal worker function for common exception handler.
21 @param ExceptionType Exception type.
22 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
23 @param ExceptionHandlerData Pointer to exception handler data.
26 CommonExceptionHandlerWorker (
27 IN EFI_EXCEPTION_TYPE ExceptionType
,
28 IN EFI_SYSTEM_CONTEXT SystemContext
,
29 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
32 EXCEPTION_HANDLER_CONTEXT
*ExceptionHandlerContext
;
33 RESERVED_VECTORS_DATA
*ReservedVectors
;
34 EFI_CPU_INTERRUPT_HANDLER
*ExternalInterruptHandler
;
36 ExceptionHandlerContext
= (EXCEPTION_HANDLER_CONTEXT
*) (UINTN
) (SystemContext
.SystemContextIa32
);
37 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
38 ExternalInterruptHandler
= ExceptionHandlerData
->ExternalInterruptHandler
;
40 switch (ReservedVectors
[ExceptionType
].Attribute
) {
41 case EFI_VECTOR_HANDOFF_HOOK_BEFORE
:
43 // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.
44 // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.
46 ExceptionHandlerContext
->ExceptionDataFlag
= (mErrorCodeFlag
& (1 << ExceptionType
)) ? TRUE
: FALSE
;
47 ExceptionHandlerContext
->OldIdtHandler
= ReservedVectors
[ExceptionType
].ExceptonHandler
;
49 case EFI_VECTOR_HANDOFF_HOOK_AFTER
:
52 // If spin-lock can be acquired, it's the first time entering here.
54 if (AcquireSpinLockOrFail (&ReservedVectors
[ExceptionType
].SpinLock
)) {
56 // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.
57 // Save the original handler to stack but skip running the new handler so the original handler is executed
60 ReservedVectors
[ExceptionType
].ApicId
= GetApicId ();
61 ArchSaveExceptionContext (ExceptionType
, SystemContext
, ExceptionHandlerData
);
62 ExceptionHandlerContext
->ExceptionDataFlag
= (mErrorCodeFlag
& (1 << ExceptionType
)) ? TRUE
: FALSE
;
63 ExceptionHandlerContext
->OldIdtHandler
= ReservedVectors
[ExceptionType
].ExceptonHandler
;
67 // If spin-lock cannot be acquired, it's the second time entering here.
68 // 'break' instead of 'return' is used so the new exception handler can be executed.
70 if (ReservedVectors
[ExceptionType
].ApicId
== GetApicId ()) {
72 // Old IDT handler has been executed, then restore CPU exception content to
73 // run new exception handler.
75 ArchRestoreExceptionContext (ExceptionType
, SystemContext
, ExceptionHandlerData
);
77 // Rlease spin lock for ApicId
79 ReleaseSpinLock (&ReservedVectors
[ExceptionType
].SpinLock
);
89 // It should never reach here
95 if (ExternalInterruptHandler
!= NULL
&&
96 ExternalInterruptHandler
[ExceptionType
] != NULL
) {
97 (ExternalInterruptHandler
[ExceptionType
]) (ExceptionType
, SystemContext
);
98 } else if (ExceptionType
< CPU_EXCEPTION_NUM
) {
100 // Get Spinlock to display CPU information
102 while (!AcquireSpinLockOrFail (&ExceptionHandlerData
->DisplayMessageSpinLock
)) {
106 // Initialize the serial port before dumping.
108 SerialPortInitialize ();
110 // Display ExceptionType, CPU information and Image information
112 DumpImageAndCpuContent (ExceptionType
, SystemContext
);
114 // Release Spinlock of output message
116 ReleaseSpinLock (&ExceptionHandlerData
->DisplayMessageSpinLock
);
118 // Enter a dead loop if needn't to execute old IDT handler further
120 if (ReservedVectors
[ExceptionType
].Attribute
!= EFI_VECTOR_HANDOFF_HOOK_BEFORE
) {
127 Internal worker function to update IDT entries accordling to vector attributes.
129 @param[in] IdtTable Pointer to IDT table.
130 @param[in] TemplateMap Pointer to a buffer where the address map is
132 @param[in] ExceptionHandlerData Pointer to exception handler data.
137 IN IA32_IDT_GATE_DESCRIPTOR
*IdtTable
,
138 IN EXCEPTION_HANDLER_TEMPLATE_MAP
*TemplateMap
,
139 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
144 UINTN InterruptHandler
;
145 RESERVED_VECTORS_DATA
*ReservedVectors
;
147 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
149 // Use current CS as the segment selector of interrupt gate in IDT
151 CodeSegment
= AsmReadCs ();
153 for (Index
= 0; Index
< ExceptionHandlerData
->IdtEntryCount
; Index
++) {
154 IdtTable
[Index
].Bits
.Selector
= CodeSegment
;
156 // Check reserved vectors attributes
158 switch (ReservedVectors
[Index
].Attribute
) {
159 case EFI_VECTOR_HANDOFF_DO_NOT_HOOK
:
161 // Keep original IDT entry
164 case EFI_VECTOR_HANDOFF_HOOK_AFTER
:
165 InitializeSpinLock (&ReservedVectors
[Index
].SpinLock
);
167 (VOID
*) ReservedVectors
[Index
].HookAfterStubHeaderCode
,
168 (VOID
*) TemplateMap
->HookAfterStubHeaderStart
,
169 TemplateMap
->ExceptionStubHeaderSize
172 (VOID
*) ReservedVectors
[Index
].HookAfterStubHeaderCode
,
174 (VOID
*) TemplateMap
->HookAfterStubHeaderStart
177 // Go on the following code
179 case EFI_VECTOR_HANDOFF_HOOK_BEFORE
:
181 // Save original IDT handler address
183 ReservedVectors
[Index
].ExceptonHandler
= ArchGetIdtHandler (&IdtTable
[Index
]);
185 // Go on the following code
189 // Update new IDT entry
191 InterruptHandler
= TemplateMap
->ExceptionStart
+ Index
* TemplateMap
->ExceptionStubHeaderSize
;
192 ArchUpdateIdtEntry (&IdtTable
[Index
], InterruptHandler
);
199 Internal worker function to initialize exception handler.
201 @param[in] VectorInfo Pointer to reserved vector list.
202 @param[in, out] ExceptionHandlerData Pointer to exception handler data.
204 @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
205 with default exception handlers.
206 @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
207 @retval EFI_UNSUPPORTED This function is not supported.
211 InitializeCpuExceptionHandlersWorker (
212 IN EFI_VECTOR_HANDOFF_INFO
*VectorInfo OPTIONAL
,
213 IN OUT EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
217 IA32_DESCRIPTOR IdtDescriptor
;
219 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap
;
220 IA32_IDT_GATE_DESCRIPTOR
*IdtTable
;
221 RESERVED_VECTORS_DATA
*ReservedVectors
;
223 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
224 SetMem ((VOID
*) ReservedVectors
, sizeof (RESERVED_VECTORS_DATA
) * CPU_EXCEPTION_NUM
, 0xff);
225 if (VectorInfo
!= NULL
) {
226 Status
= ReadAndVerifyVectorInfo (VectorInfo
, ReservedVectors
, CPU_EXCEPTION_NUM
);
227 if (EFI_ERROR (Status
)) {
228 return EFI_INVALID_PARAMETER
;
233 // Read IDT descriptor and calculate IDT size
235 AsmReadIdtr (&IdtDescriptor
);
236 IdtEntryCount
= (IdtDescriptor
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
);
237 if (IdtEntryCount
> CPU_EXCEPTION_NUM
) {
239 // CPU exeption library only setup CPU_EXCEPTION_NUM exception handler at most
241 IdtEntryCount
= CPU_EXCEPTION_NUM
;
244 IdtTable
= (IA32_IDT_GATE_DESCRIPTOR
*) IdtDescriptor
.Base
;
245 AsmGetTemplateAddressMap (&TemplateMap
);
246 ASSERT (TemplateMap
.ExceptionStubHeaderSize
<= HOOKAFTER_STUB_SIZE
);
248 ExceptionHandlerData
->IdtEntryCount
= IdtEntryCount
;
249 UpdateIdtTable (IdtTable
, &TemplateMap
, ExceptionHandlerData
);
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
261 @param[in] ExceptionHandlerData Pointer to exception handler data.
263 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
264 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
265 previously installed.
266 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
267 previously installed.
268 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
269 or this function is not supported.
272 RegisterCpuInterruptHandlerWorker (
273 IN EFI_EXCEPTION_TYPE InterruptType
,
274 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
,
275 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
278 UINTN EnabledInterruptNum
;
279 RESERVED_VECTORS_DATA
*ReservedVectors
;
280 EFI_CPU_INTERRUPT_HANDLER
*ExternalInterruptHandler
;
282 EnabledInterruptNum
= ExceptionHandlerData
->IdtEntryCount
;
283 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
284 ExternalInterruptHandler
= ExceptionHandlerData
->ExternalInterruptHandler
;
286 if (InterruptType
< 0 || InterruptType
>= (EFI_EXCEPTION_TYPE
)EnabledInterruptNum
||
287 ReservedVectors
[InterruptType
].Attribute
== EFI_VECTOR_HANDOFF_DO_NOT_HOOK
) {
288 return EFI_UNSUPPORTED
;
291 if (InterruptHandler
== NULL
&& ExternalInterruptHandler
[InterruptType
] == NULL
) {
292 return EFI_INVALID_PARAMETER
;
295 if (InterruptHandler
!= NULL
&& ExternalInterruptHandler
[InterruptType
] != NULL
) {
296 return EFI_ALREADY_STARTED
;
299 ExternalInterruptHandler
[InterruptType
] = InterruptHandler
;