1 /** @file
2   x64 CPU Exception Handler.
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 VOID
ArchUpdateIdtEntry(OUT IA32_IDT_GATE_DESCRIPTOR * IdtEntry,IN UINTN InterruptHandler)19 ArchUpdateIdtEntry (
20   OUT IA32_IDT_GATE_DESCRIPTOR       *IdtEntry,
21   IN  UINTN                          InterruptHandler
22   )
23 {
24   IdtEntry->Bits.OffsetLow   = (UINT16)(UINTN)InterruptHandler;
25   IdtEntry->Bits.OffsetHigh  = (UINT16)((UINTN)InterruptHandler >> 16);
26   IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
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 IdtEntry->Bits.OffsetLow + (((UINTN) IdtEntry->Bits.OffsetHigh)  << 16) +
42                                     (((UINTN) IdtEntry->Bits.OffsetUpper) << 32);
43 }
44 
45 /**
46   Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
47 
48   @param[in] ExceptionType        Exception type.
49   @param[in] SystemContext        Pointer to EFI_SYSTEM_CONTEXT.
50   @param[in] ExceptionHandlerData Pointer to exception handler data.
51 **/
52 VOID
ArchSaveExceptionContext(IN UINTN ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext,IN EXCEPTION_HANDLER_DATA * ExceptionHandlerData)53 ArchSaveExceptionContext (
54   IN UINTN                        ExceptionType,
55   IN EFI_SYSTEM_CONTEXT           SystemContext,
56   IN EXCEPTION_HANDLER_DATA       *ExceptionHandlerData
57   )
58 {
59   IA32_EFLAGS32           Eflags;
60   RESERVED_VECTORS_DATA   *ReservedVectors;
61 
62   ReservedVectors = ExceptionHandlerData->ReservedVectors;
63   //
64   // Save Exception context in global variable in first entry of the exception handler.
65   // So when original exception handler returns to the new exception handler (second entry),
66   // the Eflags/Cs/Eip/ExceptionData can be used.
67   //
68   ReservedVectors[ExceptionType].OldSs         = SystemContext.SystemContextX64->Ss;
69   ReservedVectors[ExceptionType].OldSp         = SystemContext.SystemContextX64->Rsp;
70   ReservedVectors[ExceptionType].OldFlags      = SystemContext.SystemContextX64->Rflags;
71   ReservedVectors[ExceptionType].OldCs         = SystemContext.SystemContextX64->Cs;
72   ReservedVectors[ExceptionType].OldIp         = SystemContext.SystemContextX64->Rip;
73   ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;
74   //
75   // Clear IF flag to avoid old IDT handler enable interrupt by IRET
76   //
77   Eflags.UintN = SystemContext.SystemContextX64->Rflags;
78   Eflags.Bits.IF = 0;
79   SystemContext.SystemContextX64->Rflags = Eflags.UintN;
80   //
81   // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
82   //
83   SystemContext.SystemContextX64->Rip = (UINTN) ReservedVectors[ExceptionType].HookAfterStubHeaderCode;
84 }
85 
86 /**
87   Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
88 
89   @param[in] ExceptionType        Exception type.
90   @param[in] SystemContext        Pointer to EFI_SYSTEM_CONTEXT.
91   @param[in] ExceptionHandlerData Pointer to exception handler data.
92 **/
93 VOID
ArchRestoreExceptionContext(IN UINTN ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext,IN EXCEPTION_HANDLER_DATA * ExceptionHandlerData)94 ArchRestoreExceptionContext (
95   IN UINTN                        ExceptionType,
96   IN EFI_SYSTEM_CONTEXT           SystemContext,
97   IN EXCEPTION_HANDLER_DATA       *ExceptionHandlerData
98   )
99 {
100   RESERVED_VECTORS_DATA   *ReservedVectors;
101 
102   ReservedVectors = ExceptionHandlerData->ReservedVectors;
103   SystemContext.SystemContextX64->Ss            = ReservedVectors[ExceptionType].OldSs;
104   SystemContext.SystemContextX64->Rsp           = ReservedVectors[ExceptionType].OldSp;
105   SystemContext.SystemContextX64->Rflags        = ReservedVectors[ExceptionType].OldFlags;
106   SystemContext.SystemContextX64->Cs            = ReservedVectors[ExceptionType].OldCs;
107   SystemContext.SystemContextX64->Rip           = ReservedVectors[ExceptionType].OldIp;
108   SystemContext.SystemContextX64->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;
109 }
110 
111 /**
112   Setup separate stack for given exceptions.
113 
114   @param[in] StackSwitchData      Pointer to data required for setuping up
115                                   stack switch.
116 
117   @retval EFI_SUCCESS             The exceptions have been successfully
118                                   initialized with new stack.
119   @retval EFI_INVALID_PARAMETER   StackSwitchData contains invalid content.
120 
121 **/
122 EFI_STATUS
ArchSetupExceptionStack(IN CPU_EXCEPTION_INIT_DATA * StackSwitchData)123 ArchSetupExceptionStack (
124   IN CPU_EXCEPTION_INIT_DATA          *StackSwitchData
125   )
126 {
127   IA32_DESCRIPTOR                   Gdtr;
128   IA32_DESCRIPTOR                   Idtr;
129   IA32_IDT_GATE_DESCRIPTOR          *IdtTable;
130   IA32_TSS_DESCRIPTOR               *TssDesc;
131   IA32_TASK_STATE_SEGMENT           *Tss;
132   UINTN                             StackTop;
133   UINTN                             Index;
134   UINTN                             Vector;
135   UINTN                             TssBase;
136   UINTN                             GdtSize;
137 
138   if (StackSwitchData == NULL ||
139       StackSwitchData->Ia32.Revision != CPU_EXCEPTION_INIT_DATA_REV ||
140       StackSwitchData->X64.KnownGoodStackTop == 0 ||
141       StackSwitchData->X64.KnownGoodStackSize == 0 ||
142       StackSwitchData->X64.StackSwitchExceptions == NULL ||
143       StackSwitchData->X64.StackSwitchExceptionNumber == 0 ||
144       StackSwitchData->X64.StackSwitchExceptionNumber > CPU_EXCEPTION_NUM ||
145       StackSwitchData->X64.GdtTable == NULL ||
146       StackSwitchData->X64.IdtTable == NULL ||
147       StackSwitchData->X64.ExceptionTssDesc == NULL ||
148       StackSwitchData->X64.ExceptionTss == NULL) {
149     return EFI_INVALID_PARAMETER;
150   }
151 
152   //
153   // The caller is responsible for that the GDT table, no matter the existing
154   // one or newly allocated, has enough space to hold descriptors for exception
155   // task-state segments.
156   //
157   if (((UINTN)StackSwitchData->X64.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
158     return EFI_INVALID_PARAMETER;
159   }
160 
161   if ((UINTN)StackSwitchData->X64.ExceptionTssDesc < (UINTN)(StackSwitchData->X64.GdtTable)) {
162     return EFI_INVALID_PARAMETER;
163   }
164 
165   if (((UINTN)StackSwitchData->X64.ExceptionTssDesc + StackSwitchData->X64.ExceptionTssDescSize) >
166       ((UINTN)(StackSwitchData->X64.GdtTable) + StackSwitchData->X64.GdtTableSize)) {
167     return EFI_INVALID_PARAMETER;
168   }
169 
170   //
171   // One task gate descriptor and one task-state segment are needed.
172   //
173   if (StackSwitchData->X64.ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {
174     return EFI_INVALID_PARAMETER;
175   }
176   if (StackSwitchData->X64.ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {
177     return EFI_INVALID_PARAMETER;
178   }
179 
180   //
181   // Interrupt stack table supports only 7 vectors.
182   //
183   TssDesc = StackSwitchData->X64.ExceptionTssDesc;
184   Tss     = StackSwitchData->X64.ExceptionTss;
185   if (StackSwitchData->X64.StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {
186     return EFI_INVALID_PARAMETER;
187   }
188 
189   //
190   // Initialize new GDT table and/or IDT table, if any
191   //
192   AsmReadIdtr (&Idtr);
193   AsmReadGdtr (&Gdtr);
194 
195   GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -
196             (UINTN)(StackSwitchData->X64.GdtTable);
197   if ((UINTN)StackSwitchData->X64.GdtTable != Gdtr.Base) {
198     CopyMem (StackSwitchData->X64.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
199     Gdtr.Base = (UINTN)StackSwitchData->X64.GdtTable;
200     Gdtr.Limit = (UINT16)GdtSize - 1;
201   }
202 
203   if ((UINTN)StackSwitchData->X64.IdtTable != Idtr.Base) {
204     Idtr.Base = (UINTN)StackSwitchData->X64.IdtTable;
205   }
206   if (StackSwitchData->X64.IdtTableSize > 0) {
207     Idtr.Limit = (UINT16)(StackSwitchData->X64.IdtTableSize - 1);
208   }
209 
210   //
211   // Fixup current task descriptor. Task-state segment for current task will
212   // be filled by processor during task switching.
213   //
214   TssBase = (UINTN)Tss;
215 
216   TssDesc->Uint128.Uint64  = 0;
217   TssDesc->Uint128.Uint64_1= 0;
218   TssDesc->Bits.LimitLow   = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
219   TssDesc->Bits.BaseLow    = (UINT16)TssBase;
220   TssDesc->Bits.BaseMidl   = (UINT8)(TssBase >> 16);
221   TssDesc->Bits.Type       = IA32_GDT_TYPE_TSS;
222   TssDesc->Bits.P          = 1;
223   TssDesc->Bits.LimitHigh  = 0;
224   TssDesc->Bits.BaseMidh   = (UINT8)(TssBase >> 24);
225   TssDesc->Bits.BaseHigh   = (UINT32)(TssBase >> 32);
226 
227   //
228   // Fixup exception task descriptor and task-state segment
229   //
230   ZeroMem (Tss, sizeof (*Tss));
231   StackTop = StackSwitchData->X64.KnownGoodStackTop - CPU_STACK_ALIGNMENT;
232   StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
233   IdtTable = StackSwitchData->X64.IdtTable;
234   for (Index = 0; Index < StackSwitchData->X64.StackSwitchExceptionNumber; ++Index) {
235     //
236     // Fixup IST
237     //
238     Tss->IST[Index] = StackTop;
239     StackTop -= StackSwitchData->X64.KnownGoodStackSize;
240 
241     //
242     // Set the IST field to enable corresponding IST
243     //
244     Vector = StackSwitchData->X64.StackSwitchExceptions[Index];
245     if (Vector >= CPU_EXCEPTION_NUM ||
246         Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)) {
247       continue;
248     }
249     IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);
250   }
251 
252   //
253   // Publish GDT
254   //
255   AsmWriteGdtr (&Gdtr);
256 
257   //
258   // Load current task
259   //
260   AsmWriteTr ((UINT16)((UINTN)StackSwitchData->X64.ExceptionTssDesc - Gdtr.Base));
261 
262   //
263   // Publish IDT
264   //
265   AsmWriteIdtr (&Idtr);
266 
267   return EFI_SUCCESS;
268 }
269 
270 /**
271   Display CPU information.
272 
273   @param ExceptionType  Exception type.
274   @param SystemContext  Pointer to EFI_SYSTEM_CONTEXT.
275 **/
276 VOID
277 EFIAPI
DumpCpuContext(IN EFI_EXCEPTION_TYPE ExceptionType,IN EFI_SYSTEM_CONTEXT SystemContext)278 DumpCpuContext (
279   IN EFI_EXCEPTION_TYPE   ExceptionType,
280   IN EFI_SYSTEM_CONTEXT   SystemContext
281   )
282 {
283   InternalPrintMessage (
284     "!!!! X64 Exception Type - %02x(%a)  CPU Apic ID - %08x !!!!\n",
285     ExceptionType,
286     GetExceptionNameStr (ExceptionType),
287     GetApicId ()
288     );
289   if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
290     InternalPrintMessage (
291       "ExceptionData - %016lx",
292       SystemContext.SystemContextX64->ExceptionData
293       );
294     if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {
295       InternalPrintMessage (
296         "  I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
297         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID)   != 0,
298         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_RSVD) != 0,
299         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_US)   != 0,
300         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_WR)   != 0,
301         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_P)    != 0,
302         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_PK)   != 0,
303         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SS)   != 0,
304         (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SGX)  != 0
305         );
306     }
307     InternalPrintMessage ("\n");
308   }
309   InternalPrintMessage (
310     "RIP  - %016lx, CS  - %016lx, RFLAGS - %016lx\n",
311     SystemContext.SystemContextX64->Rip,
312     SystemContext.SystemContextX64->Cs,
313     SystemContext.SystemContextX64->Rflags
314     );
315   InternalPrintMessage (
316     "RAX  - %016lx, RCX - %016lx, RDX - %016lx\n",
317     SystemContext.SystemContextX64->Rax,
318     SystemContext.SystemContextX64->Rcx,
319     SystemContext.SystemContextX64->Rdx
320     );
321   InternalPrintMessage (
322     "RBX  - %016lx, RSP - %016lx, RBP - %016lx\n",
323     SystemContext.SystemContextX64->Rbx,
324     SystemContext.SystemContextX64->Rsp,
325     SystemContext.SystemContextX64->Rbp
326     );
327   InternalPrintMessage (
328     "RSI  - %016lx, RDI - %016lx\n",
329     SystemContext.SystemContextX64->Rsi,
330     SystemContext.SystemContextX64->Rdi
331     );
332   InternalPrintMessage (
333     "R8   - %016lx, R9  - %016lx, R10 - %016lx\n",
334     SystemContext.SystemContextX64->R8,
335     SystemContext.SystemContextX64->R9,
336     SystemContext.SystemContextX64->R10
337     );
338   InternalPrintMessage (
339     "R11  - %016lx, R12 - %016lx, R13 - %016lx\n",
340     SystemContext.SystemContextX64->R11,
341     SystemContext.SystemContextX64->R12,
342     SystemContext.SystemContextX64->R13
343     );
344   InternalPrintMessage (
345     "R14  - %016lx, R15 - %016lx\n",
346     SystemContext.SystemContextX64->R14,
347     SystemContext.SystemContextX64->R15
348     );
349   InternalPrintMessage (
350     "DS   - %016lx, ES  - %016lx, FS  - %016lx\n",
351     SystemContext.SystemContextX64->Ds,
352     SystemContext.SystemContextX64->Es,
353     SystemContext.SystemContextX64->Fs
354     );
355   InternalPrintMessage (
356     "GS   - %016lx, SS  - %016lx\n",
357     SystemContext.SystemContextX64->Gs,
358     SystemContext.SystemContextX64->Ss
359     );
360   InternalPrintMessage (
361     "CR0  - %016lx, CR2 - %016lx, CR3 - %016lx\n",
362     SystemContext.SystemContextX64->Cr0,
363     SystemContext.SystemContextX64->Cr2,
364     SystemContext.SystemContextX64->Cr3
365     );
366   InternalPrintMessage (
367     "CR4  - %016lx, CR8 - %016lx\n",
368     SystemContext.SystemContextX64->Cr4,
369     SystemContext.SystemContextX64->Cr8
370     );
371   InternalPrintMessage (
372     "DR0  - %016lx, DR1 - %016lx, DR2 - %016lx\n",
373     SystemContext.SystemContextX64->Dr0,
374     SystemContext.SystemContextX64->Dr1,
375     SystemContext.SystemContextX64->Dr2
376     );
377   InternalPrintMessage (
378     "DR3  - %016lx, DR6 - %016lx, DR7 - %016lx\n",
379     SystemContext.SystemContextX64->Dr3,
380     SystemContext.SystemContextX64->Dr6,
381     SystemContext.SystemContextX64->Dr7
382     );
383   InternalPrintMessage (
384     "GDTR - %016lx %016lx, LDTR - %016lx\n",
385     SystemContext.SystemContextX64->Gdtr[0],
386     SystemContext.SystemContextX64->Gdtr[1],
387     SystemContext.SystemContextX64->Ldtr
388     );
389   InternalPrintMessage (
390     "IDTR - %016lx %016lx,   TR - %016lx\n",
391     SystemContext.SystemContextX64->Idtr[0],
392     SystemContext.SystemContextX64->Idtr[1],
393     SystemContext.SystemContextX64->Tr
394     );
395   InternalPrintMessage (
396     "FXSAVE_STATE - %016lx\n",
397     &SystemContext.SystemContextX64->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 RIP
416   //
417   if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
418       ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0)) {
419     //
420     // The RIP in SystemContext could not be used
421     // if it is page fault with I/D set.
422     //
423     DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp));
424   } else {
425     DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);
426   }
427 }
428