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