2 x64 CPU Exception Handler.
4 Copyright (c) 2012 - 2022, 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.
20 OUT IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
,
21 IN UINTN InterruptHandler
24 IdtEntry
->Bits
.OffsetLow
= (UINT16
)(UINTN
)InterruptHandler
;
25 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)((UINTN
)InterruptHandler
>> 16);
26 IdtEntry
->Bits
.OffsetUpper
= (UINT32
)((UINTN
)InterruptHandler
>> 32);
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 IdtEntry
->Bits
.OffsetLow
+ (((UINTN
)IdtEntry
->Bits
.OffsetHigh
) << 16) +
42 (((UINTN
)IdtEntry
->Bits
.OffsetUpper
) << 32);
46 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
48 @param[in] ExceptionType Exception type.
49 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
50 @param[in] ExceptionHandlerData Pointer to exception handler data.
53 ArchSaveExceptionContext (
54 IN UINTN ExceptionType
,
55 IN EFI_SYSTEM_CONTEXT SystemContext
,
56 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
60 RESERVED_VECTORS_DATA
*ReservedVectors
;
62 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
64 // Save Exception context in global variable in first entry of the exception handler.
65 // So when original exception handler returns to the new exception handler (second entry),
66 // the Eflags/Cs/Eip/ExceptionData can be used.
68 ReservedVectors
[ExceptionType
].OldSs
= SystemContext
.SystemContextX64
->Ss
;
69 ReservedVectors
[ExceptionType
].OldSp
= SystemContext
.SystemContextX64
->Rsp
;
70 ReservedVectors
[ExceptionType
].OldFlags
= SystemContext
.SystemContextX64
->Rflags
;
71 ReservedVectors
[ExceptionType
].OldCs
= SystemContext
.SystemContextX64
->Cs
;
72 ReservedVectors
[ExceptionType
].OldIp
= SystemContext
.SystemContextX64
->Rip
;
73 ReservedVectors
[ExceptionType
].ExceptionData
= SystemContext
.SystemContextX64
->ExceptionData
;
75 // Clear IF flag to avoid old IDT handler enable interrupt by IRET
77 Eflags
.UintN
= SystemContext
.SystemContextX64
->Rflags
;
79 SystemContext
.SystemContextX64
->Rflags
= Eflags
.UintN
;
81 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
83 SystemContext
.SystemContextX64
->Rip
= (UINTN
)ReservedVectors
[ExceptionType
].HookAfterStubHeaderCode
;
87 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
89 @param[in] ExceptionType Exception type.
90 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
91 @param[in] ExceptionHandlerData Pointer to exception handler data.
94 ArchRestoreExceptionContext (
95 IN UINTN ExceptionType
,
96 IN EFI_SYSTEM_CONTEXT SystemContext
,
97 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
100 RESERVED_VECTORS_DATA
*ReservedVectors
;
102 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
103 SystemContext
.SystemContextX64
->Ss
= ReservedVectors
[ExceptionType
].OldSs
;
104 SystemContext
.SystemContextX64
->Rsp
= ReservedVectors
[ExceptionType
].OldSp
;
105 SystemContext
.SystemContextX64
->Rflags
= ReservedVectors
[ExceptionType
].OldFlags
;
106 SystemContext
.SystemContextX64
->Cs
= ReservedVectors
[ExceptionType
].OldCs
;
107 SystemContext
.SystemContextX64
->Rip
= ReservedVectors
[ExceptionType
].OldIp
;
108 SystemContext
.SystemContextX64
->ExceptionData
= ReservedVectors
[ExceptionType
].ExceptionData
;
112 Setup separate stack for given exceptions.
114 @param[in] StackSwitchData Pointer to data required for setuping up
117 @retval EFI_SUCCESS The exceptions have been successfully
118 initialized with new stack.
119 @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
123 ArchSetupExceptionStack (
124 IN CPU_EXCEPTION_INIT_DATA
*StackSwitchData
127 IA32_DESCRIPTOR Gdtr
;
128 IA32_DESCRIPTOR Idtr
;
129 IA32_IDT_GATE_DESCRIPTOR
*IdtTable
;
130 IA32_TSS_DESCRIPTOR
*TssDesc
;
131 IA32_TASK_STATE_SEGMENT
*Tss
;
138 if ((StackSwitchData
== NULL
) ||
139 (StackSwitchData
->KnownGoodStackTop
== 0) ||
140 (StackSwitchData
->KnownGoodStackSize
== 0) ||
141 (StackSwitchData
->StackSwitchExceptions
== NULL
) ||
142 (StackSwitchData
->StackSwitchExceptionNumber
== 0) ||
143 (StackSwitchData
->StackSwitchExceptionNumber
> CPU_EXCEPTION_NUM
) ||
144 (StackSwitchData
->GdtTable
== NULL
) ||
145 (StackSwitchData
->IdtTable
== NULL
) ||
146 (StackSwitchData
->ExceptionTssDesc
== NULL
) ||
147 (StackSwitchData
->ExceptionTss
== NULL
))
149 return EFI_INVALID_PARAMETER
;
153 // The caller is responsible for that the GDT table, no matter the existing
154 // one or newly allocated, has enough space to hold descriptors for exception
155 // task-state segments.
157 if (((UINTN
)StackSwitchData
->GdtTable
& (IA32_GDT_ALIGNMENT
- 1)) != 0) {
158 return EFI_INVALID_PARAMETER
;
161 if ((UINTN
)StackSwitchData
->ExceptionTssDesc
< (UINTN
)(StackSwitchData
->GdtTable
)) {
162 return EFI_INVALID_PARAMETER
;
165 if (((UINTN
)StackSwitchData
->ExceptionTssDesc
+ StackSwitchData
->ExceptionTssDescSize
) >
166 ((UINTN
)(StackSwitchData
->GdtTable
) + StackSwitchData
->GdtTableSize
))
168 return EFI_INVALID_PARAMETER
;
172 // One task gate descriptor and one task-state segment are needed.
174 if (StackSwitchData
->ExceptionTssDescSize
< sizeof (IA32_TSS_DESCRIPTOR
)) {
175 return EFI_INVALID_PARAMETER
;
178 if (StackSwitchData
->ExceptionTssSize
< sizeof (IA32_TASK_STATE_SEGMENT
)) {
179 return EFI_INVALID_PARAMETER
;
183 // Interrupt stack table supports only 7 vectors.
185 TssDesc
= StackSwitchData
->ExceptionTssDesc
;
186 Tss
= StackSwitchData
->ExceptionTss
;
187 if (StackSwitchData
->StackSwitchExceptionNumber
> ARRAY_SIZE (Tss
->IST
)) {
188 return EFI_INVALID_PARAMETER
;
192 // Initialize new GDT table and/or IDT table, if any
197 GdtSize
= (UINTN
)TssDesc
+ sizeof (IA32_TSS_DESCRIPTOR
) -
198 (UINTN
)(StackSwitchData
->GdtTable
);
199 if ((UINTN
)StackSwitchData
->GdtTable
!= Gdtr
.Base
) {
200 CopyMem (StackSwitchData
->GdtTable
, (VOID
*)Gdtr
.Base
, Gdtr
.Limit
+ 1);
201 Gdtr
.Base
= (UINTN
)StackSwitchData
->GdtTable
;
202 Gdtr
.Limit
= (UINT16
)GdtSize
- 1;
205 if ((UINTN
)StackSwitchData
->IdtTable
!= Idtr
.Base
) {
206 Idtr
.Base
= (UINTN
)StackSwitchData
->IdtTable
;
209 if (StackSwitchData
->IdtTableSize
> 0) {
210 Idtr
.Limit
= (UINT16
)(StackSwitchData
->IdtTableSize
- 1);
214 // Fixup current task descriptor. Task-state segment for current task will
215 // be filled by processor during task switching.
217 TssBase
= (UINTN
)Tss
;
219 TssDesc
->Uint128
.Uint64
= 0;
220 TssDesc
->Uint128
.Uint64_1
= 0;
221 TssDesc
->Bits
.LimitLow
= sizeof (IA32_TASK_STATE_SEGMENT
) - 1;
222 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
223 TssDesc
->Bits
.BaseMidl
= (UINT8
)(TssBase
>> 16);
224 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
226 TssDesc
->Bits
.LimitHigh
= 0;
227 TssDesc
->Bits
.BaseMidh
= (UINT8
)(TssBase
>> 24);
228 TssDesc
->Bits
.BaseHigh
= (UINT32
)(TssBase
>> 32);
231 // Fixup exception task descriptor and task-state segment
233 ZeroMem (Tss
, sizeof (*Tss
));
234 StackTop
= StackSwitchData
->KnownGoodStackTop
- CPU_STACK_ALIGNMENT
;
235 StackTop
= (UINTN
)ALIGN_POINTER (StackTop
, CPU_STACK_ALIGNMENT
);
236 IdtTable
= StackSwitchData
->IdtTable
;
237 for (Index
= 0; Index
< StackSwitchData
->StackSwitchExceptionNumber
; ++Index
) {
241 Tss
->IST
[Index
] = StackTop
;
242 StackTop
-= StackSwitchData
->KnownGoodStackSize
;
245 // Set the IST field to enable corresponding IST
247 Vector
= StackSwitchData
->StackSwitchExceptions
[Index
];
248 if ((Vector
>= CPU_EXCEPTION_NUM
) ||
249 (Vector
>= (Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
)))
254 IdtTable
[Vector
].Bits
.Reserved_0
= (UINT8
)(Index
+ 1);
260 AsmWriteGdtr (&Gdtr
);
265 AsmWriteTr ((UINT16
)((UINTN
)StackSwitchData
->ExceptionTssDesc
- Gdtr
.Base
));
270 AsmWriteIdtr (&Idtr
);
276 Display CPU information.
278 @param ExceptionType Exception type.
279 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
284 IN EFI_EXCEPTION_TYPE ExceptionType
,
285 IN EFI_SYSTEM_CONTEXT SystemContext
288 InternalPrintMessage (
289 "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
291 GetExceptionNameStr (ExceptionType
),
294 if ((mErrorCodeFlag
& (1 << ExceptionType
)) != 0) {
295 InternalPrintMessage (
296 "ExceptionData - %016lx",
297 SystemContext
.SystemContextX64
->ExceptionData
299 if (ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) {
300 InternalPrintMessage (
301 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
302 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0,
303 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_RSVD
) != 0,
304 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_US
) != 0,
305 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_WR
) != 0,
306 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_P
) != 0,
307 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_PK
) != 0,
308 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_SS
) != 0,
309 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_SGX
) != 0
313 InternalPrintMessage ("\n");
316 InternalPrintMessage (
317 "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
318 SystemContext
.SystemContextX64
->Rip
,
319 SystemContext
.SystemContextX64
->Cs
,
320 SystemContext
.SystemContextX64
->Rflags
322 InternalPrintMessage (
323 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
324 SystemContext
.SystemContextX64
->Rax
,
325 SystemContext
.SystemContextX64
->Rcx
,
326 SystemContext
.SystemContextX64
->Rdx
328 InternalPrintMessage (
329 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
330 SystemContext
.SystemContextX64
->Rbx
,
331 SystemContext
.SystemContextX64
->Rsp
,
332 SystemContext
.SystemContextX64
->Rbp
334 InternalPrintMessage (
335 "RSI - %016lx, RDI - %016lx\n",
336 SystemContext
.SystemContextX64
->Rsi
,
337 SystemContext
.SystemContextX64
->Rdi
339 InternalPrintMessage (
340 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
341 SystemContext
.SystemContextX64
->R8
,
342 SystemContext
.SystemContextX64
->R9
,
343 SystemContext
.SystemContextX64
->R10
345 InternalPrintMessage (
346 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
347 SystemContext
.SystemContextX64
->R11
,
348 SystemContext
.SystemContextX64
->R12
,
349 SystemContext
.SystemContextX64
->R13
351 InternalPrintMessage (
352 "R14 - %016lx, R15 - %016lx\n",
353 SystemContext
.SystemContextX64
->R14
,
354 SystemContext
.SystemContextX64
->R15
356 InternalPrintMessage (
357 "DS - %016lx, ES - %016lx, FS - %016lx\n",
358 SystemContext
.SystemContextX64
->Ds
,
359 SystemContext
.SystemContextX64
->Es
,
360 SystemContext
.SystemContextX64
->Fs
362 InternalPrintMessage (
363 "GS - %016lx, SS - %016lx\n",
364 SystemContext
.SystemContextX64
->Gs
,
365 SystemContext
.SystemContextX64
->Ss
367 InternalPrintMessage (
368 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
369 SystemContext
.SystemContextX64
->Cr0
,
370 SystemContext
.SystemContextX64
->Cr2
,
371 SystemContext
.SystemContextX64
->Cr3
373 InternalPrintMessage (
374 "CR4 - %016lx, CR8 - %016lx\n",
375 SystemContext
.SystemContextX64
->Cr4
,
376 SystemContext
.SystemContextX64
->Cr8
378 InternalPrintMessage (
379 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
380 SystemContext
.SystemContextX64
->Dr0
,
381 SystemContext
.SystemContextX64
->Dr1
,
382 SystemContext
.SystemContextX64
->Dr2
384 InternalPrintMessage (
385 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
386 SystemContext
.SystemContextX64
->Dr3
,
387 SystemContext
.SystemContextX64
->Dr6
,
388 SystemContext
.SystemContextX64
->Dr7
390 InternalPrintMessage (
391 "GDTR - %016lx %016lx, LDTR - %016lx\n",
392 SystemContext
.SystemContextX64
->Gdtr
[0],
393 SystemContext
.SystemContextX64
->Gdtr
[1],
394 SystemContext
.SystemContextX64
->Ldtr
396 InternalPrintMessage (
397 "IDTR - %016lx %016lx, TR - %016lx\n",
398 SystemContext
.SystemContextX64
->Idtr
[0],
399 SystemContext
.SystemContextX64
->Idtr
[1],
400 SystemContext
.SystemContextX64
->Tr
402 InternalPrintMessage (
403 "FXSAVE_STATE - %016lx\n",
404 &SystemContext
.SystemContextX64
->FxSaveState
409 Display CPU information.
411 @param ExceptionType Exception type.
412 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
415 DumpImageAndCpuContent (
416 IN EFI_EXCEPTION_TYPE ExceptionType
,
417 IN EFI_SYSTEM_CONTEXT SystemContext
420 DumpCpuContext (ExceptionType
, SystemContext
);
422 // Dump module image base and module entry point by RIP
424 if ((ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) &&
425 ((SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0))
428 // The RIP in SystemContext could not be used
429 // if it is page fault with I/D set.
431 DumpModuleImageInfo ((*(UINTN
*)(UINTN
)SystemContext
.SystemContextX64
->Rsp
));
433 DumpModuleImageInfo (SystemContext
.SystemContextX64
->Rip
);