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