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