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