2 x64 CPU Exception Handler.
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.
20 IN 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
->Ia32
.Revision
!= CPU_EXCEPTION_INIT_DATA_REV
||
140 StackSwitchData
->X64
.KnownGoodStackTop
== 0 ||
141 StackSwitchData
->X64
.KnownGoodStackSize
== 0 ||
142 StackSwitchData
->X64
.StackSwitchExceptions
== NULL
||
143 StackSwitchData
->X64
.StackSwitchExceptionNumber
== 0 ||
144 StackSwitchData
->X64
.StackSwitchExceptionNumber
> CPU_EXCEPTION_NUM
||
145 StackSwitchData
->X64
.GdtTable
== NULL
||
146 StackSwitchData
->X64
.IdtTable
== NULL
||
147 StackSwitchData
->X64
.ExceptionTssDesc
== NULL
||
148 StackSwitchData
->X64
.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
->X64
.GdtTable
& (IA32_GDT_ALIGNMENT
- 1)) != 0) {
158 return EFI_INVALID_PARAMETER
;
161 if ((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
< (UINTN
)(StackSwitchData
->X64
.GdtTable
)) {
162 return EFI_INVALID_PARAMETER
;
165 if (((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
+ StackSwitchData
->X64
.ExceptionTssDescSize
) >
166 ((UINTN
)(StackSwitchData
->X64
.GdtTable
) + StackSwitchData
->X64
.GdtTableSize
)) {
167 return EFI_INVALID_PARAMETER
;
171 // One task gate descriptor and one task-state segment are needed.
173 if (StackSwitchData
->X64
.ExceptionTssDescSize
< sizeof (IA32_TSS_DESCRIPTOR
)) {
174 return EFI_INVALID_PARAMETER
;
176 if (StackSwitchData
->X64
.ExceptionTssSize
< sizeof (IA32_TASK_STATE_SEGMENT
)) {
177 return EFI_INVALID_PARAMETER
;
181 // Interrupt stack table supports only 7 vectors.
183 TssDesc
= StackSwitchData
->X64
.ExceptionTssDesc
;
184 Tss
= StackSwitchData
->X64
.ExceptionTss
;
185 if (StackSwitchData
->X64
.StackSwitchExceptionNumber
> ARRAY_SIZE (Tss
->IST
)) {
186 return EFI_INVALID_PARAMETER
;
190 // Initialize new GDT table and/or IDT table, if any
195 GdtSize
= (UINTN
)TssDesc
+ sizeof (IA32_TSS_DESCRIPTOR
) -
196 (UINTN
)(StackSwitchData
->X64
.GdtTable
);
197 if ((UINTN
)StackSwitchData
->X64
.GdtTable
!= Gdtr
.Base
) {
198 CopyMem (StackSwitchData
->X64
.GdtTable
, (VOID
*)Gdtr
.Base
, Gdtr
.Limit
+ 1);
199 Gdtr
.Base
= (UINTN
)StackSwitchData
->X64
.GdtTable
;
200 Gdtr
.Limit
= (UINT16
)GdtSize
- 1;
203 if ((UINTN
)StackSwitchData
->X64
.IdtTable
!= Idtr
.Base
) {
204 Idtr
.Base
= (UINTN
)StackSwitchData
->X64
.IdtTable
;
206 if (StackSwitchData
->X64
.IdtTableSize
> 0) {
207 Idtr
.Limit
= (UINT16
)(StackSwitchData
->X64
.IdtTableSize
- 1);
211 // Fixup current task descriptor. Task-state segment for current task will
212 // be filled by processor during task switching.
214 TssBase
= (UINTN
)Tss
;
216 TssDesc
->Uint128
.Uint64
= 0;
217 TssDesc
->Uint128
.Uint64_1
= 0;
218 TssDesc
->Bits
.LimitLow
= sizeof(IA32_TASK_STATE_SEGMENT
) - 1;
219 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
220 TssDesc
->Bits
.BaseMidl
= (UINT8
)(TssBase
>> 16);
221 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
223 TssDesc
->Bits
.LimitHigh
= 0;
224 TssDesc
->Bits
.BaseMidh
= (UINT8
)(TssBase
>> 24);
225 TssDesc
->Bits
.BaseHigh
= (UINT32
)(TssBase
>> 32);
228 // Fixup exception task descriptor and task-state segment
230 ZeroMem (Tss
, sizeof (*Tss
));
231 StackTop
= StackSwitchData
->X64
.KnownGoodStackTop
- CPU_STACK_ALIGNMENT
;
232 StackTop
= (UINTN
)ALIGN_POINTER (StackTop
, CPU_STACK_ALIGNMENT
);
233 IdtTable
= StackSwitchData
->X64
.IdtTable
;
234 for (Index
= 0; Index
< StackSwitchData
->X64
.StackSwitchExceptionNumber
; ++Index
) {
238 Tss
->IST
[Index
] = StackTop
;
239 StackTop
-= StackSwitchData
->X64
.KnownGoodStackSize
;
242 // Set the IST field to enable corresponding IST
244 Vector
= StackSwitchData
->X64
.StackSwitchExceptions
[Index
];
245 if (Vector
>= CPU_EXCEPTION_NUM
||
246 Vector
>= (Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
)) {
249 IdtTable
[Vector
].Bits
.Reserved_0
= (UINT8
)(Index
+ 1);
255 AsmWriteGdtr (&Gdtr
);
260 AsmWriteTr ((UINT16
)((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
- Gdtr
.Base
));
265 AsmWriteIdtr (&Idtr
);
271 Display CPU information.
273 @param ExceptionType Exception type.
274 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
279 IN EFI_EXCEPTION_TYPE ExceptionType
,
280 IN EFI_SYSTEM_CONTEXT SystemContext
283 InternalPrintMessage (
284 "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
286 GetExceptionNameStr (ExceptionType
),
289 if ((mErrorCodeFlag
& (1 << ExceptionType
)) != 0) {
290 InternalPrintMessage (
291 "ExceptionData - %016lx",
292 SystemContext
.SystemContextX64
->ExceptionData
294 if (ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) {
295 InternalPrintMessage (
296 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
297 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0,
298 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_RSVD
) != 0,
299 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_US
) != 0,
300 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_WR
) != 0,
301 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_P
) != 0,
302 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_PK
) != 0,
303 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_SS
) != 0,
304 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_SGX
) != 0
307 InternalPrintMessage ("\n");
309 InternalPrintMessage (
310 "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
311 SystemContext
.SystemContextX64
->Rip
,
312 SystemContext
.SystemContextX64
->Cs
,
313 SystemContext
.SystemContextX64
->Rflags
315 InternalPrintMessage (
316 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
317 SystemContext
.SystemContextX64
->Rax
,
318 SystemContext
.SystemContextX64
->Rcx
,
319 SystemContext
.SystemContextX64
->Rdx
321 InternalPrintMessage (
322 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
323 SystemContext
.SystemContextX64
->Rbx
,
324 SystemContext
.SystemContextX64
->Rsp
,
325 SystemContext
.SystemContextX64
->Rbp
327 InternalPrintMessage (
328 "RSI - %016lx, RDI - %016lx\n",
329 SystemContext
.SystemContextX64
->Rsi
,
330 SystemContext
.SystemContextX64
->Rdi
332 InternalPrintMessage (
333 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
334 SystemContext
.SystemContextX64
->R8
,
335 SystemContext
.SystemContextX64
->R9
,
336 SystemContext
.SystemContextX64
->R10
338 InternalPrintMessage (
339 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
340 SystemContext
.SystemContextX64
->R11
,
341 SystemContext
.SystemContextX64
->R12
,
342 SystemContext
.SystemContextX64
->R13
344 InternalPrintMessage (
345 "R14 - %016lx, R15 - %016lx\n",
346 SystemContext
.SystemContextX64
->R14
,
347 SystemContext
.SystemContextX64
->R15
349 InternalPrintMessage (
350 "DS - %016lx, ES - %016lx, FS - %016lx\n",
351 SystemContext
.SystemContextX64
->Ds
,
352 SystemContext
.SystemContextX64
->Es
,
353 SystemContext
.SystemContextX64
->Fs
355 InternalPrintMessage (
356 "GS - %016lx, SS - %016lx\n",
357 SystemContext
.SystemContextX64
->Gs
,
358 SystemContext
.SystemContextX64
->Ss
360 InternalPrintMessage (
361 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
362 SystemContext
.SystemContextX64
->Cr0
,
363 SystemContext
.SystemContextX64
->Cr2
,
364 SystemContext
.SystemContextX64
->Cr3
366 InternalPrintMessage (
367 "CR4 - %016lx, CR8 - %016lx\n",
368 SystemContext
.SystemContextX64
->Cr4
,
369 SystemContext
.SystemContextX64
->Cr8
371 InternalPrintMessage (
372 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
373 SystemContext
.SystemContextX64
->Dr0
,
374 SystemContext
.SystemContextX64
->Dr1
,
375 SystemContext
.SystemContextX64
->Dr2
377 InternalPrintMessage (
378 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
379 SystemContext
.SystemContextX64
->Dr3
,
380 SystemContext
.SystemContextX64
->Dr6
,
381 SystemContext
.SystemContextX64
->Dr7
383 InternalPrintMessage (
384 "GDTR - %016lx %016lx, LDTR - %016lx\n",
385 SystemContext
.SystemContextX64
->Gdtr
[0],
386 SystemContext
.SystemContextX64
->Gdtr
[1],
387 SystemContext
.SystemContextX64
->Ldtr
389 InternalPrintMessage (
390 "IDTR - %016lx %016lx, TR - %016lx\n",
391 SystemContext
.SystemContextX64
->Idtr
[0],
392 SystemContext
.SystemContextX64
->Idtr
[1],
393 SystemContext
.SystemContextX64
->Tr
395 InternalPrintMessage (
396 "FXSAVE_STATE - %016lx\n",
397 &SystemContext
.SystemContextX64
->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 RIP
417 if ((ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) &&
418 ((SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0)) {
420 // The RIP in SystemContext could not be used
421 // if it is page fault with I/D set.
423 DumpModuleImageInfo ((*(UINTN
*)(UINTN
)SystemContext
.SystemContextX64
->Rsp
));
425 DumpModuleImageInfo (SystemContext
.SystemContextX64
->Rip
);