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 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
->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
))
150 return EFI_INVALID_PARAMETER
;
154 // The caller is responsible for that the GDT table, no matter the existing
155 // one or newly allocated, has enough space to hold descriptors for exception
156 // task-state segments.
158 if (((UINTN
)StackSwitchData
->X64
.GdtTable
& (IA32_GDT_ALIGNMENT
- 1)) != 0) {
159 return EFI_INVALID_PARAMETER
;
162 if ((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
< (UINTN
)(StackSwitchData
->X64
.GdtTable
)) {
163 return EFI_INVALID_PARAMETER
;
166 if (((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
+ StackSwitchData
->X64
.ExceptionTssDescSize
) >
167 ((UINTN
)(StackSwitchData
->X64
.GdtTable
) + StackSwitchData
->X64
.GdtTableSize
))
169 return EFI_INVALID_PARAMETER
;
173 // One task gate descriptor and one task-state segment are needed.
175 if (StackSwitchData
->X64
.ExceptionTssDescSize
< sizeof (IA32_TSS_DESCRIPTOR
)) {
176 return EFI_INVALID_PARAMETER
;
179 if (StackSwitchData
->X64
.ExceptionTssSize
< sizeof (IA32_TASK_STATE_SEGMENT
)) {
180 return EFI_INVALID_PARAMETER
;
184 // Interrupt stack table supports only 7 vectors.
186 TssDesc
= StackSwitchData
->X64
.ExceptionTssDesc
;
187 Tss
= StackSwitchData
->X64
.ExceptionTss
;
188 if (StackSwitchData
->X64
.StackSwitchExceptionNumber
> ARRAY_SIZE (Tss
->IST
)) {
189 return EFI_INVALID_PARAMETER
;
193 // Initialize new GDT table and/or IDT table, if any
198 GdtSize
= (UINTN
)TssDesc
+ sizeof (IA32_TSS_DESCRIPTOR
) -
199 (UINTN
)(StackSwitchData
->X64
.GdtTable
);
200 if ((UINTN
)StackSwitchData
->X64
.GdtTable
!= Gdtr
.Base
) {
201 CopyMem (StackSwitchData
->X64
.GdtTable
, (VOID
*)Gdtr
.Base
, Gdtr
.Limit
+ 1);
202 Gdtr
.Base
= (UINTN
)StackSwitchData
->X64
.GdtTable
;
203 Gdtr
.Limit
= (UINT16
)GdtSize
- 1;
206 if ((UINTN
)StackSwitchData
->X64
.IdtTable
!= Idtr
.Base
) {
207 Idtr
.Base
= (UINTN
)StackSwitchData
->X64
.IdtTable
;
210 if (StackSwitchData
->X64
.IdtTableSize
> 0) {
211 Idtr
.Limit
= (UINT16
)(StackSwitchData
->X64
.IdtTableSize
- 1);
215 // Fixup current task descriptor. Task-state segment for current task will
216 // be filled by processor during task switching.
218 TssBase
= (UINTN
)Tss
;
220 TssDesc
->Uint128
.Uint64
= 0;
221 TssDesc
->Uint128
.Uint64_1
= 0;
222 TssDesc
->Bits
.LimitLow
= sizeof (IA32_TASK_STATE_SEGMENT
) - 1;
223 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
224 TssDesc
->Bits
.BaseMidl
= (UINT8
)(TssBase
>> 16);
225 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
227 TssDesc
->Bits
.LimitHigh
= 0;
228 TssDesc
->Bits
.BaseMidh
= (UINT8
)(TssBase
>> 24);
229 TssDesc
->Bits
.BaseHigh
= (UINT32
)(TssBase
>> 32);
232 // Fixup exception task descriptor and task-state segment
234 ZeroMem (Tss
, sizeof (*Tss
));
235 StackTop
= StackSwitchData
->X64
.KnownGoodStackTop
- CPU_STACK_ALIGNMENT
;
236 StackTop
= (UINTN
)ALIGN_POINTER (StackTop
, CPU_STACK_ALIGNMENT
);
237 IdtTable
= StackSwitchData
->X64
.IdtTable
;
238 for (Index
= 0; Index
< StackSwitchData
->X64
.StackSwitchExceptionNumber
; ++Index
) {
242 Tss
->IST
[Index
] = StackTop
;
243 StackTop
-= StackSwitchData
->X64
.KnownGoodStackSize
;
246 // Set the IST field to enable corresponding IST
248 Vector
= StackSwitchData
->X64
.StackSwitchExceptions
[Index
];
249 if ((Vector
>= CPU_EXCEPTION_NUM
) ||
250 (Vector
>= (Idtr
.Limit
+ 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR
)))
255 IdtTable
[Vector
].Bits
.Reserved_0
= (UINT8
)(Index
+ 1);
261 AsmWriteGdtr (&Gdtr
);
266 AsmWriteTr ((UINT16
)((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
- Gdtr
.Base
));
271 AsmWriteIdtr (&Idtr
);
277 Display CPU information.
279 @param ExceptionType Exception type.
280 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
285 IN EFI_EXCEPTION_TYPE ExceptionType
,
286 IN EFI_SYSTEM_CONTEXT SystemContext
289 InternalPrintMessage (
290 "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
292 GetExceptionNameStr (ExceptionType
),
295 if ((mErrorCodeFlag
& (1 << ExceptionType
)) != 0) {
296 InternalPrintMessage (
297 "ExceptionData - %016lx",
298 SystemContext
.SystemContextX64
->ExceptionData
300 if (ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) {
301 InternalPrintMessage (
302 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
303 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0,
304 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_RSVD
) != 0,
305 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_US
) != 0,
306 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_WR
) != 0,
307 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_P
) != 0,
308 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_PK
) != 0,
309 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_SS
) != 0,
310 (SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_SGX
) != 0
314 InternalPrintMessage ("\n");
317 InternalPrintMessage (
318 "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
319 SystemContext
.SystemContextX64
->Rip
,
320 SystemContext
.SystemContextX64
->Cs
,
321 SystemContext
.SystemContextX64
->Rflags
323 InternalPrintMessage (
324 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
325 SystemContext
.SystemContextX64
->Rax
,
326 SystemContext
.SystemContextX64
->Rcx
,
327 SystemContext
.SystemContextX64
->Rdx
329 InternalPrintMessage (
330 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
331 SystemContext
.SystemContextX64
->Rbx
,
332 SystemContext
.SystemContextX64
->Rsp
,
333 SystemContext
.SystemContextX64
->Rbp
335 InternalPrintMessage (
336 "RSI - %016lx, RDI - %016lx\n",
337 SystemContext
.SystemContextX64
->Rsi
,
338 SystemContext
.SystemContextX64
->Rdi
340 InternalPrintMessage (
341 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
342 SystemContext
.SystemContextX64
->R8
,
343 SystemContext
.SystemContextX64
->R9
,
344 SystemContext
.SystemContextX64
->R10
346 InternalPrintMessage (
347 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
348 SystemContext
.SystemContextX64
->R11
,
349 SystemContext
.SystemContextX64
->R12
,
350 SystemContext
.SystemContextX64
->R13
352 InternalPrintMessage (
353 "R14 - %016lx, R15 - %016lx\n",
354 SystemContext
.SystemContextX64
->R14
,
355 SystemContext
.SystemContextX64
->R15
357 InternalPrintMessage (
358 "DS - %016lx, ES - %016lx, FS - %016lx\n",
359 SystemContext
.SystemContextX64
->Ds
,
360 SystemContext
.SystemContextX64
->Es
,
361 SystemContext
.SystemContextX64
->Fs
363 InternalPrintMessage (
364 "GS - %016lx, SS - %016lx\n",
365 SystemContext
.SystemContextX64
->Gs
,
366 SystemContext
.SystemContextX64
->Ss
368 InternalPrintMessage (
369 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
370 SystemContext
.SystemContextX64
->Cr0
,
371 SystemContext
.SystemContextX64
->Cr2
,
372 SystemContext
.SystemContextX64
->Cr3
374 InternalPrintMessage (
375 "CR4 - %016lx, CR8 - %016lx\n",
376 SystemContext
.SystemContextX64
->Cr4
,
377 SystemContext
.SystemContextX64
->Cr8
379 InternalPrintMessage (
380 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
381 SystemContext
.SystemContextX64
->Dr0
,
382 SystemContext
.SystemContextX64
->Dr1
,
383 SystemContext
.SystemContextX64
->Dr2
385 InternalPrintMessage (
386 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
387 SystemContext
.SystemContextX64
->Dr3
,
388 SystemContext
.SystemContextX64
->Dr6
,
389 SystemContext
.SystemContextX64
->Dr7
391 InternalPrintMessage (
392 "GDTR - %016lx %016lx, LDTR - %016lx\n",
393 SystemContext
.SystemContextX64
->Gdtr
[0],
394 SystemContext
.SystemContextX64
->Gdtr
[1],
395 SystemContext
.SystemContextX64
->Ldtr
397 InternalPrintMessage (
398 "IDTR - %016lx %016lx, TR - %016lx\n",
399 SystemContext
.SystemContextX64
->Idtr
[0],
400 SystemContext
.SystemContextX64
->Idtr
[1],
401 SystemContext
.SystemContextX64
->Tr
403 InternalPrintMessage (
404 "FXSAVE_STATE - %016lx\n",
405 &SystemContext
.SystemContextX64
->FxSaveState
410 Display CPU information.
412 @param ExceptionType Exception type.
413 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
416 DumpImageAndCpuContent (
417 IN EFI_EXCEPTION_TYPE ExceptionType
,
418 IN EFI_SYSTEM_CONTEXT SystemContext
421 DumpCpuContext (ExceptionType
, SystemContext
);
423 // Dump module image base and module entry point by RIP
425 if ((ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) &&
426 ((SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0))
429 // The RIP in SystemContext could not be used
430 // if it is page fault with I/D set.
432 DumpModuleImageInfo ((*(UINTN
*)(UINTN
)SystemContext
.SystemContextX64
->Rsp
));
434 DumpModuleImageInfo (SystemContext
.SystemContextX64
->Rip
);