TianoCore EDK2 master
Loading...
Searching...
No Matches
PeiDxeSmmCpuException.c
Go to the documentation of this file.
1
9#include <Library/DebugLib.h>
10#include <Library/CcExitLib.h>
11#include "CpuExceptionCommon.h"
12
20VOID
22 IN EFI_EXCEPTION_TYPE ExceptionType,
23 IN EFI_SYSTEM_CONTEXT SystemContext,
24 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
25 )
26{
27 EFI_STATUS Status;
28 EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;
29 RESERVED_VECTORS_DATA *ReservedVectors;
30 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
31
32 switch (ExceptionType) {
33 case VC_EXCEPTION:
34 //
35 // #VC needs to be handled immediately upon enabling exception handling
36 // and therefore can't use the RegisterCpuInterruptHandler() interface.
37 //
38 // Handle the #VC:
39 // On EFI_SUCCESS - Exception has been handled, return
40 // On other - ExceptionType contains (possibly new) exception
41 // value
42 //
43 Status = CcExitHandleVc (&ExceptionType, SystemContext);
44 if (!EFI_ERROR (Status)) {
45 return;
46 }
47
48 break;
49
50 case VE_EXCEPTION:
51 //
52 // #VE needs to be handled immediately upon enabling exception handling
53 // and therefore can't use the RegisterCpuInterruptHandler() interface.
54 //
55 // Handle the #VE:
56 // On EFI_SUCCESS - Exception has been handled, return
57 // On other - ExceptionType contains (possibly new) exception
58 // value
59 //
60 Status = CcExitHandleVe (&ExceptionType, SystemContext);
61 if (!EFI_ERROR (Status)) {
62 return;
63 }
64
65 break;
66
67 default:
68 break;
69 }
70
71 ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);
72 ReservedVectors = ExceptionHandlerData->ReservedVectors;
73 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
74
75 switch (ReservedVectors[ExceptionType].Attribute) {
76 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
77 //
78 // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.
79 // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.
80 //
81 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
82 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
83 break;
84 case EFI_VECTOR_HANDOFF_HOOK_AFTER:
85 while (TRUE) {
86 //
87 // If spin-lock can be acquired, it's the first time entering here.
88 //
89 if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {
90 //
91 // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.
92 // Save the original handler to stack but skip running the new handler so the original handler is executed
93 // firstly.
94 //
95 ReservedVectors[ExceptionType].ApicId = GetApicId ();
96 ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
97 ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
98 ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
99 return;
100 }
101
102 //
103 // If spin-lock cannot be acquired, it's the second time entering here.
104 // 'break' instead of 'return' is used so the new exception handler can be executed.
105 //
106 if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {
107 //
108 // Old IDT handler has been executed, then restore CPU exception content to
109 // run new exception handler.
110 //
111 ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
112 //
113 // Release spin lock for ApicId
114 //
115 ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);
116 break;
117 }
118
119 CpuPause ();
120 }
121
122 break;
123 case 0xffffffff:
124 break;
125 default:
126 //
127 // It should never reach here
128 //
129 CpuDeadLoop ();
130 break;
131 }
132
133 if ((ExternalInterruptHandler != NULL) &&
134 (ExternalInterruptHandler[ExceptionType] != NULL))
135 {
136 (ExternalInterruptHandler[ExceptionType])(ExceptionType, SystemContext);
137 } else if (ExceptionType < CPU_EXCEPTION_NUM) {
138 //
139 // Get Spinlock to display CPU information
140 //
141 while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {
142 CpuPause ();
143 }
144
145 //
146 // Initialize the serial port before dumping.
147 //
149 //
150 // Display ExceptionType, CPU information and Image information
151 //
152 DumpImageAndCpuContent (ExceptionType, SystemContext);
153 //
154 // Release Spinlock of output message
155 //
156 ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);
157 //
158 // Enter a dead loop if needn't to execute old IDT handler further
159 //
160 if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {
161 CpuDeadLoop ();
162 }
163 }
164}
165
175VOID
177 IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
179 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
180 )
181{
182 UINT16 CodeSegment;
183 UINTN Index;
184 UINTN InterruptHandler;
185 RESERVED_VECTORS_DATA *ReservedVectors;
186
187 ReservedVectors = ExceptionHandlerData->ReservedVectors;
188 //
189 // Use current CS as the segment selector of interrupt gate in IDT
190 //
191 CodeSegment = AsmReadCs ();
192
193 for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index++) {
194 IdtTable[Index].Bits.Selector = CodeSegment;
195 //
196 // Check reserved vectors attributes
197 //
198 switch (ReservedVectors[Index].Attribute) {
200 //
201 // Keep original IDT entry
202 //
203 continue;
204 case EFI_VECTOR_HANDOFF_HOOK_AFTER:
205 InitializeSpinLock (&ReservedVectors[Index].SpinLock);
206 CopyMem (
207 (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,
208 (VOID *)TemplateMap->HookAfterStubHeaderStart,
209 TemplateMap->ExceptionStubHeaderSize
210 );
212 (VOID *)ReservedVectors[Index].HookAfterStubHeaderCode,
213 (UINT8)Index,
214 (VOID *)TemplateMap->HookAfterStubHeaderStart
215 );
216 //
217 // Go on the following code
218 //
219 case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
220 //
221 // Save original IDT handler address
222 //
223 ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);
224 //
225 // Go on the following code
226 //
227 default:
228 //
229 // Update new IDT entry
230 //
231 InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;
232 ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
233 break;
234 }
235 }
236}
237
252 IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
253 IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData
254 )
255{
256 EFI_STATUS Status;
257 IA32_DESCRIPTOR IdtDescriptor;
258 UINTN IdtEntryCount;
260 IA32_IDT_GATE_DESCRIPTOR *IdtTable;
261 RESERVED_VECTORS_DATA *ReservedVectors;
262
263 ReservedVectors = ExceptionHandlerData->ReservedVectors;
264 SetMem ((VOID *)ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * ExceptionHandlerData->IdtEntryCount, 0xff);
265 if (VectorInfo != NULL) {
266 Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, ExceptionHandlerData->IdtEntryCount);
267 if (EFI_ERROR (Status)) {
268 return EFI_INVALID_PARAMETER;
269 }
270 }
271
272 //
273 // Setup the exception handlers according to IDT size, but no more than
274 // ExceptionHandlerData->IdtEntryCount (32 in PEI and SMM, 256 in DXE) handlers.
275 //
276 AsmReadIdtr (&IdtDescriptor);
277 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
278 ExceptionHandlerData->IdtEntryCount = MIN (IdtEntryCount, ExceptionHandlerData->IdtEntryCount);
279
280 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
281 AsmGetTemplateAddressMap (&TemplateMap);
282 ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
283
284 UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);
285
286 return EFI_SUCCESS;
287}
288
308 IN EFI_EXCEPTION_TYPE InterruptType,
309 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
310 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
311 )
312{
313 UINTN EnabledInterruptNum;
314 RESERVED_VECTORS_DATA *ReservedVectors;
315 EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
316
317 EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;
318 ReservedVectors = ExceptionHandlerData->ReservedVectors;
319 ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
320
321 if ((InterruptType < 0) || (InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum) ||
322 (ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK))
323 {
324 return EFI_UNSUPPORTED;
325 }
326
327 if ((InterruptHandler == NULL) && (ExternalInterruptHandler[InterruptType] == NULL)) {
328 return EFI_INVALID_PARAMETER;
329 }
330
331 if ((InterruptHandler != NULL) && (ExternalInterruptHandler[InterruptType] != NULL)) {
332 return EFI_ALREADY_STARTED;
333 }
334
335 ExternalInterruptHandler[InterruptType] = InterruptHandler;
336 return EFI_SUCCESS;
337}
UINT64 UINTN
RETURN_STATUS EFIAPI SerialPortInitialize(VOID)
Definition: SerialPortLib.c:25
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
VOID EFIAPI CpuPause(VOID)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
EFI_STATUS EFIAPI CcExitHandleVe(IN OUT EFI_EXCEPTION_TYPE *ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext)
VOID(EFIAPI * EFI_CPU_INTERRUPT_HANDLER)(IN CONST EFI_EXCEPTION_TYPE InterruptType, IN CONST EFI_SYSTEM_CONTEXT SystemContext)
Definition: Cpu.h:52
EFI_STATUS ReadAndVerifyVectorInfo(IN EFI_VECTOR_HANDOFF_INFO *VectorInfo, OUT RESERVED_VECTORS_DATA *ReservedVector, IN UINTN VectorCount)
VOID ArchSaveExceptionContext(IN UINTN ExceptionType, IN EFI_SYSTEM_CONTEXT SystemContext, IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData)
VOID EFIAPI AsmVectorNumFixup(IN VOID *NewVectorAddr, IN UINT8 VectorNum, IN VOID *OldVectorAddr)
VOID ArchRestoreExceptionContext(IN UINTN ExceptionType, IN EFI_SYSTEM_CONTEXT SystemContext, IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData)
VOID DumpImageAndCpuContent(IN EFI_EXCEPTION_TYPE ExceptionType, IN EFI_SYSTEM_CONTEXT SystemContext)
VOID EFIAPI AsmGetTemplateAddressMap(OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap)
UINTN ArchGetIdtHandler(IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry)
VOID ArchUpdateIdtEntry(OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry, IN UINTN InterruptHandler)
UINT16 EFIAPI AsmReadCs(VOID)
UINT32 EFIAPI GetApicId(VOID)
Definition: BaseXApicLib.c:337
#define NULL
Definition: Base.h:319
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
EFI_STATUS EFIAPI CcExitHandleVc(IN OUT EFI_EXCEPTION_TYPE *ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext)
EFI_STATUS RegisterCpuInterruptHandlerWorker(IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler, IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData)
VOID UpdateIdtTable(IN IA32_IDT_GATE_DESCRIPTOR *IdtTable, IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap, IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData)
EFI_STATUS InitializeCpuExceptionHandlersWorker(IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL, IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData)
VOID CommonExceptionHandlerWorker(IN EFI_EXCEPTION_TYPE ExceptionType, IN EFI_SYSTEM_CONTEXT SystemContext, IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData)
SPIN_LOCK *EFIAPI InitializeSpinLock(OUT SPIN_LOCK *SpinLock)
SPIN_LOCK *EFIAPI ReleaseSpinLock(IN OUT SPIN_LOCK *SpinLock)
BOOLEAN EFIAPI AcquireSpinLockOrFail(IN OUT SPIN_LOCK *SpinLock)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
#define EFI_VECTOR_HANDOFF_DO_NOT_HOOK
VOID EFIAPI AsmReadIdtr(OUT IA32_DESCRIPTOR *Idtr)
Definition: X86ReadIdtr.c:24