]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c
BaseTools: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ArmPkg / Library / DefaultExceptionHandlerLib / Arm / 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
619b3998 5 Copyright (c) 2012, ARM Ltd. All rights reserved.<BR>\r
3402aac7 6\r
d6ebcab7 7 This program and the accompanying materials\r
6f72e28d 8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <Uefi.h>\r
6f72e28d 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
31f53880 24#include <Library/UefiBootServicesTableLib.h>\r
00755e1c 25#include <Library/UefiLib.h>\r
6f72e28d 26\r
27#include <Guid/DebugImageInfoTable.h>\r
6f72e28d 28\r
619b3998 29#include <Protocol/DebugSupport.h>\r
30#include <Library/DefaultExceptionHandlerLib.h>\r
6f72e28d 31\r
a1848bc0
LE
32//\r
33// The number of elements in a CHAR8 array, including the terminating NUL, that\r
34// is meant to hold the string rendering of the CPSR.\r
35//\r
36#define CPSR_STRING_SIZE 32\r
37\r
6f72e28d 38typedef struct {\r
39 UINT32 BIT;\r
40 CHAR8 Char;\r
41} CPSR_CHAR;\r
42\r
6f72e28d 43CHAR8 *\r
44GetImageName (\r
c63626b7 45 IN UINTN FaultAddress,\r
46 OUT UINTN *ImageBase,\r
47 OUT UINTN *PeCoffSizeOfHeaders\r
619b3998 48 );\r
6f72e28d 49\r
50/**\r
3402aac7
RC
51 Convert the Current Program Status Register (CPSR) to a string. The string is\r
52 a defacto standard in the ARM world.\r
53\r
6f72e28d 54 It is possible to add extra bits by adding them to CpsrChar array.\r
55\r
56 @param Cpsr ARM CPSR register value\r
a1848bc0
LE
57 @param ReturnStr CPSR_STRING_SIZE byte string that contains string\r
58 version of CPSR\r
6f72e28d 59\r
60**/\r
61VOID\r
62CpsrString (\r
63 IN UINT32 Cpsr,\r
64 OUT CHAR8 *ReturnStr\r
65 )\r
66{\r
11c20f4e 67 UINTN Index;\r
68 CHAR8* Str;\r
69 CHAR8* ModeStr;\r
6f72e28d 70 CPSR_CHAR CpsrChar[] = {\r
71 { 31, 'n' },\r
72 { 30, 'z' },\r
73 { 29, 'c' },\r
74 { 28, 'v' },\r
75\r
76 { 9, 'e' },\r
77 { 8, 'a' },\r
78 { 7, 'i' },\r
79 { 6, 'f' },\r
80 { 5, 't' },\r
81 { 0, '?' }\r
82 };\r
3402aac7 83\r
11c20f4e 84 Str = ReturnStr;\r
85\r
6f72e28d 86 for (Index = 0; CpsrChar[Index].BIT != 0; Index++, Str++) {\r
87 *Str = CpsrChar[Index].Char;\r
88 if ((Cpsr & (1 << CpsrChar[Index].BIT)) != 0) {\r
89 // Concert to upper case if bit is set\r
90 *Str &= ~0x20;\r
91 }\r
92 }\r
3402aac7 93\r
6f72e28d 94 *Str++ = '_';\r
95 *Str = '\0';\r
3402aac7 96\r
6f72e28d 97 switch (Cpsr & 0x1f) {\r
98 case 0x10:\r
99 ModeStr = "usr";\r
100 break;\r
101 case 0x011:\r
102 ModeStr = "fiq";\r
103 break;\r
104 case 0x12:\r
105 ModeStr = "irq";\r
106 break;\r
107 case 0x13:\r
108 ModeStr = "svc";\r
109 break;\r
110 case 0x16:\r
111 ModeStr = "mon";\r
112 break;\r
113 case 0x17:\r
114 ModeStr = "abt";\r
115 break;\r
116 case 0x1b:\r
117 ModeStr = "und";\r
118 break;\r
119 case 0x1f:\r
120 ModeStr = "sys";\r
121 break;\r
3402aac7 122\r
6f72e28d 123 default:\r
124 ModeStr = "???";\r
125 break;\r
126 }\r
3402aac7 127\r
a1848bc0
LE
128 //\r
129 // See the interface contract in the leading comment block.\r
130 //\r
131 AsciiStrCatS (Str, CPSR_STRING_SIZE - (Str - ReturnStr), ModeStr);\r
3402aac7 132}\r
d5b0f232 133\r
134CHAR8 *\r
135FaultStatusToString (\r
136 IN UINT32 Status\r
137 )\r
138{\r
139 CHAR8 *FaultSource;\r
140\r
141 switch (Status) {\r
142 case 0x01: FaultSource = "Alignment fault"; break;\r
143 case 0x02: FaultSource = "Debug event fault"; break;\r
144 case 0x03: FaultSource = "Access Flag fault on Section"; break;\r
145 case 0x04: FaultSource = "Cache maintenance operation fault[2]"; break;\r
146 case 0x05: FaultSource = "Translation fault on Section"; break;\r
147 case 0x06: FaultSource = "Access Flag fault on Page"; break;\r
148 case 0x07: FaultSource = "Translation fault on Page"; break;\r
149 case 0x08: FaultSource = "Precise External Abort"; break;\r
150 case 0x09: FaultSource = "Domain fault on Section"; break;\r
151 case 0x0b: FaultSource = "Domain fault on Page"; break;\r
152 case 0x0c: FaultSource = "External abort on translation, first level"; break;\r
153 case 0x0d: FaultSource = "Permission fault on Section"; break;\r
154 case 0x0e: FaultSource = "External abort on translation, second level"; break;\r
155 case 0x0f: FaultSource = "Permission fault on Page"; break;\r
156 case 0x16: FaultSource = "Imprecise External Abort"; break;\r
157 default: FaultSource = "No function"; break;\r
158 }\r
159\r
160 return FaultSource;\r
161}\r
162\r
11c20f4e 163STATIC CHAR8 *gExceptionTypeString[] = {\r
6f72e28d 164 "Reset",\r
165 "Undefined OpCode",\r
619b3998 166 "SVC",\r
6f72e28d 167 "Prefetch Abort",\r
168 "Data Abort",\r
169 "Undefined",\r
170 "IRQ",\r
171 "FIQ"\r
172};\r
173\r
6f72e28d 174/**\r
175 This is the default action to take on an unexpected exception\r
3402aac7 176\r
6f72e28d 177 Since this is exception context don't do anything crazy like try to allcoate memory.\r
178\r
179 @param ExceptionType Type of the exception\r
180 @param SystemContext Register state at the time of the Exception\r
181\r
182\r
183**/\r
184VOID\r
185DefaultExceptionHandler (\r
186 IN EFI_EXCEPTION_TYPE ExceptionType,\r
187 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
188 )\r
189{\r
7755dfd3 190 CHAR8 Buffer[100];\r
191 UINTN CharCount;\r
d5b0f232 192 UINT32 DfsrStatus;\r
65e27445 193 UINT32 IfsrStatus;\r
d5b0f232 194 BOOLEAN DfsrWrite;\r
d629c283 195 UINT32 PcAdjust = 0;\r
6f72e28d 196\r
7755dfd3 197 CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"\n%a Exception PC at 0x%08x CPSR 0x%08x ",\r
91c38d4e 198 gExceptionTypeString[ExceptionType], SystemContext.SystemContextArm->PC, SystemContext.SystemContextArm->CPSR);\r
31f53880
AB
199 SerialPortWrite ((UINT8 *)Buffer, CharCount);\r
200 if (gST->ConOut != NULL) {\r
201 AsciiPrint (Buffer);\r
202 }\r
7755dfd3 203\r
6f72e28d 204 DEBUG_CODE_BEGIN ();\r
205 CHAR8 *Pdb;\r
206 UINT32 ImageBase;\r
207 UINT32 PeCoffSizeOfHeader;\r
208 UINT32 Offset;\r
a1848bc0
LE
209 CHAR8 CpsrStr[CPSR_STRING_SIZE]; // char per bit. Lower 5-bits are mode\r
210 // that is a 3 char string\r
6f72e28d 211 CHAR8 Buffer[80];\r
097bd461 212 UINT8 *DisAsm;\r
f3198cba 213 UINT32 ItBlock;\r
3402aac7 214\r
6f72e28d 215 CpsrString (SystemContext.SystemContextArm->CPSR, CpsrStr);\r
216 DEBUG ((EFI_D_ERROR, "%a\n", CpsrStr));\r
3402aac7 217\r
6f72e28d 218 Pdb = GetImageName (SystemContext.SystemContextArm->PC, &ImageBase, &PeCoffSizeOfHeader);\r
219 Offset = SystemContext.SystemContextArm->PC - ImageBase;\r
220 if (Pdb != NULL) {\r
221 DEBUG ((EFI_D_ERROR, "%a\n", Pdb));\r
222\r
223 //\r
3402aac7 224 // A PE/COFF image loads its headers into memory so the headers are\r
11c20f4e 225 // included in the linked addresses. ELF and Mach-O images do not\r
6f72e28d 226 // include the headers so the first byte of the image is usually\r
227 // text (code). If you look at link maps from ELF or Mach-O images\r
11c20f4e 228 // you need to subtract out the size of the PE/COFF header to get\r
3402aac7 229 // get the offset that matches the link map.\r
6f72e28d 230 //\r
231 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
3402aac7 232\r
6f72e28d 233 // If we come from an image it is safe to show the instruction. We know it should not fault\r
097bd461 234 DisAsm = (UINT8 *)(UINTN)SystemContext.SystemContextArm->PC;\r
f3198cba 235 ItBlock = 0;\r
236 DisassembleInstruction (&DisAsm, (SystemContext.SystemContextArm->CPSR & BIT5) == BIT5, TRUE, &ItBlock, Buffer, sizeof (Buffer));\r
097bd461 237 DEBUG ((EFI_D_ERROR, "\n%a", Buffer));\r
3402aac7 238\r
d629c283 239 switch (ExceptionType) {\r
240 case EXCEPT_ARM_UNDEFINED_INSTRUCTION:\r
241 case EXCEPT_ARM_SOFTWARE_INTERRUPT:\r
242 case EXCEPT_ARM_PREFETCH_ABORT:\r
243 case EXCEPT_ARM_DATA_ABORT:\r
244 // advance PC past the faulting instruction\r
245 PcAdjust = (UINTN)DisAsm - SystemContext.SystemContextArm->PC;\r
246 break;\r
3402aac7 247\r
d629c283 248 default:\r
249 break;\r
250 }\r
097bd461 251\r
6f72e28d 252 }\r
253 DEBUG_CODE_END ();\r
254 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
255 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
256 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
257 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 258 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
259\r
260 // Bit10 is Status[4] Bit3:0 is Status[3:0]\r
261 DfsrStatus = (SystemContext.SystemContextArm->DFSR & 0xf) | ((SystemContext.SystemContextArm->DFSR >> 6) & 0x10);\r
262 DfsrWrite = (SystemContext.SystemContextArm->DFSR & BIT11) != 0;\r
263 if (DfsrStatus != 0x00) {\r
264 DEBUG ((EFI_D_ERROR, " %a: %a 0x%08x\n", FaultStatusToString (DfsrStatus), DfsrWrite ? "write to" : "read from", SystemContext.SystemContextArm->DFAR));\r
265 }\r
65e27445 266\r
267 IfsrStatus = (SystemContext.SystemContextArm->IFSR & 0xf) | ((SystemContext.SystemContextArm->IFSR >> 6) & 0x10);\r
268 if (IfsrStatus != 0) {\r
269 DEBUG ((EFI_D_ERROR, " Instruction %a at 0x%08x\n", FaultStatusToString (SystemContext.SystemContextArm->IFSR & 0xf), SystemContext.SystemContextArm->IFAR));\r
d5b0f232 270 }\r
6f72e28d 271\r
d5b0f232 272 DEBUG ((EFI_D_ERROR, "\n"));\r
6f72e28d 273 ASSERT (FALSE);\r
3402aac7 274\r
5c8bc8be
AB
275 CpuDeadLoop (); // may return if executing under a debugger\r
276\r
bb02cb80 277 // Clear the error registers that we have already displayed incase some one wants to keep going\r
278 SystemContext.SystemContextArm->DFSR = 0;\r
279 SystemContext.SystemContextArm->IFSR = 0;\r
280\r
3402aac7 281 // If some one is stepping past the exception handler adjust the PC to point to the next instruction\r
d629c283 282 SystemContext.SystemContextArm->PC += PcAdjust;\r
6f72e28d 283}\r