]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandler.c
Update execption handler to print out DFSR & IFSR info.
[mirror_edk2.git] / ArmPkg / Library / DefaultExceptionHandlerLib / DefaultExceptionHandler.c
CommitLineData
6f72e28d 1/** @file\r
2 Default exception handler\r
3\r
4 Copyright (c) 2008-2010, Apple Inc. All rights reserved.\r
5 \r
6 All rights reserved. This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Uefi.h>\r
17#include <Library/UefiLib.h>\r
18#include <Library/BaseLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/PeCoffGetEntryPointLib.h>\r
21\r
22#include <Guid/DebugImageInfoTable.h>\r
23#include <Protocol/DebugSupport.h>\r
24#include <Protocol/LoadedImage.h>\r
25\r
26\r
27VOID\r
28DisassembleArmInstruction (\r
29 IN UINT32 *OpCodePtr,\r
30 OUT CHAR8 *Buf,\r
31 OUT UINTN Size\r
32 );\r
33\r
34VOID\r
35DisassembleThumbInstruction (\r
36 IN UINT16 *OpCodePtr,\r
37 OUT CHAR8 *Buf,\r
38 OUT UINTN Size\r
39 );\r
40\r
41\r
42EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL;\r
43\r
44\r
45typedef struct {\r
46 UINT32 BIT;\r
47 CHAR8 Char;\r
48} CPSR_CHAR;\r
49\r
50\r
51\r
52 \r
53/**\r
54 Use the EFI Debug Image Table to lookup the FaultAddress and find which PE/COFF image \r
55 it came from. As long as the PE/COFF image contains a debug directory entry a \r
56 string can be returned. For ELF and Mach-O images the string points to the Mach-O or ELF\r
57 image. Microsoft tools contain a pointer to the PDB file that contains the debug information.\r
58\r
59 @param FaultAddress Address to find PE/COFF image for. \r
60 @param ImageBase Return load address of found image\r
61 @param PeCoffSizeOfHeaders Return the size of the PE/COFF header for the image that was found\r
62\r
63 @retval NULL FaultAddress not in a loaded PE/COFF image.\r
64 @retval Path and file name of PE/COFF image.\r
65 \r
66**/\r
67CHAR8 *\r
68GetImageName (\r
69 IN UINT32 FaultAddress,\r
70 OUT UINT32 *ImageBase,\r
71 OUT UINT32 *PeCoffSizeOfHeaders\r
72 )\r
73{\r
74 EFI_DEBUG_IMAGE_INFO *DebugTable;\r
75 UINTN Entry;\r
76 CHAR8 *Address;\r
77\r
78 \r
79 DebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable;\r
80 if (DebugTable == NULL) {\r
81 return NULL;\r
82 }\r
83\r
84 Address = (CHAR8 *)(UINTN)FaultAddress;\r
85 for (Entry = 0; Entry < gDebugImageTableHeader->TableSize; Entry++, DebugTable++) {\r
86 if (DebugTable->NormalImage != NULL) {\r
87 if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && \r
88 (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {\r
89 if ((Address >= (CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase) &&\r
90 (Address <= ((CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolInstance->ImageSize))) {\r
91 *ImageBase = (UINT32)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase;\r
92 *PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)*ImageBase);\r
93 return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase);\r
94 } \r
95 }\r
96 } \r
97 }\r
98\r
99 return NULL;\r
100}\r
101\r
102\r
103/**\r
104 Convert the Current Program Status Register (CPSR) to a string. The string is \r
105 a defacto standard in the ARM world. \r
106 \r
107 It is possible to add extra bits by adding them to CpsrChar array.\r
108\r
109 @param Cpsr ARM CPSR register value\r
110 @param ReturnStr 32 byte string that contains string version of CPSR\r
111\r
112**/\r
113VOID\r
114CpsrString (\r
115 IN UINT32 Cpsr,\r
116 OUT CHAR8 *ReturnStr\r
117 )\r
118{\r
119 UINTN Index;\r
120 CHAR8 *Str = ReturnStr;\r
121 CHAR8 *ModeStr;\r
122 CPSR_CHAR CpsrChar[] = {\r
123 { 31, 'n' },\r
124 { 30, 'z' },\r
125 { 29, 'c' },\r
126 { 28, 'v' },\r
127\r
128 { 9, 'e' },\r
129 { 8, 'a' },\r
130 { 7, 'i' },\r
131 { 6, 'f' },\r
132 { 5, 't' },\r
133 { 0, '?' }\r
134 };\r
135 \r
136 for (Index = 0; CpsrChar[Index].BIT != 0; Index++, Str++) {\r
137 *Str = CpsrChar[Index].Char;\r
138 if ((Cpsr & (1 << CpsrChar[Index].BIT)) != 0) {\r
139 // Concert to upper case if bit is set\r
140 *Str &= ~0x20;\r
141 }\r
142 }\r
143 \r
144 *Str++ = '_';\r
145 *Str = '\0';\r
146 \r
147 switch (Cpsr & 0x1f) {\r
148 case 0x10:\r
149 ModeStr = "usr";\r
150 break;\r
151 case 0x011:\r
152 ModeStr = "fiq";\r
153 break;\r
154 case 0x12:\r
155 ModeStr = "irq";\r
156 break;\r
157 case 0x13:\r
158 ModeStr = "svc";\r
159 break;\r
160 case 0x16:\r
161 ModeStr = "mon";\r
162 break;\r
163 case 0x17:\r
164 ModeStr = "abt";\r
165 break;\r
166 case 0x1b:\r
167 ModeStr = "und";\r
168 break;\r
169 case 0x1f:\r
170 ModeStr = "sys";\r
171 break;\r
172 \r
173 default:\r
174 ModeStr = "???";\r
175 break;\r
176 }\r
177 \r
178 AsciiStrCat (Str, ModeStr);\r
179 return;\r
180} \r
d5b0f232 181\r
182CHAR8 *\r
183FaultStatusToString (\r
184 IN UINT32 Status\r
185 )\r
186{\r
187 CHAR8 *FaultSource;\r
188\r
189 switch (Status) {\r
190 case 0x01: FaultSource = "Alignment fault"; break;\r
191 case 0x02: FaultSource = "Debug event fault"; break;\r
192 case 0x03: FaultSource = "Access Flag fault on Section"; break;\r
193 case 0x04: FaultSource = "Cache maintenance operation fault[2]"; break;\r
194 case 0x05: FaultSource = "Translation fault on Section"; break;\r
195 case 0x06: FaultSource = "Access Flag fault on Page"; break;\r
196 case 0x07: FaultSource = "Translation fault on Page"; break;\r
197 case 0x08: FaultSource = "Precise External Abort"; break;\r
198 case 0x09: FaultSource = "Domain fault on Section"; break;\r
199 case 0x0b: FaultSource = "Domain fault on Page"; break;\r
200 case 0x0c: FaultSource = "External abort on translation, first level"; break;\r
201 case 0x0d: FaultSource = "Permission fault on Section"; break;\r
202 case 0x0e: FaultSource = "External abort on translation, second level"; break;\r
203 case 0x0f: FaultSource = "Permission fault on Page"; break;\r
204 case 0x16: FaultSource = "Imprecise External Abort"; break;\r
205 default: FaultSource = "No function"; break;\r
206 }\r
207\r
208 return FaultSource;\r
209}\r
210\r
211\r
6f72e28d 212CHAR8 *gExceptionTypeString[] = {\r
213 "Reset",\r
214 "Undefined OpCode",\r
215 "SWI",\r
216 "Prefetch Abort",\r
217 "Data Abort",\r
218 "Undefined",\r
219 "IRQ",\r
220 "FIQ"\r
221};\r
222\r
223\r
224/**\r
225 This is the default action to take on an unexpected exception\r
226 \r
227 Since this is exception context don't do anything crazy like try to allcoate memory.\r
228\r
229 @param ExceptionType Type of the exception\r
230 @param SystemContext Register state at the time of the Exception\r
231\r
232\r
233**/\r
234VOID\r
235DefaultExceptionHandler (\r
236 IN EFI_EXCEPTION_TYPE ExceptionType,\r
237 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
238 )\r
239{\r
d5b0f232 240 UINT32 DfsrStatus;\r
241 BOOLEAN DfsrWrite;\r
6f72e28d 242\r
243 DEBUG ((EFI_D_ERROR, "\n%a Exception PC at 0x%08x CPSR 0x%08x ", gExceptionTypeString[ExceptionType], SystemContext.SystemContextArm->PC, SystemContext.SystemContextArm->CPSR));\r
244 DEBUG_CODE_BEGIN ();\r
245 CHAR8 *Pdb;\r
246 UINT32 ImageBase;\r
247 UINT32 PeCoffSizeOfHeader;\r
248 UINT32 Offset;\r
249 CHAR8 CpsrStr[32]; // char per bit. Lower 5-bits are mode that is a 3 char string\r
250 CHAR8 Buffer[80];\r
251 \r
252 CpsrString (SystemContext.SystemContextArm->CPSR, CpsrStr);\r
253 DEBUG ((EFI_D_ERROR, "%a\n", CpsrStr));\r
254 \r
255 Pdb = GetImageName (SystemContext.SystemContextArm->PC, &ImageBase, &PeCoffSizeOfHeader);\r
256 Offset = SystemContext.SystemContextArm->PC - ImageBase;\r
257 if (Pdb != NULL) {\r
258 DEBUG ((EFI_D_ERROR, "%a\n", Pdb));\r
259\r
260 //\r
261 // A PE/COFF image loads its headers into memory so the headers are \r
262 // included in the linked addressess. ELF and Mach-O images do not\r
263 // include the headers so the first byte of the image is usually\r
264 // text (code). If you look at link maps from ELF or Mach-O images\r
265 // you need to subtact out the size of the PE/COFF header to get\r
266 // get the offset that matches the link map. \r
267 //\r
268 DEBUG ((EFI_D_ERROR, "loaded at 0x%08x (PE/COFF offset) 0x%x (ELF or Mach-O offset) 0x%x", ImageBase, Offset, Offset - PeCoffSizeOfHeader));\r
269 \r
270 // If we come from an image it is safe to show the instruction. We know it should not fault\r
271 if ((SystemContext.SystemContextArm->CPSR & 0x20) == 0) {\r
272 // ARM\r
273 DisassembleArmInstruction ((UINT32 *)(UINTN)SystemContext.SystemContextArm->PC, Buffer, sizeof (Buffer));\r
274 DEBUG ((EFI_D_ERROR, "\n%a", Buffer));\r
275 } else {\r
276 // Thumb\r
d5b0f232 277 DisassembleThumbInstruction ((UINT16 *)(UINTN)SystemContext.SystemContextArm->PC, Buffer, sizeof (Buffer));\r
278 DEBUG ((EFI_D_ERROR, "\n%a", Buffer));\r
6f72e28d 279 }\r
280 }\r
281 DEBUG_CODE_END ();\r
282 DEBUG ((EFI_D_ERROR, "\n R0 0x%08x R1 0x%08x R2 0x%08x R3 0x%08x\n", SystemContext.SystemContextArm->R0, SystemContext.SystemContextArm->R1, SystemContext.SystemContextArm->R2, SystemContext.SystemContextArm->R3));\r
283 DEBUG ((EFI_D_ERROR, " R4 0x%08x R5 0x%08x R6 0x%08x R7 0x%08x\n", SystemContext.SystemContextArm->R4, SystemContext.SystemContextArm->R5, SystemContext.SystemContextArm->R6, SystemContext.SystemContextArm->R7));\r
284 DEBUG ((EFI_D_ERROR, " R8 0x%08x R9 0x%08x R10 0x%08x R11 0x%08x\n", SystemContext.SystemContextArm->R8, SystemContext.SystemContextArm->R9, SystemContext.SystemContextArm->R10, SystemContext.SystemContextArm->R11));\r
285 DEBUG ((EFI_D_ERROR, " R12 0x%08x SP 0x%08x LR 0x%08x PC 0x%08x\n", SystemContext.SystemContextArm->R12, SystemContext.SystemContextArm->SP, SystemContext.SystemContextArm->LR, SystemContext.SystemContextArm->PC));\r
d5b0f232 286 DEBUG ((EFI_D_ERROR, "DFSR 0x%08x DFAR 0x%08x IFSR 0x%08x IFAR 0x%08x\n", SystemContext.SystemContextArm->DFSR, SystemContext.SystemContextArm->DFAR, SystemContext.SystemContextArm->IFSR, SystemContext.SystemContextArm->IFAR));\r
287\r
288 // Bit10 is Status[4] Bit3:0 is Status[3:0]\r
289 DfsrStatus = (SystemContext.SystemContextArm->DFSR & 0xf) | ((SystemContext.SystemContextArm->DFSR >> 6) & 0x10);\r
290 DfsrWrite = (SystemContext.SystemContextArm->DFSR & BIT11) != 0;\r
291 if (DfsrStatus != 0x00) {\r
292 DEBUG ((EFI_D_ERROR, " %a: %a 0x%08x\n", FaultStatusToString (DfsrStatus), DfsrWrite ? "write to" : "read from", SystemContext.SystemContextArm->DFAR));\r
293 }\r
294 if (SystemContext.SystemContextArm->IFSR & 0xf != 0x00) {\r
295 DEBUG ((EFI_D_ERROR, "Instruction %a at 0x%08x, \n", FaultStatusToString (SystemContext.SystemContextArm->IFSR & 0xf), SystemContext.SystemContextArm->IFAR));\r
296 }\r
6f72e28d 297\r
d5b0f232 298 DEBUG ((EFI_D_ERROR, "\n"));\r
6f72e28d 299 ASSERT (FALSE);\r
300}\r
301\r
302\r
303\r
304\r
305/**\r
306 The constructor function caches EFI Debug table information for use in the exception handler.\r
307 \r
308\r
309 @param ImageHandle The firmware allocated handle for the EFI image.\r
310 @param SystemTable A pointer to the EFI System Table.\r
311 \r
312 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
313\r
314**/\r
315EFI_STATUS\r
316EFIAPI\r
317DefaultExceptionHandlerConstructor (\r
318 IN EFI_HANDLE ImageHandle,\r
319 IN EFI_SYSTEM_TABLE *SystemTable\r
320 )\r
321{\r
322 EFI_STATUS Status;\r
323 \r
324 \r
325 Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader);\r
326 if (EFI_ERROR (Status)) {\r
327 gDebugImageTableHeader = NULL;\r
328 }\r
329 return Status;\r
330}\r