]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
1aafb7dac1398bd1daff663e312dd561446df49a
[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 IN 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 return EFI_INVALID_PARAMETER;
146 }
147
148 //
149 // The caller is responsible for that the GDT table, no matter the existing
150 // one or newly allocated, has enough space to hold descriptors for exception
151 // task-state segments.
152 //
153 if (((UINTN)StackSwitchData->Ia32.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
154 return EFI_INVALID_PARAMETER;
155 }
156
157 if ((UINTN)StackSwitchData->Ia32.ExceptionTssDesc < (UINTN)(StackSwitchData->Ia32.GdtTable)) {
158 return EFI_INVALID_PARAMETER;
159 }
160
161 if ((UINTN)StackSwitchData->Ia32.ExceptionTssDesc + StackSwitchData->Ia32.ExceptionTssDescSize >
162 ((UINTN)(StackSwitchData->Ia32.GdtTable) + StackSwitchData->Ia32.GdtTableSize)) {
163 return EFI_INVALID_PARAMETER;
164 }
165
166 //
167 // We need one descriptor and one TSS for current task and every exception
168 // specified.
169 //
170 if (StackSwitchData->Ia32.ExceptionTssDescSize <
171 sizeof (IA32_TSS_DESCRIPTOR) * (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1)) {
172 return EFI_INVALID_PARAMETER;
173 }
174 if (StackSwitchData->Ia32.ExceptionTssSize <
175 sizeof (IA32_TASK_STATE_SEGMENT) * (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1)) {
176 return EFI_INVALID_PARAMETER;
177 }
178
179 TssDesc = StackSwitchData->Ia32.ExceptionTssDesc;
180 Tss = StackSwitchData->Ia32.ExceptionTss;
181
182 //
183 // Initialize new GDT table and/or IDT table, if any
184 //
185 AsmReadIdtr (&Idtr);
186 AsmReadGdtr (&Gdtr);
187
188 GdtSize = (UINTN)TssDesc +
189 sizeof (IA32_TSS_DESCRIPTOR) *
190 (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1) -
191 (UINTN)(StackSwitchData->Ia32.GdtTable);
192 if ((UINTN)StackSwitchData->Ia32.GdtTable != Gdtr.Base) {
193 CopyMem (StackSwitchData->Ia32.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
194 Gdtr.Base = (UINTN)StackSwitchData->Ia32.GdtTable;
195 Gdtr.Limit = (UINT16)GdtSize - 1;
196 }
197
198 if ((UINTN)StackSwitchData->Ia32.IdtTable != Idtr.Base) {
199 Idtr.Base = (UINTN)StackSwitchData->Ia32.IdtTable;
200 }
201 if (StackSwitchData->Ia32.IdtTableSize > 0) {
202 Idtr.Limit = (UINT16)(StackSwitchData->Ia32.IdtTableSize - 1);
203 }
204
205 //
206 // Fixup current task descriptor. Task-state segment for current task will
207 // be filled by processor during task switching.
208 //
209 TssBase = (UINTN)Tss;
210
211 TssDesc->Uint64 = 0;
212 TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
213 TssDesc->Bits.BaseLow = (UINT16)TssBase;
214 TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);
215 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
216 TssDesc->Bits.P = 1;
217 TssDesc->Bits.LimitHigh = 0;
218 TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);
219
220 //
221 // Fixup exception task descriptor and task-state segment
222 //
223 AsmGetTssTemplateMap (&TemplateMap);
224 StackTop = StackSwitchData->Ia32.KnownGoodStackTop - CPU_STACK_ALIGNMENT;
225 StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
226 IdtTable = StackSwitchData->Ia32.IdtTable;
227 for (Index = 0; Index < StackSwitchData->Ia32.StackSwitchExceptionNumber; ++Index) {
228 TssDesc += 1;
229 Tss += 1;
230
231 //
232 // Fixup TSS descriptor
233 //
234 TssBase = (UINTN)Tss;
235
236 TssDesc->Uint64 = 0;
237 TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
238 TssDesc->Bits.BaseLow = (UINT16)TssBase;
239 TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);
240 TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
241 TssDesc->Bits.P = 1;
242 TssDesc->Bits.LimitHigh = 0;
243 TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);
244
245 //
246 // Fixup TSS
247 //
248 Vector = StackSwitchData->Ia32.StackSwitchExceptions[Index];
249 if (Vector >= CPU_EXCEPTION_NUM ||
250 Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)) {
251 continue;
252 }
253
254 ZeroMem (Tss, sizeof (*Tss));
255 Tss->EIP = (UINT32)(TemplateMap.ExceptionStart
256 + Vector * TemplateMap.ExceptionStubHeaderSize);
257 Tss->EFLAGS = 0x2;
258 Tss->ESP = StackTop;
259 Tss->CR3 = AsmReadCr3 ();
260 Tss->ES = AsmReadEs ();
261 Tss->CS = AsmReadCs ();
262 Tss->SS = AsmReadSs ();
263 Tss->DS = AsmReadDs ();
264 Tss->FS = AsmReadFs ();
265 Tss->GS = AsmReadGs ();
266
267 StackTop -= StackSwitchData->Ia32.KnownGoodStackSize;
268
269 //
270 // Update IDT to use Task Gate for given exception
271 //
272 IdtTable[Vector].Bits.OffsetLow = 0;
273 IdtTable[Vector].Bits.Selector = (UINT16)((UINTN)TssDesc - Gdtr.Base);
274 IdtTable[Vector].Bits.Reserved_0 = 0;
275 IdtTable[Vector].Bits.GateType = IA32_IDT_GATE_TYPE_TASK;
276 IdtTable[Vector].Bits.OffsetHigh = 0;
277 }
278
279 //
280 // Publish GDT
281 //
282 AsmWriteGdtr (&Gdtr);
283
284 //
285 // Load current task
286 //
287 AsmWriteTr ((UINT16)((UINTN)StackSwitchData->Ia32.ExceptionTssDesc - Gdtr.Base));
288
289 //
290 // Publish IDT
291 //
292 AsmWriteIdtr (&Idtr);
293
294 return EFI_SUCCESS;
295 }
296
297 /**
298 Display processor context.
299
300 @param[in] ExceptionType Exception type.
301 @param[in] SystemContext Processor context to be display.
302 **/
303 VOID
304 EFIAPI
305 DumpCpuContext (
306 IN EFI_EXCEPTION_TYPE ExceptionType,
307 IN EFI_SYSTEM_CONTEXT SystemContext
308 )
309 {
310 InternalPrintMessage (
311 "!!!! IA32 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
312 ExceptionType,
313 GetExceptionNameStr (ExceptionType),
314 GetApicId ()
315 );
316 if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
317 InternalPrintMessage (
318 "ExceptionData - %08x",
319 SystemContext.SystemContextIa32->ExceptionData
320 );
321 if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {
322 InternalPrintMessage (
323 " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
324 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,
325 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,
326 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,
327 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,
328 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0,
329 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_PK) != 0,
330 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SS) != 0,
331 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SGX) != 0
332 );
333 }
334 InternalPrintMessage ("\n");
335 }
336 InternalPrintMessage (
337 "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
338 SystemContext.SystemContextIa32->Eip,
339 SystemContext.SystemContextIa32->Cs,
340 SystemContext.SystemContextIa32->Eflags
341 );
342 InternalPrintMessage (
343 "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
344 SystemContext.SystemContextIa32->Eax,
345 SystemContext.SystemContextIa32->Ecx,
346 SystemContext.SystemContextIa32->Edx,
347 SystemContext.SystemContextIa32->Ebx
348 );
349 InternalPrintMessage (
350 "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
351 SystemContext.SystemContextIa32->Esp,
352 SystemContext.SystemContextIa32->Ebp,
353 SystemContext.SystemContextIa32->Esi,
354 SystemContext.SystemContextIa32->Edi
355 );
356 InternalPrintMessage (
357 "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
358 SystemContext.SystemContextIa32->Ds,
359 SystemContext.SystemContextIa32->Es,
360 SystemContext.SystemContextIa32->Fs,
361 SystemContext.SystemContextIa32->Gs,
362 SystemContext.SystemContextIa32->Ss
363 );
364 InternalPrintMessage (
365 "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
366 SystemContext.SystemContextIa32->Cr0,
367 SystemContext.SystemContextIa32->Cr2,
368 SystemContext.SystemContextIa32->Cr3,
369 SystemContext.SystemContextIa32->Cr4
370 );
371 InternalPrintMessage (
372 "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
373 SystemContext.SystemContextIa32->Dr0,
374 SystemContext.SystemContextIa32->Dr1,
375 SystemContext.SystemContextIa32->Dr2,
376 SystemContext.SystemContextIa32->Dr3
377 );
378 InternalPrintMessage (
379 "DR6 - %08x, DR7 - %08x\n",
380 SystemContext.SystemContextIa32->Dr6,
381 SystemContext.SystemContextIa32->Dr7
382 );
383 InternalPrintMessage (
384 "GDTR - %08x %08x, IDTR - %08x %08x\n",
385 SystemContext.SystemContextIa32->Gdtr[0],
386 SystemContext.SystemContextIa32->Gdtr[1],
387 SystemContext.SystemContextIa32->Idtr[0],
388 SystemContext.SystemContextIa32->Idtr[1]
389 );
390 InternalPrintMessage (
391 "LDTR - %08x, TR - %08x\n",
392 SystemContext.SystemContextIa32->Ldtr,
393 SystemContext.SystemContextIa32->Tr
394 );
395 InternalPrintMessage (
396 "FXSAVE_STATE - %08x\n",
397 &SystemContext.SystemContextIa32->FxSaveState
398 );
399 }
400
401 /**
402 Display CPU information.
403
404 @param ExceptionType Exception type.
405 @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
406 **/
407 VOID
408 DumpImageAndCpuContent (
409 IN EFI_EXCEPTION_TYPE ExceptionType,
410 IN EFI_SYSTEM_CONTEXT SystemContext
411 )
412 {
413 DumpCpuContext (ExceptionType, SystemContext);
414 //
415 // Dump module image base and module entry point by EIP
416 //
417 if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
418 ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0)) {
419 //
420 // The EIP in SystemContext could not be used
421 // if it is page fault with I/D set.
422 //
423 DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp));
424 } else {
425 DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);
426 }
427 }