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