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
ArchUpdateIdtEntry(OUT IA32_IDT_GATE_DESCRIPTOR * IdtEntry,IN UINTN InterruptHandler)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
ArchGetIdtHandler(IN IA32_IDT_GATE_DESCRIPTOR * IdtEntry)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
ArchSaveExceptionContext(IN UINTN ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext,IN EXCEPTION_HANDLER_DATA * ExceptionHandlerData)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
ArchRestoreExceptionContext(IN UINTN ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext,IN EXCEPTION_HANDLER_DATA * ExceptionHandlerData)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
ArchSetupExceptionStack(IN CPU_EXCEPTION_INIT_DATA * StackSwitchData)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
DumpCpuContext(IN EFI_EXCEPTION_TYPE ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext)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
DumpImageAndCpuContent(IN EFI_EXCEPTION_TYPE ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext)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 }
428