]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
cd7dccd48141025da8a1644fb0a6165b1e982f79
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ArchExceptionHandler.c
1 /** @file
2 x64 CPU Exception Handler.
3
4 Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "CpuExceptionCommon.h"
10
11 /**
12 Return address map of exception handler template so that C code can generate
13 exception tables.
14
15 @param IdtEntry Pointer to IDT entry to be updated.
16 @param InterruptHandler IDT handler value.
17 **/
18 VOID
19 ArchUpdateIdtEntry (
20 OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
21 IN UINTN InterruptHandler
22 )
23 {
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;
28 }
29
30 /**
31 Read IDT handler value from IDT entry.
32
33 @param IdtEntry Pointer to IDT entry to be read.
34
35 **/
36 UINTN
37 ArchGetIdtHandler (
38 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
39 )
40 {
41 return IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16) +
42 (((UINTN)IdtEntry->Bits.OffsetUpper) << 32);
43 }
44
45 /**
46 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
47
48 @param[in] ExceptionType Exception type.
49 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
50 @param[in] ExceptionHandlerData Pointer to exception handler data.
51 **/
52 VOID
53 ArchSaveExceptionContext (
54 IN UINTN ExceptionType,
55 IN EFI_SYSTEM_CONTEXT SystemContext,
56 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
57 )
58 {
59 IA32_EFLAGS32 Eflags;
60 RESERVED_VECTORS_DATA *ReservedVectors;
61
62 ReservedVectors = ExceptionHandlerData->ReservedVectors;
63 //
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.
67 //
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;
74 //
75 // Clear IF flag to avoid old IDT handler enable interrupt by IRET
76 //
77 Eflags.UintN = SystemContext.SystemContextX64->Rflags;
78 Eflags.Bits.IF = 0;
79 SystemContext.SystemContextX64->Rflags = Eflags.UintN;
80 //
81 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
82 //
83 SystemContext.SystemContextX64->Rip = (UINTN)ReservedVectors[ExceptionType].HookAfterStubHeaderCode;
84 }
85
86 /**
87 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
88
89 @param[in] ExceptionType Exception type.
90 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
91 @param[in] ExceptionHandlerData Pointer to exception handler data.
92 **/
93 VOID
94 ArchRestoreExceptionContext (
95 IN UINTN ExceptionType,
96 IN EFI_SYSTEM_CONTEXT SystemContext,
97 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
98 )
99 {
100 RESERVED_VECTORS_DATA *ReservedVectors;
101
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;
109 }
110
111 /**
112 Setup separate stack for given exceptions.
113
114 @param[in] StackSwitchData Pointer to data required for setuping up
115 stack switch.
116
117 @retval EFI_SUCCESS The exceptions have been successfully
118 initialized with new stack.
119 @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
120
121 **/
122 EFI_STATUS
123 ArchSetupExceptionStack (
124 IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
125 )
126 {
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;
132 UINTN StackTop;
133 UINTN Index;
134 UINTN Vector;
135 UINTN TssBase;
136 UINTN GdtSize;
137
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 {
150 return EFI_INVALID_PARAMETER;
151 }
152
153 //
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.
157 //
158 if (((UINTN)StackSwitchData->X64.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
159 return EFI_INVALID_PARAMETER;
160 }
161
162 if ((UINTN)StackSwitchData->X64.ExceptionTssDesc < (UINTN)(StackSwitchData->X64.GdtTable)) {
163 return EFI_INVALID_PARAMETER;
164 }
165
166 if (((UINTN)StackSwitchData->X64.ExceptionTssDesc + StackSwitchData->X64.ExceptionTssDescSize) >
167 ((UINTN)(StackSwitchData->X64.GdtTable) + StackSwitchData->X64.GdtTableSize))
168 {
169 return EFI_INVALID_PARAMETER;
170 }
171
172 //
173 // One task gate descriptor and one task-state segment are needed.
174 //
175 if (StackSwitchData->X64.ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {
176 return EFI_INVALID_PARAMETER;
177 }
178
179 if (StackSwitchData->X64.ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {
180 return EFI_INVALID_PARAMETER;
181 }
182
183 //
184 // Interrupt stack table supports only 7 vectors.
185 //
186 TssDesc = StackSwitchData->X64.ExceptionTssDesc;
187 Tss = StackSwitchData->X64.ExceptionTss;
188 if (StackSwitchData->X64.StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {
189 return EFI_INVALID_PARAMETER;
190 }
191
192 //
193 // Initialize new GDT table and/or IDT table, if any
194 //
195 AsmReadIdtr (&Idtr);
196 AsmReadGdtr (&Gdtr);
197
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;
204 }
205
206 if ((UINTN)StackSwitchData->X64.IdtTable != Idtr.Base) {
207 Idtr.Base = (UINTN)StackSwitchData->X64.IdtTable;
208 }
209
210 if (StackSwitchData->X64.IdtTableSize > 0) {
211 Idtr.Limit = (UINT16)(StackSwitchData->X64.IdtTableSize - 1);
212 }
213
214 //
215 // Fixup current task descriptor. Task-state segment for current task will
216 // be filled by processor during task switching.
217 //
218 TssBase = (UINTN)Tss;
219
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;
226 TssDesc->Bits.P = 1;
227 TssDesc->Bits.LimitHigh = 0;
228 TssDesc->Bits.BaseMidh = (UINT8)(TssBase >> 24);
229 TssDesc->Bits.BaseHigh = (UINT32)(TssBase >> 32);
230
231 //
232 // Fixup exception task descriptor and task-state segment
233 //
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) {
239 //
240 // Fixup IST
241 //
242 Tss->IST[Index] = StackTop;
243 StackTop -= StackSwitchData->X64.KnownGoodStackSize;
244
245 //
246 // Set the IST field to enable corresponding IST
247 //
248 Vector = StackSwitchData->X64.StackSwitchExceptions[Index];
249 if ((Vector >= CPU_EXCEPTION_NUM) ||
250 (Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
251 {
252 continue;
253 }
254
255 IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);
256 }
257
258 //
259 // Publish GDT
260 //
261 AsmWriteGdtr (&Gdtr);
262
263 //
264 // Load current task
265 //
266 AsmWriteTr ((UINT16)((UINTN)StackSwitchData->X64.ExceptionTssDesc - Gdtr.Base));
267
268 //
269 // Publish IDT
270 //
271 AsmWriteIdtr (&Idtr);
272
273 return EFI_SUCCESS;
274 }
275
276 /**
277 Display CPU information.
278
279 @param ExceptionType Exception type.
280 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
281 **/
282 VOID
283 EFIAPI
284 DumpCpuContext (
285 IN EFI_EXCEPTION_TYPE ExceptionType,
286 IN EFI_SYSTEM_CONTEXT SystemContext
287 )
288 {
289 InternalPrintMessage (
290 "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
291 ExceptionType,
292 GetExceptionNameStr (ExceptionType),
293 GetApicId ()
294 );
295 if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
296 InternalPrintMessage (
297 "ExceptionData - %016lx",
298 SystemContext.SystemContextX64->ExceptionData
299 );
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
311 );
312 }
313
314 InternalPrintMessage ("\n");
315 }
316
317 InternalPrintMessage (
318 "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
319 SystemContext.SystemContextX64->Rip,
320 SystemContext.SystemContextX64->Cs,
321 SystemContext.SystemContextX64->Rflags
322 );
323 InternalPrintMessage (
324 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
325 SystemContext.SystemContextX64->Rax,
326 SystemContext.SystemContextX64->Rcx,
327 SystemContext.SystemContextX64->Rdx
328 );
329 InternalPrintMessage (
330 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
331 SystemContext.SystemContextX64->Rbx,
332 SystemContext.SystemContextX64->Rsp,
333 SystemContext.SystemContextX64->Rbp
334 );
335 InternalPrintMessage (
336 "RSI - %016lx, RDI - %016lx\n",
337 SystemContext.SystemContextX64->Rsi,
338 SystemContext.SystemContextX64->Rdi
339 );
340 InternalPrintMessage (
341 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
342 SystemContext.SystemContextX64->R8,
343 SystemContext.SystemContextX64->R9,
344 SystemContext.SystemContextX64->R10
345 );
346 InternalPrintMessage (
347 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
348 SystemContext.SystemContextX64->R11,
349 SystemContext.SystemContextX64->R12,
350 SystemContext.SystemContextX64->R13
351 );
352 InternalPrintMessage (
353 "R14 - %016lx, R15 - %016lx\n",
354 SystemContext.SystemContextX64->R14,
355 SystemContext.SystemContextX64->R15
356 );
357 InternalPrintMessage (
358 "DS - %016lx, ES - %016lx, FS - %016lx\n",
359 SystemContext.SystemContextX64->Ds,
360 SystemContext.SystemContextX64->Es,
361 SystemContext.SystemContextX64->Fs
362 );
363 InternalPrintMessage (
364 "GS - %016lx, SS - %016lx\n",
365 SystemContext.SystemContextX64->Gs,
366 SystemContext.SystemContextX64->Ss
367 );
368 InternalPrintMessage (
369 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
370 SystemContext.SystemContextX64->Cr0,
371 SystemContext.SystemContextX64->Cr2,
372 SystemContext.SystemContextX64->Cr3
373 );
374 InternalPrintMessage (
375 "CR4 - %016lx, CR8 - %016lx\n",
376 SystemContext.SystemContextX64->Cr4,
377 SystemContext.SystemContextX64->Cr8
378 );
379 InternalPrintMessage (
380 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
381 SystemContext.SystemContextX64->Dr0,
382 SystemContext.SystemContextX64->Dr1,
383 SystemContext.SystemContextX64->Dr2
384 );
385 InternalPrintMessage (
386 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
387 SystemContext.SystemContextX64->Dr3,
388 SystemContext.SystemContextX64->Dr6,
389 SystemContext.SystemContextX64->Dr7
390 );
391 InternalPrintMessage (
392 "GDTR - %016lx %016lx, LDTR - %016lx\n",
393 SystemContext.SystemContextX64->Gdtr[0],
394 SystemContext.SystemContextX64->Gdtr[1],
395 SystemContext.SystemContextX64->Ldtr
396 );
397 InternalPrintMessage (
398 "IDTR - %016lx %016lx, TR - %016lx\n",
399 SystemContext.SystemContextX64->Idtr[0],
400 SystemContext.SystemContextX64->Idtr[1],
401 SystemContext.SystemContextX64->Tr
402 );
403 InternalPrintMessage (
404 "FXSAVE_STATE - %016lx\n",
405 &SystemContext.SystemContextX64->FxSaveState
406 );
407 }
408
409 /**
410 Display CPU information.
411
412 @param ExceptionType Exception type.
413 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
414 **/
415 VOID
416 DumpImageAndCpuContent (
417 IN EFI_EXCEPTION_TYPE ExceptionType,
418 IN EFI_SYSTEM_CONTEXT SystemContext
419 )
420 {
421 DumpCpuContext (ExceptionType, SystemContext);
422 //
423 // Dump module image base and module entry point by RIP
424 //
425 if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
426 ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0))
427 {
428 //
429 // The RIP in SystemContext could not be used
430 // if it is page fault with I/D set.
431 //
432 DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp));
433 } else {
434 DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);
435 }
436 }