1/** @file
2  Default exception handler
3
4  Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
5
6  This program and the accompanying materials
7  are licensed and made available under the terms and conditions of the BSD License
8  which accompanies this distribution.  The full text of the license may be found at
9  http://opensource.org/licenses/bsd-license.php
10
11  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include <Base.h>
17#include <Library/BaseLib.h>
18#include <Library/PrintLib.h>
19#include <Library/ArmDisassemblerLib.h>
20
21CHAR8 *gCondition[] = {
22  "EQ",
23  "NE",
24  "CS",
25  "CC",
26  "MI",
27  "PL",
28  "VS",
29  "VC",
30  "HI",
31  "LS",
32  "GE",
33  "LT",
34  "GT",
35  "LE",
36  "",
37  "2"
38};
39
40#define COND(_a)  gCondition[((_a) >> 28)]
41
42CHAR8 *gReg[] = {
43  "r0",
44  "r1",
45  "r2",
46  "r3",
47  "r4",
48  "r5",
49  "r6",
50  "r7",
51  "r8",
52  "r9",
53  "r10",
54  "r11",
55  "r12",
56  "sp",
57  "lr",
58  "pc"
59};
60
61CHAR8 *gLdmAdr[] = {
62  "DA",
63  "IA",
64  "DB",
65  "IB"
66};
67
68CHAR8 *gLdmStack[] = {
69  "FA",
70  "FD",
71  "EA",
72  "ED"
73};
74
75#define LDM_EXT(_reg, _off) ((_reg == 13) ? gLdmStack[(_off)] : gLdmAdr[(_off)])
76
77
78#define SIGN(_U)  ((_U) ? "" : "-")
79#define WRITE(_W) ((_W) ? "!" : "")
80#define BYTE(_B)  ((_B) ? "B":"")
81#define USER(_B)  ((_B) ? "^" : "")
82
83CHAR8 mMregListStr[4*15 + 1];
84
85CHAR8 *
86MRegList (
87  UINT32  OpCode
88  )
89{
90  UINTN     Index, Start, End;
91  BOOLEAN   First;
92
93  mMregListStr[0] = '\0';
94  AsciiStrCatS (mMregListStr, sizeof mMregListStr, "{");
95  for (Index = 0, First = TRUE; Index <= 15; Index++) {
96    if ((OpCode & (1 << Index)) != 0) {
97      Start = End = Index;
98      for (Index++; ((OpCode & (1 << Index)) != 0) && Index <= 15; Index++) {
99        End = Index;
100      }
101
102      if (!First) {
103        AsciiStrCatS (mMregListStr, sizeof mMregListStr, ",");
104      } else {
105        First = FALSE;
106      }
107
108      if (Start == End) {
109        AsciiStrCatS (mMregListStr, sizeof mMregListStr, gReg[Start]);
110        AsciiStrCatS (mMregListStr, sizeof mMregListStr, ", ");
111      } else {
112        AsciiStrCatS (mMregListStr, sizeof mMregListStr, gReg[Start]);
113        AsciiStrCatS (mMregListStr, sizeof mMregListStr, "-");
114        AsciiStrCatS (mMregListStr, sizeof mMregListStr, gReg[End]);
115      }
116    }
117  }
118  if (First) {
119    AsciiStrCatS (mMregListStr, sizeof mMregListStr, "ERROR");
120  }
121  AsciiStrCatS (mMregListStr, sizeof mMregListStr, "}");
122
123  // BugBug: Make caller pass in buffer it is cleaner
124  return mMregListStr;
125}
126
127CHAR8 *
128FieldMask (
129  IN  UINT32  Mask
130  )
131{
132  return "";
133}
134
135UINT32
136RotateRight (
137  IN UINT32 Op,
138  IN UINT32 Shift
139  )
140{
141  return (Op >> Shift) | (Op << (32 - Shift));
142}
143
144
145/**
146  Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
147  point to next instructin.
148
149  We cheat and only decode instructions that access
150  memory. If the instruction is not found we dump the instruction in hex.
151
152  @param  OpCodePtr   Pointer to pointer of ARM instruction to disassemble.
153  @param  Buf         Buffer to sprintf disassembly into.
154  @param  Size        Size of Buf in bytes.
155  @param  Extended    TRUE dump hex for instruction too.
156
157**/
158VOID
159DisassembleArmInstruction (
160  IN  UINT32    **OpCodePtr,
161  OUT CHAR8     *Buf,
162  OUT UINTN     Size,
163  IN  BOOLEAN   Extended
164  )
165{
166  UINT32    OpCode = **OpCodePtr;
167  CHAR8     *Type, *Root;
168  BOOLEAN   I, P, U, B, W, L, S, H;
169  UINT32    Rn, Rd, Rm;
170  UINT32    imode, offset_8, offset_12;
171  UINT32    Index;
172  UINT32    shift_imm, shift;
173
174  I = (OpCode & BIT25) == BIT25;
175  P = (OpCode & BIT24) == BIT24;
176  U = (OpCode & BIT23) == BIT23;
177  B = (OpCode & BIT22) == BIT22;  // Also called S
178  W = (OpCode & BIT21) == BIT21;
179  L = (OpCode & BIT20) == BIT20;
180  S = (OpCode & BIT6) == BIT6;
181  H = (OpCode & BIT5) == BIT5;
182  Rn = (OpCode >> 16) & 0xf;
183  Rd = (OpCode >> 12) & 0xf;
184  Rm = (OpCode & 0xf);
185
186
187  if (Extended) {
188    Index = AsciiSPrint (Buf, Size, "0x%08x   ", OpCode);
189    Buf += Index;
190    Size -= Index;
191  }
192
193  // LDREX, STREX
194  if ((OpCode  & 0x0fe000f0) == 0x01800090) {
195    if (L) {
196      // A4.1.27  LDREX{<cond>} <Rd>, [<Rn>]
197      AsciiSPrint (Buf, Size, "LDREX%a %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn]);
198    } else {
199     // A4.1.103  STREX{<cond>} <Rd>, <Rm>, [<Rn>]
200      AsciiSPrint (Buf, Size, "STREX%a %a, %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn], gReg[Rn]);
201    }
202    return;
203  }
204
205  // LDM/STM
206  if ((OpCode  & 0x0e000000) == 0x08000000) {
207    if (L) {
208      // A4.1.20 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers>
209      // A4.1.21 LDM{<cond>}<addressing_mode> <Rn>, <registers_without_pc>^
210      // A4.1.22 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers_and_pc>^
211      AsciiSPrint (Buf, Size, "LDM%a%a, %a%a, %a", COND (OpCode), LDM_EXT (Rn ,(OpCode >> 23) & 3), gReg[Rn], WRITE (W), MRegList (OpCode), USER (B));
212    } else {
213      // A4.1.97 STM{<cond>}<addressing_mode> <Rn>{!}, <registers>
214      // A4.1.98 STM{<cond>}<addressing_mode> <Rn>, <registers>^
215      AsciiSPrint (Buf, Size, "STM%a%a, %a%a, %a", COND (OpCode), LDM_EXT (Rn ,(OpCode >> 23) & 3), gReg[Rn], WRITE (W), MRegList (OpCode), USER (B));
216    }
217    return;
218  }
219
220  // LDR/STR Address Mode 2
221  if ( ((OpCode  & 0x0c000000) == 0x04000000) || ((OpCode & 0xfd70f000 ) == 0xf550f000) ) {
222    offset_12 = OpCode & 0xfff;
223    if ((OpCode & 0xfd70f000 ) == 0xf550f000) {
224      Index = AsciiSPrint (Buf, Size, "PLD");
225    } else {
226      Index = AsciiSPrint (Buf, Size, "%a%a%a%a %a, ", L ? "LDR" : "STR", COND (OpCode), BYTE (B), (!(P) && W) ? "T":"", gReg[Rd]);
227    }
228    if (P) {
229      if (!I) {
230        // A5.2.2 [<Rn>, #+/-<offset_12>]
231        // A5.2.5 [<Rn>, #+/-<offset_12>]
232        AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x]%a", gReg[Rn], SIGN (U), offset_12, WRITE (W));
233      } else if ((OpCode & 0x03000ff0) == 0x03000000) {
234        // A5.2.3 [<Rn>, +/-<Rm>]
235        // A5.2.6 [<Rn>, +/-<Rm>]!
236        AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a]%a", gReg[Rn], SIGN (U), WRITE (W));
237      } else {
238        // A5.2.4 [<Rn>, +/-<Rm>, LSL #<shift_imm>]
239        // A5.2.7 [<Rn>, +/-<Rm>, LSL #<shift_imm>]!
240        shift_imm = (OpCode >> 7) & 0x1f;
241        shift = (OpCode >> 5) & 0x3;
242        if (shift == 0x0) {
243          Type = "LSL";
244        } else if (shift == 0x1) {
245          Type = "LSR";
246          if (shift_imm == 0) {
247            shift_imm = 32;
248          }
249        } else if (shift == 0x12) {
250          Type = "ASR";
251        } else if (shift_imm == 0) {
252          AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, RRX]%a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W));
253          return;
254        } else {
255          Type = "ROR";
256        }
257
258        AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, #%d]%a", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm, WRITE (W));
259      }
260    } else {  // !P
261      if (!I) {
262        // A5.2.8  [<Rn>], #+/-<offset_12>
263        AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x", gReg[Rn], SIGN (U), offset_12);
264      } else if ((OpCode & 0x03000ff0) == 0x03000000) {
265        // A5.2.9  [<Rn>], +/-<Rm>
266        AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]);
267      } else {
268        // A5.2.10 [<Rn>], +/-<Rm>, LSL #<shift_imm>
269        shift_imm = (OpCode >> 7) & 0x1f;
270        shift = (OpCode >> 5) & 0x3;
271
272        if (shift == 0x0) {
273          Type = "LSL";
274        } else if (shift == 0x1) {
275          Type = "LSR";
276          if (shift_imm == 0) {
277            shift_imm = 32;
278          }
279        } else if (shift == 0x12) {
280          Type = "ASR";
281        } else if (shift_imm == 0) {
282          AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, RRX", gReg[Rn], SIGN (U), gReg[Rm]);
283          // FIx me
284          return;
285        } else {
286          Type = "ROR";
287        }
288
289        AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, #%d", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm);
290      }
291    }
292    return;
293  }
294
295  if ((OpCode  & 0x0e000000) == 0x00000000) {
296    // LDR/STR address mode 3
297    // LDR|STR{<cond>}H|SH|SB|D <Rd>, <addressing_mode>
298    if (L) {
299      if (!S) {
300        Root = "LDR%aH %a, ";
301      } else if (!H) {
302        Root = "LDR%aSB %a, ";
303      } else {
304        Root = "LDR%aSH %a, ";
305      }
306    } else {
307      if (!S) {
308        Root = "STR%aH %a ";
309      } else if (!H) {
310        Root = "LDR%aD %a ";
311      } else {
312        Root = "STR%aD %a ";
313      }
314    }
315
316    Index = AsciiSPrint (Buf, Size, Root, COND (OpCode), gReg[Rd]);
317
318    S = (OpCode & BIT6) == BIT6;
319    H = (OpCode & BIT5) == BIT5;
320    offset_8 = ((OpCode >> 4) | (OpCode * 0xf)) & 0xff;
321    if (P & !W) {
322      // Immediate offset/index
323      if (B) {
324        // A5.3.2  [<Rn>, #+/-<offset_8>]
325        // A5.3.4  [<Rn>, #+/-<offset_8>]!
326        AsciiSPrint  (&Buf[Index], Size - Index, "[%a, #%a%d]%a", gReg[Rn], SIGN (U), offset_8, WRITE (W));
327      } else {
328        // A5.3.3  [<Rn>, +/-<Rm>]
329        // A5.3.5  [<Rn>, +/-<Rm>]!
330        AsciiSPrint  (&Buf[Index], Size - Index, "[%a, #%a%]a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W));
331      }
332    } else {
333      // Register offset/index
334      if (B) {
335        // A5.3.6 [<Rn>], #+/-<offset_8>
336        AsciiSPrint  (&Buf[Index], Size - Index, "[%a], #%a%d", gReg[Rn], SIGN (U), offset_8);
337      } else {
338        // A5.3.7 [<Rn>], +/-<Rm>
339        AsciiSPrint  (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]);
340      }
341    }
342    return;
343  }
344
345  if ((OpCode  & 0x0fb000f0) == 0x01000050) {
346    // A4.1.108  SWP   SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
347    // A4.1.109  SWPB  SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
348    AsciiSPrint (Buf, Size, "SWP%a%a %a, %a, [%a]", COND (OpCode), BYTE (B), gReg[Rd], gReg[Rm], gReg[Rn]);
349    return;
350  }
351
352  if ((OpCode  & 0xfe5f0f00) == 0xf84d0500) {
353    // A4.1.90 SRS SRS<addressing_mode> #<mode>{!}
354    AsciiSPrint (Buf, Size, "SRS%a #0x%x%a", gLdmStack[(OpCode >> 23) & 3], OpCode & 0x1f, WRITE (W));
355    return;
356  }
357
358  if ((OpCode  & 0xfe500f00) == 0xf8100500) {
359    // A4.1.59 RFE<addressing_mode> <Rn>{!}
360    AsciiSPrint (Buf, Size, "RFE%a %a", gLdmStack[(OpCode >> 23) & 3], gReg[Rn], WRITE (W));
361    return;
362  }
363
364  if ((OpCode  & 0xfff000f0) == 0xe1200070) {
365    // A4.1.7 BKPT <immed_16>
366    AsciiSPrint (Buf, Size, "BKPT %x", ((OpCode >> 8) | (OpCode & 0xf)) & 0xffff);
367    return;
368  }
369
370  if ((OpCode  & 0xfff10020) == 0xf1000000) {
371    // A4.1.16 CPS<effect> <iflags> {, #<mode>}
372    if (((OpCode >> 6) & 0x7) == 0) {
373      AsciiSPrint (Buf, Size, "CPS #0x%x", (OpCode & 0x2f));
374    } else {
375      imode = (OpCode >> 18) & 0x3;
376      Index = AsciiSPrint (Buf, Size, "CPS%a %a%a%a", (imode == 3) ? "ID":"IE", (OpCode & BIT8) ? "A":"", (OpCode & BIT7) ? "I":"", (OpCode & BIT6) ? "F":"");
377      if ((OpCode & BIT17) != 0) {
378        AsciiSPrint (&Buf[Index], Size - Index, ", #0x%x", OpCode & 0x1f);
379      }
380    }
381    return;
382  }
383
384  if ((OpCode  & 0x0f000000) == 0x0f000000) {
385    // A4.1.107 SWI{<cond>} <immed_24>
386    AsciiSPrint (Buf, Size, "SWI%a %x", COND (OpCode), OpCode & 0x00ffffff);
387    return;
388  }
389
390  if ((OpCode  & 0x0fb00000) == 0x01000000) {
391    // A4.1.38 MRS{<cond>} <Rd>, CPSR  MRS{<cond>} <Rd>, SPSR
392    AsciiSPrint (Buf, Size, "MRS%a %a, %a", COND (OpCode), gReg[Rd], B ? "SPSR" : "CPSR");
393    return;
394  }
395
396
397  if ((OpCode  & 0x0db00000) == 0x03200000) {
398    // A4.1.38 MSR{<cond>} CPSR_<fields>, #<immediate> MSR{<cond>} CPSR_<fields>, <Rm>
399    if (I) {
400      // MSR{<cond>} CPSR_<fields>, #<immediate>
401      AsciiSPrint (Buf, Size, "MRS%a %a_%a, #0x%x", COND (OpCode),  B ? "SPSR" : "CPSR", FieldMask ((OpCode >> 16) & 0xf), RotateRight (OpCode & 0xf, ((OpCode >> 8) & 0xf) *2));
402    } else {
403      // MSR{<cond>} CPSR_<fields>, <Rm>
404      AsciiSPrint (Buf, Size, "MRS%a %a_%a, %a", COND (OpCode), B ? "SPSR" : "CPSR", gReg[Rd]);
405    }
406    return;
407  }
408
409  if ((OpCode  & 0xff000010) == 0xfe000000) {
410    // A4.1.13 CDP{<cond>} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
411    AsciiSPrint (Buf, Size, "CDP%a 0x%x, 0x%x, CR%d, CR%d, CR%d, 0x%x", COND (OpCode), (OpCode >> 8) & 0xf, (OpCode >> 20) & 0xf, Rn, Rd, Rm, (OpCode >> 5) &0x7);
412    return;
413  }
414
415  if ((OpCode  & 0x0e000000) == 0x0c000000) {
416    // A4.1.19 LDC and A4.1.96 SDC
417    if ((OpCode & 0xf0000000) == 0xf0000000) {
418      Index = AsciiSPrint (Buf, Size, "%a2 0x%x, CR%d, ", L ? "LDC":"SDC", (OpCode >> 8) & 0xf, Rd);
419    } else {
420      Index = AsciiSPrint (Buf, Size, "%a%a 0x%x, CR%d, ",  L ? "LDC":"SDC", COND (OpCode), (OpCode >> 8) & 0xf, Rd);
421    }
422
423    if (!P) {
424      if (!W) {
425        // A5.5.5.5 [<Rn>], <option>
426      AsciiSPrint (&Buf[Index], Size - Index, "[%a], {0x%x}", gReg[Rn], OpCode & 0xff);
427      } else {
428        // A.5.5.4  [<Rn>], #+/-<offset_8>*4
429      AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x*4", gReg[Rn], SIGN (U), OpCode & 0xff);
430      }
431    } else {
432      // A5.5.5.2 [<Rn>, #+/-<offset_8>*4 ]!
433      AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x*4]%a", gReg[Rn], SIGN (U), OpCode & 0xff, WRITE (W));
434    }
435
436  }
437
438  if ((OpCode  & 0x0f000010) == 0x0e000010) {
439    // A4.1.32 MRC2, MCR2
440    AsciiSPrint (Buf, Size, "%a%a 0x%x, 0x%x, %a, CR%d, CR%d, 0x%x", L ? "MRC":"MCR", COND (OpCode), (OpCode >> 8) & 0xf, (OpCode >> 20) & 0xf, gReg[Rd], Rn, Rm, (OpCode >> 5) &0x7);
441    return;
442  }
443
444  if ((OpCode  & 0x0ff00000) == 0x0c400000) {
445    // A4.1.33 MRRC2, MCRR2
446    AsciiSPrint (Buf, Size, "%a%a 0x%x, 0x%x, %a, %a, CR%d", L ? "MRRC":"MCRR", COND (OpCode), (OpCode >> 4) & 0xf, (OpCode >> 20) & 0xf, gReg[Rd], gReg[Rn], Rm);
447    return;
448  }
449
450  AsciiSPrint (Buf, Size, "Faulting OpCode 0x%08x", OpCode);
451
452  *OpCodePtr += 1;
453  return;
454}
455
456