1 /** @file
2   CPU Exception Handler Library common functions.
3 
4   Copyright (c) 2012 - 2016, 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 // Error code flag indicating whether or not an error code will be
19 // pushed on the stack if an exception occurs.
20 //
21 // 1 means an error code will be pushed, otherwise 0
22 //
23 CONST UINT32 mErrorCodeFlag = 0x00027d00;
24 
25 //
26 // Define the maximum message length
27 //
28 #define MAX_DEBUG_MESSAGE_LENGTH  0x100
29 
30 CONST CHAR8 mExceptionReservedStr[] = "Reserved";
31 CONST CHAR8 *mExceptionNameStr[] = {
32   "#DE - Divide Error",
33   "#DB - Debug",
34   "NMI Interrupt",
35   "#BP - Breakpoint",
36   "#OF - Overflow",
37   "#BR - BOUND Range Exceeded",
38   "#UD - Invalid Opcode",
39   "#NM - Device Not Available",
40   "#DF - Double Fault",
41   "Coprocessor Segment Overrun",
42   "#TS - Invalid TSS",
43   "#NP - Segment Not Present",
44   "#SS - Stack Fault Fault",
45   "#GP - General Protection",
46   "#PF - Page-Fault",
47   "Reserved",
48   "#MF - x87 FPU Floating-Point Error",
49   "#AC - Alignment Check",
50   "#MC - Machine-Check",
51   "#XM - SIMD floating-point",
52   "#VE - Virtualization"
53 };
54 
55 #define EXCEPTION_KNOWN_NAME_NUM  (sizeof (mExceptionNameStr) / sizeof (CHAR8 *))
56 
57 /**
58   Get ASCII format string exception name by exception type.
59 
60   @param ExceptionType  Exception type.
61 
62   @return  ASCII format string exception name.
63 **/
64 CONST CHAR8 *
GetExceptionNameStr(IN EFI_EXCEPTION_TYPE ExceptionType)65 GetExceptionNameStr (
66   IN EFI_EXCEPTION_TYPE          ExceptionType
67   )
68 {
69   if ((UINTN) ExceptionType < EXCEPTION_KNOWN_NAME_NUM) {
70     return mExceptionNameStr[ExceptionType];
71   } else {
72     return mExceptionReservedStr;
73   }
74 }
75 
76 /**
77   Prints a message to the serial port.
78 
79   @param  Format      Format string for the message to print.
80   @param  ...         Variable argument list whose contents are accessed
81                       based on the format string specified by Format.
82 
83 **/
84 VOID
85 EFIAPI
InternalPrintMessage(IN CONST CHAR8 * Format,...)86 InternalPrintMessage (
87   IN  CONST CHAR8  *Format,
88   ...
89   )
90 {
91   CHAR8    Buffer[MAX_DEBUG_MESSAGE_LENGTH];
92   VA_LIST  Marker;
93 
94   //
95   // Convert the message to an ASCII String
96   //
97   VA_START (Marker, Format);
98   AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
99   VA_END (Marker);
100 
101   //
102   // Send the print string to a Serial Port
103   //
104   SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
105 }
106 
107 /**
108   Find and display image base address and return image base and its entry point.
109 
110   @param CurrentEip      Current instruction pointer.
111   @param EntryPoint      Return module entry point if module header is found.
112 
113   @return !0     Image base address.
114   @return 0      Image header cannot be found.
115 **/
116 UINTN
FindModuleImageBase(IN UINTN CurrentEip,OUT UINTN * EntryPoint)117 FindModuleImageBase (
118   IN  UINTN              CurrentEip,
119   OUT UINTN              *EntryPoint
120   )
121 {
122   UINTN                                Pe32Data;
123   EFI_IMAGE_DOS_HEADER                 *DosHdr;
124   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
125   VOID                                 *PdbPointer;
126 
127   //
128   // Find Image Base
129   //
130   Pe32Data = CurrentEip & ~(mImageAlignSize - 1);
131   while (Pe32Data != 0) {
132     DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
133     if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
134       //
135       // DOS image header is present, so read the PE header after the DOS image header.
136       //
137       Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
138       //
139       // Make sure PE header address does not overflow and is less than the initial address.
140       //
141       if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < CurrentEip)) {
142         if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
143           //
144           // It's PE image.
145           //
146           InternalPrintMessage ("!!!! Find PE image ");
147           *EntryPoint = (UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff);
148           break;
149         }
150       }
151     } else {
152       //
153       // DOS image header is not present, TE header is at the image base.
154       //
155       Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
156       if ((Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) &&
157           ((Hdr.Te->Machine == IMAGE_FILE_MACHINE_I386) || Hdr.Te->Machine == IMAGE_FILE_MACHINE_X64)) {
158         //
159         // It's TE image, it TE header and Machine type match
160         //
161         InternalPrintMessage ("!!!! Find TE image ");
162         *EntryPoint = (UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
163         break;
164       }
165     }
166 
167     //
168     // Not found the image base, check the previous aligned address
169     //
170     Pe32Data -= mImageAlignSize;
171   }
172 
173   if (Pe32Data != 0) {
174     PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
175     if (PdbPointer != NULL) {
176       InternalPrintMessage ("%a", PdbPointer);
177     } else {
178       InternalPrintMessage ("(No PDB) " );
179     }
180   } else {
181     InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
182   }
183 
184   return Pe32Data;
185 }
186 
187 /**
188   Read and save reserved vector information
189 
190   @param[in]  VectorInfo        Pointer to reserved vector list.
191   @param[out] ReservedVector    Pointer to reserved vector data buffer.
192   @param[in]  VectorCount       Vector number to be updated.
193 
194   @return EFI_SUCCESS           Read and save vector info successfully.
195   @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
196 
197 **/
198 EFI_STATUS
ReadAndVerifyVectorInfo(IN EFI_VECTOR_HANDOFF_INFO * VectorInfo,OUT RESERVED_VECTORS_DATA * ReservedVector,IN UINTN VectorCount)199 ReadAndVerifyVectorInfo (
200   IN  EFI_VECTOR_HANDOFF_INFO       *VectorInfo,
201   OUT RESERVED_VECTORS_DATA         *ReservedVector,
202   IN  UINTN                         VectorCount
203   )
204 {
205   while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
206     if (VectorInfo->Attribute > EFI_VECTOR_HANDOFF_HOOK_AFTER) {
207       //
208       // If vector attrubute is invalid
209       //
210       return EFI_INVALID_PARAMETER;
211     }
212     if (VectorInfo->VectorNumber < VectorCount) {
213       ReservedVector[VectorInfo->VectorNumber].Attribute = VectorInfo->Attribute;
214     }
215     VectorInfo ++;
216   }
217   return EFI_SUCCESS;
218 }