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