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