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