2 IA32 CPU Exception Handler functons.
4 Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "CpuExceptionCommon.h"
12 Return address map of exception handler template so that C code can generate
15 @param IdtEntry Pointer to IDT entry to be updated.
16 @param InterruptHandler IDT handler value.
21 OUT IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
,
22 IN UINTN InterruptHandler
25 IdtEntry
->Bits
.OffsetLow
= (UINT16
)(UINTN
)InterruptHandler
;
26 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)((UINTN
)InterruptHandler
>> 16);
27 IdtEntry
->Bits
.GateType
= IA32_IDT_GATE_TYPE_INTERRUPT_32
;
31 Read IDT handler value from IDT entry.
33 @param IdtEntry Pointer to IDT entry to be read.
38 IN IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
41 return (UINTN
)IdtEntry
->Bits
.OffsetLow
+ (((UINTN
)IdtEntry
->Bits
.OffsetHigh
) << 16);
45 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
47 @param[in] ExceptionType Exception type.
48 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
49 @param[in] ExceptionHandlerData Pointer to exception handler data.
52 ArchSaveExceptionContext (
53 IN UINTN ExceptionType
,
54 IN EFI_SYSTEM_CONTEXT SystemContext
,
55 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
59 RESERVED_VECTORS_DATA
*ReservedVectors
;
61 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
63 // Save Exception context in global variable in first entry of the exception handler.
64 // So when original exception handler returns to the new exception handler (second entry),
65 // the Eflags/Cs/Eip/ExceptionData can be used.
67 ReservedVectors
[ExceptionType
].OldFlags
= SystemContext
.SystemContextIa32
->Eflags
;
68 ReservedVectors
[ExceptionType
].OldCs
= SystemContext
.SystemContextIa32
->Cs
;
69 ReservedVectors
[ExceptionType
].OldIp
= SystemContext
.SystemContextIa32
->Eip
;
70 ReservedVectors
[ExceptionType
].ExceptionData
= SystemContext
.SystemContextIa32
->ExceptionData
;
72 // Clear IF flag to avoid old IDT handler enable interrupt by IRET
74 Eflags
.UintN
= SystemContext
.SystemContextIa32
->Eflags
;
76 SystemContext
.SystemContextIa32
->Eflags
= Eflags
.UintN
;
78 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
80 SystemContext
.SystemContextIa32
->Eip
= (UINTN
)ReservedVectors
[ExceptionType
].HookAfterStubHeaderCode
;
84 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
86 @param[in] ExceptionType Exception type.
87 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
88 @param[in] ExceptionHandlerData Pointer to exception handler data.
91 ArchRestoreExceptionContext (
92 IN UINTN ExceptionType
,
93 IN EFI_SYSTEM_CONTEXT SystemContext
,
94 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
97 RESERVED_VECTORS_DATA
*ReservedVectors
;
99 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
100 SystemContext
.SystemContextIa32
->Eflags
= ReservedVectors
[ExceptionType
].OldFlags
;
101 SystemContext
.SystemContextIa32
->Cs
= ReservedVectors
[ExceptionType
].OldCs
;
102 SystemContext
.SystemContextIa32
->Eip
= ReservedVectors
[ExceptionType
].OldIp
;
103 SystemContext
.SystemContextIa32
->ExceptionData
= ReservedVectors
[ExceptionType
].ExceptionData
;
107 Setup separate stack for given exceptions.
109 @param[in] StackSwitchData Pointer to data required for setuping up
112 @retval EFI_SUCCESS The exceptions have been successfully
113 initialized with new stack.
114 @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
118 ArchSetupExceptionStack (
119 IN CPU_EXCEPTION_INIT_DATA
*StackSwitchData
122 IA32_DESCRIPTOR Gdtr
;
123 IA32_DESCRIPTOR Idtr
;
124 IA32_IDT_GATE_DESCRIPTOR
*IdtTable
;
125 IA32_TSS_DESCRIPTOR
*TssDesc
;
126 IA32_TASK_STATE_SEGMENT
*Tss
;
132 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap
;
134 if ((StackSwitchData
== NULL
) ||
135 (StackSwitchData
->Ia32
.Revision
!= CPU_EXCEPTION_INIT_DATA_REV
) ||
136 (StackSwitchData
->Ia32
.KnownGoodStackTop
== 0) ||
137 (StackSwitchData
->Ia32
.KnownGoodStackSize
== 0) ||
138 (StackSwitchData
->Ia32
.StackSwitchExceptions
== NULL
) ||
139 (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
== 0) ||
140 (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
> CPU_EXCEPTION_NUM
) ||
141 (StackSwitchData
->Ia32
.GdtTable
== NULL
) ||
142 (StackSwitchData
->Ia32
.IdtTable
== NULL
) ||
143 (StackSwitchData
->Ia32
.ExceptionTssDesc
== NULL
) ||
144 (StackSwitchData
->Ia32
.ExceptionTss
== NULL
))
146 return EFI_INVALID_PARAMETER
;
150 // The caller is responsible for that the GDT table, no matter the existing
151 // one or newly allocated, has enough space to hold descriptors for exception
152 // task-state segments.
154 if (((UINTN
)StackSwitchData
->Ia32
.GdtTable
& (IA32_GDT_ALIGNMENT
- 1)) != 0) {
155 return EFI_INVALID_PARAMETER
;
158 if ((UINTN
)StackSwitchData
->Ia32
.ExceptionTssDesc
< (UINTN
)(StackSwitchData
->Ia32
.GdtTable
)) {
159 return EFI_INVALID_PARAMETER
;
162 if ((UINTN
)StackSwitchData
->Ia32
.ExceptionTssDesc
+ StackSwitchData
->Ia32
.ExceptionTssDescSize
>
163 ((UINTN
)(StackSwitchData
->Ia32
.GdtTable
) + StackSwitchData
->Ia32
.GdtTableSize
))
165 return EFI_INVALID_PARAMETER
;
169 // We need one descriptor and one TSS for current task and every exception
172 if (StackSwitchData
->Ia32
.ExceptionTssDescSize
<
173 sizeof (IA32_TSS_DESCRIPTOR
) * (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
+ 1))
175 return EFI_INVALID_PARAMETER
;
178 if (StackSwitchData
->Ia32
.ExceptionTssSize
<
179 sizeof (IA32_TASK_STATE_SEGMENT
) * (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
+ 1))
181 return EFI_INVALID_PARAMETER
;
184 TssDesc
= StackSwitchData
->Ia32
.ExceptionTssDesc
;
185 Tss
= StackSwitchData
->Ia32
.ExceptionTss
;
188 // Initialize new GDT table and/or IDT table, if any
193 GdtSize
= (UINTN
)TssDesc
+
194 sizeof (IA32_TSS_DESCRIPTOR
) *
195 (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
+ 1) -
196 (UINTN
)(StackSwitchData
->Ia32
.GdtTable
);
197 if ((UINTN
)StackSwitchData
->Ia32
.GdtTable
!= Gdtr
.Base
) {
198 CopyMem (StackSwitchData
->Ia32
.GdtTable
, (VOID
*)Gdtr
.Base
, Gdtr
.Limit
+ 1);
199 Gdtr
.Base
= (UINTN
)StackSwitchData
->Ia32
.GdtTable
;
200 Gdtr
.Limit
= (UINT16
)GdtSize
- 1;
203 if ((UINTN
)StackSwitchData
->Ia32
.IdtTable
!= Idtr
.Base
) {
204 Idtr
.Base
= (UINTN
)StackSwitchData
->Ia32
.IdtTable
;
207 if (StackSwitchData
->Ia32
.IdtTableSize
> 0) {
208 Idtr
.Limit
= (UINT16
)(StackSwitchData
->Ia32
.IdtTableSize
- 1);
212 // Fixup current task descriptor. Task-state segment for current task will
213 // be filled by processor during task switching.
215 TssBase
= (UINTN
)Tss
;
218 TssDesc
->Bits
.LimitLow
= sizeof (IA32_TASK_STATE_SEGMENT
) - 1;
219 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
220 TssDesc
->Bits
.BaseMid
= (UINT8
)(TssBase
>> 16);
221 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
223 TssDesc
->Bits
.LimitHigh
= 0;
224 TssDesc
->Bits
.BaseHigh
= (UINT8
)(TssBase
>> 24);
227 // Fixup exception task descriptor and task-state segment
229 AsmGetTssTemplateMap (&TemplateMap
);
230 StackTop
= StackSwitchData
->Ia32
.KnownGoodStackTop
- CPU_STACK_ALIGNMENT
;
231 StackTop
= (UINTN
)ALIGN_POINTER (StackTop
, CPU_STACK_ALIGNMENT
);
232 IdtTable
= StackSwitchData
->Ia32
.IdtTable
;
233 for (Index
= 0; Index
< StackSwitchData
->Ia32
.StackSwitchExceptionNumber
; ++Index
) {
238 // Fixup TSS descriptor
240 TssBase
= (UINTN
)Tss
;
243 TssDesc
->Bits
.LimitLow
= sizeof (IA32_TASK_STATE_SEGMENT
) - 1;
244 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
245 TssDesc
->Bits
.BaseMid
= (UINT8
)(TssBase
>> 16);
246 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
248 TssDesc
->Bits
.LimitHigh
= 0;
249 TssDesc
->Bits
.BaseHigh
= (UINT8
)(TssBase
>> 24);
254 Vector
= StackSwitchData
->Ia32
.StackSwitchExceptions
[Index
];
255 if ((Vector
>= CPU_EXCEPTION_NUM
) ||
256 (Vector
>= (Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
)))
261 ZeroMem (Tss
, sizeof (*Tss
));
262 Tss
->EIP
= (UINT32
)(TemplateMap
.ExceptionStart
263 + Vector
* TemplateMap
.ExceptionStubHeaderSize
);
266 Tss
->CR3
= AsmReadCr3 ();
267 Tss
->ES
= AsmReadEs ();
268 Tss
->CS
= AsmReadCs ();
269 Tss
->SS
= AsmReadSs ();
270 Tss
->DS
= AsmReadDs ();
271 Tss
->FS
= AsmReadFs ();
272 Tss
->GS
= AsmReadGs ();
274 StackTop
-= StackSwitchData
->Ia32
.KnownGoodStackSize
;
277 // Update IDT to use Task Gate for given exception
279 IdtTable
[Vector
].Bits
.OffsetLow
= 0;
280 IdtTable
[Vector
].Bits
.Selector
= (UINT16
)((UINTN
)TssDesc
- Gdtr
.Base
);
281 IdtTable
[Vector
].Bits
.Reserved_0
= 0;
282 IdtTable
[Vector
].Bits
.GateType
= IA32_IDT_GATE_TYPE_TASK
;
283 IdtTable
[Vector
].Bits
.OffsetHigh
= 0;
289 AsmWriteGdtr (&Gdtr
);
294 AsmWriteTr ((UINT16
)((UINTN
)StackSwitchData
->Ia32
.ExceptionTssDesc
- Gdtr
.Base
));
299 AsmWriteIdtr (&Idtr
);
305 Display processor context.
307 @param[in] ExceptionType Exception type.
308 @param[in] SystemContext Processor context to be display.
313 IN EFI_EXCEPTION_TYPE ExceptionType
,
314 IN EFI_SYSTEM_CONTEXT SystemContext
317 InternalPrintMessage (
318 "!!!! IA32 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
320 GetExceptionNameStr (ExceptionType
),
323 if ((mErrorCodeFlag
& (1 << ExceptionType
)) != 0) {
324 InternalPrintMessage (
325 "ExceptionData - %08x",
326 SystemContext
.SystemContextIa32
->ExceptionData
328 if (ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) {
329 InternalPrintMessage (
330 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
331 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0,
332 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_RSVD
) != 0,
333 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_US
) != 0,
334 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_WR
) != 0,
335 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_P
) != 0,
336 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_PK
) != 0,
337 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_SS
) != 0,
338 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_SGX
) != 0
342 InternalPrintMessage ("\n");
345 InternalPrintMessage (
346 "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
347 SystemContext
.SystemContextIa32
->Eip
,
348 SystemContext
.SystemContextIa32
->Cs
,
349 SystemContext
.SystemContextIa32
->Eflags
351 InternalPrintMessage (
352 "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
353 SystemContext
.SystemContextIa32
->Eax
,
354 SystemContext
.SystemContextIa32
->Ecx
,
355 SystemContext
.SystemContextIa32
->Edx
,
356 SystemContext
.SystemContextIa32
->Ebx
358 InternalPrintMessage (
359 "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
360 SystemContext
.SystemContextIa32
->Esp
,
361 SystemContext
.SystemContextIa32
->Ebp
,
362 SystemContext
.SystemContextIa32
->Esi
,
363 SystemContext
.SystemContextIa32
->Edi
365 InternalPrintMessage (
366 "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
367 SystemContext
.SystemContextIa32
->Ds
,
368 SystemContext
.SystemContextIa32
->Es
,
369 SystemContext
.SystemContextIa32
->Fs
,
370 SystemContext
.SystemContextIa32
->Gs
,
371 SystemContext
.SystemContextIa32
->Ss
373 InternalPrintMessage (
374 "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
375 SystemContext
.SystemContextIa32
->Cr0
,
376 SystemContext
.SystemContextIa32
->Cr2
,
377 SystemContext
.SystemContextIa32
->Cr3
,
378 SystemContext
.SystemContextIa32
->Cr4
380 InternalPrintMessage (
381 "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
382 SystemContext
.SystemContextIa32
->Dr0
,
383 SystemContext
.SystemContextIa32
->Dr1
,
384 SystemContext
.SystemContextIa32
->Dr2
,
385 SystemContext
.SystemContextIa32
->Dr3
387 InternalPrintMessage (
388 "DR6 - %08x, DR7 - %08x\n",
389 SystemContext
.SystemContextIa32
->Dr6
,
390 SystemContext
.SystemContextIa32
->Dr7
392 InternalPrintMessage (
393 "GDTR - %08x %08x, IDTR - %08x %08x\n",
394 SystemContext
.SystemContextIa32
->Gdtr
[0],
395 SystemContext
.SystemContextIa32
->Gdtr
[1],
396 SystemContext
.SystemContextIa32
->Idtr
[0],
397 SystemContext
.SystemContextIa32
->Idtr
[1]
399 InternalPrintMessage (
400 "LDTR - %08x, TR - %08x\n",
401 SystemContext
.SystemContextIa32
->Ldtr
,
402 SystemContext
.SystemContextIa32
->Tr
404 InternalPrintMessage (
405 "FXSAVE_STATE - %08x\n",
406 &SystemContext
.SystemContextIa32
->FxSaveState
411 Display CPU information.
413 @param ExceptionType Exception type.
414 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
417 DumpImageAndCpuContent (
418 IN EFI_EXCEPTION_TYPE ExceptionType
,
419 IN EFI_SYSTEM_CONTEXT SystemContext
422 DumpCpuContext (ExceptionType
, SystemContext
);
424 // Dump module image base and module entry point by EIP
426 if ((ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) &&
427 ((SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0))
430 // The EIP in SystemContext could not be used
431 // if it is page fault with I/D set.
433 DumpModuleImageInfo ((*(UINTN
*)(UINTN
)SystemContext
.SystemContextIa32
->Esp
));
435 DumpModuleImageInfo (SystemContext
.SystemContextIa32
->Eip
);