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