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