]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ArchExceptionHandler.c
CommitLineData
8f07f895 1/** @file\r
e3644786 2 x64 CPU Exception Handler.\r
8f07f895 3\r
f1688ec9 4 Copyright (c) 2012 - 2022, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8f07f895 6\r
7**/\r
8\r
9#include "CpuExceptionCommon.h"\r
10\r
11/**\r
e41aad15
JF
12 Return address map of exception handler template so that C code can generate\r
13 exception tables.\r
8f07f895 14\r
e41aad15
JF
15 @param IdtEntry Pointer to IDT entry to be updated.\r
16 @param InterruptHandler IDT handler value.\r
8f07f895 17**/\r
18VOID\r
e41aad15 19ArchUpdateIdtEntry (\r
053e878b
MK
20 OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,\r
21 IN UINTN InterruptHandler\r
8f07f895 22 )\r
23{\r
e41aad15
JF
24 IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;\r
25 IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);\r
dd563742 26 IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);\r
e41aad15
JF
27 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;\r
28}\r
29\r
30/**\r
31 Read IDT handler value from IDT entry.\r
32\r
33 @param IdtEntry Pointer to IDT entry to be read.\r
34\r
35**/\r
36UINTN\r
37ArchGetIdtHandler (\r
053e878b 38 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry\r
e41aad15
JF
39 )\r
40{\r
053e878b
MK
41 return IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16) +\r
42 (((UINTN)IdtEntry->Bits.OffsetUpper) << 32);\r
e41aad15 43}\r
8f07f895 44\r
e41aad15
JF
45/**\r
46 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
47\r
81b21fc2
JF
48 @param[in] ExceptionType Exception type.\r
49 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
50 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
e41aad15
JF
51**/\r
52VOID\r
53ArchSaveExceptionContext (\r
053e878b
MK
54 IN UINTN ExceptionType,\r
55 IN EFI_SYSTEM_CONTEXT SystemContext,\r
56 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
57 )\r
58{\r
053e878b
MK
59 IA32_EFLAGS32 Eflags;\r
60 RESERVED_VECTORS_DATA *ReservedVectors;\r
81b21fc2
JF
61\r
62 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
8f07f895 63 //\r
87a9dd0d
RN
64 // Save Exception context in global variable in first entry of the exception handler.\r
65 // So when original exception handler returns to the new exception handler (second entry),\r
66 // the Eflags/Cs/Eip/ExceptionData can be used.\r
8f07f895 67 //\r
81b21fc2
JF
68 ReservedVectors[ExceptionType].OldSs = SystemContext.SystemContextX64->Ss;\r
69 ReservedVectors[ExceptionType].OldSp = SystemContext.SystemContextX64->Rsp;\r
70 ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextX64->Rflags;\r
71 ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextX64->Cs;\r
72 ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextX64->Rip;\r
73 ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;\r
8f07f895 74 //\r
e41aad15 75 // Clear IF flag to avoid old IDT handler enable interrupt by IRET\r
8f07f895 76 //\r
053e878b
MK
77 Eflags.UintN = SystemContext.SystemContextX64->Rflags;\r
78 Eflags.Bits.IF = 0;\r
e41aad15
JF
79 SystemContext.SystemContextX64->Rflags = Eflags.UintN;\r
80 //\r
87a9dd0d 81 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.\r
e41aad15 82 //\r
053e878b 83 SystemContext.SystemContextX64->Rip = (UINTN)ReservedVectors[ExceptionType].HookAfterStubHeaderCode;\r
8f07f895 84}\r
85\r
86/**\r
e41aad15 87 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
8f07f895 88\r
368c54e7
JF
89 @param[in] ExceptionType Exception type.\r
90 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
91 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
8f07f895 92**/\r
93VOID\r
e41aad15 94ArchRestoreExceptionContext (\r
053e878b
MK
95 IN UINTN ExceptionType,\r
96 IN EFI_SYSTEM_CONTEXT SystemContext,\r
97 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
98 )\r
99{\r
053e878b 100 RESERVED_VECTORS_DATA *ReservedVectors;\r
368c54e7 101\r
053e878b 102 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
368c54e7
JF
103 SystemContext.SystemContextX64->Ss = ReservedVectors[ExceptionType].OldSs;\r
104 SystemContext.SystemContextX64->Rsp = ReservedVectors[ExceptionType].OldSp;\r
105 SystemContext.SystemContextX64->Rflags = ReservedVectors[ExceptionType].OldFlags;\r
106 SystemContext.SystemContextX64->Cs = ReservedVectors[ExceptionType].OldCs;\r
107 SystemContext.SystemContextX64->Rip = ReservedVectors[ExceptionType].OldIp;\r
108 SystemContext.SystemContextX64->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;\r
e41aad15
JF
109}\r
110\r
0ff5aa9c 111/**\r
76cf3d35 112 Setup separate stacks for certain exception handlers.\r
0ff5aa9c 113\r
76cf3d35
ZL
114 @param[in] Buffer Point to buffer used to separate exception stack.\r
115 @param[in, out] BufferSize On input, it indicates the byte size of Buffer.\r
116 If the size is not enough, the return status will\r
117 be EFI_BUFFER_TOO_SMALL, and output BufferSize\r
118 will be the size it needs.\r
0ff5aa9c 119\r
76cf3d35
ZL
120 @retval EFI_SUCCESS The stacks are assigned successfully.\r
121 @retval EFI_BUFFER_TOO_SMALL This BufferSize is too small.\r
122 @retval EFI_UNSUPPORTED This function is not supported.\r
0ff5aa9c
JW
123**/\r
124EFI_STATUS\r
7c4207e9 125ArchSetupExceptionStack (\r
76cf3d35
ZL
126 IN VOID *Buffer,\r
127 IN OUT UINTN *BufferSize\r
0ff5aa9c
JW
128 )\r
129{\r
053e878b
MK
130 IA32_DESCRIPTOR Gdtr;\r
131 IA32_DESCRIPTOR Idtr;\r
132 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
133 IA32_TSS_DESCRIPTOR *TssDesc;\r
134 IA32_TASK_STATE_SEGMENT *Tss;\r
76cf3d35 135 VOID *NewGdtTable;\r
053e878b
MK
136 UINTN StackTop;\r
137 UINTN Index;\r
138 UINTN Vector;\r
139 UINTN TssBase;\r
76cf3d35
ZL
140 UINT8 *StackSwitchExceptions;\r
141 UINTN NeedBufferSize;\r
053e878b 142\r
76cf3d35 143 if (BufferSize == NULL) {\r
0ff5aa9c
JW
144 return EFI_INVALID_PARAMETER;\r
145 }\r
146\r
147 //\r
148 // Interrupt stack table supports only 7 vectors.\r
149 //\r
76cf3d35
ZL
150 if (CPU_STACK_SWITCH_EXCEPTION_NUMBER > ARRAY_SIZE (Tss->IST)) {\r
151 return EFI_UNSUPPORTED;\r
0ff5aa9c
JW
152 }\r
153\r
154 //\r
76cf3d35
ZL
155 // Total needed size includes stack size, new GDT table size, TSS size.\r
156 // Add another DESCRIPTOR size for alignment requiremet.\r
157 //\r
158 // Layout of memory needed for each processor:\r
159 // --------------------------------\r
160 // | |\r
161 // | Stack Size | X ExceptionNumber\r
162 // | |\r
163 // --------------------------------\r
164 // | Alignment | (just in case)\r
165 // --------------------------------\r
166 // | |\r
167 // | Original GDT |\r
168 // | |\r
169 // --------------------------------\r
170 // | |\r
171 // | Exception task descriptors | X 1\r
172 // | |\r
173 // --------------------------------\r
174 // | |\r
175 // | Exception task-state segment | X 1\r
176 // | |\r
177 // --------------------------------\r
0ff5aa9c 178 //\r
0ff5aa9c 179 AsmReadGdtr (&Gdtr);\r
76cf3d35
ZL
180 NeedBufferSize = CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE +\r
181 sizeof (IA32_TSS_DESCRIPTOR) +\r
182 Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE +\r
183 CPU_TSS_SIZE;\r
184\r
185 if (*BufferSize < NeedBufferSize) {\r
186 *BufferSize = NeedBufferSize;\r
187 return EFI_BUFFER_TOO_SMALL;\r
0ff5aa9c
JW
188 }\r
189\r
76cf3d35
ZL
190 if (Buffer == NULL) {\r
191 return EFI_INVALID_PARAMETER;\r
0ff5aa9c 192 }\r
053e878b 193\r
76cf3d35
ZL
194 AsmReadIdtr (&Idtr);\r
195 StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;\r
196 StackTop = (UINTN)Buffer + CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE;\r
197 NewGdtTable = ALIGN_POINTER (StackTop, sizeof (IA32_TSS_DESCRIPTOR));\r
198 TssDesc = (IA32_TSS_DESCRIPTOR *)((UINTN)NewGdtTable + Gdtr.Limit + 1);\r
199 Tss = (IA32_TASK_STATE_SEGMENT *)((UINTN)TssDesc + CPU_TSS_DESC_SIZE);\r
200\r
201 CopyMem (NewGdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
202 Gdtr.Base = (UINTN)NewGdtTable;\r
203 Gdtr.Limit = (UINT16)(Gdtr.Limit + CPU_TSS_DESC_SIZE);\r
0ff5aa9c
JW
204\r
205 //\r
206 // Fixup current task descriptor. Task-state segment for current task will\r
207 // be filled by processor during task switching.\r
208 //\r
209 TssBase = (UINTN)Tss;\r
210\r
053e878b
MK
211 TssDesc->Uint128.Uint64 = 0;\r
212 TssDesc->Uint128.Uint64_1 = 0;\r
213 TssDesc->Bits.LimitLow = sizeof (IA32_TASK_STATE_SEGMENT) - 1;\r
214 TssDesc->Bits.BaseLow = (UINT16)TssBase;\r
215 TssDesc->Bits.BaseMidl = (UINT8)(TssBase >> 16);\r
216 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;\r
217 TssDesc->Bits.P = 1;\r
218 TssDesc->Bits.LimitHigh = 0;\r
219 TssDesc->Bits.BaseMidh = (UINT8)(TssBase >> 24);\r
220 TssDesc->Bits.BaseHigh = (UINT32)(TssBase >> 32);\r
0ff5aa9c
JW
221\r
222 //\r
223 // Fixup exception task descriptor and task-state segment\r
224 //\r
eae7b476 225 ZeroMem (Tss, sizeof (*Tss));\r
a670f12a
TD
226 //\r
227 // Plus 1 byte is for compact stack layout in case StackTop is already aligned.\r
228 //\r
229 StackTop = StackTop - CPU_STACK_ALIGNMENT + 1;\r
0ff5aa9c 230 StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);\r
76cf3d35
ZL
231 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)Idtr.Base;\r
232 for (Index = 0; Index < CPU_STACK_SWITCH_EXCEPTION_NUMBER; ++Index) {\r
0ff5aa9c
JW
233 //\r
234 // Fixup IST\r
235 //\r
d69ba6a7 236 Tss->IST[Index] = StackTop;\r
76cf3d35 237 StackTop -= CPU_KNOWN_GOOD_STACK_SIZE;\r
0ff5aa9c
JW
238\r
239 //\r
240 // Set the IST field to enable corresponding IST\r
241 //\r
76cf3d35 242 Vector = StackSwitchExceptions[Index];\r
053e878b
MK
243 if ((Vector >= CPU_EXCEPTION_NUM) ||\r
244 (Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))\r
245 {\r
0ff5aa9c
JW
246 continue;\r
247 }\r
053e878b 248\r
0ff5aa9c
JW
249 IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);\r
250 }\r
251\r
252 //\r
253 // Publish GDT\r
254 //\r
255 AsmWriteGdtr (&Gdtr);\r
256\r
257 //\r
258 // Load current task\r
259 //\r
76cf3d35 260 AsmWriteTr ((UINT16)((UINTN)TssDesc - Gdtr.Base));\r
0ff5aa9c
JW
261\r
262 return EFI_SUCCESS;\r
263}\r
264\r
e41aad15 265/**\r
3f25e6ea 266 Display CPU information.\r
e41aad15
JF
267\r
268 @param ExceptionType Exception type.\r
269 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
270**/\r
271VOID\r
1b2f7b3e
JF
272EFIAPI\r
273DumpCpuContext (\r
053e878b
MK
274 IN EFI_EXCEPTION_TYPE ExceptionType,\r
275 IN EFI_SYSTEM_CONTEXT SystemContext\r
8f07f895 276 )\r
277{\r
8f07f895 278 InternalPrintMessage (\r
a51ee144 279 "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",\r
8f07f895 280 ExceptionType,\r
a51ee144 281 GetExceptionNameStr (ExceptionType),\r
8f07f895 282 GetApicId ()\r
283 );\r
1b2f7b3e
JF
284 if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {\r
285 InternalPrintMessage (\r
286 "ExceptionData - %016lx",\r
287 SystemContext.SystemContextX64->ExceptionData\r
288 );\r
289 if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {\r
290 InternalPrintMessage (\r
0d25074c 291 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",\r
1b2f7b3e
JF
292 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0,\r
293 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_RSVD) != 0,\r
294 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_US) != 0,\r
295 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_WR) != 0,\r
296 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_P) != 0,\r
297 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_PK) != 0,\r
0d25074c 298 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SS) != 0,\r
1b2f7b3e
JF
299 (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SGX) != 0\r
300 );\r
301 }\r
053e878b 302\r
1b2f7b3e
JF
303 InternalPrintMessage ("\n");\r
304 }\r
053e878b 305\r
8f07f895 306 InternalPrintMessage (\r
307 "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",\r
308 SystemContext.SystemContextX64->Rip,\r
309 SystemContext.SystemContextX64->Cs,\r
310 SystemContext.SystemContextX64->Rflags\r
311 );\r
8f07f895 312 InternalPrintMessage (\r
313 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",\r
314 SystemContext.SystemContextX64->Rax,\r
315 SystemContext.SystemContextX64->Rcx,\r
316 SystemContext.SystemContextX64->Rdx\r
317 );\r
318 InternalPrintMessage (\r
319 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",\r
320 SystemContext.SystemContextX64->Rbx,\r
321 SystemContext.SystemContextX64->Rsp,\r
322 SystemContext.SystemContextX64->Rbp\r
323 );\r
324 InternalPrintMessage (\r
325 "RSI - %016lx, RDI - %016lx\n",\r
326 SystemContext.SystemContextX64->Rsi,\r
327 SystemContext.SystemContextX64->Rdi\r
328 );\r
329 InternalPrintMessage (\r
330 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",\r
331 SystemContext.SystemContextX64->R8,\r
332 SystemContext.SystemContextX64->R9,\r
333 SystemContext.SystemContextX64->R10\r
334 );\r
335 InternalPrintMessage (\r
336 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",\r
337 SystemContext.SystemContextX64->R11,\r
338 SystemContext.SystemContextX64->R12,\r
339 SystemContext.SystemContextX64->R13\r
340 );\r
341 InternalPrintMessage (\r
342 "R14 - %016lx, R15 - %016lx\n",\r
343 SystemContext.SystemContextX64->R14,\r
344 SystemContext.SystemContextX64->R15\r
345 );\r
346 InternalPrintMessage (\r
347 "DS - %016lx, ES - %016lx, FS - %016lx\n",\r
348 SystemContext.SystemContextX64->Ds,\r
349 SystemContext.SystemContextX64->Es,\r
350 SystemContext.SystemContextX64->Fs\r
351 );\r
352 InternalPrintMessage (\r
353 "GS - %016lx, SS - %016lx\n",\r
354 SystemContext.SystemContextX64->Gs,\r
355 SystemContext.SystemContextX64->Ss\r
356 );\r
357 InternalPrintMessage (\r
358 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",\r
359 SystemContext.SystemContextX64->Cr0,\r
360 SystemContext.SystemContextX64->Cr2,\r
361 SystemContext.SystemContextX64->Cr3\r
362 );\r
363 InternalPrintMessage (\r
364 "CR4 - %016lx, CR8 - %016lx\n",\r
365 SystemContext.SystemContextX64->Cr4,\r
366 SystemContext.SystemContextX64->Cr8\r
367 );\r
368 InternalPrintMessage (\r
369 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",\r
370 SystemContext.SystemContextX64->Dr0,\r
371 SystemContext.SystemContextX64->Dr1,\r
372 SystemContext.SystemContextX64->Dr2\r
373 );\r
374 InternalPrintMessage (\r
375 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",\r
376 SystemContext.SystemContextX64->Dr3,\r
377 SystemContext.SystemContextX64->Dr6,\r
378 SystemContext.SystemContextX64->Dr7\r
379 );\r
380 InternalPrintMessage (\r
381 "GDTR - %016lx %016lx, LDTR - %016lx\n",\r
382 SystemContext.SystemContextX64->Gdtr[0],\r
383 SystemContext.SystemContextX64->Gdtr[1],\r
384 SystemContext.SystemContextX64->Ldtr\r
385 );\r
386 InternalPrintMessage (\r
387 "IDTR - %016lx %016lx, TR - %016lx\n",\r
388 SystemContext.SystemContextX64->Idtr[0],\r
389 SystemContext.SystemContextX64->Idtr[1],\r
390 SystemContext.SystemContextX64->Tr\r
391 );\r
dd563742 392 InternalPrintMessage (\r
8f07f895 393 "FXSAVE_STATE - %016lx\n",\r
394 &SystemContext.SystemContextX64->FxSaveState\r
395 );\r
1b2f7b3e 396}\r
8f07f895 397\r
1b2f7b3e
JF
398/**\r
399 Display CPU information.\r
400\r
401 @param ExceptionType Exception type.\r
402 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
403**/\r
404VOID\r
405DumpImageAndCpuContent (\r
053e878b
MK
406 IN EFI_EXCEPTION_TYPE ExceptionType,\r
407 IN EFI_SYSTEM_CONTEXT SystemContext\r
1b2f7b3e
JF
408 )\r
409{\r
410 DumpCpuContext (ExceptionType, SystemContext);\r
8f07f895 411 //\r
1b2f7b3e 412 // Dump module image base and module entry point by RIP\r
8f07f895 413 //\r
bb207f6c 414 if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&\r
053e878b
MK
415 ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0))\r
416 {\r
bb207f6c
SZ
417 //\r
418 // The RIP in SystemContext could not be used\r
419 // if it is page fault with I/D set.\r
420 //\r
421 DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp));\r
422 } else {\r
423 DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);\r
424 }\r
8f07f895 425}\r