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 IN 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
) {
145 return EFI_INVALID_PARAMETER
;
149 // The caller is responsible for that the GDT table, no matter the existing
150 // one or newly allocated, has enough space to hold descriptors for exception
151 // task-state segments.
153 if (((UINTN
)StackSwitchData
->Ia32
.GdtTable
& (IA32_GDT_ALIGNMENT
- 1)) != 0) {
154 return EFI_INVALID_PARAMETER
;
157 if ((UINTN
)StackSwitchData
->Ia32
.ExceptionTssDesc
< (UINTN
)(StackSwitchData
->Ia32
.GdtTable
)) {
158 return EFI_INVALID_PARAMETER
;
161 if ((UINTN
)StackSwitchData
->Ia32
.ExceptionTssDesc
+ StackSwitchData
->Ia32
.ExceptionTssDescSize
>
162 ((UINTN
)(StackSwitchData
->Ia32
.GdtTable
) + StackSwitchData
->Ia32
.GdtTableSize
)) {
163 return EFI_INVALID_PARAMETER
;
167 // We need one descriptor and one TSS for current task and every exception
170 if (StackSwitchData
->Ia32
.ExceptionTssDescSize
<
171 sizeof (IA32_TSS_DESCRIPTOR
) * (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
+ 1)) {
172 return EFI_INVALID_PARAMETER
;
174 if (StackSwitchData
->Ia32
.ExceptionTssSize
<
175 sizeof (IA32_TASK_STATE_SEGMENT
) * (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
+ 1)) {
176 return EFI_INVALID_PARAMETER
;
179 TssDesc
= StackSwitchData
->Ia32
.ExceptionTssDesc
;
180 Tss
= StackSwitchData
->Ia32
.ExceptionTss
;
183 // Initialize new GDT table and/or IDT table, if any
188 GdtSize
= (UINTN
)TssDesc
+
189 sizeof (IA32_TSS_DESCRIPTOR
) *
190 (StackSwitchData
->Ia32
.StackSwitchExceptionNumber
+ 1) -
191 (UINTN
)(StackSwitchData
->Ia32
.GdtTable
);
192 if ((UINTN
)StackSwitchData
->Ia32
.GdtTable
!= Gdtr
.Base
) {
193 CopyMem (StackSwitchData
->Ia32
.GdtTable
, (VOID
*)Gdtr
.Base
, Gdtr
.Limit
+ 1);
194 Gdtr
.Base
= (UINTN
)StackSwitchData
->Ia32
.GdtTable
;
195 Gdtr
.Limit
= (UINT16
)GdtSize
- 1;
198 if ((UINTN
)StackSwitchData
->Ia32
.IdtTable
!= Idtr
.Base
) {
199 Idtr
.Base
= (UINTN
)StackSwitchData
->Ia32
.IdtTable
;
201 if (StackSwitchData
->Ia32
.IdtTableSize
> 0) {
202 Idtr
.Limit
= (UINT16
)(StackSwitchData
->Ia32
.IdtTableSize
- 1);
206 // Fixup current task descriptor. Task-state segment for current task will
207 // be filled by processor during task switching.
209 TssBase
= (UINTN
)Tss
;
212 TssDesc
->Bits
.LimitLow
= sizeof(IA32_TASK_STATE_SEGMENT
) - 1;
213 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
214 TssDesc
->Bits
.BaseMid
= (UINT8
)(TssBase
>> 16);
215 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
217 TssDesc
->Bits
.LimitHigh
= 0;
218 TssDesc
->Bits
.BaseHigh
= (UINT8
)(TssBase
>> 24);
221 // Fixup exception task descriptor and task-state segment
223 AsmGetTssTemplateMap (&TemplateMap
);
224 StackTop
= StackSwitchData
->Ia32
.KnownGoodStackTop
- CPU_STACK_ALIGNMENT
;
225 StackTop
= (UINTN
)ALIGN_POINTER (StackTop
, CPU_STACK_ALIGNMENT
);
226 IdtTable
= StackSwitchData
->Ia32
.IdtTable
;
227 for (Index
= 0; Index
< StackSwitchData
->Ia32
.StackSwitchExceptionNumber
; ++Index
) {
232 // Fixup TSS descriptor
234 TssBase
= (UINTN
)Tss
;
237 TssDesc
->Bits
.LimitLow
= sizeof(IA32_TASK_STATE_SEGMENT
) - 1;
238 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
239 TssDesc
->Bits
.BaseMid
= (UINT8
)(TssBase
>> 16);
240 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
242 TssDesc
->Bits
.LimitHigh
= 0;
243 TssDesc
->Bits
.BaseHigh
= (UINT8
)(TssBase
>> 24);
248 Vector
= StackSwitchData
->Ia32
.StackSwitchExceptions
[Index
];
249 if (Vector
>= CPU_EXCEPTION_NUM
||
250 Vector
>= (Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
)) {
254 ZeroMem (Tss
, sizeof (*Tss
));
255 Tss
->EIP
= (UINT32
)(TemplateMap
.ExceptionStart
256 + Vector
* TemplateMap
.ExceptionStubHeaderSize
);
259 Tss
->CR3
= AsmReadCr3 ();
260 Tss
->ES
= AsmReadEs ();
261 Tss
->CS
= AsmReadCs ();
262 Tss
->SS
= AsmReadSs ();
263 Tss
->DS
= AsmReadDs ();
264 Tss
->FS
= AsmReadFs ();
265 Tss
->GS
= AsmReadGs ();
267 StackTop
-= StackSwitchData
->Ia32
.KnownGoodStackSize
;
270 // Update IDT to use Task Gate for given exception
272 IdtTable
[Vector
].Bits
.OffsetLow
= 0;
273 IdtTable
[Vector
].Bits
.Selector
= (UINT16
)((UINTN
)TssDesc
- Gdtr
.Base
);
274 IdtTable
[Vector
].Bits
.Reserved_0
= 0;
275 IdtTable
[Vector
].Bits
.GateType
= IA32_IDT_GATE_TYPE_TASK
;
276 IdtTable
[Vector
].Bits
.OffsetHigh
= 0;
282 AsmWriteGdtr (&Gdtr
);
287 AsmWriteTr ((UINT16
)((UINTN
)StackSwitchData
->Ia32
.ExceptionTssDesc
- Gdtr
.Base
));
292 AsmWriteIdtr (&Idtr
);
298 Display processor context.
300 @param[in] ExceptionType Exception type.
301 @param[in] SystemContext Processor context to be display.
306 IN EFI_EXCEPTION_TYPE ExceptionType
,
307 IN EFI_SYSTEM_CONTEXT SystemContext
310 InternalPrintMessage (
311 "!!!! IA32 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
313 GetExceptionNameStr (ExceptionType
),
316 if ((mErrorCodeFlag
& (1 << ExceptionType
)) != 0) {
317 InternalPrintMessage (
318 "ExceptionData - %08x",
319 SystemContext
.SystemContextIa32
->ExceptionData
321 if (ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) {
322 InternalPrintMessage (
323 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
324 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0,
325 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_RSVD
) != 0,
326 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_US
) != 0,
327 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_WR
) != 0,
328 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_P
) != 0,
329 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_PK
) != 0,
330 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_SS
) != 0,
331 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_SGX
) != 0
334 InternalPrintMessage ("\n");
336 InternalPrintMessage (
337 "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
338 SystemContext
.SystemContextIa32
->Eip
,
339 SystemContext
.SystemContextIa32
->Cs
,
340 SystemContext
.SystemContextIa32
->Eflags
342 InternalPrintMessage (
343 "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
344 SystemContext
.SystemContextIa32
->Eax
,
345 SystemContext
.SystemContextIa32
->Ecx
,
346 SystemContext
.SystemContextIa32
->Edx
,
347 SystemContext
.SystemContextIa32
->Ebx
349 InternalPrintMessage (
350 "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
351 SystemContext
.SystemContextIa32
->Esp
,
352 SystemContext
.SystemContextIa32
->Ebp
,
353 SystemContext
.SystemContextIa32
->Esi
,
354 SystemContext
.SystemContextIa32
->Edi
356 InternalPrintMessage (
357 "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
358 SystemContext
.SystemContextIa32
->Ds
,
359 SystemContext
.SystemContextIa32
->Es
,
360 SystemContext
.SystemContextIa32
->Fs
,
361 SystemContext
.SystemContextIa32
->Gs
,
362 SystemContext
.SystemContextIa32
->Ss
364 InternalPrintMessage (
365 "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
366 SystemContext
.SystemContextIa32
->Cr0
,
367 SystemContext
.SystemContextIa32
->Cr2
,
368 SystemContext
.SystemContextIa32
->Cr3
,
369 SystemContext
.SystemContextIa32
->Cr4
371 InternalPrintMessage (
372 "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
373 SystemContext
.SystemContextIa32
->Dr0
,
374 SystemContext
.SystemContextIa32
->Dr1
,
375 SystemContext
.SystemContextIa32
->Dr2
,
376 SystemContext
.SystemContextIa32
->Dr3
378 InternalPrintMessage (
379 "DR6 - %08x, DR7 - %08x\n",
380 SystemContext
.SystemContextIa32
->Dr6
,
381 SystemContext
.SystemContextIa32
->Dr7
383 InternalPrintMessage (
384 "GDTR - %08x %08x, IDTR - %08x %08x\n",
385 SystemContext
.SystemContextIa32
->Gdtr
[0],
386 SystemContext
.SystemContextIa32
->Gdtr
[1],
387 SystemContext
.SystemContextIa32
->Idtr
[0],
388 SystemContext
.SystemContextIa32
->Idtr
[1]
390 InternalPrintMessage (
391 "LDTR - %08x, TR - %08x\n",
392 SystemContext
.SystemContextIa32
->Ldtr
,
393 SystemContext
.SystemContextIa32
->Tr
395 InternalPrintMessage (
396 "FXSAVE_STATE - %08x\n",
397 &SystemContext
.SystemContextIa32
->FxSaveState
402 Display CPU information.
404 @param ExceptionType Exception type.
405 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
408 DumpImageAndCpuContent (
409 IN EFI_EXCEPTION_TYPE ExceptionType
,
410 IN EFI_SYSTEM_CONTEXT SystemContext
413 DumpCpuContext (ExceptionType
, SystemContext
);
415 // Dump module image base and module entry point by EIP
417 if ((ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) &&
418 ((SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0)) {
420 // The EIP in SystemContext could not be used
421 // if it is page fault with I/D set.
423 DumpModuleImageInfo ((*(UINTN
*)(UINTN
)SystemContext
.SystemContextIa32
->Esp
));
425 DumpModuleImageInfo (SystemContext
.SystemContextIa32
->Eip
);