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