]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ArchExceptionHandler.c
CommitLineData
8f07f895 1/** @file\r
e3644786 2 IA32 CPU Exception Handler functons.\r
8f07f895 3\r
0d25074c 4 Copyright (c) 2012 - 2019, 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
14\r
15 @param IdtEntry Pointer to IDT entry to be updated.\r
16 @param InterruptHandler IDT handler value.\r
8f07f895 17\r
18**/\r
19VOID\r
e41aad15
JF
20ArchUpdateIdtEntry (\r
21 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry,\r
22 IN UINTN InterruptHandler\r
23 )\r
24{\r
25 IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;\r
26 IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);\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
8f07f895 39 )\r
40{\r
e41aad15
JF
41 return (UINTN)IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16);\r
42}\r
43\r
44/**\r
45 Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
8f07f895 46\r
81b21fc2
JF
47 @param[in] ExceptionType Exception type.\r
48 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
49 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
e41aad15
JF
50**/\r
51VOID\r
52ArchSaveExceptionContext (\r
81b21fc2
JF
53 IN UINTN ExceptionType,\r
54 IN EFI_SYSTEM_CONTEXT SystemContext,\r
55 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
56 )\r
57{\r
58 IA32_EFLAGS32 Eflags;\r
81b21fc2
JF
59 RESERVED_VECTORS_DATA *ReservedVectors;\r
60\r
61 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
8f07f895 62 //\r
87a9dd0d
RN
63 // Save Exception context in global variable in first entry of the exception handler.\r
64 // So when original exception handler returns to the new exception handler (second entry),\r
65 // the Eflags/Cs/Eip/ExceptionData can be used.\r
8f07f895 66 //\r
81b21fc2
JF
67 ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextIa32->Eflags;\r
68 ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextIa32->Cs;\r
69 ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextIa32->Eip;\r
70 ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextIa32->ExceptionData;\r
e41aad15
JF
71 //\r
72 // Clear IF flag to avoid old IDT handler enable interrupt by IRET\r
8f07f895 73 //\r
e41aad15 74 Eflags.UintN = SystemContext.SystemContextIa32->Eflags;\r
dd563742 75 Eflags.Bits.IF = 0;\r
e41aad15 76 SystemContext.SystemContextIa32->Eflags = Eflags.UintN;\r
8f07f895 77 //\r
87a9dd0d 78 // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.\r
e41aad15 79 //\r
81b21fc2 80 SystemContext.SystemContextIa32->Eip = (UINTN) ReservedVectors[ExceptionType].HookAfterStubHeaderCode;\r
e41aad15 81}\r
8f07f895 82\r
e41aad15
JF
83/**\r
84 Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.\r
8f07f895 85\r
368c54e7
JF
86 @param[in] ExceptionType Exception type.\r
87 @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.\r
88 @param[in] ExceptionHandlerData Pointer to exception handler data.\r
e41aad15
JF
89**/\r
90VOID\r
91ArchRestoreExceptionContext (\r
368c54e7
JF
92 IN UINTN ExceptionType,\r
93 IN EFI_SYSTEM_CONTEXT SystemContext,\r
94 IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData\r
e41aad15
JF
95 )\r
96{\r
368c54e7
JF
97 RESERVED_VECTORS_DATA *ReservedVectors;\r
98\r
99 ReservedVectors = ExceptionHandlerData->ReservedVectors;\r
100 SystemContext.SystemContextIa32->Eflags = ReservedVectors[ExceptionType].OldFlags;\r
101 SystemContext.SystemContextIa32->Cs = ReservedVectors[ExceptionType].OldCs;\r
102 SystemContext.SystemContextIa32->Eip = ReservedVectors[ExceptionType].OldIp;\r
103 SystemContext.SystemContextIa32->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;\r
8f07f895 104}\r
105\r
0ff5aa9c
JW
106/**\r
107 Setup separate stack for given exceptions.\r
108\r
109 @param[in] StackSwitchData Pointer to data required for setuping up\r
110 stack switch.\r
111\r
112 @retval EFI_SUCCESS The exceptions have been successfully\r
113 initialized with new stack.\r
114 @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.\r
115\r
116**/\r
117EFI_STATUS\r
7c4207e9 118ArchSetupExceptionStack (\r
0ff5aa9c
JW
119 IN CPU_EXCEPTION_INIT_DATA *StackSwitchData\r
120 )\r
121{\r
122 IA32_DESCRIPTOR Gdtr;\r
123 IA32_DESCRIPTOR Idtr;\r
124 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
125 IA32_TSS_DESCRIPTOR *TssDesc;\r
126 IA32_TASK_STATE_SEGMENT *Tss;\r
127 UINTN StackTop;\r
128 UINTN Index;\r
129 UINTN Vector;\r
130 UINTN TssBase;\r
131 UINTN GdtSize;\r
132 EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;\r
133\r
134 if (StackSwitchData == NULL ||\r
135 StackSwitchData->Ia32.Revision != CPU_EXCEPTION_INIT_DATA_REV ||\r
136 StackSwitchData->Ia32.KnownGoodStackTop == 0 ||\r
137 StackSwitchData->Ia32.KnownGoodStackSize == 0 ||\r
138 StackSwitchData->Ia32.StackSwitchExceptions == NULL ||\r
139 StackSwitchData->Ia32.StackSwitchExceptionNumber == 0 ||\r
140 StackSwitchData->Ia32.StackSwitchExceptionNumber > CPU_EXCEPTION_NUM ||\r
141 StackSwitchData->Ia32.GdtTable == NULL ||\r
142 StackSwitchData->Ia32.IdtTable == NULL ||\r
143 StackSwitchData->Ia32.ExceptionTssDesc == NULL ||\r
144 StackSwitchData->Ia32.ExceptionTss == NULL) {\r
145 return EFI_INVALID_PARAMETER;\r
146 }\r
147\r
148 //\r
149 // The caller is responsible for that the GDT table, no matter the existing\r
150 // one or newly allocated, has enough space to hold descriptors for exception\r
151 // task-state segments.\r
152 //\r
153 if (((UINTN)StackSwitchData->Ia32.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {\r
154 return EFI_INVALID_PARAMETER;\r
155 }\r
156\r
157 if ((UINTN)StackSwitchData->Ia32.ExceptionTssDesc < (UINTN)(StackSwitchData->Ia32.GdtTable)) {\r
158 return EFI_INVALID_PARAMETER;\r
159 }\r
160\r
161 if ((UINTN)StackSwitchData->Ia32.ExceptionTssDesc + StackSwitchData->Ia32.ExceptionTssDescSize >\r
162 ((UINTN)(StackSwitchData->Ia32.GdtTable) + StackSwitchData->Ia32.GdtTableSize)) {\r
163 return EFI_INVALID_PARAMETER;\r
164 }\r
165\r
166 //\r
167 // We need one descriptor and one TSS for current task and every exception\r
168 // specified.\r
169 //\r
170 if (StackSwitchData->Ia32.ExceptionTssDescSize <\r
171 sizeof (IA32_TSS_DESCRIPTOR) * (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1)) {\r
172 return EFI_INVALID_PARAMETER;\r
173 }\r
174 if (StackSwitchData->Ia32.ExceptionTssSize <\r
175 sizeof (IA32_TASK_STATE_SEGMENT) * (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1)) {\r
176 return EFI_INVALID_PARAMETER;\r
177 }\r
178\r
179 TssDesc = StackSwitchData->Ia32.ExceptionTssDesc;\r
180 Tss = StackSwitchData->Ia32.ExceptionTss;\r
181\r
182 //\r
183 // Initialize new GDT table and/or IDT table, if any\r
184 //\r
185 AsmReadIdtr (&Idtr);\r
186 AsmReadGdtr (&Gdtr);\r
187\r
188 GdtSize = (UINTN)TssDesc +\r
189 sizeof (IA32_TSS_DESCRIPTOR) *\r
190 (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1) -\r
191 (UINTN)(StackSwitchData->Ia32.GdtTable);\r
192 if ((UINTN)StackSwitchData->Ia32.GdtTable != Gdtr.Base) {\r
193 CopyMem (StackSwitchData->Ia32.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);\r
194 Gdtr.Base = (UINTN)StackSwitchData->Ia32.GdtTable;\r
195 Gdtr.Limit = (UINT16)GdtSize - 1;\r
196 }\r
197\r
198 if ((UINTN)StackSwitchData->Ia32.IdtTable != Idtr.Base) {\r
199 Idtr.Base = (UINTN)StackSwitchData->Ia32.IdtTable;\r
200 }\r
201 if (StackSwitchData->Ia32.IdtTableSize > 0) {\r
202 Idtr.Limit = (UINT16)(StackSwitchData->Ia32.IdtTableSize - 1);\r
203 }\r
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
eae7b476 211 TssDesc->Uint64 = 0;\r
0ff5aa9c
JW
212 TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;\r
213 TssDesc->Bits.BaseLow = (UINT16)TssBase;\r
214 TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
215 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;\r
d69ba6a7 216 TssDesc->Bits.P = 1;\r
0ff5aa9c
JW
217 TssDesc->Bits.LimitHigh = 0;\r
218 TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);\r
219\r
220 //\r
221 // Fixup exception task descriptor and task-state segment\r
222 //\r
223 AsmGetTssTemplateMap (&TemplateMap);\r
224 StackTop = StackSwitchData->Ia32.KnownGoodStackTop - CPU_STACK_ALIGNMENT;\r
225 StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);\r
226 IdtTable = StackSwitchData->Ia32.IdtTable;\r
227 for (Index = 0; Index < StackSwitchData->Ia32.StackSwitchExceptionNumber; ++Index) {\r
228 TssDesc += 1;\r
229 Tss += 1;\r
230\r
231 //\r
232 // Fixup TSS descriptor\r
233 //\r
234 TssBase = (UINTN)Tss;\r
235\r
eae7b476 236 TssDesc->Uint64 = 0;\r
0ff5aa9c
JW
237 TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;\r
238 TssDesc->Bits.BaseLow = (UINT16)TssBase;\r
239 TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);\r
240 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;\r
d69ba6a7 241 TssDesc->Bits.P = 1;\r
0ff5aa9c
JW
242 TssDesc->Bits.LimitHigh = 0;\r
243 TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);\r
244\r
245 //\r
246 // Fixup TSS\r
247 //\r
248 Vector = StackSwitchData->Ia32.StackSwitchExceptions[Index];\r
249 if (Vector >= CPU_EXCEPTION_NUM ||\r
250 Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)) {\r
251 continue;\r
252 }\r
253\r
eae7b476 254 ZeroMem (Tss, sizeof (*Tss));\r
d69ba6a7 255 Tss->EIP = (UINT32)(TemplateMap.ExceptionStart\r
0ff5aa9c 256 + Vector * TemplateMap.ExceptionStubHeaderSize);\r
d69ba6a7
JW
257 Tss->EFLAGS = 0x2;\r
258 Tss->ESP = StackTop;\r
259 Tss->CR3 = AsmReadCr3 ();\r
260 Tss->ES = AsmReadEs ();\r
261 Tss->CS = AsmReadCs ();\r
262 Tss->SS = AsmReadSs ();\r
263 Tss->DS = AsmReadDs ();\r
264 Tss->FS = AsmReadFs ();\r
265 Tss->GS = AsmReadGs ();\r
0ff5aa9c
JW
266\r
267 StackTop -= StackSwitchData->Ia32.KnownGoodStackSize;\r
268\r
269 //\r
270 // Update IDT to use Task Gate for given exception\r
271 //\r
272 IdtTable[Vector].Bits.OffsetLow = 0;\r
273 IdtTable[Vector].Bits.Selector = (UINT16)((UINTN)TssDesc - Gdtr.Base);\r
274 IdtTable[Vector].Bits.Reserved_0 = 0;\r
275 IdtTable[Vector].Bits.GateType = IA32_IDT_GATE_TYPE_TASK;\r
276 IdtTable[Vector].Bits.OffsetHigh = 0;\r
277 }\r
278\r
279 //\r
280 // Publish GDT\r
281 //\r
282 AsmWriteGdtr (&Gdtr);\r
283\r
284 //\r
285 // Load current task\r
286 //\r
287 AsmWriteTr ((UINT16)((UINTN)StackSwitchData->Ia32.ExceptionTssDesc - Gdtr.Base));\r
288\r
289 //\r
290 // Publish IDT\r
291 //\r
292 AsmWriteIdtr (&Idtr);\r
293\r
294 return EFI_SUCCESS;\r
295}\r
296\r
8f07f895 297/**\r
1b2f7b3e 298 Display processor context.\r
8f07f895 299\r
1b2f7b3e
JF
300 @param[in] ExceptionType Exception type.\r
301 @param[in] SystemContext Processor context to be display.\r
8f07f895 302**/\r
303VOID\r
1b2f7b3e
JF
304EFIAPI\r
305DumpCpuContext (\r
e41aad15 306 IN EFI_EXCEPTION_TYPE ExceptionType,\r
8f07f895 307 IN EFI_SYSTEM_CONTEXT SystemContext\r
308 )\r
309{\r
8f07f895 310 InternalPrintMessage (\r
a51ee144 311 "!!!! IA32 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",\r
8f07f895 312 ExceptionType,\r
a51ee144 313 GetExceptionNameStr (ExceptionType),\r
8f07f895 314 GetApicId ()\r
315 );\r
1b2f7b3e
JF
316 if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {\r
317 InternalPrintMessage (\r
318 "ExceptionData - %08x",\r
319 SystemContext.SystemContextIa32->ExceptionData\r
320 );\r
321 if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {\r
322 InternalPrintMessage (\r
0d25074c 323 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",\r
1b2f7b3e
JF
324 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,\r
325 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,\r
326 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,\r
327 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,\r
328 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0,\r
329 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_PK) != 0,\r
0d25074c 330 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SS) != 0,\r
1b2f7b3e
JF
331 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SGX) != 0\r
332 );\r
333 }\r
334 InternalPrintMessage ("\n");\r
335 }\r
8f07f895 336 InternalPrintMessage (\r
337 "EIP - %08x, CS - %08x, EFLAGS - %08x\n",\r
338 SystemContext.SystemContextIa32->Eip,\r
339 SystemContext.SystemContextIa32->Cs,\r
340 SystemContext.SystemContextIa32->Eflags\r
341 );\r
8f07f895 342 InternalPrintMessage (\r
343 "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",\r
344 SystemContext.SystemContextIa32->Eax,\r
345 SystemContext.SystemContextIa32->Ecx,\r
346 SystemContext.SystemContextIa32->Edx,\r
347 SystemContext.SystemContextIa32->Ebx\r
348 );\r
349 InternalPrintMessage (\r
350 "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",\r
351 SystemContext.SystemContextIa32->Esp,\r
352 SystemContext.SystemContextIa32->Ebp,\r
353 SystemContext.SystemContextIa32->Esi,\r
354 SystemContext.SystemContextIa32->Edi\r
355 );\r
356 InternalPrintMessage (\r
357 "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",\r
358 SystemContext.SystemContextIa32->Ds,\r
359 SystemContext.SystemContextIa32->Es,\r
360 SystemContext.SystemContextIa32->Fs,\r
361 SystemContext.SystemContextIa32->Gs,\r
362 SystemContext.SystemContextIa32->Ss\r
363 );\r
364 InternalPrintMessage (\r
365 "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",\r
366 SystemContext.SystemContextIa32->Cr0,\r
367 SystemContext.SystemContextIa32->Cr2,\r
368 SystemContext.SystemContextIa32->Cr3,\r
369 SystemContext.SystemContextIa32->Cr4\r
370 );\r
371 InternalPrintMessage (\r
372 "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",\r
373 SystemContext.SystemContextIa32->Dr0,\r
374 SystemContext.SystemContextIa32->Dr1,\r
375 SystemContext.SystemContextIa32->Dr2,\r
376 SystemContext.SystemContextIa32->Dr3\r
377 );\r
378 InternalPrintMessage (\r
379 "DR6 - %08x, DR7 - %08x\n",\r
380 SystemContext.SystemContextIa32->Dr6,\r
381 SystemContext.SystemContextIa32->Dr7\r
382 );\r
383 InternalPrintMessage (\r
384 "GDTR - %08x %08x, IDTR - %08x %08x\n",\r
385 SystemContext.SystemContextIa32->Gdtr[0],\r
386 SystemContext.SystemContextIa32->Gdtr[1],\r
387 SystemContext.SystemContextIa32->Idtr[0],\r
388 SystemContext.SystemContextIa32->Idtr[1]\r
389 );\r
390 InternalPrintMessage (\r
391 "LDTR - %08x, TR - %08x\n",\r
392 SystemContext.SystemContextIa32->Ldtr,\r
393 SystemContext.SystemContextIa32->Tr\r
394 );\r
395 InternalPrintMessage (\r
396 "FXSAVE_STATE - %08x\n",\r
397 &SystemContext.SystemContextIa32->FxSaveState\r
398 );\r
1b2f7b3e
JF
399}\r
400\r
401/**\r
402 Display CPU information.\r
8f07f895 403\r
1b2f7b3e
JF
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
8f07f895 414 //\r
1b2f7b3e 415 // Dump module image base and module entry point by EIP\r
8f07f895 416 //\r
bb207f6c
SZ
417 if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&\r
418 ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0)) {\r
419 //\r
420 // The EIP 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.SystemContextIa32->Esp));\r
424 } else {\r
425 DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);\r
426 }\r
8f07f895 427}\r