2 x64 CPU Exception Handler.
4 Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "CpuExceptionCommon.h"
18 Return address map of exception handler template so that C code can generate
21 @param IdtEntry Pointer to IDT entry to be updated.
22 @param InterruptHandler IDT handler value.
26 IN IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
,
27 IN UINTN InterruptHandler
30 IdtEntry
->Bits
.OffsetLow
= (UINT16
)(UINTN
)InterruptHandler
;
31 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)((UINTN
)InterruptHandler
>> 16);
32 IdtEntry
->Bits
.OffsetUpper
= (UINT32
)((UINTN
)InterruptHandler
>> 32);
33 IdtEntry
->Bits
.GateType
= IA32_IDT_GATE_TYPE_INTERRUPT_32
;
37 Read IDT handler value from IDT entry.
39 @param IdtEntry Pointer to IDT entry to be read.
44 IN IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
47 return IdtEntry
->Bits
.OffsetLow
+ (((UINTN
) IdtEntry
->Bits
.OffsetHigh
) << 16) +
48 (((UINTN
) IdtEntry
->Bits
.OffsetUpper
) << 32);
52 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
54 @param[in] ExceptionType Exception type.
55 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
56 @param[in] ExceptionHandlerData Pointer to exception handler data.
59 ArchSaveExceptionContext (
60 IN UINTN ExceptionType
,
61 IN EFI_SYSTEM_CONTEXT SystemContext
,
62 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
66 RESERVED_VECTORS_DATA
*ReservedVectors
;
68 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
70 // Save Exception context in global variable in first entry of the exception handler.
71 // So when original exception handler returns to the new exception handler (second entry),
72 // the Eflags/Cs/Eip/ExceptionData can be used.
74 ReservedVectors
[ExceptionType
].OldSs
= SystemContext
.SystemContextX64
->Ss
;
75 ReservedVectors
[ExceptionType
].OldSp
= SystemContext
.SystemContextX64
->Rsp
;
76 ReservedVectors
[ExceptionType
].OldFlags
= SystemContext
.SystemContextX64
->Rflags
;
77 ReservedVectors
[ExceptionType
].OldCs
= SystemContext
.SystemContextX64
->Cs
;
78 ReservedVectors
[ExceptionType
].OldIp
= SystemContext
.SystemContextX64
->Rip
;
79 ReservedVectors
[ExceptionType
].ExceptionData
= SystemContext
.SystemContextX64
->ExceptionData
;
81 // Clear IF flag to avoid old IDT handler enable interrupt by IRET
83 Eflags
.UintN
= SystemContext
.SystemContextX64
->Rflags
;
85 SystemContext
.SystemContextX64
->Rflags
= Eflags
.UintN
;
87 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
89 SystemContext
.SystemContextX64
->Rip
= (UINTN
) ReservedVectors
[ExceptionType
].HookAfterStubHeaderCode
;
93 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
95 @param[in] ExceptionType Exception type.
96 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
97 @param[in] ExceptionHandlerData Pointer to exception handler data.
100 ArchRestoreExceptionContext (
101 IN UINTN ExceptionType
,
102 IN EFI_SYSTEM_CONTEXT SystemContext
,
103 IN EXCEPTION_HANDLER_DATA
*ExceptionHandlerData
106 RESERVED_VECTORS_DATA
*ReservedVectors
;
108 ReservedVectors
= ExceptionHandlerData
->ReservedVectors
;
109 SystemContext
.SystemContextX64
->Ss
= ReservedVectors
[ExceptionType
].OldSs
;
110 SystemContext
.SystemContextX64
->Rsp
= ReservedVectors
[ExceptionType
].OldSp
;
111 SystemContext
.SystemContextX64
->Rflags
= ReservedVectors
[ExceptionType
].OldFlags
;
112 SystemContext
.SystemContextX64
->Cs
= ReservedVectors
[ExceptionType
].OldCs
;
113 SystemContext
.SystemContextX64
->Rip
= ReservedVectors
[ExceptionType
].OldIp
;
114 SystemContext
.SystemContextX64
->ExceptionData
= ReservedVectors
[ExceptionType
].ExceptionData
;
118 Setup separate stack for given exceptions.
120 @param[in] StackSwitchData Pointer to data required for setuping up
123 @retval EFI_SUCCESS The exceptions have been successfully
124 initialized with new stack.
125 @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
129 ArchSetupExceptionStack (
130 IN CPU_EXCEPTION_INIT_DATA
*StackSwitchData
133 IA32_DESCRIPTOR Gdtr
;
134 IA32_DESCRIPTOR Idtr
;
135 IA32_IDT_GATE_DESCRIPTOR
*IdtTable
;
136 IA32_TSS_DESCRIPTOR
*TssDesc
;
137 IA32_TASK_STATE_SEGMENT
*Tss
;
144 if (StackSwitchData
== NULL
||
145 StackSwitchData
->Ia32
.Revision
!= CPU_EXCEPTION_INIT_DATA_REV
||
146 StackSwitchData
->X64
.KnownGoodStackTop
== 0 ||
147 StackSwitchData
->X64
.KnownGoodStackSize
== 0 ||
148 StackSwitchData
->X64
.StackSwitchExceptions
== NULL
||
149 StackSwitchData
->X64
.StackSwitchExceptionNumber
== 0 ||
150 StackSwitchData
->X64
.StackSwitchExceptionNumber
> CPU_EXCEPTION_NUM
||
151 StackSwitchData
->X64
.GdtTable
== NULL
||
152 StackSwitchData
->X64
.IdtTable
== NULL
||
153 StackSwitchData
->X64
.ExceptionTssDesc
== NULL
||
154 StackSwitchData
->X64
.ExceptionTss
== NULL
) {
155 return EFI_INVALID_PARAMETER
;
159 // The caller is responsible for that the GDT table, no matter the existing
160 // one or newly allocated, has enough space to hold descriptors for exception
161 // task-state segments.
163 if (((UINTN
)StackSwitchData
->X64
.GdtTable
& (IA32_GDT_ALIGNMENT
- 1)) != 0) {
164 return EFI_INVALID_PARAMETER
;
167 if ((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
< (UINTN
)(StackSwitchData
->X64
.GdtTable
)) {
168 return EFI_INVALID_PARAMETER
;
171 if (((UINTN
)StackSwitchData
->X64
.ExceptionTssDesc
+ StackSwitchData
->X64
.ExceptionTssDescSize
) >
172 ((UINTN
)(StackSwitchData
->X64
.GdtTable
) + StackSwitchData
->X64
.GdtTableSize
)) {
173 return EFI_INVALID_PARAMETER
;
177 // One task gate descriptor and one task-state segment are needed.
179 if (StackSwitchData
->X64
.ExceptionTssDescSize
< sizeof (IA32_TSS_DESCRIPTOR
)) {
180 return EFI_INVALID_PARAMETER
;
182 if (StackSwitchData
->X64
.ExceptionTssSize
< sizeof (IA32_TASK_STATE_SEGMENT
)) {
183 return EFI_INVALID_PARAMETER
;
187 // Interrupt stack table supports only 7 vectors.
189 TssDesc
= StackSwitchData
->X64
.ExceptionTssDesc
;
190 Tss
= StackSwitchData
->X64
.ExceptionTss
;
191 if (StackSwitchData
->X64
.StackSwitchExceptionNumber
> ARRAY_SIZE (Tss
->IST
)) {
192 return EFI_INVALID_PARAMETER
;
196 // Initialize new GDT table and/or IDT table, if any
201 GdtSize
= (UINTN
)TssDesc
+ sizeof (IA32_TSS_DESCRIPTOR
) -
202 (UINTN
)(StackSwitchData
->X64
.GdtTable
);
203 if ((UINTN
)StackSwitchData
->X64
.GdtTable
!= Gdtr
.Base
) {
204 CopyMem (StackSwitchData
->X64
.GdtTable
, (VOID
*)Gdtr
.Base
, Gdtr
.Limit
+ 1);
205 Gdtr
.Base
= (UINTN
)StackSwitchData
->X64
.GdtTable
;
206 Gdtr
.Limit
= (UINT16
)GdtSize
- 1;
209 if ((UINTN
)StackSwitchData
->X64
.IdtTable
!= Idtr
.Base
) {
210 Idtr
.Base
= (UINTN
)StackSwitchData
->X64
.IdtTable
;
212 if (StackSwitchData
->X64
.IdtTableSize
> 0) {
213 Idtr
.Limit
= (UINT16
)(StackSwitchData
->X64
.IdtTableSize
- 1);
217 // Fixup current task descriptor. Task-state segment for current task will
218 // be filled by processor during task switching.
220 TssBase
= (UINTN
)Tss
;
222 TssDesc
->Uint128
.Uint64
= 0;
223 TssDesc
->Uint128
.Uint64_1
= 0;
224 TssDesc
->Bits
.LimitLow
= sizeof(IA32_TASK_STATE_SEGMENT
) - 1;
225 TssDesc
->Bits
.BaseLow
= (UINT16
)TssBase
;
226 TssDesc
->Bits
.BaseMidl
= (UINT8
)(TssBase
>> 16);
227 TssDesc
->Bits
.Type
= IA32_GDT_TYPE_TSS
;
229 TssDesc
->Bits
.LimitHigh
= 0;
230 TssDesc
->Bits
.BaseMidh
= (UINT8
)(TssBase
>> 24);
231 TssDesc
->Bits
.BaseHigh
= (UINT32
)(TssBase
>> 32);
234 // Fixup exception task descriptor and task-state segment
236 ZeroMem (Tss
, sizeof (*Tss
));
237 StackTop
= StackSwitchData
->X64
.KnownGoodStackTop
- CPU_STACK_ALIGNMENT
;
238 StackTop
= (UINTN
)ALIGN_POINTER (StackTop
, CPU_STACK_ALIGNMENT
);
239 IdtTable
= StackSwitchData
->X64
.IdtTable
;
240 for (Index
= 0; Index
< StackSwitchData
->X64
.StackSwitchExceptionNumber
; ++Index
) {
244 Tss
->IST
[Index
] = StackTop
;
245 StackTop
-= StackSwitchData
->X64
.KnownGoodStackSize
;
248 // Set the IST field to enable corresponding IST
250 Vector
= StackSwitchData
->X64
.StackSwitchExceptions
[Index
];
251 if (Vector
>= CPU_EXCEPTION_NUM
||
252 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
313 InternalPrintMessage ("\n");
315 InternalPrintMessage (
316 "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
317 SystemContext
.SystemContextX64
->Rip
,
318 SystemContext
.SystemContextX64
->Cs
,
319 SystemContext
.SystemContextX64
->Rflags
321 InternalPrintMessage (
322 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
323 SystemContext
.SystemContextX64
->Rax
,
324 SystemContext
.SystemContextX64
->Rcx
,
325 SystemContext
.SystemContextX64
->Rdx
327 InternalPrintMessage (
328 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
329 SystemContext
.SystemContextX64
->Rbx
,
330 SystemContext
.SystemContextX64
->Rsp
,
331 SystemContext
.SystemContextX64
->Rbp
333 InternalPrintMessage (
334 "RSI - %016lx, RDI - %016lx\n",
335 SystemContext
.SystemContextX64
->Rsi
,
336 SystemContext
.SystemContextX64
->Rdi
338 InternalPrintMessage (
339 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
340 SystemContext
.SystemContextX64
->R8
,
341 SystemContext
.SystemContextX64
->R9
,
342 SystemContext
.SystemContextX64
->R10
344 InternalPrintMessage (
345 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
346 SystemContext
.SystemContextX64
->R11
,
347 SystemContext
.SystemContextX64
->R12
,
348 SystemContext
.SystemContextX64
->R13
350 InternalPrintMessage (
351 "R14 - %016lx, R15 - %016lx\n",
352 SystemContext
.SystemContextX64
->R14
,
353 SystemContext
.SystemContextX64
->R15
355 InternalPrintMessage (
356 "DS - %016lx, ES - %016lx, FS - %016lx\n",
357 SystemContext
.SystemContextX64
->Ds
,
358 SystemContext
.SystemContextX64
->Es
,
359 SystemContext
.SystemContextX64
->Fs
361 InternalPrintMessage (
362 "GS - %016lx, SS - %016lx\n",
363 SystemContext
.SystemContextX64
->Gs
,
364 SystemContext
.SystemContextX64
->Ss
366 InternalPrintMessage (
367 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
368 SystemContext
.SystemContextX64
->Cr0
,
369 SystemContext
.SystemContextX64
->Cr2
,
370 SystemContext
.SystemContextX64
->Cr3
372 InternalPrintMessage (
373 "CR4 - %016lx, CR8 - %016lx\n",
374 SystemContext
.SystemContextX64
->Cr4
,
375 SystemContext
.SystemContextX64
->Cr8
377 InternalPrintMessage (
378 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
379 SystemContext
.SystemContextX64
->Dr0
,
380 SystemContext
.SystemContextX64
->Dr1
,
381 SystemContext
.SystemContextX64
->Dr2
383 InternalPrintMessage (
384 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
385 SystemContext
.SystemContextX64
->Dr3
,
386 SystemContext
.SystemContextX64
->Dr6
,
387 SystemContext
.SystemContextX64
->Dr7
389 InternalPrintMessage (
390 "GDTR - %016lx %016lx, LDTR - %016lx\n",
391 SystemContext
.SystemContextX64
->Gdtr
[0],
392 SystemContext
.SystemContextX64
->Gdtr
[1],
393 SystemContext
.SystemContextX64
->Ldtr
395 InternalPrintMessage (
396 "IDTR - %016lx %016lx, TR - %016lx\n",
397 SystemContext
.SystemContextX64
->Idtr
[0],
398 SystemContext
.SystemContextX64
->Idtr
[1],
399 SystemContext
.SystemContextX64
->Tr
401 InternalPrintMessage (
402 "FXSAVE_STATE - %016lx\n",
403 &SystemContext
.SystemContextX64
->FxSaveState
408 Display CPU information.
410 @param ExceptionType Exception type.
411 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
414 DumpImageAndCpuContent (
415 IN EFI_EXCEPTION_TYPE ExceptionType
,
416 IN EFI_SYSTEM_CONTEXT SystemContext
419 DumpCpuContext (ExceptionType
, SystemContext
);
421 // Dump module image base and module entry point by RIP
423 if ((ExceptionType
== EXCEPT_IA32_PAGE_FAULT
) &&
424 ((SystemContext
.SystemContextX64
->ExceptionData
& IA32_PF_EC_ID
) != 0)) {
426 // The RIP in SystemContext could not be used
427 // if it is page fault with I/D set.
429 DumpModuleImageInfo ((*(UINTN
*)(UINTN
)SystemContext
.SystemContextX64
->Rsp
));
431 DumpModuleImageInfo (SystemContext
.SystemContextX64
->Rip
);